Add stage 06: Lua bootstrap
The goal of stage 06 is to try parse zig synax in lua. I pulled in lpeglable 1.2.0 and parser-gen off github to get started. All of this needs to be cleaned up rather soon. Lua boostraps using tcc and musl from the previous stage. Since musl 0.6.0 doesn't support dynamic linking this build of lua doesn't support shared libraries. I couldn't easily patch musl with dlopen and friends so instead I link statically and call deps with c api.
This commit is contained in:
parent
2ae045cf8a
commit
e6b88d5a0f
170 changed files with 72518 additions and 2 deletions
20
06/parser-gen/LICENSE
Normal file
20
06/parser-gen/LICENSE
Normal file
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Benas Vaitkevicius
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
397
06/parser-gen/README.md
Normal file
397
06/parser-gen/README.md
Normal file
|
@ -0,0 +1,397 @@
|
|||
# parser-gen
|
||||
|
||||
A Lua parser generator that makes it possible to describe grammars in a [PEG](https://en.wikipedia.org/wiki/Parsing_expression_grammar) syntax. The tool will parse a given input using a provided grammar and if the matching is successful produce an AST as an output with the captured values using [Lpeg](http://www.inf.puc-rio.br/~roberto/lpeg/). If the matching fails, labelled errors can be used in the grammar to indicate failure position, and recovery grammars are generated to continue parsing the input using [LpegLabel](https://github.com/sqmedeiros/lpeglabel). The tool can also automatically generate error labels and recovery grammars for LL(1) grammars.
|
||||
|
||||
parser-gen is a [GSoC 2017](https://developers.google.com/open-source/gsoc/) project, and was completed with the help of my mentor [@sqmedeiros](https://github.com/sqmedeiros) from [LabLua](http://www.lua.inf.puc-rio.br/). A blog documenting the progress of the project can be found [here](https://parsergen.blogspot.com/2017/08/parser-generator-based-on-lpeglabel.html).
|
||||
|
||||
---
|
||||
# Table of contents
|
||||
|
||||
* [Requirements](#requirements)
|
||||
|
||||
* [Syntax](#syntax)
|
||||
|
||||
* [Grammar Syntax](#grammar-syntax)
|
||||
|
||||
* [Example: Tiny Parser](#example-tiny-parser)
|
||||
|
||||
# Requirements
|
||||
```
|
||||
lua >= 5.1
|
||||
lpeglabel >= 1.2.0
|
||||
```
|
||||
# Syntax
|
||||
|
||||
### compile
|
||||
|
||||
This function generates a PEG parser from the grammar description.
|
||||
|
||||
```lua
|
||||
local pg = require "parser-gen"
|
||||
grammar = pg.compile(input,definitions [, errorgen, noast])
|
||||
```
|
||||
*Arguments*:
|
||||
|
||||
`input` - A string containing a PEG grammar description. For complete PEG syntax see the grammar section of this document.
|
||||
|
||||
`definitions` - table of custom functions and definitions used inside the grammar, for example {equals=equals}, where equals is a function.
|
||||
|
||||
`errorgen` - **EXPERIMENTAL** optional boolean parameter(default:false), when enabled generates error labels automatically. Works well only on LL(1) grammars. Custom error labels have precedence over automatically generated ones.
|
||||
|
||||
`noast` - optional boolean parameter(default:false), when enabled does not generate an AST for the parse.
|
||||
|
||||
*Output*:
|
||||
|
||||
`grammar` - a compiled grammar on success, throws error on failure.
|
||||
|
||||
### setlabels
|
||||
|
||||
If custom error labels are used, the function *setlabels* allows setting their description (and custom recovery pattern):
|
||||
```lua
|
||||
pg.setlabels(t)
|
||||
```
|
||||
Example table of a simple error and one with a custom recovery expression:
|
||||
```lua
|
||||
-- grammar rule: " ifexp <- 'if' exp 'then'^missingThen stmt 'end'^missingEnd "
|
||||
local t = {
|
||||
missingEnd = "Missing 'end' in if expression",
|
||||
missingThen = {"Missing 'then' in if expression", " (!stmt .)* "} -- a custom recovery pattern
|
||||
}
|
||||
pg.setlabels(t)
|
||||
```
|
||||
If the recovery pattern is not set, then the one specified by the rule SYNC will be used. It is by default set to:
|
||||
```lua
|
||||
SKIP <- %s / %nl -- a space ' ' or newline '\n' character
|
||||
SYNC <- .? (!SKIP .)*
|
||||
```
|
||||
Learn more about special rules in the grammar section.
|
||||
|
||||
### parse
|
||||
|
||||
This operation attempts to match a grammar to the given input.
|
||||
|
||||
```lua
|
||||
result, errors = pg.parse(input, grammar [, errorfunction])
|
||||
```
|
||||
*Arguments*:
|
||||
|
||||
`input` - an input string that the tool will attempt to parse.
|
||||
|
||||
`grammar` - a compiled grammar.
|
||||
|
||||
`errorfunction` - an optional function that will be called if an error is encountered, with the arguments `desc` for the error description set using `setlabels()`; location indicators `line` and `col`; the remaining string before failure `sfail` and a custom recovery expression `trec` if available.
|
||||
Example:
|
||||
```lua
|
||||
local errs = 0
|
||||
local function printerror(desc,line,col,sfail,trec)
|
||||
errs = errs+1
|
||||
print("Error #"..errs..": "..desc.." before '"..sfail.."' on line "..line.."(col "..col..")")
|
||||
end
|
||||
|
||||
result, errors = pg.parse(input,grammar,printerror)
|
||||
```
|
||||
*Output*:
|
||||
|
||||
If the parse is succesful, the function returns an abstract syntax tree containing the captures `result` and a table of any encountered `errors`. If the parse was unsuccessful, `result` is going to be **nil**.
|
||||
Also, if the `noast` option is enabled when compiling the grammar, the function will then produce the longest match length or any custom captures used.
|
||||
|
||||
### calcline
|
||||
|
||||
Calculates line and column information regarding position i of the subject (exported from the relabel module).
|
||||
|
||||
```lua
|
||||
line, col = pg.calcline(subject, position)
|
||||
```
|
||||
*Arguments*:
|
||||
|
||||
`subject` - subject string
|
||||
|
||||
`position` - position inside the string, for example, the one given by automatic AST generation.
|
||||
|
||||
### usenodes
|
||||
|
||||
When AST generation is enabled, this function will enable the "node" mode, where only rules tagged with a `node` prefix will generate AST entries. Must be used before compiling the grammar.
|
||||
|
||||
```lua
|
||||
pg.usenodes(value)
|
||||
```
|
||||
*Arguments*:
|
||||
|
||||
`value` - a boolean value that enables or disables this function
|
||||
|
||||
# Grammar Syntax
|
||||
|
||||
The grammar used for this tool is described using a PEG-like syntax, that is identical to the one provided by the [re](http://www.inf.puc-rio.br/~roberto/lpeg/re.html) module, with an extension of labelled failures provided by [relabel](https://github.com/sqmedeiros/lpeglabel) module (except numbered labels). That is, all grammars that work with relabel should work with parser-gen as long as numbered error labels are not used, as they are not supported by parser-gen.
|
||||
|
||||
Since a parser generated with parser-gen automatically consumes space characters, builds ASTs and generates errors, additional extensions have been added based on the [ANTLR](http://www.antlr.org/) syntax.
|
||||
|
||||
### Basic syntax
|
||||
|
||||
The syntax of parser-gen grammars is somewhat similar to regex syntax. The next table summarizes the tools syntax. A p represents an arbitrary pattern; num represents a number (`[0-9]+`); name represents an identifier (`[a-zA-Z][a-zA-Z0-9_]*`).`defs` is the definitions table provided when compiling the grammar. Note that error names must be set using `setlabels()` before compiling the grammar. Constructions are listed in order of decreasing precedence.
|
||||
|
||||
<table border="1">
|
||||
<tbody><tr><td><b>Syntax</b></td><td><b>Description</b></td></tr>
|
||||
<tr><td><code>( p )</code></td> <td>grouping</td></tr>
|
||||
<tr><td><code>'string'</code></td> <td>literal string</td></tr>
|
||||
<tr><td><code>"string"</code></td> <td>literal string</td></tr>
|
||||
<tr><td><code>[class]</code></td> <td>character class</td></tr>
|
||||
<tr><td><code>.</code></td> <td>any character</td></tr>
|
||||
<tr><td><code>%name</code></td>
|
||||
<td>pattern <code>defs[name]</code> or a pre-defined pattern</td></tr>
|
||||
<tr><td><code>name</code></td><td>non terminal</td></tr>
|
||||
<tr><td><code><name></code></td><td>non terminal</td></tr>
|
||||
<tr><td><code>%{name}</code></td> <td>error label</td></tr>
|
||||
<tr><td><code>{}</code></td> <td>position capture</td></tr>
|
||||
<tr><td><code>{ p }</code></td> <td>simple capture</td></tr>
|
||||
<tr><td><code>{: p :}</code></td> <td>anonymous group capture</td></tr>
|
||||
<tr><td><code>{:name: p :}</code></td> <td>named group capture</td></tr>
|
||||
<tr><td><code>{~ p ~}</code></td> <td>substitution capture</td></tr>
|
||||
<tr><td><code>{| p |}</code></td> <td>table capture</td></tr>
|
||||
<tr><td><code>=name</code></td> <td>back reference
|
||||
</td></tr>
|
||||
<tr><td><code>p ?</code></td> <td>optional match</td></tr>
|
||||
<tr><td><code>p *</code></td> <td>zero or more repetitions</td></tr>
|
||||
<tr><td><code>p +</code></td> <td>one or more repetitions</td></tr>
|
||||
<tr><td><code>p^num</code></td> <td>exactly <code>n</code> repetitions</td></tr>
|
||||
<tr><td><code>p^+num</code></td>
|
||||
<td>at least <code>n</code> repetitions</td></tr>
|
||||
<tr><td><code>p^-num</code></td>
|
||||
<td>at most <code>n</code> repetitions</td></tr>
|
||||
<tr><td><code>p^name</code></td> <td>match p or throw error label name.</td></tr>
|
||||
<tr><td><code>p -> 'string'</code></td> <td>string capture</td></tr>
|
||||
<tr><td><code>p -> "string"</code></td> <td>string capture</td></tr>
|
||||
<tr><td><code>p -> num</code></td> <td>numbered capture</td></tr>
|
||||
<tr><td><code>p -> name</code></td> <td>function/query/string capture
|
||||
equivalent to <code>p / defs[name]</code></td></tr>
|
||||
<tr><td><code>p => name</code></td> <td>match-time capture
|
||||
equivalent to <code>lpeg.Cmt(p, defs[name])</code></td></tr>
|
||||
<tr><td><code>& p</code></td> <td>and predicate</td></tr>
|
||||
<tr><td><code>! p</code></td> <td>not predicate</td></tr>
|
||||
<tr><td><code>p1 p2</code></td> <td>concatenation</td></tr>
|
||||
<tr><td><code>p1 //{name [, name, ...]} p2</code></td> <td>specifies recovery pattern p2 for p1
|
||||
when one of the labels is thrown</td></tr>
|
||||
<tr><td><code>p1 / p2</code></td> <td>ordered choice</td></tr>
|
||||
<tr><td>(<code>name <- p</code>)<sup>+</sup></td> <td>grammar</td></tr>
|
||||
</tbody></table>
|
||||
|
||||
|
||||
The grammar below is used to match balanced parenthesis
|
||||
|
||||
```lua
|
||||
balanced <- "(" ([^()] / balanced)* ")"
|
||||
```
|
||||
For more examples check out the [re](http://www.inf.puc-rio.br/~roberto/lpeg/re.html) page, see the Tiny parser below or the [Lua parser](https://github.com/vsbenas/parser-gen/blob/master/parsers/lua-parser.lua) writen with this tool.
|
||||
|
||||
### Error labels
|
||||
|
||||
Error labels are provided by the relabel function %{errorname} (errorname must follow `[A-Za-z][A-Za-z0-9_]*` format). Usually we use error labels in a syntax like `'a' ('b' / %{errB}) 'c'`, which throws an error label if `'b'` is not matched. This syntax is quite complicated so an additional syntax is allowed `'a' 'b'^errB 'c'`, which allows cleaner description of grammars. Note: all errors must be defined in a table using parser-gen.setlabels() before compiling and parsing the grammar.
|
||||
|
||||
### Tokens
|
||||
|
||||
Non-terminals with names in all capital letters, i.e. `[A-Z]+`, are considered tokens and are treated as a single object in parsing. That is, the whole string matched by a token is captured in a single AST entry and space characters are not consumed. Consider two examples:
|
||||
```lua
|
||||
-- a token non-terminal
|
||||
grammar = pg.compile [[
|
||||
WORD <- [A-Z]+
|
||||
]]
|
||||
res, _ = pg.parse("AA A", grammar) -- outputs {rule="WORD", "AA"}
|
||||
```
|
||||
```lua
|
||||
-- a non-token non-terminal
|
||||
grammar = pg.compile [[
|
||||
word <- [A-Z]+
|
||||
]]
|
||||
res, _ = pg.parse("AA A", grammar) -- outputs {rule="word", "A", "A", "A"}
|
||||
```
|
||||
|
||||
### Fragments
|
||||
|
||||
If a token definition is followed by a `fragment` keyword, then the parser does not build an AST entry for that token. Essentially, these rules are used to simplify grammars without building unnecessarily complicated ASTS. Example of `fragment` usage:
|
||||
```lua
|
||||
grammar = pg.compile [[
|
||||
WORD <- LETTER+
|
||||
fragment LETTER <- [A-Z]
|
||||
]]
|
||||
res, _ = pg.parse("AA A", grammar) -- outputs {rule="WORD", "AA"}
|
||||
```
|
||||
Without using `fragment`:
|
||||
```lua
|
||||
grammar = pg.compile [[
|
||||
WORD <- LETTER+
|
||||
LETTER <- [A-Z]
|
||||
]]
|
||||
res, _ = pg.parse("AA A", grammar) -- outputs {rule="WORD", {rule="LETTER", "A"}, {rule="LETTER", "A"}}
|
||||
|
||||
```
|
||||
|
||||
### Nodes
|
||||
|
||||
When node mode is enabled using `pg.usenodes(true)` only rules prefixed with a `node` keyword will generate AST entries:
|
||||
```lua
|
||||
grammar = pg.compile [[
|
||||
node WORD <- LETTER+
|
||||
LETTER <- [A-Z]
|
||||
]]
|
||||
res, _ = pg.parse("AA A", grammar) -- outputs {rule="WORD", "AA"}
|
||||
```
|
||||
### Special rules
|
||||
|
||||
There are two special rules used by the grammar:
|
||||
|
||||
#### SKIP
|
||||
|
||||
The `SKIP` rule identifies which characters to skip in a grammar. For example, most programming languages do not take into acount any space or newline characters. By default, SKIP is set to:
|
||||
```lua
|
||||
SKIP <- %s / %nl
|
||||
```
|
||||
This rule can be extended to contain semicolons `';'`, comments, or any other patterns that the parser can safely ignore.
|
||||
|
||||
Character skipping can be disabled by using:
|
||||
```lua
|
||||
SKIP <- ''
|
||||
```
|
||||
|
||||
#### SYNC
|
||||
|
||||
This rule specifies the general recovery expression both for custom errors and automatically generated ones. By default:
|
||||
```lua
|
||||
SYNC <- .? (!SKIP .)*
|
||||
```
|
||||
The default SYNC rule consumes any characters until the next character matched by SKIP, usually a space or a newline. That means, if some statement in a program is invalid, the parser will continue parsing after a space or a newline character.
|
||||
|
||||
For some programming languages it might be useful to skip to a semicolon or a keyword, since they usually indicate the end of a statement, so SYNC could be something like:
|
||||
```lua
|
||||
HELPER <- ';' / 'end' / SKIP -- etc
|
||||
SYNC <- (!HELPER .)* SKIP* -- we can consume the spaces after syncing with them as well
|
||||
```
|
||||
|
||||
Recovery grammars can be disabled by using:
|
||||
```lua
|
||||
SYNC <- ''
|
||||
```
|
||||
# Example: Tiny parser
|
||||
|
||||
Below is the full code from *parsers/tiny-parser.lua*:
|
||||
```lua
|
||||
local pg = require "parser-gen"
|
||||
local peg = require "peg-parser"
|
||||
local errs = {errMissingThen = "Missing Then"} -- one custom error
|
||||
pg.setlabels(errs)
|
||||
|
||||
--warning: experimental error generation function is enabled. If the grammar isn't LL(1), set errorgen to false
|
||||
local errorgen = true
|
||||
|
||||
local grammar = pg.compile([[
|
||||
|
||||
program <- stmtsequence !.
|
||||
stmtsequence <- statement (';' statement)*
|
||||
statement <- ifstmt / repeatstmt / assignstmt / readstmt / writestmt
|
||||
ifstmt <- 'if' exp 'then'^errMissingThen stmtsequence elsestmt? 'end'
|
||||
elsestmt <- ('else' stmtsequence)
|
||||
repeatstmt <- 'repeat' stmtsequence 'until' exp
|
||||
assignstmt <- IDENTIFIER ':=' exp
|
||||
readstmt <- 'read' IDENTIFIER
|
||||
writestmt <- 'write' exp
|
||||
exp <- simpleexp (COMPARISONOP simpleexp)*
|
||||
COMPARISONOP <- '<' / '='
|
||||
simpleexp <- term (ADDOP term)*
|
||||
ADDOP <- [+-]
|
||||
term <- factor (MULOP factor)*
|
||||
MULOP <- [*/]
|
||||
factor <- '(' exp ')' / NUMBER / IDENTIFIER
|
||||
|
||||
NUMBER <- '-'? [0-9]+
|
||||
KEYWORDS <- 'if' / 'repeat' / 'read' / 'write' / 'then' / 'else' / 'end' / 'until'
|
||||
RESERVED <- KEYWORDS ![a-zA-Z]
|
||||
IDENTIFIER <- !RESERVED [a-zA-Z]+
|
||||
HELPER <- ';' / %nl / %s / KEYWORDS / !.
|
||||
SYNC <- (!HELPER .)*
|
||||
|
||||
]], _, errorgen)
|
||||
|
||||
local errors = 0
|
||||
local function printerror(desc,line,col,sfail,trec)
|
||||
errors = errors+1
|
||||
print("Error #"..errors..": "..desc.." on line "..line.."(col "..col..")")
|
||||
end
|
||||
|
||||
|
||||
local function parse(input)
|
||||
errors = 0
|
||||
result, errors = pg.parse(input,grammar,printerror)
|
||||
return result, errors
|
||||
end
|
||||
|
||||
if arg[1] then
|
||||
-- argument must be in quotes if it contains spaces
|
||||
res, errs = parse(arg[1])
|
||||
peg.print_t(res)
|
||||
peg.print_r(errs)
|
||||
end
|
||||
local ret = {parse=parse}
|
||||
return ret
|
||||
```
|
||||
For input: `lua tiny-parser-nocap.lua "if a b:=1"` we get:
|
||||
```lua
|
||||
Error #1: Missing Then on line 1(col 6)
|
||||
Error #2: Expected stmtsequence on line 1(col 9)
|
||||
Error #3: Expected 'end' on line 1(col 9)
|
||||
-- ast:
|
||||
rule='program',
|
||||
pos=1,
|
||||
{
|
||||
rule='stmtsequence',
|
||||
pos=1,
|
||||
{
|
||||
rule='statement',
|
||||
pos=1,
|
||||
{
|
||||
rule='ifstmt',
|
||||
pos=1,
|
||||
'if',
|
||||
{
|
||||
rule='exp',
|
||||
pos=4,
|
||||
{
|
||||
rule='simpleexp',
|
||||
pos=4,
|
||||
{
|
||||
rule='term',
|
||||
pos=4,
|
||||
{
|
||||
rule='factor',
|
||||
pos=4,
|
||||
{
|
||||
rule='IDENTIFIER',
|
||||
pos=4,
|
||||
'a',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
-- error table:
|
||||
[1] => {
|
||||
[msg] => 'Missing Then' -- custom error is used over the automatically generated one
|
||||
[line] => '1'
|
||||
[col] => '6'
|
||||
[label] => 'errMissingThen'
|
||||
}
|
||||
[2] => {
|
||||
[msg] => 'Expected stmtsequence' -- automatically generated errors
|
||||
[line] => '1'
|
||||
[col] => '9'
|
||||
[label] => 'errorgen6'
|
||||
}
|
||||
[3] => {
|
||||
[msg] => 'Expected 'end''
|
||||
[line] => '1'
|
||||
[col] => '9'
|
||||
[label] => 'errorgen4'
|
||||
}
|
||||
```
|
||||
|
||||
|
32
06/parser-gen/equals.lua
Normal file
32
06/parser-gen/equals.lua
Normal file
|
@ -0,0 +1,32 @@
|
|||
-- this function compares if two tables are equal
|
||||
local function equals(o1, o2, ignore_mt)
|
||||
if o1 == o2 then return true end
|
||||
local o1Type = type(o1)
|
||||
local o2Type = type(o2)
|
||||
if o1Type ~= o2Type then return false end
|
||||
if o1Type ~= 'table' then return false end
|
||||
|
||||
if not ignore_mt then
|
||||
local mt1 = getmetatable(o1)
|
||||
if mt1 and mt1.__eq then
|
||||
--compare using built in method
|
||||
return o1 == o2
|
||||
end
|
||||
end
|
||||
|
||||
local keySet = {}
|
||||
|
||||
for key1, value1 in pairs(o1) do
|
||||
local value2 = o2[key1]
|
||||
if value2 == nil or equals(value1, value2, ignore_mt) == false then
|
||||
return false
|
||||
end
|
||||
keySet[key1] = true
|
||||
end
|
||||
|
||||
for key2, _ in pairs(o2) do
|
||||
if not keySet[key2] then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return {equals=equals}
|
401
06/parser-gen/errorgen.lua
Normal file
401
06/parser-gen/errorgen.lua
Normal file
|
@ -0,0 +1,401 @@
|
|||
-- Error generation code for LL(1) grammars
|
||||
-- AST funcs:
|
||||
|
||||
local function isfinal(t)
|
||||
return t["t"] or t["nt"] or t["func"] or t["s"] or t["num"]
|
||||
end
|
||||
|
||||
local function isaction(t)
|
||||
return t["action"]
|
||||
end
|
||||
|
||||
|
||||
local function isrule(t)
|
||||
return t and t["rulename"]
|
||||
end
|
||||
|
||||
local function isgrammar(t)
|
||||
if type(t) == "table" and not(t["action"]) then
|
||||
return isrule(t[1])
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function istoken (t)
|
||||
return t["token"] == "1"
|
||||
end
|
||||
|
||||
local function finalNode (t)
|
||||
if t["t"] then
|
||||
return"t",t["t"] -- terminal
|
||||
elseif t["nt"] then
|
||||
return "nt", t["nt"], istoken(t) -- nonterminal
|
||||
elseif t["func"] then
|
||||
return "func", t["func"] -- function
|
||||
elseif t["s"] then
|
||||
return "s", t["s"]
|
||||
elseif t["num"] then
|
||||
return "num", t["num"]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--[[
|
||||
|
||||
function rightleaf:
|
||||
|
||||
returns the right-most concatenation in the AST.
|
||||
used for followset keys
|
||||
|
||||
input: ((A B) C)
|
||||
output: {"nt_C"}
|
||||
|
||||
input: (A / B / C) (D / 'e')
|
||||
output: {"nt_D","t_e"}
|
||||
|
||||
input: A*
|
||||
output: {'',"nt_A"}
|
||||
|
||||
input: !A
|
||||
output: {"not_nt_A"}
|
||||
]]
|
||||
local function addnot(t)
|
||||
local ret = {}
|
||||
for k,v in pairs(t) do
|
||||
ret[k] = "not_"..v
|
||||
end
|
||||
return ret
|
||||
end
|
||||
local function addepsilon(t)
|
||||
local ret = t
|
||||
table.insert(ret, '')
|
||||
return ret
|
||||
end
|
||||
local function mergetables(first,second)
|
||||
local ret = first
|
||||
for k,v in pairs(second) do
|
||||
table.insert(ret, v)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function rightleaf(t)
|
||||
local action = t.action
|
||||
local op1 = t.op1
|
||||
local op2 = t.op2
|
||||
|
||||
if isfinal(t) then
|
||||
|
||||
-- todo: replace nt_A with FIRST(A)
|
||||
local typefn, fn, tok = finalNode(t)
|
||||
local ret = typefn .. "_" .. fn -- terminals: t_if, nonterminals: nt_if
|
||||
return {ret}
|
||||
|
||||
end
|
||||
|
||||
|
||||
if action == "or" then
|
||||
|
||||
return mergetables(rightleaf(op1), rightleaf(op2))
|
||||
|
||||
elseif action == "and" then -- consider only RHS
|
||||
|
||||
return rightleaf(op2)
|
||||
|
||||
elseif action == "&" then
|
||||
|
||||
return rightleaf(op1)
|
||||
|
||||
elseif action == "!" then
|
||||
|
||||
return addnot(rightleaf(op1))
|
||||
|
||||
elseif action == "+" then
|
||||
|
||||
return rightleaf(op1)
|
||||
|
||||
elseif action == "*" or action == "?" then
|
||||
|
||||
return addepsilon(rightleaf(op1))
|
||||
|
||||
elseif action == "^" then
|
||||
|
||||
op2 = op2["num"] -- second operand is number
|
||||
if op2 >= 1 then
|
||||
return rightleaf(op1)
|
||||
else
|
||||
return addepsilon(rightleaf(op1))
|
||||
end
|
||||
|
||||
elseif action == "^LABEL" or action == "->" or action == "=>" or action == "tcap" or action == "gcap" or action == "subcap" or action == "scap" then
|
||||
|
||||
return rightleaf(op1)
|
||||
|
||||
elseif action == "bref" or action == "poscap" then
|
||||
|
||||
return addepsilon({}) -- only empty string
|
||||
|
||||
elseif action == "anychar" then
|
||||
|
||||
return {"_anychar"}
|
||||
|
||||
elseif action == "label" then
|
||||
|
||||
return addepsilon({})
|
||||
|
||||
elseif action == "%" then
|
||||
|
||||
return addepsilon({})
|
||||
|
||||
elseif action == "invert" then
|
||||
|
||||
return addnot(rightleaf(op1))
|
||||
|
||||
elseif action == "range" then
|
||||
|
||||
return {"_anychar"}
|
||||
|
||||
else
|
||||
error("Unsupported action '"..action.."'")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local FOLLOW = {}
|
||||
|
||||
local function follow_aux(t, dontsplit)
|
||||
|
||||
local action = t.action
|
||||
local op1 = t.op1
|
||||
local op2 = t.op2
|
||||
|
||||
|
||||
if isfinal(t) then
|
||||
|
||||
return {t}
|
||||
|
||||
end
|
||||
|
||||
if action == "or" then
|
||||
|
||||
if dontsplit then -- do not split "(B / C)" in "A (B / C)"
|
||||
return {t}
|
||||
else -- return both
|
||||
return mergetables(follow_aux(op1), follow_aux(op2))
|
||||
end
|
||||
|
||||
elseif action == "and" then -- magic happens here
|
||||
|
||||
-- (A (B / D)) (!E C / D)
|
||||
|
||||
-- 1) FOLLOW(B) = FOLLOW(D) = {(!E C / D)}
|
||||
local rightset = rightleaf(op1)
|
||||
local rhs = follow_aux(op2)
|
||||
for k,v in pairs(rightset) do
|
||||
if not FOLLOW[v] then
|
||||
FOLLOW[v] = {}
|
||||
end
|
||||
-- TODO: check if rhs already exists in FOLLOW(v)
|
||||
table.insert(FOLLOW[v],rhs)
|
||||
|
||||
end
|
||||
|
||||
-- 2) FOLLOW(A) = {(B / D)}
|
||||
|
||||
return follow_aux(op1)
|
||||
|
||||
|
||||
elseif action == "&" then
|
||||
|
||||
return follow_aux(op1)
|
||||
|
||||
elseif action == "!" then
|
||||
|
||||
return {action="!", op1=follow_aux(op1)}
|
||||
|
||||
elseif action == "+" then
|
||||
|
||||
return follow_aux(op1)
|
||||
|
||||
elseif action == "*" then
|
||||
|
||||
return addepsilon(follow_aux(op1))
|
||||
|
||||
elseif action == "?" then
|
||||
|
||||
return addepsilon(follow_aux(op1))
|
||||
|
||||
elseif action == "^" then
|
||||
|
||||
op2 = op2["num"]
|
||||
|
||||
if op2 >= 1 then
|
||||
return follow_aux(op1)
|
||||
else
|
||||
return addepsilon(follow_aux(op1))
|
||||
end
|
||||
|
||||
elseif action == "^LABEL" or action == "->" or action == "=>" or action == "tcap" or action == "gcap" or action == "subcap" or action == "scap" then
|
||||
|
||||
return follow_aux(op1)
|
||||
|
||||
elseif action == "bref" or action == "poscap" then
|
||||
|
||||
return addepsilon({}) -- only empty string
|
||||
|
||||
elseif action == "anychar" then
|
||||
|
||||
return {"_anychar"}
|
||||
|
||||
elseif action == "label" then
|
||||
|
||||
return addepsilon({})
|
||||
|
||||
elseif action == "%" then
|
||||
|
||||
return addepsilon({})
|
||||
|
||||
elseif action == "invert" then
|
||||
|
||||
return {t} -- whole table
|
||||
|
||||
elseif action == "range" then
|
||||
|
||||
return {"_anychar"}
|
||||
|
||||
else
|
||||
error("Unsupported action '"..action.."'")
|
||||
end
|
||||
end
|
||||
|
||||
-- function: follow
|
||||
-- finds follow set for the whole AST, with key (rule, term)
|
||||
local function follow (t)
|
||||
local followset = {}
|
||||
if isgrammar(t) then
|
||||
for pos,val in pairs(t) do
|
||||
local rule = val.rulename
|
||||
FOLLOW = {} -- reset for each rule
|
||||
follow_aux(val.rule) -- apply recursive function
|
||||
followset[rule] = FOLLOW
|
||||
end
|
||||
else
|
||||
FOLLOW = {}
|
||||
follow_aux(t)
|
||||
followset[''] = FOLLOW
|
||||
end
|
||||
return followset
|
||||
end
|
||||
|
||||
-- functions to add errors
|
||||
-- find size of table
|
||||
local function getn (t)
|
||||
local size = 0
|
||||
for _, _ in pairs(t) do
|
||||
size = size+1
|
||||
end
|
||||
return size
|
||||
end
|
||||
-- generate error message by traversing table to the left
|
||||
local function printexpect(op)
|
||||
--peg.print_r(op)
|
||||
if isfinal(op) then
|
||||
if op["t"] then
|
||||
return "'"..op["t"].."'"
|
||||
end
|
||||
return op["nt"] or op["func"] or op["s"] or op["num"]
|
||||
else
|
||||
local test = op.op1
|
||||
if not test then
|
||||
return op.action
|
||||
else
|
||||
return printexpect(test)
|
||||
end
|
||||
end
|
||||
end
|
||||
local GENERATED_ERRORS = 0
|
||||
local TERRS = {}
|
||||
local function generateerror(op, after)
|
||||
|
||||
local desc = "Expected "..printexpect(op)
|
||||
|
||||
local err = GENERATED_ERRORS+1
|
||||
if err >= 255 then
|
||||
error("Error label limit reached(255)")
|
||||
end
|
||||
local name = "errorgen"..err
|
||||
TERRS[name] = desc
|
||||
GENERATED_ERRORS = GENERATED_ERRORS+1
|
||||
return name
|
||||
end
|
||||
|
||||
|
||||
local function tryadderror(op, after)
|
||||
|
||||
if FOLLOW then
|
||||
|
||||
local rhs = rightleaf(after)
|
||||
-- (A / B) C
|
||||
-- generate error iff #FOLLOW(A) OR #FOLLOW(B) = 1
|
||||
local generate = false
|
||||
for k,v in pairs(rhs) do
|
||||
if FOLLOW[v] then
|
||||
local n = getn(FOLLOW[v])
|
||||
generate = generate or n==1
|
||||
end
|
||||
end
|
||||
if generate then
|
||||
local lab = generateerror(op, after)
|
||||
return {action="^LABEL",op1=op,op2={s=lab}}
|
||||
end
|
||||
end
|
||||
return op
|
||||
end
|
||||
|
||||
|
||||
-- function: adderrors
|
||||
-- traverses the AST and adds error labels where possible
|
||||
|
||||
local function adderrors_aux(ast,tokenrule)
|
||||
|
||||
if not ast then
|
||||
return nil
|
||||
end
|
||||
|
||||
if isaction(ast) then
|
||||
|
||||
local act, op1, op2
|
||||
act = ast["action"]
|
||||
op1 = ast["op1"]
|
||||
op2 = ast["op2"]
|
||||
|
||||
if act == "and" and not tokenrule then
|
||||
|
||||
op2 = tryadderror(op2, op1)
|
||||
|
||||
end
|
||||
|
||||
ast["op1"] = adderrors_aux(op1,tokenrule)
|
||||
ast["op2"] = adderrors_aux(op2,tokenrule)
|
||||
end
|
||||
return ast
|
||||
end
|
||||
local function adderrors(t, followset)
|
||||
GENERATED_ERRORS = 0
|
||||
TERRS = {}
|
||||
if isgrammar(t) then
|
||||
for pos,val in pairs(t) do
|
||||
local currentrule = val.rulename
|
||||
FOLLOW = followset[currentrule]
|
||||
local rule = val.rule
|
||||
local istokenrule = val.token == "1"
|
||||
adderrors_aux(rule,istokenrule)
|
||||
end
|
||||
else
|
||||
FOLLOW = followset['']
|
||||
adderrors_aux(t,false)
|
||||
end
|
||||
return TERRS
|
||||
end
|
||||
|
||||
return {follow=follow,adderrors=adderrors}
|
160
06/parser-gen/parser-gen-tests.lua
Normal file
160
06/parser-gen/parser-gen-tests.lua
Normal file
|
@ -0,0 +1,160 @@
|
|||
local pg = require "parser-gen"
|
||||
local peg = require "peg-parser"
|
||||
local re = require "relabel"
|
||||
|
||||
local eq = require "equals"
|
||||
|
||||
local equals = eq.equals
|
||||
|
||||
|
||||
local pr = peg.print_r
|
||||
|
||||
|
||||
-- terminals
|
||||
-- space allowed
|
||||
rule = pg.compile [[
|
||||
rule <- 'a'
|
||||
]]
|
||||
str = "a a aa "
|
||||
res = pg.parse(str,rule)
|
||||
assert(res)
|
||||
|
||||
-- space not allowed
|
||||
rule = pg.compile [[
|
||||
RULE <- 'a' 'b'
|
||||
]]
|
||||
str = "a b"
|
||||
res = pg.parse(str,rule)
|
||||
assert(not res)
|
||||
|
||||
-- space not allowed 2
|
||||
rule = pg.compile [[
|
||||
rule <- 'a' 'b'
|
||||
SKIP <- ''
|
||||
SYNC <- ''
|
||||
]]
|
||||
str = "a b"
|
||||
res = pg.parse(str,rule)
|
||||
assert(not res)
|
||||
|
||||
-- custom space
|
||||
rule = pg.compile [[
|
||||
rule <- 'a' 'b'
|
||||
SKIP <- DOT
|
||||
DOT <- '.'
|
||||
]]
|
||||
str = "a...b"
|
||||
res = pg.parse(str,rule)
|
||||
assert(res)
|
||||
|
||||
-- non terminals
|
||||
-- space allowed
|
||||
rule = pg.compile [[
|
||||
rule <- A B
|
||||
A <- 'a'
|
||||
B <- 'b'
|
||||
]]
|
||||
str = "a b"
|
||||
res, err = pg.parse(str,rule)
|
||||
assert(res)
|
||||
-- no spaces allowed
|
||||
rule = pg.compile [[
|
||||
RULE <- A B
|
||||
A <- 'a'
|
||||
B <- 'b'
|
||||
]]
|
||||
str = "a b"
|
||||
res = pg.parse(str,rule)
|
||||
assert(not res)
|
||||
|
||||
-- space in the beginning and end of string
|
||||
rule = pg.compile [[
|
||||
rule <- A B
|
||||
A <- 'a'
|
||||
B <- 'b'
|
||||
]]
|
||||
str = " a b "
|
||||
res = pg.parse(str,rule)
|
||||
assert(res)
|
||||
|
||||
|
||||
|
||||
-- TESTING CAPTURES
|
||||
|
||||
r = pg.compile([[ rule <- {| {:'a' 'b':}* |}
|
||||
|
||||
]],_,_,true)
|
||||
res = pg.parse("ababab", r)
|
||||
|
||||
assert(equals(res,{"ab","ab","ab"}))
|
||||
-- space in capture
|
||||
|
||||
rule = pg.compile([[ rule <- {| {: 'a' :}* |}
|
||||
]],_,_,true)
|
||||
str = " a a a "
|
||||
res = pg.parse(str,rule)
|
||||
|
||||
assert(equals(res,{"a","a","a"})) -- fails
|
||||
|
||||
-- TESTING ERROR LABELS
|
||||
local labs = {errName = "Error number 1",errName2 = "Error number 2"}
|
||||
pg.setlabels(labs)
|
||||
rule = pg.compile [[ rule <- 'a' / %{errName}
|
||||
SYNC <- ''
|
||||
]]
|
||||
local errorcalled = false
|
||||
local function err(desc, line, col, sfail, recexp)
|
||||
errorcalled = true
|
||||
assert(desc == "Error number 1")
|
||||
end
|
||||
res = pg.parse("b",rule,err)
|
||||
assert(errorcalled)
|
||||
|
||||
-- TESTING ERROR RECOVERY
|
||||
|
||||
local labs = {errName = "Error number 1",errName2 = "Error number 2"}
|
||||
pg.setlabels(labs)
|
||||
|
||||
rule = pg.compile [[
|
||||
rule <- As //{errName,errName2} Bs
|
||||
As <- 'a'* / %{errName2}
|
||||
Bs <- 'b'*
|
||||
]]
|
||||
res1 = pg.parse(" a a a",rule)
|
||||
res2 = pg.parse("b b b ",rule)
|
||||
assert(res1 and res2)
|
||||
|
||||
-- TESTING ERROR GENERATION
|
||||
|
||||
pg.setlabels({})
|
||||
rule = pg.compile([[
|
||||
rule <- A B C
|
||||
A <- 'a'
|
||||
B <- 'b'
|
||||
C <- 'c'
|
||||
|
||||
]],_,true)
|
||||
res1, errs = pg.parse("ab",rule)
|
||||
assert(errs[1]["msg"] == "Expected C")
|
||||
|
||||
-- TESTING RECOVERY GENERATION
|
||||
|
||||
|
||||
-- SELF-DESCRIPTION
|
||||
pg.setlabels(peg.labels)
|
||||
gram = pg.compile(peg.gram, peg.defs,_,true)
|
||||
res1, errs = pg.parse(peg.gram,gram)
|
||||
assert(res1) -- parse succesful
|
||||
|
||||
--[[ this test is invalid since tool added ^LABEL syntax
|
||||
r = re.compile(peg.gram,peg.defs)
|
||||
res2 = r:match(peg.gram)
|
||||
|
||||
--peg.print_r(res2)
|
||||
|
||||
assert(equals(res1, res2))
|
||||
]]--
|
||||
|
||||
|
||||
|
||||
print("all tests succesful")
|
566
06/parser-gen/parser-gen.lua
Normal file
566
06/parser-gen/parser-gen.lua
Normal file
|
@ -0,0 +1,566 @@
|
|||
local peg = require "parser-gen.peg-parser"
|
||||
local eg = require "parser-gen.errorgen"
|
||||
local s = require "parser-gen.stack"
|
||||
|
||||
-- create stack for tokens inside captures. nil - not inside capture, 0 - inside capture, 1 - token found inside capture
|
||||
local tokenstack = s.Stack:Create()
|
||||
|
||||
|
||||
|
||||
local subject, errors, errorfunc
|
||||
|
||||
-- Lua 5.1 compatibility:
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
|
||||
local Predef = { nl = m.P"\n", cr = m.P"\r", tab = m.P"\t" }
|
||||
|
||||
|
||||
local mem = {} -- for compiled grammars
|
||||
|
||||
local function updatelocale()
|
||||
m.locale(Predef)
|
||||
local any = m.P(1)
|
||||
Predef.a = Predef.alpha
|
||||
Predef.c = Predef.cntrl
|
||||
Predef.d = Predef.digit
|
||||
Predef.g = Predef.graph
|
||||
Predef.l = Predef.lower
|
||||
Predef.p = Predef.punct
|
||||
Predef.s = Predef.space
|
||||
Predef.u = Predef.upper
|
||||
Predef.w = Predef.alnum
|
||||
Predef.x = Predef.xdigit
|
||||
Predef.A = any - Predef.a
|
||||
Predef.C = any - Predef.c
|
||||
Predef.D = any - Predef.d
|
||||
Predef.G = any - Predef.g
|
||||
Predef.L = any - Predef.l
|
||||
Predef.P = any - Predef.p
|
||||
Predef.S = any - Predef.s
|
||||
Predef.U = any - Predef.u
|
||||
Predef.W = any - Predef.w
|
||||
Predef.X = any - Predef.x
|
||||
mem = {}
|
||||
end
|
||||
|
||||
updatelocale()
|
||||
|
||||
local definitions = {}
|
||||
local tlabels = {}
|
||||
local totallabels = 0
|
||||
local tlabelnames = {} -- reverse table
|
||||
local tdescs = {}
|
||||
local trecs = {} -- recovery for each error
|
||||
|
||||
|
||||
local function defaultsync(patt)
|
||||
return (m.P(1)^-1) * (-patt * m.P(1))^0
|
||||
end
|
||||
|
||||
-- TODO: store these variables for each grammar
|
||||
local SKIP = (Predef.space + Predef.nl)
|
||||
local SYNC = defaultsync(SKIP)
|
||||
|
||||
|
||||
local recovery = true
|
||||
local skipspaces = true
|
||||
local buildast = true
|
||||
|
||||
local function sync (patt)
|
||||
return patt --(-patt * m.P(1))^0 * patt^0 -- skip until we find the pattern and consume it(if we do)
|
||||
end
|
||||
|
||||
|
||||
local function pattspaces (patt)
|
||||
if skipspaces then
|
||||
return patt * SKIP^0
|
||||
else
|
||||
return patt
|
||||
end
|
||||
end
|
||||
|
||||
local function token (patt)
|
||||
local incapture = tokenstack:pop() -- returns nil if not in capture
|
||||
if not incapture then
|
||||
return pattspaces(patt)
|
||||
end
|
||||
tokenstack:push(1)
|
||||
return patt
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-- functions used by the tool
|
||||
|
||||
local function iscompiled (gr)
|
||||
return m.type(gr) == "pattern"
|
||||
end
|
||||
|
||||
local function istoken (t)
|
||||
return t["token"] == "1"
|
||||
end
|
||||
|
||||
local function isfinal(t)
|
||||
return t["t"] or t["nt"] or t["func"] or t["s"] or t["num"]
|
||||
end
|
||||
|
||||
local function isaction(t)
|
||||
return t["action"]
|
||||
end
|
||||
|
||||
|
||||
local function isrule(t)
|
||||
return t and t["rulename"]
|
||||
end
|
||||
local function isgrammar(t)
|
||||
if type(t) == "table" and not(t["action"]) then
|
||||
return isrule(t[1])
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function iscapture (action)
|
||||
return action == "=>" or action == "gcap" or action == "scap" or action == "subcap" or action == "poscap"
|
||||
end
|
||||
|
||||
local function finalNode (t)
|
||||
if t["t"] then
|
||||
return"t",t["t"] -- terminal
|
||||
elseif t["nt"] then
|
||||
return "nt", t["nt"], istoken(t) -- nonterminal
|
||||
elseif t["func"] then
|
||||
return "func", t["func"] -- function
|
||||
elseif t["s"] then
|
||||
return "s", t["s"]
|
||||
elseif t["num"] then
|
||||
return "num", t["num"]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
local bg = {} -- local variable to keep global function buildgrammar
|
||||
|
||||
|
||||
local function addspaces (caps)
|
||||
local hastoken = tokenstack:pop()
|
||||
if hastoken == 1 then
|
||||
return pattspaces(caps)
|
||||
end
|
||||
return caps
|
||||
end
|
||||
|
||||
local function applyaction(action, op1, op2, labels,tokenrule)
|
||||
if action == "or" then
|
||||
if labels then -- labels = {{s="errName"},{s="errName2"}}
|
||||
for i, v in ipairs(labels) do
|
||||
local labname = v["s"]
|
||||
local lab = tlabels[labname]
|
||||
if not lab then
|
||||
error("Label '"..labname.."' undefined")
|
||||
end
|
||||
labels[i] = lab
|
||||
end
|
||||
return m.Rec(op1,op2,unpack(labels))
|
||||
end
|
||||
return op1 + op2
|
||||
elseif action == "and" then
|
||||
|
||||
return op1 * op2
|
||||
elseif action == "&" then
|
||||
return #op1
|
||||
elseif action == "!" then
|
||||
return -op1
|
||||
elseif action == "+" then
|
||||
return op1^1
|
||||
elseif action == "*" then
|
||||
return op1^0
|
||||
elseif action == "?" then
|
||||
return op1^-1
|
||||
elseif action == "^" then
|
||||
return op1^op2
|
||||
elseif action == "^LABEL" then
|
||||
local lab = tlabels[op2]
|
||||
if not lab then
|
||||
error("Label '"..op2.."' unspecified using setlabels()")
|
||||
end
|
||||
return op1 + m.T(lab)
|
||||
elseif action == "->" then
|
||||
return op1 / op2
|
||||
-- in captures we add SPACES^0
|
||||
elseif action == "=>" then
|
||||
return addspaces(m.Cmt(op1,op2))
|
||||
elseif action == "tcap" then
|
||||
return m.Ct(op1) -- nospaces
|
||||
elseif action == "gcap" then
|
||||
return addspaces(m.Cg(op1, op2))
|
||||
elseif action == "bref" then
|
||||
return m.Cb(op1) --m.Cmt(m.Cb(op1), equalcap) -- do we need to add spaces to bcap?
|
||||
elseif action == "poscap" then
|
||||
return addspaces(m.Cp())
|
||||
elseif action == "subcap" then
|
||||
return addspaces(m.Cs(op1))
|
||||
elseif action == "scap" then
|
||||
return addspaces(m.C(op1))
|
||||
elseif action == "anychar" then
|
||||
if buildast and not tokenrule then
|
||||
return m.C(m.P(1))
|
||||
end
|
||||
return m.P(1)
|
||||
elseif action == "label" then
|
||||
local lab = tlabels[op1]
|
||||
if not lab then
|
||||
error("Label '"..op1.."' unspecified using setlabels()")
|
||||
end
|
||||
return m.T(lab) -- lpeglabel
|
||||
elseif action == "%" then
|
||||
if definitions[op1] then
|
||||
return definitions[op1]
|
||||
elseif Predef[op1] then
|
||||
return Predef[op1]
|
||||
else
|
||||
error("Definition for '%"..op1.."' unspecified(use second parameter of parser-gen.compile())")
|
||||
end
|
||||
elseif action == "invert" then
|
||||
return m.P(1) - op1
|
||||
elseif action == "range" then
|
||||
local res = m.R(op1)
|
||||
if not tokenrule then
|
||||
if buildast then
|
||||
res = m.C(res)
|
||||
end
|
||||
res = token(res)
|
||||
end
|
||||
return res
|
||||
else
|
||||
error("Unsupported action '"..action.."'")
|
||||
end
|
||||
end
|
||||
|
||||
local function applyfinal(action, term, tokenterm, tokenrule)
|
||||
|
||||
if action == "t" then
|
||||
local res = m.P(term)
|
||||
if not tokenrule then
|
||||
if buildast then
|
||||
res = m.C(res)
|
||||
end
|
||||
if skipspaces then
|
||||
res = token(res)
|
||||
end
|
||||
end
|
||||
return res
|
||||
elseif action == "nt" then
|
||||
if skipspaces and tokenterm and (not tokenrule) then
|
||||
return token(m.V(term))
|
||||
else
|
||||
return m.V(term)
|
||||
end
|
||||
elseif action == "func" then
|
||||
if definitions[term] then
|
||||
return definitions[term]
|
||||
else
|
||||
error("Definition for function '"..term.."' unspecified (use second parameter of parser-gen.compile())")
|
||||
end
|
||||
elseif action == "s" then -- simple string
|
||||
return term
|
||||
elseif action == "num" then -- numbered string
|
||||
return tonumber(term)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function applygrammar(gram)
|
||||
return m.P(gram)
|
||||
end
|
||||
|
||||
local function traverse (ast, tokenrule)
|
||||
if not ast then
|
||||
return nil
|
||||
end
|
||||
|
||||
if isfinal(ast) then
|
||||
local typefn, fn, tok = finalNode(ast)
|
||||
return applyfinal(typefn, fn, tok, tokenrule)
|
||||
|
||||
elseif isaction(ast) then
|
||||
|
||||
local act, op1, op2, labs, ret1, ret2
|
||||
act = ast["action"]
|
||||
op1 = ast["op1"]
|
||||
op2 = ast["op2"]
|
||||
labs = ast["condition"] -- recovery operations
|
||||
|
||||
-- post-order traversal
|
||||
if iscapture(act) then
|
||||
tokenstack:push(0) -- not found any tokens yet
|
||||
end
|
||||
|
||||
ret1 = traverse(op1, tokenrule)
|
||||
ret2 = traverse(op2, tokenrule)
|
||||
|
||||
|
||||
return applyaction(act, ret1, ret2, labs, tokenrule)
|
||||
|
||||
elseif isgrammar(ast) then
|
||||
--
|
||||
local g = bg.buildgrammar (ast)
|
||||
return applygrammar (g)
|
||||
|
||||
else
|
||||
peg.print_r(ast)
|
||||
error("Unsupported AST")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function specialrules(ast, builder)
|
||||
-- initialize values
|
||||
SKIP = (Predef.space + Predef.nl)
|
||||
skipspaces = true
|
||||
SYNC = nil
|
||||
recovery = true
|
||||
-- find SPACE and SYNC rules
|
||||
for i, v in ipairs(ast) do
|
||||
local name = v["rulename"]
|
||||
local rule
|
||||
if name == "SKIP" then
|
||||
rule = traverse(v["rule"], true)
|
||||
if v["rule"]["t"] == '' then
|
||||
skipspaces = false
|
||||
else
|
||||
skipspaces = true
|
||||
SKIP = rule
|
||||
end
|
||||
builder[name] = rule
|
||||
elseif name == "SYNC" then
|
||||
rule = traverse(v["rule"], true)
|
||||
if v["rule"]["t"] == '' then-- SYNC <- ''
|
||||
recovery=false
|
||||
else
|
||||
recovery= true
|
||||
SYNC = rule
|
||||
end
|
||||
builder[name] = rule
|
||||
end
|
||||
end
|
||||
if not SYNC and recovery then
|
||||
SYNC = defaultsync(SKIP)
|
||||
end
|
||||
end
|
||||
|
||||
local function recorderror(position,label)
|
||||
-- call error function here
|
||||
local line, col = peg.calcline(subject, position)
|
||||
local desc
|
||||
if label == 0 then
|
||||
desc = "Syntax error"
|
||||
else
|
||||
desc = tdescs[label]
|
||||
end
|
||||
if errorfunc then
|
||||
local temp = string.sub(subject,position)
|
||||
local strend = string.find(temp, "\n")
|
||||
local sfail = string.sub(temp, 1, strend)
|
||||
errorfunc(desc,line,col,sfail,trecs[label])
|
||||
end
|
||||
|
||||
local err = { line = line, col = col, label=tlabelnames[label], msg = desc }
|
||||
table.insert(errors, err)
|
||||
|
||||
end
|
||||
local function record(label)
|
||||
return (m.Cp() * m.Cc(label)) / recorderror
|
||||
end
|
||||
|
||||
local function buildrecovery(grammar)
|
||||
|
||||
local synctoken = pattspaces(sync(SYNC))
|
||||
local grec = grammar
|
||||
|
||||
for k,v in pairs(tlabels) do
|
||||
|
||||
if trecs[v] then -- custom sync token
|
||||
grec = m.Rec(grec,record(v) * pattspaces(trecs[v]), v)
|
||||
else -- use global sync token
|
||||
grec = m.Rec(grec,record(v) * synctoken, v)
|
||||
end
|
||||
end
|
||||
return grec
|
||||
|
||||
end
|
||||
local usenode = false
|
||||
|
||||
local function usenodes(val)
|
||||
usenode = val
|
||||
end
|
||||
|
||||
|
||||
function bg.buildgrammar (ast)
|
||||
local builder = {}
|
||||
specialrules(ast, builder)
|
||||
local initialrule
|
||||
for i, v in ipairs(ast) do
|
||||
local istokenrule = v["token"] == "1"
|
||||
local isfragment = v["fragment"] == "1"
|
||||
local isnode = v["node"] == "1"
|
||||
|
||||
if isnode and not usenodes then
|
||||
error("Node mode disabled - please use parser-gen.usenodes(true) before compiling the grammar")
|
||||
end
|
||||
|
||||
local name = v["rulename"]
|
||||
local isspecial = name == "SKIP" or name == "SYNC"
|
||||
local rule = v["rule"]
|
||||
if i == 1 then
|
||||
initialrule = name
|
||||
table.insert(builder, name) -- lpeg syntax
|
||||
builder[name] = traverse(rule, istokenrule)
|
||||
else
|
||||
if not builder[name] then -- dont traverse rules for SKIP and SYNC twice
|
||||
builder[name] = traverse(rule, istokenrule)
|
||||
end
|
||||
end
|
||||
if buildast and not isfragment and not isspecial and ((not usenode) or (usenode and isnode)) then
|
||||
if istokenrule then
|
||||
builder[name] = m.C(builder[name])
|
||||
end
|
||||
builder[name] = m.Ct(m.Cg(m.Cc(name),"rule") * m.Cg(m.Cp(),"pos") * builder[name])
|
||||
end
|
||||
end
|
||||
|
||||
if skipspaces then
|
||||
builder[initialrule] = SKIP^0 * builder[initialrule] -- skip spaces at the beginning of the input
|
||||
end
|
||||
if recovery then
|
||||
builder[initialrule] = buildrecovery(builder[initialrule]) -- build recovery on top of initial rule
|
||||
end
|
||||
return builder
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
local function build(ast, defs)
|
||||
if defs then
|
||||
definitions = defs
|
||||
end
|
||||
if isgrammar(ast) then
|
||||
return traverse(ast)
|
||||
else
|
||||
SKIP = (Predef.space + Predef.nl)
|
||||
skipspaces = true
|
||||
SYNC = nil
|
||||
recovery = true
|
||||
SYNC = defaultsync(SKIP)
|
||||
local res = SKIP ^0 * traverse(ast)
|
||||
if buildast then
|
||||
res = m.Ct(res)
|
||||
end
|
||||
return res -- input is not a grammar - skip spaces and sync by default
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- recovery grammar
|
||||
|
||||
|
||||
|
||||
|
||||
-- end
|
||||
|
||||
|
||||
|
||||
-- t = {errName="Error description",...}
|
||||
local function setlabels (t, errorgen)
|
||||
local index
|
||||
if errorgen then
|
||||
index = totallabels + 1
|
||||
else
|
||||
-- reset error tables
|
||||
index = 1
|
||||
tlabels = {}
|
||||
|
||||
tdescs = {}
|
||||
trecs = {}
|
||||
end
|
||||
for key,value in pairs(t) do
|
||||
if index >= 255 then
|
||||
error("Error label limit reached(255)")
|
||||
end
|
||||
if type(value) == "table" then -- we have a recovery expression
|
||||
tdescs[index] = value[1]
|
||||
|
||||
trecs[index] = traverse(peg.pegToAST(value[2]), true)-- PEG to LPEG
|
||||
else
|
||||
tdescs[index] = value
|
||||
end
|
||||
tlabels[key] = index
|
||||
tlabelnames[index] = key -- reverse table
|
||||
index = index + 1
|
||||
end
|
||||
totallabels = index-1
|
||||
end
|
||||
|
||||
|
||||
local function compile (input, defs, generrors, nocaptures)
|
||||
if iscompiled(input) then
|
||||
return input
|
||||
end
|
||||
if not mem[input] then
|
||||
buildast = true
|
||||
if nocaptures then
|
||||
buildast=false
|
||||
end
|
||||
--re.setlabels(tlabels)
|
||||
--re.compile(input,defs)
|
||||
-- build ast
|
||||
local ast = peg.pegToAST(input)
|
||||
if generrors then
|
||||
local follow = eg.follow(ast)
|
||||
local errors = eg.adderrors(ast, follow)
|
||||
setlabels (errors, true) -- add errors generated by errorgen
|
||||
end
|
||||
local gram = build(ast,defs)
|
||||
if not gram then
|
||||
-- find error using relabel module
|
||||
|
||||
end
|
||||
mem[input] = gram-- store if the user forgets to compile it
|
||||
end
|
||||
return mem[input]
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function parse (input, grammar, errorfunction)
|
||||
if not iscompiled(grammar) then
|
||||
|
||||
local cp = compile(grammar)
|
||||
grammar = cp
|
||||
end
|
||||
-- set up recovery table
|
||||
errorfunc = errorfunction
|
||||
subject = input
|
||||
errors = {}
|
||||
-- end
|
||||
local r, e, sfail = m.match(grammar,input)
|
||||
if not r then
|
||||
recorderror(#input - #sfail, e)
|
||||
end
|
||||
if #errors == 0 then errors=nil end
|
||||
return r, errors
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local pg = {compile=compile, setlabels=setlabels, parse=parse,follow=follow, calcline = peg.calcline, usenodes = usenodes}
|
||||
|
||||
return pg
|
292
06/parser-gen/parsers/lua-5.3.4-tests/all.lua
Normal file
292
06/parser-gen/parsers/lua-5.3.4-tests/all.lua
Normal file
|
@ -0,0 +1,292 @@
|
|||
#!../lua
|
||||
-- $Id: all.lua,v 1.95 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice at the end of this file
|
||||
|
||||
|
||||
|
||||
local version = "Lua 5.3"
|
||||
if _VERSION ~= version then
|
||||
io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION,
|
||||
"\nExiting tests\n")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
_G._ARG = arg -- save arg for other tests
|
||||
|
||||
|
||||
-- next variables control the execution of some tests
|
||||
-- true means no test (so an undefined variable does not skip a test)
|
||||
-- defaults are for Linux; test everything.
|
||||
-- Make true to avoid long or memory consuming tests
|
||||
_soft = rawget(_G, "_soft") or false
|
||||
-- Make true to avoid non-portable tests
|
||||
_port = rawget(_G, "_port") or false
|
||||
-- Make true to avoid messages about tests not performed
|
||||
_nomsg = rawget(_G, "_nomsg") or false
|
||||
|
||||
|
||||
local usertests = rawget(_G, "_U")
|
||||
|
||||
if usertests then
|
||||
-- tests for sissies ;) Avoid problems
|
||||
_soft = true
|
||||
_port = true
|
||||
_nomsg = true
|
||||
end
|
||||
|
||||
-- tests should require debug when needed
|
||||
debug = nil
|
||||
|
||||
if usertests then
|
||||
T = nil -- no "internal" tests for user tests
|
||||
else
|
||||
T = rawget(_G, "T") -- avoid problems with 'strict' module
|
||||
end
|
||||
|
||||
math.randomseed(0)
|
||||
|
||||
--[=[
|
||||
example of a long [comment],
|
||||
[[spanning several [lines]]]
|
||||
|
||||
]=]
|
||||
|
||||
print("current path:\n****" .. package.path .. "****\n")
|
||||
|
||||
|
||||
local initclock = os.clock()
|
||||
local lastclock = initclock
|
||||
local walltime = os.time()
|
||||
|
||||
local collectgarbage = collectgarbage
|
||||
|
||||
do -- (
|
||||
|
||||
-- track messages for tests not performed
|
||||
local msgs = {}
|
||||
function Message (m)
|
||||
if not _nomsg then
|
||||
print(m)
|
||||
msgs[#msgs+1] = string.sub(m, 3, -3)
|
||||
end
|
||||
end
|
||||
|
||||
assert(os.setlocale"C")
|
||||
|
||||
local T,print,format,write,assert,type,unpack,floor =
|
||||
T,print,string.format,io.write,assert,type,table.unpack,math.floor
|
||||
|
||||
-- use K for 1000 and M for 1000000 (not 2^10 -- 2^20)
|
||||
local function F (m)
|
||||
local function round (m)
|
||||
m = m + 0.04999
|
||||
return format("%.1f", m) -- keep one decimal digit
|
||||
end
|
||||
if m < 1000 then return m
|
||||
else
|
||||
m = m / 1000
|
||||
if m < 1000 then return round(m).."K"
|
||||
else
|
||||
return round(m/1000).."M"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local showmem
|
||||
if not T then
|
||||
local max = 0
|
||||
showmem = function ()
|
||||
local m = collectgarbage("count") * 1024
|
||||
max = (m > max) and m or max
|
||||
print(format(" ---- total memory: %s, max memory: %s ----\n",
|
||||
F(m), F(max)))
|
||||
end
|
||||
else
|
||||
showmem = function ()
|
||||
T.checkmemory()
|
||||
local total, numblocks, maxmem = T.totalmem()
|
||||
local count = collectgarbage("count")
|
||||
print(format(
|
||||
"\n ---- total memory: %s (%.0fK), max use: %s, blocks: %d\n",
|
||||
F(total), count, F(maxmem), numblocks))
|
||||
print(format("\t(strings: %d, tables: %d, functions: %d, "..
|
||||
"\n\tudata: %d, threads: %d)",
|
||||
T.totalmem"string", T.totalmem"table", T.totalmem"function",
|
||||
T.totalmem"userdata", T.totalmem"thread"))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- redefine dofile to run files through dump/undump
|
||||
--
|
||||
local function report (n) print("\n***** FILE '"..n.."'*****") end
|
||||
local olddofile = dofile
|
||||
local dofile = function (n, strip)
|
||||
showmem()
|
||||
local c = os.clock()
|
||||
print(string.format("time: %g (+%g)", c - initclock, c - lastclock))
|
||||
lastclock = c
|
||||
report(n)
|
||||
local f = assert(loadfile(n))
|
||||
local b = string.dump(f, strip)
|
||||
f = assert(load(b))
|
||||
return f()
|
||||
end
|
||||
|
||||
dofile('main.lua')
|
||||
|
||||
do
|
||||
local next, setmetatable, stderr = next, setmetatable, io.stderr
|
||||
-- track collections
|
||||
local mt = {}
|
||||
-- each time a table is collected, remark it for finalization
|
||||
-- on next cycle
|
||||
mt.__gc = function (o)
|
||||
stderr:write'.' -- mark progress
|
||||
local n = setmetatable(o, mt) -- remark it
|
||||
end
|
||||
local n = setmetatable({}, mt) -- create object
|
||||
end
|
||||
|
||||
report"gc.lua"
|
||||
local f = assert(loadfile('gc.lua'))
|
||||
f()
|
||||
|
||||
dofile('db.lua')
|
||||
assert(dofile('calls.lua') == deep and deep)
|
||||
olddofile('strings.lua')
|
||||
olddofile('literals.lua')
|
||||
dofile('tpack.lua')
|
||||
assert(dofile('attrib.lua') == 27)
|
||||
|
||||
assert(dofile('locals.lua') == 5)
|
||||
dofile('constructs.lua')
|
||||
dofile('code.lua', true)
|
||||
if not _G._soft then
|
||||
report('big.lua')
|
||||
local f = coroutine.wrap(assert(loadfile('big.lua')))
|
||||
assert(f() == 'b')
|
||||
assert(f() == 'a')
|
||||
end
|
||||
dofile('nextvar.lua')
|
||||
dofile('pm.lua')
|
||||
dofile('utf8.lua')
|
||||
dofile('api.lua')
|
||||
assert(dofile('events.lua') == 12)
|
||||
dofile('vararg.lua')
|
||||
dofile('closure.lua')
|
||||
dofile('coroutine.lua')
|
||||
dofile('goto.lua', true)
|
||||
dofile('errors.lua')
|
||||
dofile('math.lua')
|
||||
dofile('sort.lua', true)
|
||||
dofile('bitwise.lua')
|
||||
assert(dofile('verybig.lua', true) == 10); collectgarbage()
|
||||
dofile('files.lua')
|
||||
|
||||
if #msgs > 0 then
|
||||
print("\ntests not performed:")
|
||||
for i=1,#msgs do
|
||||
print(msgs[i])
|
||||
end
|
||||
print()
|
||||
end
|
||||
|
||||
-- no test module should define 'debug'
|
||||
assert(debug == nil)
|
||||
|
||||
local debug = require "debug"
|
||||
|
||||
print(string.format("%d-bit integers, %d-bit floats",
|
||||
string.packsize("j") * 8, string.packsize("n") * 8))
|
||||
|
||||
debug.sethook(function (a) assert(type(a) == 'string') end, "cr")
|
||||
|
||||
-- to survive outside block
|
||||
_G.showmem = showmem
|
||||
|
||||
end --)
|
||||
|
||||
local _G, showmem, print, format, clock, time, difftime, assert, open =
|
||||
_G, showmem, print, string.format, os.clock, os.time, os.difftime,
|
||||
assert, io.open
|
||||
|
||||
-- file with time of last performed test
|
||||
local fname = T and "time-debug.txt" or "time.txt"
|
||||
local lasttime
|
||||
|
||||
if not usertests then
|
||||
-- open file with time of last performed test
|
||||
local f = io.open(fname)
|
||||
if f then
|
||||
lasttime = assert(tonumber(f:read'a'))
|
||||
f:close();
|
||||
else -- no such file; assume it is recording time for first time
|
||||
lasttime = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- erase (almost) all globals
|
||||
print('cleaning all!!!!')
|
||||
for n in pairs(_G) do
|
||||
if not ({___Glob = 1, tostring = 1})[n] then
|
||||
_G[n] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
collectgarbage();showmem()
|
||||
|
||||
local clocktime = clock() - initclock
|
||||
walltime = difftime(time(), walltime)
|
||||
|
||||
print(format("\n\ntotal time: %.2fs (wall time: %gs)\n", clocktime, walltime))
|
||||
|
||||
if not usertests then
|
||||
lasttime = lasttime or clocktime -- if no last time, ignore difference
|
||||
-- check whether current test time differs more than 5% from last time
|
||||
local diff = (clocktime - lasttime) / lasttime
|
||||
local tolerance = 0.05 -- 5%
|
||||
if (diff >= tolerance or diff <= -tolerance) then
|
||||
print(format("WARNING: time difference from previous test: %+.1f%%",
|
||||
diff * 100))
|
||||
end
|
||||
assert(open(fname, "w")):write(clocktime):close()
|
||||
end
|
||||
|
||||
print("final OK !!!")
|
||||
|
||||
|
||||
|
||||
--[[
|
||||
*****************************************************************************
|
||||
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************
|
||||
]]
|
||||
|
1172
06/parser-gen/parsers/lua-5.3.4-tests/api.lua
Normal file
1172
06/parser-gen/parsers/lua-5.3.4-tests/api.lua
Normal file
File diff suppressed because it is too large
Load diff
470
06/parser-gen/parsers/lua-5.3.4-tests/attrib.lua
Normal file
470
06/parser-gen/parsers/lua-5.3.4-tests/attrib.lua
Normal file
|
@ -0,0 +1,470 @@
|
|||
-- $Id: attrib.lua,v 1.65 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print "testing require"
|
||||
|
||||
assert(require"string" == string)
|
||||
assert(require"math" == math)
|
||||
assert(require"table" == table)
|
||||
assert(require"io" == io)
|
||||
assert(require"os" == os)
|
||||
assert(require"coroutine" == coroutine)
|
||||
|
||||
assert(type(package.path) == "string")
|
||||
assert(type(package.cpath) == "string")
|
||||
assert(type(package.loaded) == "table")
|
||||
assert(type(package.preload) == "table")
|
||||
|
||||
assert(type(package.config) == "string")
|
||||
print("package config: "..string.gsub(package.config, "\n", "|"))
|
||||
|
||||
do
|
||||
-- create a path with 'max' templates,
|
||||
-- each with 1-10 repetitions of '?'
|
||||
local max = _soft and 100 or 2000
|
||||
local t = {}
|
||||
for i = 1,max do t[i] = string.rep("?", i%10 + 1) end
|
||||
t[#t + 1] = ";" -- empty template
|
||||
local path = table.concat(t, ";")
|
||||
-- use that path in a search
|
||||
local s, err = package.searchpath("xuxu", path)
|
||||
-- search fails; check that message has an occurence of
|
||||
-- '??????????' with ? replaced by xuxu and at least 'max' lines
|
||||
assert(not s and
|
||||
string.find(err, string.rep("xuxu", 10)) and
|
||||
#string.gsub(err, "[^\n]", "") >= max)
|
||||
-- path with one very long template
|
||||
local path = string.rep("?", max)
|
||||
local s, err = package.searchpath("xuxu", path)
|
||||
assert(not s and string.find(err, string.rep('xuxu', max)))
|
||||
end
|
||||
|
||||
do
|
||||
local oldpath = package.path
|
||||
package.path = {}
|
||||
local s, err = pcall(require, "no-such-file")
|
||||
assert(not s and string.find(err, "package.path"))
|
||||
package.path = oldpath
|
||||
end
|
||||
|
||||
print('+')
|
||||
|
||||
|
||||
-- The next tests for 'require' assume some specific directories and
|
||||
-- libraries.
|
||||
|
||||
if not _port then --[
|
||||
|
||||
local dirsep = string.match(package.config, "^([^\n]+)\n")
|
||||
|
||||
-- auxiliary directory with C modules and temporary files
|
||||
local DIR = "libs" .. dirsep
|
||||
|
||||
-- prepend DIR to a name and correct directory separators
|
||||
local function D (x)
|
||||
x = string.gsub(x, "/", dirsep)
|
||||
return DIR .. x
|
||||
end
|
||||
|
||||
-- prepend DIR and pospend proper C lib. extension to a name
|
||||
local function DC (x)
|
||||
local ext = (dirsep == '\\') and ".dll" or ".so"
|
||||
return D(x .. ext)
|
||||
end
|
||||
|
||||
|
||||
local function createfiles (files, preextras, posextras)
|
||||
for n,c in pairs(files) do
|
||||
io.output(D(n))
|
||||
io.write(string.format(preextras, n))
|
||||
io.write(c)
|
||||
io.write(string.format(posextras, n))
|
||||
io.close(io.output())
|
||||
end
|
||||
end
|
||||
|
||||
function removefiles (files)
|
||||
for n in pairs(files) do
|
||||
os.remove(D(n))
|
||||
end
|
||||
end
|
||||
|
||||
local files = {
|
||||
["names.lua"] = "do return {...} end\n",
|
||||
["err.lua"] = "B = 15; a = a + 1;",
|
||||
["synerr.lua"] = "B =",
|
||||
["A.lua"] = "",
|
||||
["B.lua"] = "assert(...=='B');require 'A'",
|
||||
["A.lc"] = "",
|
||||
["A"] = "",
|
||||
["L"] = "",
|
||||
["XXxX"] = "",
|
||||
["C.lua"] = "package.loaded[...] = 25; require'C'",
|
||||
}
|
||||
|
||||
AA = nil
|
||||
local extras = [[
|
||||
NAME = '%s'
|
||||
REQUIRED = ...
|
||||
return AA]]
|
||||
|
||||
createfiles(files, "", extras)
|
||||
|
||||
-- testing explicit "dir" separator in 'searchpath'
|
||||
assert(package.searchpath("C.lua", D"?", "", "") == D"C.lua")
|
||||
assert(package.searchpath("C.lua", D"?", ".", ".") == D"C.lua")
|
||||
assert(package.searchpath("--x-", D"?", "-", "X") == D"XXxX")
|
||||
assert(package.searchpath("---xX", D"?", "---", "XX") == D"XXxX")
|
||||
assert(package.searchpath(D"C.lua", "?", dirsep) == D"C.lua")
|
||||
assert(package.searchpath(".\\C.lua", D"?", "\\") == D"./C.lua")
|
||||
|
||||
local oldpath = package.path
|
||||
|
||||
package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR)
|
||||
|
||||
local try = function (p, n, r)
|
||||
NAME = nil
|
||||
local rr = require(p)
|
||||
assert(NAME == n)
|
||||
assert(REQUIRED == p)
|
||||
assert(rr == r)
|
||||
end
|
||||
|
||||
a = require"names"
|
||||
assert(a[1] == "names" and a[2] == D"names.lua")
|
||||
|
||||
_G.a = nil
|
||||
local st, msg = pcall(require, "err")
|
||||
assert(not st and string.find(msg, "arithmetic") and B == 15)
|
||||
st, msg = pcall(require, "synerr")
|
||||
assert(not st and string.find(msg, "error loading module"))
|
||||
|
||||
assert(package.searchpath("C", package.path) == D"C.lua")
|
||||
assert(require"C" == 25)
|
||||
assert(require"C" == 25)
|
||||
AA = nil
|
||||
try('B', 'B.lua', true)
|
||||
assert(package.loaded.B)
|
||||
assert(require"B" == true)
|
||||
assert(package.loaded.A)
|
||||
assert(require"C" == 25)
|
||||
package.loaded.A = nil
|
||||
try('B', nil, true) -- should not reload package
|
||||
try('A', 'A.lua', true)
|
||||
package.loaded.A = nil
|
||||
os.remove(D'A.lua')
|
||||
AA = {}
|
||||
try('A', 'A.lc', AA) -- now must find second option
|
||||
assert(package.searchpath("A", package.path) == D"A.lc")
|
||||
assert(require("A") == AA)
|
||||
AA = false
|
||||
try('K', 'L', false) -- default option
|
||||
try('K', 'L', false) -- default option (should reload it)
|
||||
assert(rawget(_G, "_REQUIREDNAME") == nil)
|
||||
|
||||
AA = "x"
|
||||
try("X", "XXxX", AA)
|
||||
|
||||
|
||||
removefiles(files)
|
||||
|
||||
|
||||
-- testing require of sub-packages
|
||||
|
||||
local _G = _G
|
||||
|
||||
package.path = string.gsub("D/?.lua;D/?/init.lua", "D/", DIR)
|
||||
|
||||
files = {
|
||||
["P1/init.lua"] = "AA = 10",
|
||||
["P1/xuxu.lua"] = "AA = 20",
|
||||
}
|
||||
|
||||
createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n")
|
||||
AA = 0
|
||||
|
||||
local m = assert(require"P1")
|
||||
assert(AA == 0 and m.AA == 10)
|
||||
assert(require"P1" == m)
|
||||
assert(require"P1" == m)
|
||||
|
||||
assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua")
|
||||
m.xuxu = assert(require"P1.xuxu")
|
||||
assert(AA == 0 and m.xuxu.AA == 20)
|
||||
assert(require"P1.xuxu" == m.xuxu)
|
||||
assert(require"P1.xuxu" == m.xuxu)
|
||||
assert(require"P1" == m and m.AA == 10)
|
||||
|
||||
|
||||
removefiles(files)
|
||||
|
||||
|
||||
package.path = ""
|
||||
assert(not pcall(require, "file_does_not_exist"))
|
||||
package.path = "??\0?"
|
||||
assert(not pcall(require, "file_does_not_exist1"))
|
||||
|
||||
package.path = oldpath
|
||||
|
||||
-- check 'require' error message
|
||||
local fname = "file_does_not_exist2"
|
||||
local m, err = pcall(require, fname)
|
||||
for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do
|
||||
t = string.gsub(t, "?", fname)
|
||||
assert(string.find(err, t, 1, true))
|
||||
end
|
||||
|
||||
do -- testing 'package.searchers' not being a table
|
||||
local searchers = package.searchers
|
||||
package.searchers = 3
|
||||
local st, msg = pcall(require, 'a')
|
||||
assert(not st and string.find(msg, "must be a table"))
|
||||
package.searchers = searchers
|
||||
end
|
||||
|
||||
local function import(...)
|
||||
local f = {...}
|
||||
return function (m)
|
||||
for i=1, #f do m[f[i]] = _G[f[i]] end
|
||||
end
|
||||
end
|
||||
|
||||
-- cannot change environment of a C function
|
||||
assert(not pcall(module, 'XUXU'))
|
||||
|
||||
|
||||
|
||||
-- testing require of C libraries
|
||||
|
||||
|
||||
local p = "" -- On Mac OS X, redefine this to "_"
|
||||
|
||||
-- check whether loadlib works in this system
|
||||
local st, err, when = package.loadlib(DC"lib1", "*")
|
||||
if not st then
|
||||
local f, err, when = package.loadlib("donotexist", p.."xuxu")
|
||||
assert(not f and type(err) == "string" and when == "absent")
|
||||
;(Message or print)('\n >>> cannot load dynamic library <<<\n')
|
||||
print(err, when)
|
||||
else
|
||||
-- tests for loadlib
|
||||
local f = assert(package.loadlib(DC"lib1", p.."onefunction"))
|
||||
local a, b = f(15, 25)
|
||||
assert(a == 25 and b == 15)
|
||||
|
||||
f = assert(package.loadlib(DC"lib1", p.."anotherfunc"))
|
||||
assert(f(10, 20) == "10%20\n")
|
||||
|
||||
-- check error messages
|
||||
local f, err, when = package.loadlib(DC"lib1", p.."xuxu")
|
||||
assert(not f and type(err) == "string" and when == "init")
|
||||
f, err, when = package.loadlib("donotexist", p.."xuxu")
|
||||
assert(not f and type(err) == "string" and when == "open")
|
||||
|
||||
-- symbols from 'lib1' must be visible to other libraries
|
||||
f = assert(package.loadlib(DC"lib11", p.."luaopen_lib11"))
|
||||
assert(f() == "exported")
|
||||
|
||||
-- test C modules with prefixes in names
|
||||
package.cpath = DC"?"
|
||||
local lib2 = require"lib2-v2"
|
||||
-- check correct access to global environment and correct
|
||||
-- parameters
|
||||
assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2")
|
||||
assert(lib2.id("x") == "x")
|
||||
|
||||
-- test C submodules
|
||||
local fs = require"lib1.sub"
|
||||
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
|
||||
assert(fs.id(45) == 45)
|
||||
end
|
||||
|
||||
_ENV = _G
|
||||
|
||||
|
||||
-- testing preload
|
||||
|
||||
do
|
||||
local p = package
|
||||
package = {}
|
||||
p.preload.pl = function (...)
|
||||
local _ENV = {...}
|
||||
function xuxu (x) return x+20 end
|
||||
return _ENV
|
||||
end
|
||||
|
||||
local pl = require"pl"
|
||||
assert(require"pl" == pl)
|
||||
assert(pl.xuxu(10) == 30)
|
||||
assert(pl[1] == "pl" and pl[2] == nil)
|
||||
|
||||
package = p
|
||||
assert(type(package.path) == "string")
|
||||
end
|
||||
|
||||
print('+')
|
||||
|
||||
end --]
|
||||
|
||||
print("testing assignments, logical operators, and constructors")
|
||||
|
||||
local res, res2 = 27
|
||||
|
||||
a, b = 1, 2+3
|
||||
assert(a==1 and b==5)
|
||||
a={}
|
||||
function f() return 10, 11, 12 end
|
||||
a.x, b, a[1] = 1, 2, f()
|
||||
assert(a.x==1 and b==2 and a[1]==10)
|
||||
a[f()], b, a[f()+3] = f(), a, 'x'
|
||||
assert(a[10] == 10 and b == a and a[13] == 'x')
|
||||
|
||||
do
|
||||
local f = function (n) local x = {}; for i=1,n do x[i]=i end;
|
||||
return table.unpack(x) end;
|
||||
local a,b,c
|
||||
a,b = 0, f(1)
|
||||
assert(a == 0 and b == 1)
|
||||
A,b = 0, f(1)
|
||||
assert(A == 0 and b == 1)
|
||||
a,b,c = 0,5,f(4)
|
||||
assert(a==0 and b==5 and c==1)
|
||||
a,b,c = 0,5,f(0)
|
||||
assert(a==0 and b==5 and c==nil)
|
||||
end
|
||||
|
||||
a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
|
||||
assert(not a and b and c and d==6)
|
||||
|
||||
d = 20
|
||||
a, b, c, d = f()
|
||||
assert(a==10 and b==11 and c==12 and d==nil)
|
||||
a,b = f(), 1, 2, 3, f()
|
||||
assert(a==10 and b==1)
|
||||
|
||||
assert(a<b == false and a>b == true)
|
||||
assert((10 and 2) == 2)
|
||||
assert((10 or 2) == 10)
|
||||
assert((10 or assert(nil)) == 10)
|
||||
assert(not (nil and assert(nil)))
|
||||
assert((nil or "alo") == "alo")
|
||||
assert((nil and 10) == nil)
|
||||
assert((false and 10) == false)
|
||||
assert((true or 10) == true)
|
||||
assert((false or 10) == 10)
|
||||
assert(false ~= nil)
|
||||
assert(nil ~= false)
|
||||
assert(not nil == true)
|
||||
assert(not not nil == false)
|
||||
assert(not not 1 == true)
|
||||
assert(not not a == true)
|
||||
assert(not not (6 or nil) == true)
|
||||
assert(not not (nil and 56) == false)
|
||||
assert(not not (nil and true) == false)
|
||||
assert(not 10 == false)
|
||||
assert(not {} == false)
|
||||
assert(not 0.5 == false)
|
||||
assert(not "x" == false)
|
||||
|
||||
assert({} ~= {})
|
||||
print('+')
|
||||
|
||||
a = {}
|
||||
a[true] = 20
|
||||
a[false] = 10
|
||||
assert(a[1<2] == 20 and a[1>2] == 10)
|
||||
|
||||
function f(a) return a end
|
||||
|
||||
local a = {}
|
||||
for i=3000,-3000,-1 do a[i + 0.0] = i; end
|
||||
a[10e30] = "alo"; a[true] = 10; a[false] = 20
|
||||
assert(a[10e30] == 'alo' and a[not 1] == 20 and a[10<20] == 10)
|
||||
for i=3000,-3000,-1 do assert(a[i] == i); end
|
||||
a[print] = assert
|
||||
a[f] = print
|
||||
a[a] = a
|
||||
assert(a[a][a][a][a][print] == assert)
|
||||
a[print](a[a[f]] == a[print])
|
||||
assert(not pcall(function () local a = {}; a[nil] = 10 end))
|
||||
assert(not pcall(function () local a = {[nil] = 10} end))
|
||||
assert(a[nil] == nil)
|
||||
a = nil
|
||||
|
||||
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
|
||||
a, a.x, a.y = a, a[-3]
|
||||
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
|
||||
a[1], f(a)[2], b, c = {['alo']=assert}, 10, a[1], a[f], 6, 10, 23, f(a), 2
|
||||
a[1].alo(a[2]==10 and b==10 and c==print)
|
||||
|
||||
|
||||
-- test of large float/integer indices
|
||||
|
||||
-- compute maximum integer where all bits fit in a float
|
||||
local maxint = math.maxinteger
|
||||
|
||||
while maxint - 1.0 == maxint - 0.0 do -- trim (if needed) to fit in a float
|
||||
maxint = maxint // 2
|
||||
end
|
||||
|
||||
maxintF = maxint + 0.0 -- float version
|
||||
|
||||
assert(math.type(maxintF) == "float" and maxintF >= 2.0^14)
|
||||
|
||||
-- floats and integers must index the same places
|
||||
a[maxintF] = 10; a[maxintF - 1.0] = 11;
|
||||
a[-maxintF] = 12; a[-maxintF + 1.0] = 13;
|
||||
|
||||
assert(a[maxint] == 10 and a[maxint - 1] == 11 and
|
||||
a[-maxint] == 12 and a[-maxint + 1] == 13)
|
||||
|
||||
a[maxint] = 20
|
||||
a[-maxint] = 22
|
||||
|
||||
assert(a[maxintF] == 20 and a[maxintF - 1.0] == 11 and
|
||||
a[-maxintF] == 22 and a[-maxintF + 1.0] == 13)
|
||||
|
||||
a = nil
|
||||
|
||||
|
||||
-- test conflicts in multiple assignment
|
||||
do
|
||||
local a,i,j,b
|
||||
a = {'a', 'b'}; i=1; j=2; b=a
|
||||
i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i
|
||||
assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and
|
||||
b[3] == 1)
|
||||
end
|
||||
|
||||
-- repeat test with upvalues
|
||||
do
|
||||
local a,i,j,b
|
||||
a = {'a', 'b'}; i=1; j=2; b=a
|
||||
local function foo ()
|
||||
i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i
|
||||
end
|
||||
foo()
|
||||
assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and
|
||||
b[3] == 1)
|
||||
local t = {}
|
||||
(function (a) t[a], a = 10, 20 end)(1);
|
||||
assert(t[1] == 10)
|
||||
end
|
||||
|
||||
-- bug in 5.2 beta
|
||||
local function foo ()
|
||||
local a
|
||||
return function ()
|
||||
local b
|
||||
a, b = 3, 14 -- local and upvalue have same index
|
||||
return a, b
|
||||
end
|
||||
end
|
||||
|
||||
local a, b = foo()()
|
||||
assert(a == 3 and b == 14)
|
||||
|
||||
print('OK')
|
||||
|
||||
return res
|
||||
|
82
06/parser-gen/parsers/lua-5.3.4-tests/big.lua
Normal file
82
06/parser-gen/parsers/lua-5.3.4-tests/big.lua
Normal file
|
@ -0,0 +1,82 @@
|
|||
-- $Id: big.lua,v 1.32 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
if _soft then
|
||||
return 'a'
|
||||
end
|
||||
|
||||
print "testing large tables"
|
||||
|
||||
local debug = require"debug"
|
||||
|
||||
local lim = 2^18 + 1000
|
||||
local prog = { "local y = {0" }
|
||||
for i = 1, lim do prog[#prog + 1] = i end
|
||||
prog[#prog + 1] = "}\n"
|
||||
prog[#prog + 1] = "X = y\n"
|
||||
prog[#prog + 1] = ("assert(X[%d] == %d)"):format(lim - 1, lim - 2)
|
||||
prog[#prog + 1] = "return 0"
|
||||
prog = table.concat(prog, ";")
|
||||
|
||||
local env = {string = string, assert = assert}
|
||||
local f = assert(load(prog, nil, nil, env))
|
||||
|
||||
f()
|
||||
assert(env.X[lim] == lim - 1 and env.X[lim + 1] == lim)
|
||||
for k in pairs(env) do env[k] = nil end
|
||||
|
||||
-- yields during accesses larger than K (in RK)
|
||||
setmetatable(env, {
|
||||
__index = function (t, n) coroutine.yield('g'); return _G[n] end,
|
||||
__newindex = function (t, n, v) coroutine.yield('s'); _G[n] = v end,
|
||||
})
|
||||
|
||||
X = nil
|
||||
co = coroutine.wrap(f)
|
||||
assert(co() == 's')
|
||||
assert(co() == 'g')
|
||||
assert(co() == 'g')
|
||||
assert(co() == 0)
|
||||
|
||||
assert(X[lim] == lim - 1 and X[lim + 1] == lim)
|
||||
|
||||
-- errors in accesses larger than K (in RK)
|
||||
getmetatable(env).__index = function () end
|
||||
getmetatable(env).__newindex = function () end
|
||||
local e, m = pcall(f)
|
||||
assert(not e and m:find("global 'X'"))
|
||||
|
||||
-- errors in metamethods
|
||||
getmetatable(env).__newindex = function () error("hi") end
|
||||
local e, m = xpcall(f, debug.traceback)
|
||||
assert(not e and m:find("'__newindex'"))
|
||||
|
||||
f, X = nil
|
||||
|
||||
coroutine.yield'b'
|
||||
|
||||
if 2^32 == 0 then -- (small integers) {
|
||||
|
||||
print "testing string length overflow"
|
||||
|
||||
local repstrings = 192 -- number of strings to be concatenated
|
||||
local ssize = math.ceil(2.0^32 / repstrings) + 1 -- size of each string
|
||||
|
||||
assert(repstrings * ssize > 2.0^32) -- it should be larger than maximum size
|
||||
|
||||
local longs = string.rep("\0", ssize) -- create one long string
|
||||
|
||||
-- create function to concatentate 'repstrings' copies of its argument
|
||||
local rep = assert(load(
|
||||
"local a = ...; return " .. string.rep("a", repstrings, "..")))
|
||||
|
||||
local a, b = pcall(rep, longs) -- call that function
|
||||
|
||||
-- it should fail without creating string (result would be too large)
|
||||
assert(not a and string.find(b, "overflow"))
|
||||
|
||||
end -- }
|
||||
|
||||
print'OK'
|
||||
|
||||
return 'a'
|
328
06/parser-gen/parsers/lua-5.3.4-tests/bitwise.lua
Normal file
328
06/parser-gen/parsers/lua-5.3.4-tests/bitwise.lua
Normal file
|
@ -0,0 +1,328 @@
|
|||
-- $Id: bitwise.lua,v 1.26 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print("testing bitwise operations")
|
||||
|
||||
local numbits = string.packsize('j') * 8
|
||||
|
||||
assert(~0 == -1)
|
||||
|
||||
assert((1 << (numbits - 1)) == math.mininteger)
|
||||
|
||||
-- basic tests for bitwise operators;
|
||||
-- use variables to avoid constant folding
|
||||
local a, b, c, d
|
||||
a = 0xFFFFFFFFFFFFFFFF
|
||||
assert(a == -1 and a & -1 == a and a & 35 == 35)
|
||||
a = 0xF0F0F0F0F0F0F0F0
|
||||
assert(a | -1 == -1)
|
||||
assert(a ~ a == 0 and a ~ 0 == a and a ~ ~a == -1)
|
||||
assert(a >> 4 == ~a)
|
||||
a = 0xF0; b = 0xCC; c = 0xAA; d = 0xFD
|
||||
assert(a | b ~ c & d == 0xF4)
|
||||
|
||||
a = 0xF0.0; b = 0xCC.0; c = "0xAA.0"; d = "0xFD.0"
|
||||
assert(a | b ~ c & d == 0xF4)
|
||||
|
||||
a = 0xF0000000; b = 0xCC000000;
|
||||
c = 0xAA000000; d = 0xFD000000
|
||||
assert(a | b ~ c & d == 0xF4000000)
|
||||
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
|
||||
|
||||
a = a << 32
|
||||
b = b << 32
|
||||
c = c << 32
|
||||
d = d << 32
|
||||
assert(a | b ~ c & d == 0xF4000000 << 32)
|
||||
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
|
||||
|
||||
assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000)
|
||||
assert(-1 >> (numbits - 1) == 1)
|
||||
assert(-1 >> numbits == 0 and
|
||||
-1 >> -numbits == 0 and
|
||||
-1 << numbits == 0 and
|
||||
-1 << -numbits == 0)
|
||||
|
||||
assert((2^30 - 1) << 2^30 == 0)
|
||||
assert((2^30 - 1) >> 2^30 == 0)
|
||||
|
||||
assert(1 >> -3 == 1 << 3 and 1000 >> 5 == 1000 << -5)
|
||||
|
||||
|
||||
-- coercion from strings to integers
|
||||
assert("0xffffffffffffffff" | 0 == -1)
|
||||
assert("0xfffffffffffffffe" & "-1" == -2)
|
||||
assert(" \t-0xfffffffffffffffe\n\t" & "-1" == 2)
|
||||
assert(" \n -45 \t " >> " -2 " == -45 * 4)
|
||||
|
||||
-- out of range number
|
||||
assert(not pcall(function () return "0xffffffffffffffff.0" | 0 end))
|
||||
|
||||
-- embedded zeros
|
||||
assert(not pcall(function () return "0xffffffffffffffff\0" | 0 end))
|
||||
|
||||
print'+'
|
||||
|
||||
|
||||
package.preload.bit32 = function () --{
|
||||
|
||||
-- no built-in 'bit32' library: implement it using bitwise operators
|
||||
|
||||
local bit = {}
|
||||
|
||||
function bit.bnot (a)
|
||||
return ~a & 0xFFFFFFFF
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- in all vararg functions, avoid creating 'arg' table when there are
|
||||
-- only 2 (or less) parameters, as 2 parameters is the common case
|
||||
--
|
||||
|
||||
function bit.band (x, y, z, ...)
|
||||
if not z then
|
||||
|
||||
else
|
||||
local arg = {...}
|
||||
local res = x & y & z
|
||||
for i = 1, #arg do res = res & arg[i] end
|
||||
return res & 0xFFFFFFFF
|
||||
end
|
||||
end
|
||||
|
||||
function bit.bor (x, y, z, ...)
|
||||
if not z then
|
||||
return ((x or 0) | (y or 0)) & 0xFFFFFFFF
|
||||
else
|
||||
local arg = {...}
|
||||
local res = x | y | z
|
||||
for i = 1, #arg do res = res | arg[i] end
|
||||
return res & 0xFFFFFFFF
|
||||
end
|
||||
end
|
||||
|
||||
function bit.bxor (x, y, z, ...)
|
||||
if not z then
|
||||
return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF
|
||||
else
|
||||
local arg = {...}
|
||||
local res = x ~ y ~ z
|
||||
for i = 1, #arg do res = res ~ arg[i] end
|
||||
return res & 0xFFFFFFFF
|
||||
end
|
||||
end
|
||||
|
||||
function bit.btest (...)
|
||||
return bit.band(...) ~= 0
|
||||
end
|
||||
|
||||
function bit.lshift (a, b)
|
||||
return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF
|
||||
end
|
||||
|
||||
function bit.rshift (a, b)
|
||||
return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF
|
||||
end
|
||||
|
||||
function bit.arshift (a, b)
|
||||
a = a & 0xFFFFFFFF
|
||||
if b <= 0 or (a & 0x80000000) == 0 then
|
||||
return (a >> b) & 0xFFFFFFFF
|
||||
else
|
||||
return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF
|
||||
end
|
||||
end
|
||||
|
||||
function bit.lrotate (a ,b)
|
||||
b = b & 31
|
||||
a = a & 0xFFFFFFFF
|
||||
a = (a << b) | (a >> (32 - b))
|
||||
return a & 0xFFFFFFFF
|
||||
end
|
||||
|
||||
function bit.rrotate (a, b)
|
||||
return bit.lrotate(a, -b)
|
||||
end
|
||||
|
||||
local function checkfield (f, w)
|
||||
w = w or 1
|
||||
assert(f >= 0, "field cannot be negative")
|
||||
assert(w > 0, "width must be positive")
|
||||
assert(f + w <= 32, "trying to access non-existent bits")
|
||||
return f, ~(-1 << w)
|
||||
end
|
||||
|
||||
function bit.extract (a, f, w)
|
||||
local f, mask = checkfield(f, w)
|
||||
return (a >> f) & mask
|
||||
end
|
||||
|
||||
function bit.replace (a, v, f, w)
|
||||
local f, mask = checkfield(f, w)
|
||||
v = v & mask
|
||||
a = (a & ~(mask << f)) | (v << f)
|
||||
return a & 0xFFFFFFFF
|
||||
end
|
||||
|
||||
return bit
|
||||
|
||||
end --}
|
||||
|
||||
|
||||
print("testing bitwise library")
|
||||
|
||||
local bit32 = require'bit32'
|
||||
|
||||
assert(bit32.band() == bit32.bnot(0))
|
||||
assert(bit32.btest() == true)
|
||||
assert(bit32.bor() == 0)
|
||||
assert(bit32.bxor() == 0)
|
||||
|
||||
assert(bit32.band() == bit32.band(0xffffffff))
|
||||
assert(bit32.band(1,2) == 0)
|
||||
|
||||
|
||||
-- out-of-range numbers
|
||||
assert(bit32.band(-1) == 0xffffffff)
|
||||
assert(bit32.band((1 << 33) - 1) == 0xffffffff)
|
||||
assert(bit32.band(-(1 << 33) - 1) == 0xffffffff)
|
||||
assert(bit32.band((1 << 33) + 1) == 1)
|
||||
assert(bit32.band(-(1 << 33) + 1) == 1)
|
||||
assert(bit32.band(-(1 << 40)) == 0)
|
||||
assert(bit32.band(1 << 40) == 0)
|
||||
assert(bit32.band(-(1 << 40) - 2) == 0xfffffffe)
|
||||
assert(bit32.band((1 << 40) - 4) == 0xfffffffc)
|
||||
|
||||
assert(bit32.lrotate(0, -1) == 0)
|
||||
assert(bit32.lrotate(0, 7) == 0)
|
||||
assert(bit32.lrotate(0x12345678, 0) == 0x12345678)
|
||||
assert(bit32.lrotate(0x12345678, 32) == 0x12345678)
|
||||
assert(bit32.lrotate(0x12345678, 4) == 0x23456781)
|
||||
assert(bit32.rrotate(0x12345678, -4) == 0x23456781)
|
||||
assert(bit32.lrotate(0x12345678, -8) == 0x78123456)
|
||||
assert(bit32.rrotate(0x12345678, 8) == 0x78123456)
|
||||
assert(bit32.lrotate(0xaaaaaaaa, 2) == 0xaaaaaaaa)
|
||||
assert(bit32.lrotate(0xaaaaaaaa, -2) == 0xaaaaaaaa)
|
||||
for i = -50, 50 do
|
||||
assert(bit32.lrotate(0x89abcdef, i) == bit32.lrotate(0x89abcdef, i%32))
|
||||
end
|
||||
|
||||
assert(bit32.lshift(0x12345678, 4) == 0x23456780)
|
||||
assert(bit32.lshift(0x12345678, 8) == 0x34567800)
|
||||
assert(bit32.lshift(0x12345678, -4) == 0x01234567)
|
||||
assert(bit32.lshift(0x12345678, -8) == 0x00123456)
|
||||
assert(bit32.lshift(0x12345678, 32) == 0)
|
||||
assert(bit32.lshift(0x12345678, -32) == 0)
|
||||
assert(bit32.rshift(0x12345678, 4) == 0x01234567)
|
||||
assert(bit32.rshift(0x12345678, 8) == 0x00123456)
|
||||
assert(bit32.rshift(0x12345678, 32) == 0)
|
||||
assert(bit32.rshift(0x12345678, -32) == 0)
|
||||
assert(bit32.arshift(0x12345678, 0) == 0x12345678)
|
||||
assert(bit32.arshift(0x12345678, 1) == 0x12345678 // 2)
|
||||
assert(bit32.arshift(0x12345678, -1) == 0x12345678 * 2)
|
||||
assert(bit32.arshift(-1, 1) == 0xffffffff)
|
||||
assert(bit32.arshift(-1, 24) == 0xffffffff)
|
||||
assert(bit32.arshift(-1, 32) == 0xffffffff)
|
||||
assert(bit32.arshift(-1, -1) == bit32.band(-1 * 2, 0xffffffff))
|
||||
|
||||
assert(0x12345678 << 4 == 0x123456780)
|
||||
assert(0x12345678 << 8 == 0x1234567800)
|
||||
assert(0x12345678 << -4 == 0x01234567)
|
||||
assert(0x12345678 << -8 == 0x00123456)
|
||||
assert(0x12345678 << 32 == 0x1234567800000000)
|
||||
assert(0x12345678 << -32 == 0)
|
||||
assert(0x12345678 >> 4 == 0x01234567)
|
||||
assert(0x12345678 >> 8 == 0x00123456)
|
||||
assert(0x12345678 >> 32 == 0)
|
||||
assert(0x12345678 >> -32 == 0x1234567800000000)
|
||||
|
||||
print("+")
|
||||
-- some special cases
|
||||
local c = {0, 1, 2, 3, 10, 0x80000000, 0xaaaaaaaa, 0x55555555,
|
||||
0xffffffff, 0x7fffffff}
|
||||
|
||||
for _, b in pairs(c) do
|
||||
assert(bit32.band(b) == b)
|
||||
assert(bit32.band(b, b) == b)
|
||||
assert(bit32.band(b, b, b, b) == b)
|
||||
assert(bit32.btest(b, b) == (b ~= 0))
|
||||
assert(bit32.band(b, b, b) == b)
|
||||
assert(bit32.band(b, b, b, ~b) == 0)
|
||||
assert(bit32.btest(b, b, b) == (b ~= 0))
|
||||
assert(bit32.band(b, bit32.bnot(b)) == 0)
|
||||
assert(bit32.bor(b, bit32.bnot(b)) == bit32.bnot(0))
|
||||
assert(bit32.bor(b) == b)
|
||||
assert(bit32.bor(b, b) == b)
|
||||
assert(bit32.bor(b, b, b) == b)
|
||||
assert(bit32.bor(b, b, 0, ~b) == 0xffffffff)
|
||||
assert(bit32.bxor(b) == b)
|
||||
assert(bit32.bxor(b, b) == 0)
|
||||
assert(bit32.bxor(b, b, b) == b)
|
||||
assert(bit32.bxor(b, b, b, b) == 0)
|
||||
assert(bit32.bxor(b, 0) == b)
|
||||
assert(bit32.bnot(b) ~= b)
|
||||
assert(bit32.bnot(bit32.bnot(b)) == b)
|
||||
assert(bit32.bnot(b) == (1 << 32) - 1 - b)
|
||||
assert(bit32.lrotate(b, 32) == b)
|
||||
assert(bit32.rrotate(b, 32) == b)
|
||||
assert(bit32.lshift(bit32.lshift(b, -4), 4) == bit32.band(b, bit32.bnot(0xf)))
|
||||
assert(bit32.rshift(bit32.rshift(b, 4), -4) == bit32.band(b, bit32.bnot(0xf)))
|
||||
end
|
||||
|
||||
-- for this test, use at most 24 bits (mantissa of a single float)
|
||||
c = {0, 1, 2, 3, 10, 0x800000, 0xaaaaaa, 0x555555, 0xffffff, 0x7fffff}
|
||||
for _, b in pairs(c) do
|
||||
for i = -40, 40 do
|
||||
local x = bit32.lshift(b, i)
|
||||
local y = math.floor(math.fmod(b * 2.0^i, 2.0^32))
|
||||
assert(math.fmod(x - y, 2.0^32) == 0)
|
||||
end
|
||||
end
|
||||
|
||||
assert(not pcall(bit32.band, {}))
|
||||
assert(not pcall(bit32.bnot, "a"))
|
||||
assert(not pcall(bit32.lshift, 45))
|
||||
assert(not pcall(bit32.lshift, 45, print))
|
||||
assert(not pcall(bit32.rshift, 45, print))
|
||||
|
||||
print("+")
|
||||
|
||||
|
||||
-- testing extract/replace
|
||||
|
||||
assert(bit32.extract(0x12345678, 0, 4) == 8)
|
||||
assert(bit32.extract(0x12345678, 4, 4) == 7)
|
||||
assert(bit32.extract(0xa0001111, 28, 4) == 0xa)
|
||||
assert(bit32.extract(0xa0001111, 31, 1) == 1)
|
||||
assert(bit32.extract(0x50000111, 31, 1) == 0)
|
||||
assert(bit32.extract(0xf2345679, 0, 32) == 0xf2345679)
|
||||
|
||||
assert(not pcall(bit32.extract, 0, -1))
|
||||
assert(not pcall(bit32.extract, 0, 32))
|
||||
assert(not pcall(bit32.extract, 0, 0, 33))
|
||||
assert(not pcall(bit32.extract, 0, 31, 2))
|
||||
|
||||
assert(bit32.replace(0x12345678, 5, 28, 4) == 0x52345678)
|
||||
assert(bit32.replace(0x12345678, 0x87654321, 0, 32) == 0x87654321)
|
||||
assert(bit32.replace(0, 1, 2) == 2^2)
|
||||
assert(bit32.replace(0, -1, 4) == 2^4)
|
||||
assert(bit32.replace(-1, 0, 31) == (1 << 31) - 1)
|
||||
assert(bit32.replace(-1, 0, 1, 2) == (1 << 32) - 7)
|
||||
|
||||
|
||||
-- testing conversion of floats
|
||||
|
||||
assert(bit32.bor(3.0) == 3)
|
||||
assert(bit32.bor(-4.0) == 0xfffffffc)
|
||||
|
||||
-- large floats and large-enough integers?
|
||||
if 2.0^50 < 2.0^50 + 1.0 and 2.0^50 < (-1 >> 1) then
|
||||
assert(bit32.bor(2.0^32 - 5.0) == 0xfffffffb)
|
||||
assert(bit32.bor(-2.0^32 - 6.0) == 0xfffffffa)
|
||||
assert(bit32.bor(2.0^48 - 5.0) == 0xfffffffb)
|
||||
assert(bit32.bor(-2.0^48 - 6.0) == 0xfffffffa)
|
||||
end
|
||||
|
||||
print'OK'
|
||||
|
401
06/parser-gen/parsers/lua-5.3.4-tests/calls.lua
Normal file
401
06/parser-gen/parsers/lua-5.3.4-tests/calls.lua
Normal file
|
@ -0,0 +1,401 @@
|
|||
-- $Id: calls.lua,v 1.60 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print("testing functions and calls")
|
||||
|
||||
local debug = require "debug"
|
||||
|
||||
-- get the opportunity to test 'type' too ;)
|
||||
|
||||
assert(type(1<2) == 'boolean')
|
||||
assert(type(true) == 'boolean' and type(false) == 'boolean')
|
||||
assert(type(nil) == 'nil'
|
||||
and type(-3) == 'number'
|
||||
and type'x' == 'string'
|
||||
and type{} == 'table'
|
||||
and type(type) == 'function')
|
||||
|
||||
assert(type(assert) == type(print))
|
||||
function f (x) return a:x (x) end
|
||||
assert(type(f) == 'function')
|
||||
assert(not pcall(type))
|
||||
|
||||
|
||||
do -- test error in 'print' too...
|
||||
local tostring = _ENV.tostring
|
||||
|
||||
_ENV.tostring = nil
|
||||
local st, msg = pcall(print, 1)
|
||||
assert(st == false and string.find(msg, "attempt to call a nil value"))
|
||||
|
||||
_ENV.tostring = function () return {} end
|
||||
local st, msg = pcall(print, 1)
|
||||
assert(st == false and string.find(msg, "must return a string"))
|
||||
|
||||
_ENV.tostring = tostring
|
||||
end
|
||||
|
||||
|
||||
-- testing local-function recursion
|
||||
fact = false
|
||||
do
|
||||
local res = 1
|
||||
local function fact (n)
|
||||
if n==0 then return res
|
||||
else return n*fact(n-1)
|
||||
end
|
||||
end
|
||||
assert(fact(5) == 120)
|
||||
end
|
||||
assert(fact == false)
|
||||
|
||||
-- testing declarations
|
||||
a = {i = 10}
|
||||
self = 20
|
||||
function a:x (x) return x+self.i end
|
||||
function a.y (x) return x+self end
|
||||
|
||||
assert(a:x(1)+10 == a.y(1))
|
||||
|
||||
a.t = {i=-100}
|
||||
a["t"].x = function (self, a,b) return self.i+a+b end
|
||||
|
||||
assert(a.t:x(2,3) == -95)
|
||||
|
||||
do
|
||||
local a = {x=0}
|
||||
function a:add (x) self.x, a.y = self.x+x, 20; return self end
|
||||
assert(a:add(10):add(20):add(30).x == 60 and a.y == 20)
|
||||
end
|
||||
|
||||
local a = {b={c={}}}
|
||||
|
||||
function a.b.c.f1 (x) return x+1 end
|
||||
function a.b.c:f2 (x,y) self[x] = y end
|
||||
assert(a.b.c.f1(4) == 5)
|
||||
a.b.c:f2('k', 12); assert(a.b.c.k == 12)
|
||||
|
||||
print('+')
|
||||
|
||||
t = nil -- 'declare' t
|
||||
function f(a,b,c) local d = 'a'; t={a,b,c,d} end
|
||||
|
||||
f( -- this line change must be valid
|
||||
1,2)
|
||||
assert(t[1] == 1 and t[2] == 2 and t[3] == nil and t[4] == 'a')
|
||||
f(1,2, -- this one too
|
||||
3,4)
|
||||
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
|
||||
|
||||
function fat(x)
|
||||
if x <= 1 then return 1
|
||||
else return x*load("return fat(" .. x-1 .. ")", "")()
|
||||
end
|
||||
end
|
||||
|
||||
assert(load "load 'assert(fat(6)==720)' () ")()
|
||||
a = load('return fat(5), 3')
|
||||
a,b = a()
|
||||
assert(a == 120 and b == 3)
|
||||
print('+')
|
||||
|
||||
function err_on_n (n)
|
||||
if n==0 then error(); exit(1);
|
||||
else err_on_n (n-1); exit(1);
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
function dummy (n)
|
||||
if n > 0 then
|
||||
assert(not pcall(err_on_n, n))
|
||||
dummy(n-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dummy(10)
|
||||
|
||||
function deep (n)
|
||||
if n>0 then deep(n-1) end
|
||||
end
|
||||
deep(10)
|
||||
deep(200)
|
||||
|
||||
-- testing tail call
|
||||
function deep (n) if n>0 then return deep(n-1) else return 101 end end
|
||||
assert(deep(30000) == 101)
|
||||
a = {}
|
||||
function a:deep (n) if n>0 then return self:deep(n-1) else return 101 end end
|
||||
assert(a:deep(30000) == 101)
|
||||
|
||||
print('+')
|
||||
|
||||
|
||||
a = nil
|
||||
(function (x) a=x end)(23)
|
||||
assert(a == 23 and (function (x) return x*2 end)(20) == 40)
|
||||
|
||||
|
||||
-- testing closures
|
||||
|
||||
-- fixed-point operator
|
||||
Z = function (le)
|
||||
local function a (f)
|
||||
return le(function (x) return f(f)(x) end)
|
||||
end
|
||||
return a(a)
|
||||
end
|
||||
|
||||
|
||||
-- non-recursive factorial
|
||||
|
||||
F = function (f)
|
||||
return function (n)
|
||||
if n == 0 then return 1
|
||||
else return n*f(n-1) end
|
||||
end
|
||||
end
|
||||
|
||||
fat = Z(F)
|
||||
|
||||
assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4))
|
||||
|
||||
local function g (z)
|
||||
local function f (a,b,c,d)
|
||||
return function (x,y) return a+b+c+d+a+x+y+z end
|
||||
end
|
||||
return f(z,z+1,z+2,z+3)
|
||||
end
|
||||
|
||||
f = g(10)
|
||||
assert(f(9, 16) == 10+11+12+13+10+9+16+10)
|
||||
|
||||
Z, F, f = nil
|
||||
print('+')
|
||||
|
||||
-- testing multiple returns
|
||||
|
||||
function unlpack (t, i)
|
||||
i = i or 1
|
||||
if (i <= #t) then
|
||||
return t[i], unlpack(t, i+1)
|
||||
end
|
||||
end
|
||||
|
||||
function equaltab (t1, t2)
|
||||
assert(#t1 == #t2)
|
||||
for i = 1, #t1 do
|
||||
assert(t1[i] == t2[i])
|
||||
end
|
||||
end
|
||||
|
||||
local pack = function (...) return (table.pack(...)) end
|
||||
|
||||
function f() return 1,2,30,4 end
|
||||
function ret2 (a,b) return a,b end
|
||||
|
||||
local a,b,c,d = unlpack{1,2,3}
|
||||
assert(a==1 and b==2 and c==3 and d==nil)
|
||||
a = {1,2,3,4,false,10,'alo',false,assert}
|
||||
equaltab(pack(unlpack(a)), a)
|
||||
equaltab(pack(unlpack(a), -1), {1,-1})
|
||||
a,b,c,d = ret2(f()), ret2(f())
|
||||
assert(a==1 and b==1 and c==2 and d==nil)
|
||||
a,b,c,d = unlpack(pack(ret2(f()), ret2(f())))
|
||||
assert(a==1 and b==1 and c==2 and d==nil)
|
||||
a,b,c,d = unlpack(pack(ret2(f()), (ret2(f()))))
|
||||
assert(a==1 and b==1 and c==nil and d==nil)
|
||||
|
||||
a = ret2{ unlpack{1,2,3}, unlpack{3,2,1}, unlpack{"a", "b"}}
|
||||
assert(a[1] == 1 and a[2] == 3 and a[3] == "a" and a[4] == "b")
|
||||
|
||||
|
||||
-- testing calls with 'incorrect' arguments
|
||||
rawget({}, "x", 1)
|
||||
rawset({}, "x", 1, 2)
|
||||
assert(math.sin(1,2) == math.sin(1))
|
||||
table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")
|
||||
|
||||
|
||||
-- test for generic load
|
||||
local x = "-- a comment\0\0\0\n x = 10 + \n23; \
|
||||
local a = function () x = 'hi' end; \
|
||||
return '\0'"
|
||||
function read1 (x)
|
||||
local i = 0
|
||||
return function ()
|
||||
collectgarbage()
|
||||
i=i+1
|
||||
return string.sub(x, i, i)
|
||||
end
|
||||
end
|
||||
|
||||
function cannotload (msg, a,b)
|
||||
assert(not a and string.find(b, msg))
|
||||
end
|
||||
|
||||
a = assert(load(read1(x), "modname", "t", _G))
|
||||
assert(a() == "\0" and _G.x == 33)
|
||||
assert(debug.getinfo(a).source == "modname")
|
||||
-- cannot read text in binary mode
|
||||
cannotload("attempt to load a text chunk", load(read1(x), "modname", "b", {}))
|
||||
cannotload("attempt to load a text chunk", load(x, "modname", "b"))
|
||||
|
||||
a = assert(load(function () return nil end))
|
||||
a() -- empty chunk
|
||||
|
||||
assert(not load(function () return true end))
|
||||
|
||||
|
||||
-- small bug
|
||||
local t = {nil, "return ", "3"}
|
||||
f, msg = load(function () return table.remove(t, 1) end)
|
||||
assert(f() == nil) -- should read the empty chunk
|
||||
|
||||
-- another small bug (in 5.2.1)
|
||||
f = load(string.dump(function () return 1 end), nil, "b", {})
|
||||
assert(type(f) == "function" and f() == 1)
|
||||
|
||||
|
||||
x = string.dump(load("x = 1; return x"))
|
||||
a = assert(load(read1(x), nil, "b"))
|
||||
assert(a() == 1 and _G.x == 1)
|
||||
cannotload("attempt to load a binary chunk", load(read1(x), nil, "t"))
|
||||
cannotload("attempt to load a binary chunk", load(x, nil, "t"))
|
||||
|
||||
assert(not pcall(string.dump, print)) -- no dump of C functions
|
||||
|
||||
cannotload("unexpected symbol", load(read1("*a = 123")))
|
||||
cannotload("unexpected symbol", load("*a = 123"))
|
||||
cannotload("hhi", load(function () error("hhi") end))
|
||||
|
||||
-- any value is valid for _ENV
|
||||
assert(load("return _ENV", nil, nil, 123)() == 123)
|
||||
|
||||
|
||||
-- load when _ENV is not first upvalue
|
||||
local x; XX = 123
|
||||
local function h ()
|
||||
local y=x -- use 'x', so that it becomes 1st upvalue
|
||||
return XX -- global name
|
||||
end
|
||||
local d = string.dump(h)
|
||||
x = load(d, "", "b")
|
||||
assert(debug.getupvalue(x, 2) == '_ENV')
|
||||
debug.setupvalue(x, 2, _G)
|
||||
assert(x() == 123)
|
||||
|
||||
assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17)
|
||||
|
||||
|
||||
-- test generic load with nested functions
|
||||
x = [[
|
||||
return function (x)
|
||||
return function (y)
|
||||
return function (z)
|
||||
return x+y+z
|
||||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
a = assert(load(read1(x)))
|
||||
assert(a()(2)(3)(10) == 15)
|
||||
|
||||
|
||||
-- test for dump/undump with upvalues
|
||||
local a, b = 20, 30
|
||||
x = load(string.dump(function (x)
|
||||
if x == "set" then a = 10+b; b = b+1 else
|
||||
return a
|
||||
end
|
||||
end), "", "b", nil)
|
||||
assert(x() == nil)
|
||||
assert(debug.setupvalue(x, 1, "hi") == "a")
|
||||
assert(x() == "hi")
|
||||
assert(debug.setupvalue(x, 2, 13) == "b")
|
||||
assert(not debug.setupvalue(x, 3, 10)) -- only 2 upvalues
|
||||
x("set")
|
||||
assert(x() == 23)
|
||||
x("set")
|
||||
assert(x() == 24)
|
||||
|
||||
-- test for dump/undump with many upvalues
|
||||
do
|
||||
local nup = 200 -- maximum number of local variables
|
||||
local prog = {"local a1"}
|
||||
for i = 2, nup do prog[#prog + 1] = ", a" .. i end
|
||||
prog[#prog + 1] = " = 1"
|
||||
for i = 2, nup do prog[#prog + 1] = ", " .. i end
|
||||
local sum = 1
|
||||
prog[#prog + 1] = "; return function () return a1"
|
||||
for i = 2, nup do prog[#prog + 1] = " + a" .. i; sum = sum + i end
|
||||
prog[#prog + 1] = " end"
|
||||
prog = table.concat(prog)
|
||||
local f = assert(load(prog))()
|
||||
assert(f() == sum)
|
||||
|
||||
f = load(string.dump(f)) -- main chunk now has many upvalues
|
||||
local a = 10
|
||||
local h = function () return a end
|
||||
for i = 1, nup do
|
||||
debug.upvaluejoin(f, i, h, 1)
|
||||
end
|
||||
assert(f() == 10 * nup)
|
||||
end
|
||||
|
||||
-- test for long method names
|
||||
do
|
||||
local t = {x = 1}
|
||||
function t:_012345678901234567890123456789012345678901234567890123456789 ()
|
||||
return self.x
|
||||
end
|
||||
assert(t:_012345678901234567890123456789012345678901234567890123456789() == 1)
|
||||
end
|
||||
|
||||
|
||||
-- test for bug in parameter adjustment
|
||||
assert((function () return nil end)(4) == nil)
|
||||
assert((function () local a; return a end)(4) == nil)
|
||||
assert((function (a) return a end)() == nil)
|
||||
|
||||
|
||||
print("testing binary chunks")
|
||||
do
|
||||
local header = string.pack("c4BBc6BBBBBj",
|
||||
"\27Lua", -- signature
|
||||
5*16 + 3, -- version 5.3
|
||||
0, -- format
|
||||
"\x19\x93\r\n\x1a\n", -- data
|
||||
string.packsize("i"), -- sizeof(int)
|
||||
string.packsize("T"), -- sizeof(size_t)
|
||||
4, -- size of instruction
|
||||
string.packsize("j"), -- sizeof(lua integer)
|
||||
string.packsize("n"), -- sizeof(lua number)
|
||||
0x5678 -- LUAC_INT
|
||||
-- LUAC_NUM may not have a unique binary representation (padding...)
|
||||
)
|
||||
local c = string.dump(function () local a = 1; local b = 3; return a+b*3 end)
|
||||
|
||||
assert(string.sub(c, 1, #header) == header)
|
||||
|
||||
-- corrupted header
|
||||
for i = 1, #header do
|
||||
local s = string.sub(c, 1, i - 1) ..
|
||||
string.char(string.byte(string.sub(c, i, i)) + 1) ..
|
||||
string.sub(c, i + 1, -1)
|
||||
assert(#s == #c)
|
||||
assert(not load(s))
|
||||
end
|
||||
|
||||
-- loading truncated binary chunks
|
||||
for i = 1, #c - 1 do
|
||||
local st, msg = load(string.sub(c, 1, i))
|
||||
assert(not st and string.find(msg, "truncated"))
|
||||
end
|
||||
assert(assert(load(c))() == 10)
|
||||
end
|
||||
|
||||
print('OK')
|
||||
return deep
|
247
06/parser-gen/parsers/lua-5.3.4-tests/closure.lua
Normal file
247
06/parser-gen/parsers/lua-5.3.4-tests/closure.lua
Normal file
|
@ -0,0 +1,247 @@
|
|||
-- $Id: closure.lua,v 1.59 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print "testing closures"
|
||||
|
||||
local A,B = 0,{g=10}
|
||||
function f(x)
|
||||
local a = {}
|
||||
for i=1,1000 do
|
||||
local y = 0
|
||||
do
|
||||
a[i] = function () B.g = B.g+1; y = y+x; return y+A end
|
||||
end
|
||||
end
|
||||
local dummy = function () return a[A] end
|
||||
collectgarbage()
|
||||
A = 1; assert(dummy() == a[1]); A = 0;
|
||||
assert(a[1]() == x)
|
||||
assert(a[3]() == x)
|
||||
collectgarbage()
|
||||
assert(B.g == 12)
|
||||
return a
|
||||
end
|
||||
|
||||
local a = f(10)
|
||||
-- force a GC in this level
|
||||
local x = {[1] = {}} -- to detect a GC
|
||||
setmetatable(x, {__mode = 'kv'})
|
||||
while x[1] do -- repeat until GC
|
||||
local a = A..A..A..A -- create garbage
|
||||
A = A+1
|
||||
end
|
||||
assert(a[1]() == 20+A)
|
||||
assert(a[1]() == 30+A)
|
||||
assert(a[2]() == 10+A)
|
||||
collectgarbage()
|
||||
assert(a[2]() == 20+A)
|
||||
assert(a[2]() == 30+A)
|
||||
assert(a[3]() == 20+A)
|
||||
assert(a[8]() == 10+A)
|
||||
assert(getmetatable(x).__mode == 'kv')
|
||||
assert(B.g == 19)
|
||||
|
||||
|
||||
-- testing equality
|
||||
a = {}
|
||||
for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end
|
||||
assert(a[3] == a[4] and a[4] == a[5])
|
||||
|
||||
for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end
|
||||
assert(a[3] ~= a[4] and a[4] ~= a[5])
|
||||
|
||||
local function f()
|
||||
return function (x) return math.sin(_ENV[x]) end
|
||||
end
|
||||
assert(f() == f())
|
||||
|
||||
|
||||
-- testing closures with 'for' control variable
|
||||
a = {}
|
||||
for i=1,10 do
|
||||
a[i] = {set = function(x) i=x end, get = function () return i end}
|
||||
if i == 3 then break end
|
||||
end
|
||||
assert(a[4] == nil)
|
||||
a[1].set(10)
|
||||
assert(a[2].get() == 2)
|
||||
a[2].set('a')
|
||||
assert(a[3].get() == 3)
|
||||
assert(a[2].get() == 'a')
|
||||
|
||||
a = {}
|
||||
local t = {"a", "b"}
|
||||
for i = 1, #t do
|
||||
local k = t[i]
|
||||
a[i] = {set = function(x, y) i=x; k=y end,
|
||||
get = function () return i, k end}
|
||||
if i == 2 then break end
|
||||
end
|
||||
a[1].set(10, 20)
|
||||
local r,s = a[2].get()
|
||||
assert(r == 2 and s == 'b')
|
||||
r,s = a[1].get()
|
||||
assert(r == 10 and s == 20)
|
||||
a[2].set('a', 'b')
|
||||
r,s = a[2].get()
|
||||
assert(r == "a" and s == "b")
|
||||
|
||||
|
||||
-- testing closures with 'for' control variable x break
|
||||
for i=1,3 do
|
||||
f = function () return i end
|
||||
break
|
||||
end
|
||||
assert(f() == 1)
|
||||
|
||||
for k = 1, #t do
|
||||
local v = t[k]
|
||||
f = function () return k, v end
|
||||
break
|
||||
end
|
||||
assert(({f()})[1] == 1)
|
||||
assert(({f()})[2] == "a")
|
||||
|
||||
|
||||
-- testing closure x break x return x errors
|
||||
|
||||
local b
|
||||
function f(x)
|
||||
local first = 1
|
||||
while 1 do
|
||||
if x == 3 and not first then return end
|
||||
local a = 'xuxu'
|
||||
b = function (op, y)
|
||||
if op == 'set' then
|
||||
a = x+y
|
||||
else
|
||||
return a
|
||||
end
|
||||
end
|
||||
if x == 1 then do break end
|
||||
elseif x == 2 then return
|
||||
else if x ~= 3 then error() end
|
||||
end
|
||||
first = nil
|
||||
end
|
||||
end
|
||||
|
||||
for i=1,3 do
|
||||
f(i)
|
||||
assert(b('get') == 'xuxu')
|
||||
b('set', 10); assert(b('get') == 10+i)
|
||||
b = nil
|
||||
end
|
||||
|
||||
pcall(f, 4);
|
||||
assert(b('get') == 'xuxu')
|
||||
b('set', 10); assert(b('get') == 14)
|
||||
|
||||
|
||||
local w
|
||||
-- testing multi-level closure
|
||||
function f(x)
|
||||
return function (y)
|
||||
return function (z) return w+x+y+z end
|
||||
end
|
||||
end
|
||||
|
||||
y = f(10)
|
||||
w = 1.345
|
||||
assert(y(20)(30) == 60+w)
|
||||
|
||||
-- testing closures x repeat-until
|
||||
|
||||
local a = {}
|
||||
local i = 1
|
||||
repeat
|
||||
local x = i
|
||||
a[i] = function () i = x+1; return x end
|
||||
until i > 10 or a[i]() ~= x
|
||||
assert(i == 11 and a[1]() == 1 and a[3]() == 3 and i == 4)
|
||||
|
||||
|
||||
-- testing closures created in 'then' and 'else' parts of 'if's
|
||||
a = {}
|
||||
for i = 1, 10 do
|
||||
if i % 3 == 0 then
|
||||
local y = 0
|
||||
a[i] = function (x) local t = y; y = x; return t end
|
||||
elseif i % 3 == 1 then
|
||||
goto L1
|
||||
error'not here'
|
||||
::L1::
|
||||
local y = 1
|
||||
a[i] = function (x) local t = y; y = x; return t end
|
||||
elseif i % 3 == 2 then
|
||||
local t
|
||||
goto l4
|
||||
::l4a:: a[i] = t; goto l4b
|
||||
error("should never be here!")
|
||||
::l4::
|
||||
local y = 2
|
||||
t = function (x) local t = y; y = x; return t end
|
||||
goto l4a
|
||||
error("should never be here!")
|
||||
::l4b::
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, 10 do
|
||||
assert(a[i](i * 10) == i % 3 and a[i]() == i * 10)
|
||||
end
|
||||
|
||||
print'+'
|
||||
|
||||
|
||||
-- test for correctly closing upvalues in tail calls of vararg functions
|
||||
local function t ()
|
||||
local function c(a,b) assert(a=="test" and b=="OK") end
|
||||
local function v(f, ...) c("test", f() ~= 1 and "FAILED" or "OK") end
|
||||
local x = 1
|
||||
return v(function() return x end)
|
||||
end
|
||||
t()
|
||||
|
||||
|
||||
-- test for debug manipulation of upvalues
|
||||
local debug = require'debug'
|
||||
|
||||
do
|
||||
local a , b, c = 3, 5, 7
|
||||
foo1 = function () return a+b end;
|
||||
foo2 = function () return b+a end;
|
||||
do
|
||||
local a = 10
|
||||
foo3 = function () return a+b end;
|
||||
end
|
||||
end
|
||||
|
||||
assert(debug.upvalueid(foo1, 1))
|
||||
assert(debug.upvalueid(foo1, 2))
|
||||
assert(not pcall(debug.upvalueid, foo1, 3))
|
||||
assert(debug.upvalueid(foo1, 1) == debug.upvalueid(foo2, 2))
|
||||
assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo2, 1))
|
||||
assert(debug.upvalueid(foo3, 1))
|
||||
assert(debug.upvalueid(foo1, 1) ~= debug.upvalueid(foo3, 1))
|
||||
assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo3, 2))
|
||||
|
||||
assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil)
|
||||
|
||||
assert(foo1() == 3 + 5 and foo2() == 5 + 3)
|
||||
debug.upvaluejoin(foo1, 2, foo2, 2)
|
||||
assert(foo1() == 3 + 3 and foo2() == 5 + 3)
|
||||
assert(foo3() == 10 + 5)
|
||||
debug.upvaluejoin(foo3, 2, foo2, 1)
|
||||
assert(foo3() == 10 + 5)
|
||||
debug.upvaluejoin(foo3, 2, foo2, 2)
|
||||
assert(foo3() == 10 + 3)
|
||||
|
||||
assert(not pcall(debug.upvaluejoin, foo1, 3, foo2, 1))
|
||||
assert(not pcall(debug.upvaluejoin, foo1, 1, foo2, 3))
|
||||
assert(not pcall(debug.upvaluejoin, foo1, 0, foo2, 1))
|
||||
assert(not pcall(debug.upvaluejoin, print, 1, foo2, 1))
|
||||
assert(not pcall(debug.upvaluejoin, {}, 1, foo2, 1))
|
||||
assert(not pcall(debug.upvaluejoin, foo1, 1, print, 1))
|
||||
|
||||
print'OK'
|
239
06/parser-gen/parsers/lua-5.3.4-tests/code.lua
Normal file
239
06/parser-gen/parsers/lua-5.3.4-tests/code.lua
Normal file
|
@ -0,0 +1,239 @@
|
|||
-- $Id: code.lua,v 1.42 2016/11/07 13:04:32 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
if T==nil then
|
||||
(Message or print)('\n >>> testC not active: skipping opcode tests <<<\n')
|
||||
return
|
||||
end
|
||||
print "testing code generation and optimizations"
|
||||
|
||||
|
||||
-- this code gave an error for the code checker
|
||||
do
|
||||
local function f (a)
|
||||
for k,v,w in a do end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- testing reuse in constant table
|
||||
local function checkKlist (func, list)
|
||||
local k = T.listk(func)
|
||||
assert(#k == #list)
|
||||
for i = 1, #k do
|
||||
assert(k[i] == list[i] and math.type(k[i]) == math.type(list[i]))
|
||||
end
|
||||
end
|
||||
|
||||
local function foo ()
|
||||
local a
|
||||
a = 3;
|
||||
a = 0; a = 0.0; a = -7 + 7
|
||||
a = 3.78/4; a = 3.78/4
|
||||
a = -3.78/4; a = 3.78/4; a = -3.78/4
|
||||
a = -3.79/4; a = 0.0; a = -0;
|
||||
a = 3; a = 3.0; a = 3; a = 3.0
|
||||
end
|
||||
|
||||
checkKlist(foo, {3, 0, 0.0, 3.78/4, -3.78/4, -3.79/4, 3.0})
|
||||
|
||||
|
||||
-- testing opcodes
|
||||
|
||||
function check (f, ...)
|
||||
local arg = {...}
|
||||
local c = T.listcode(f)
|
||||
for i=1, #arg do
|
||||
-- print(arg[i], c[i])
|
||||
assert(string.find(c[i], '- '..arg[i]..' *%d'))
|
||||
end
|
||||
assert(c[#arg+2] == nil)
|
||||
end
|
||||
|
||||
|
||||
function checkequal (a, b)
|
||||
a = T.listcode(a)
|
||||
b = T.listcode(b)
|
||||
for i = 1, #a do
|
||||
a[i] = string.gsub(a[i], '%b()', '') -- remove line number
|
||||
b[i] = string.gsub(b[i], '%b()', '') -- remove line number
|
||||
assert(a[i] == b[i])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- some basic instructions
|
||||
check(function ()
|
||||
(function () end){f()}
|
||||
end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN')
|
||||
|
||||
|
||||
-- sequence of LOADNILs
|
||||
check(function ()
|
||||
local a,b,c
|
||||
local d; local e;
|
||||
local f,g,h;
|
||||
d = nil; d=nil; b=nil; a=nil; c=nil;
|
||||
end, 'LOADNIL', 'RETURN')
|
||||
|
||||
check(function ()
|
||||
local a,b,c,d = 1,1,1,1
|
||||
d=nil;c=nil;b=nil;a=nil
|
||||
end, 'LOADK', 'LOADK', 'LOADK', 'LOADK', 'LOADNIL', 'RETURN')
|
||||
|
||||
do
|
||||
local a,b,c,d = 1,1,1,1
|
||||
d=nil;c=nil;b=nil;a=nil
|
||||
assert(a == nil and b == nil and c == nil and d == nil)
|
||||
end
|
||||
|
||||
|
||||
-- single return
|
||||
check (function (a,b,c) return a end, 'RETURN')
|
||||
|
||||
|
||||
-- infinite loops
|
||||
check(function () while true do local a = -1 end end,
|
||||
'LOADK', 'JMP', 'RETURN')
|
||||
|
||||
check(function () while 1 do local a = -1 end end,
|
||||
'LOADK', 'JMP', 'RETURN')
|
||||
|
||||
check(function () repeat local x = 1 until true end,
|
||||
'LOADK', 'RETURN')
|
||||
|
||||
|
||||
-- concat optimization
|
||||
check(function (a,b,c,d) return a..b..c..d end,
|
||||
'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN')
|
||||
|
||||
-- not
|
||||
check(function () return not not nil end, 'LOADBOOL', 'RETURN')
|
||||
check(function () return not not false end, 'LOADBOOL', 'RETURN')
|
||||
check(function () return not not true end, 'LOADBOOL', 'RETURN')
|
||||
check(function () return not not 1 end, 'LOADBOOL', 'RETURN')
|
||||
|
||||
-- direct access to locals
|
||||
check(function ()
|
||||
local a,b,c,d
|
||||
a = b*2
|
||||
c[2], a[b] = -((a + d/2 - a[b]) ^ a.x), b
|
||||
end,
|
||||
'LOADNIL',
|
||||
'MUL',
|
||||
'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW',
|
||||
'UNM', 'SETTABLE', 'SETTABLE', 'RETURN')
|
||||
|
||||
|
||||
-- direct access to constants
|
||||
check(function ()
|
||||
local a,b
|
||||
a.x = 3.2
|
||||
a.x = b
|
||||
a[b] = 'x'
|
||||
end,
|
||||
'LOADNIL', 'SETTABLE', 'SETTABLE', 'SETTABLE', 'RETURN')
|
||||
|
||||
check(function ()
|
||||
local a,b
|
||||
a = 1 - a
|
||||
b = 1/a
|
||||
b = 5-4
|
||||
end,
|
||||
'LOADNIL', 'SUB', 'DIV', 'LOADK', 'RETURN')
|
||||
|
||||
check(function ()
|
||||
local a,b
|
||||
a[true] = false
|
||||
end,
|
||||
'LOADNIL', 'SETTABLE', 'RETURN')
|
||||
|
||||
|
||||
-- constant folding
|
||||
local function checkK (func, val)
|
||||
check(func, 'LOADK', 'RETURN')
|
||||
local k = T.listk(func)
|
||||
assert(#k == 1 and k[1] == val and math.type(k[1]) == math.type(val))
|
||||
assert(func() == val)
|
||||
end
|
||||
checkK(function () return 0.0 end, 0.0)
|
||||
checkK(function () return 0 end, 0)
|
||||
checkK(function () return -0//1 end, 0)
|
||||
checkK(function () return 3^-1 end, 1/3)
|
||||
checkK(function () return (1 + 1)^(50 + 50) end, 2^100)
|
||||
checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0)
|
||||
checkK(function () return (-3^0 + 5) // 3.0 end, 1.0)
|
||||
checkK(function () return -3 % 5 end, 2)
|
||||
checkK(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0)
|
||||
checkK(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0)
|
||||
checkK(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4)
|
||||
checkK(function () return ~(~0xFF0 | 0xFF0) end, 0)
|
||||
checkK(function () return ~~-100024.0 end, -100024)
|
||||
checkK(function () return ((100 << 6) << -4) >> 2 end, 100)
|
||||
|
||||
|
||||
-- no foldings
|
||||
check(function () return -0.0 end, 'LOADK', 'UNM', 'RETURN')
|
||||
check(function () return 3/0 end, 'DIV', 'RETURN')
|
||||
check(function () return 0%0 end, 'MOD', 'RETURN')
|
||||
check(function () return -4//0 end, 'IDIV', 'RETURN')
|
||||
|
||||
-- bug in constant folding for 5.1
|
||||
check(function () return -nil end, 'LOADNIL', 'UNM', 'RETURN')
|
||||
|
||||
|
||||
check(function ()
|
||||
local a,b,c
|
||||
b[c], a = c, b
|
||||
b[a], a = c, b
|
||||
a, b = c, a
|
||||
a = a
|
||||
end,
|
||||
'LOADNIL',
|
||||
'MOVE', 'MOVE', 'SETTABLE',
|
||||
'MOVE', 'MOVE', 'MOVE', 'SETTABLE',
|
||||
'MOVE', 'MOVE', 'MOVE',
|
||||
-- no code for a = a
|
||||
'RETURN')
|
||||
|
||||
|
||||
-- x == nil , x ~= nil
|
||||
checkequal(function () if (a==nil) then a=1 end; if a~=nil then a=1 end end,
|
||||
function () if (a==9) then a=1 end; if a~=9 then a=1 end end)
|
||||
|
||||
check(function () if a==nil then a='a' end end,
|
||||
'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
|
||||
|
||||
-- de morgan
|
||||
checkequal(function () local a; if not (a or b) then b=a end end,
|
||||
function () local a; if (not a and not b) then b=a end end)
|
||||
|
||||
checkequal(function (l) local a; return 0 <= a and a <= l end,
|
||||
function (l) local a; return not (not(a >= 0) or not(a <= l)) end)
|
||||
|
||||
|
||||
-- if-goto optimizations
|
||||
check(function (a, b, c, d, e)
|
||||
if a == b then goto l1
|
||||
elseif a == c then goto l2
|
||||
elseif a == d then goto l2
|
||||
else if a == e then goto l3
|
||||
else goto l3
|
||||
end
|
||||
end
|
||||
::l1:: ::l2:: ::l3:: ::l4::
|
||||
end, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP', 'RETURN')
|
||||
|
||||
checkequal(
|
||||
function (a) while a < 10 do a = a + 1 end end,
|
||||
function (a) ::L2:: if not(a < 10) then goto L1 end; a = a + 1;
|
||||
goto L2; ::L1:: end
|
||||
)
|
||||
|
||||
checkequal(
|
||||
function (a) while a < 10 do a = a + 1 end end,
|
||||
function (a) while true do if not(a < 10) then break end; a = a + 1; end end
|
||||
)
|
||||
|
||||
print 'OK'
|
||||
|
313
06/parser-gen/parsers/lua-5.3.4-tests/constructs.lua
Normal file
313
06/parser-gen/parsers/lua-5.3.4-tests/constructs.lua
Normal file
|
@ -0,0 +1,313 @@
|
|||
-- $Id: constructs.lua,v 1.41 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
;;print "testing syntax";;
|
||||
|
||||
local debug = require "debug"
|
||||
|
||||
|
||||
local function checkload (s, msg)
|
||||
assert(string.find(select(2, load(s)), msg))
|
||||
end
|
||||
|
||||
-- testing semicollons
|
||||
do ;;; end
|
||||
; do ; a = 3; assert(a == 3) end;
|
||||
;
|
||||
|
||||
|
||||
-- invalid operations should not raise errors when not executed
|
||||
if false then a = 3 // 0; a = 0 % 0 end
|
||||
|
||||
|
||||
-- testing priorities
|
||||
|
||||
assert(2^3^2 == 2^(3^2));
|
||||
assert(2^3*4 == (2^3)*4);
|
||||
assert(2.0^-2 == 1/4 and -2^- -2 == - - -4);
|
||||
assert(not nil and 2 and not(2>3 or 3<2));
|
||||
assert(-3-1-5 == 0+0-9);
|
||||
assert(-2^2 == -4 and (-2)^2 == 4 and 2*2-3-1 == 0);
|
||||
assert(-3%5 == 2 and -3+5 == 2)
|
||||
assert(2*1+3/3 == 3 and 1+2 .. 3*1 == "33");
|
||||
assert(not(2+1 > 3*1) and "a".."b" > "a");
|
||||
|
||||
assert("7" .. 3 << 1 == 146)
|
||||
assert(10 >> 1 .. "9" == 0)
|
||||
assert(10 | 1 .. "9" == 27)
|
||||
|
||||
assert(0xF0 | 0xCC ~ 0xAA & 0xFD == 0xF4)
|
||||
assert(0xFD & 0xAA ~ 0xCC | 0xF0 == 0xF4)
|
||||
assert(0xF0 & 0x0F + 1 == 0x10)
|
||||
|
||||
assert(3^4//2^3//5 == 2)
|
||||
|
||||
assert(-3+4*5//2^3^2//9+4%10/3 == (-3)+(((4*5)//(2^(3^2)))//9)+((4%10)/3))
|
||||
|
||||
assert(not ((true or false) and nil))
|
||||
assert( true or false and nil)
|
||||
|
||||
-- old bug
|
||||
assert((((1 or false) and true) or false) == true)
|
||||
assert((((nil and true) or false) and true) == false)
|
||||
|
||||
local a,b = 1,nil;
|
||||
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
|
||||
x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
|
||||
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
|
||||
|
||||
x,y=1,2;
|
||||
assert((x>y) and x or y == 2);
|
||||
x,y=2,1;
|
||||
assert((x>y) and x or y == 2);
|
||||
|
||||
assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891)
|
||||
|
||||
|
||||
-- silly loops
|
||||
repeat until 1; repeat until true;
|
||||
while false do end; while nil do end;
|
||||
|
||||
do -- test old bug (first name could not be an `upvalue')
|
||||
local a; function f(x) x={a=1}; x={x=1}; x={G=1} end
|
||||
end
|
||||
|
||||
function f (i)
|
||||
if type(i) ~= 'number' then return i,'jojo'; end;
|
||||
if i > 0 then return i, f(i-1); end;
|
||||
end
|
||||
|
||||
x = {f(3), f(5), f(10);};
|
||||
assert(x[1] == 3 and x[2] == 5 and x[3] == 10 and x[4] == 9 and x[12] == 1);
|
||||
assert(x[nil] == nil)
|
||||
x = {f'alo', f'xixi', nil};
|
||||
assert(x[1] == 'alo' and x[2] == 'xixi' and x[3] == nil);
|
||||
x = {f'alo'..'xixi'};
|
||||
assert(x[1] == 'aloxixi')
|
||||
x = {f{}}
|
||||
assert(x[2] == 'jojo' and type(x[1]) == 'table')
|
||||
|
||||
|
||||
local f = function (i)
|
||||
if i < 10 then return 'a';
|
||||
elseif i < 20 then return 'b';
|
||||
elseif i < 30 then return 'c';
|
||||
end;
|
||||
end
|
||||
|
||||
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
|
||||
|
||||
for i=1,1000 do break; end;
|
||||
n=100;
|
||||
i=3;
|
||||
t = {};
|
||||
a=nil
|
||||
while not a do
|
||||
a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
|
||||
end
|
||||
assert(a == n*(n+1)/2 and i==3);
|
||||
assert(t[1] and t[n] and not t[0] and not t[n+1])
|
||||
|
||||
function f(b)
|
||||
local x = 1;
|
||||
repeat
|
||||
local a;
|
||||
if b==1 then local b=1; x=10; break
|
||||
elseif b==2 then x=20; break;
|
||||
elseif b==3 then x=30;
|
||||
else local a,b,c,d=math.sin(1); x=x+1;
|
||||
end
|
||||
until x>=12;
|
||||
return x;
|
||||
end;
|
||||
|
||||
assert(f(1) == 10 and f(2) == 20 and f(3) == 30 and f(4)==12)
|
||||
|
||||
|
||||
local f = function (i)
|
||||
if i < 10 then return 'a'
|
||||
elseif i < 20 then return 'b'
|
||||
elseif i < 30 then return 'c'
|
||||
else return 8
|
||||
end
|
||||
end
|
||||
|
||||
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == 8)
|
||||
|
||||
local a, b = nil, 23
|
||||
x = {f(100)*2+3 or a, a or b+2}
|
||||
assert(x[1] == 19 and x[2] == 25)
|
||||
x = {f=2+3 or a, a = b+2}
|
||||
assert(x.f == 5 and x.a == 25)
|
||||
|
||||
a={y=1}
|
||||
x = {a.y}
|
||||
assert(x[1] == 1)
|
||||
|
||||
function f(i)
|
||||
while 1 do
|
||||
if i>0 then i=i-1;
|
||||
else return; end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function g(i)
|
||||
while 1 do
|
||||
if i>0 then i=i-1
|
||||
else return end
|
||||
end
|
||||
end
|
||||
|
||||
f(10); g(10);
|
||||
|
||||
do
|
||||
function f () return 1,2,3; end
|
||||
local a, b, c = f();
|
||||
assert(a==1 and b==2 and c==3)
|
||||
a, b, c = (f());
|
||||
assert(a==1 and b==nil and c==nil)
|
||||
end
|
||||
|
||||
local a,b = 3 and f();
|
||||
assert(a==1 and b==nil)
|
||||
|
||||
function g() f(); return; end;
|
||||
assert(g() == nil)
|
||||
function g() return nil or f() end
|
||||
a,b = g()
|
||||
assert(a==1 and b==nil)
|
||||
|
||||
print'+';
|
||||
|
||||
|
||||
f = [[
|
||||
return function ( a , b , c , d , e )
|
||||
local x = a >= b or c or ( d and e ) or nil
|
||||
return x
|
||||
end , { a = 1 , b = 2 >= 1 , } or { 1 };
|
||||
]]
|
||||
f = string.gsub(f, "%s+", "\n"); -- force a SETLINE between opcodes
|
||||
f,a = load(f)();
|
||||
assert(a.a == 1 and a.b)
|
||||
|
||||
function g (a,b,c,d,e)
|
||||
if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
|
||||
end
|
||||
|
||||
function h (a,b,c,d,e)
|
||||
while (a>=b or c or (d and e) or nil) do return 1; end;
|
||||
return 0;
|
||||
end;
|
||||
|
||||
assert(f(2,1) == true and g(2,1) == 1 and h(2,1) == 1)
|
||||
assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
|
||||
assert(f(1,2,'a')
|
||||
~= -- force SETLINE before nil
|
||||
nil, "")
|
||||
assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
|
||||
assert(f(1,2,nil,1,'x') == 'x' and g(1,2,nil,1,'x') == 1 and
|
||||
h(1,2,nil,1,'x') == 1)
|
||||
assert(f(1,2,nil,nil,'x') == nil and g(1,2,nil,nil,'x') == 0 and
|
||||
h(1,2,nil,nil,'x') == 0)
|
||||
assert(f(1,2,nil,1,nil) == nil and g(1,2,nil,1,nil) == 0 and
|
||||
h(1,2,nil,1,nil) == 0)
|
||||
|
||||
assert(1 and 2<3 == true and 2<3 and 'a'<'b' == true)
|
||||
x = 2<3 and not 3; assert(x==false)
|
||||
x = 2<1 or (2>1 and 'a'); assert(x=='a')
|
||||
|
||||
|
||||
do
|
||||
local a; if nil then a=1; else a=2; end; -- this nil comes as PUSHNIL 2
|
||||
assert(a==2)
|
||||
end
|
||||
|
||||
function F(a)
|
||||
assert(debug.getinfo(1, "n").name == 'F')
|
||||
return a,2,3
|
||||
end
|
||||
|
||||
a,b = F(1)~=nil; assert(a == true and b == nil);
|
||||
a,b = F(nil)==nil; assert(a == true and b == nil)
|
||||
|
||||
----------------------------------------------------------------
|
||||
------------------------------------------------------------------
|
||||
|
||||
-- sometimes will be 0, sometimes will not...
|
||||
_ENV.GLOB1 = math.floor(os.time()) % 2
|
||||
|
||||
-- basic expressions with their respective values
|
||||
local basiccases = {
|
||||
{"nil", nil},
|
||||
{"false", false},
|
||||
{"true", true},
|
||||
{"10", 10},
|
||||
{"(0==_ENV.GLOB1)", 0 == _ENV.GLOB1},
|
||||
}
|
||||
|
||||
print('testing short-circuit optimizations (' .. _ENV.GLOB1 .. ')')
|
||||
|
||||
|
||||
-- operators with their respective values
|
||||
local binops = {
|
||||
{" and ", function (a,b) if not a then return a else return b end end},
|
||||
{" or ", function (a,b) if a then return a else return b end end},
|
||||
}
|
||||
|
||||
local cases = {}
|
||||
|
||||
-- creates all combinations of '(cases[i] op cases[n-i])' plus
|
||||
-- 'not(cases[i] op cases[n-i])' (syntax + value)
|
||||
local function createcases (n)
|
||||
local res = {}
|
||||
for i = 1, n - 1 do
|
||||
for _, v1 in ipairs(cases[i]) do
|
||||
for _, v2 in ipairs(cases[n - i]) do
|
||||
for _, op in ipairs(binops) do
|
||||
local t = {
|
||||
"(" .. v1[1] .. op[1] .. v2[1] .. ")",
|
||||
op[2](v1[2], v2[2])
|
||||
}
|
||||
res[#res + 1] = t
|
||||
res[#res + 1] = {"not" .. t[1], not t[2]}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
-- do not do too many combinations for soft tests
|
||||
local level = _soft and 3 or 4
|
||||
|
||||
cases[1] = basiccases
|
||||
for i = 2, level do cases[i] = createcases(i) end
|
||||
print("+")
|
||||
|
||||
local prog = [[if %s then IX = true end; return %s]]
|
||||
|
||||
local i = 0
|
||||
for n = 1, level do
|
||||
for _, v in pairs(cases[n]) do
|
||||
local s = v[1]
|
||||
local p = load(string.format(prog, s, s), "")
|
||||
IX = false
|
||||
assert(p() == v[2] and IX == not not v[2])
|
||||
i = i + 1
|
||||
if i % 60000 == 0 then print('+') end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------
|
||||
|
||||
-- testing some syntax errors (chosen through 'gcov')
|
||||
checkload("for x do", "expected")
|
||||
checkload("x:call", "expected")
|
||||
|
||||
if not _soft then
|
||||
-- control structure too long
|
||||
local s = string.rep("a = a + 1\n", 2^18)
|
||||
s = "while true do " .. s .. "end"
|
||||
checkload(s, "too long")
|
||||
end
|
||||
|
||||
print'OK'
|
874
06/parser-gen/parsers/lua-5.3.4-tests/coroutine.lua
Normal file
874
06/parser-gen/parsers/lua-5.3.4-tests/coroutine.lua
Normal file
|
@ -0,0 +1,874 @@
|
|||
-- $Id: coroutine.lua,v 1.42 2016/11/07 13:03:20 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print "testing coroutines"
|
||||
|
||||
local debug = require'debug'
|
||||
|
||||
local f
|
||||
|
||||
local main, ismain = coroutine.running()
|
||||
assert(type(main) == "thread" and ismain)
|
||||
assert(not coroutine.resume(main))
|
||||
assert(not coroutine.isyieldable())
|
||||
assert(not pcall(coroutine.yield))
|
||||
|
||||
|
||||
-- trivial errors
|
||||
assert(not pcall(coroutine.resume, 0))
|
||||
assert(not pcall(coroutine.status, 0))
|
||||
|
||||
|
||||
-- tests for multiple yield/resume arguments
|
||||
|
||||
local function eqtab (t1, t2)
|
||||
assert(#t1 == #t2)
|
||||
for i = 1, #t1 do
|
||||
local v = t1[i]
|
||||
assert(t2[i] == v)
|
||||
end
|
||||
end
|
||||
|
||||
_G.x = nil -- declare x
|
||||
function foo (a, ...)
|
||||
local x, y = coroutine.running()
|
||||
assert(x == f and y == false)
|
||||
-- next call should not corrupt coroutine (but must fail,
|
||||
-- as it attempts to resume the running coroutine)
|
||||
assert(coroutine.resume(f) == false)
|
||||
assert(coroutine.status(f) == "running")
|
||||
local arg = {...}
|
||||
assert(coroutine.isyieldable())
|
||||
for i=1,#arg do
|
||||
_G.x = {coroutine.yield(table.unpack(arg[i]))}
|
||||
end
|
||||
return table.unpack(a)
|
||||
end
|
||||
|
||||
f = coroutine.create(foo)
|
||||
assert(type(f) == "thread" and coroutine.status(f) == "suspended")
|
||||
assert(string.find(tostring(f), "thread"))
|
||||
local s,a,b,c,d
|
||||
s,a,b,c,d = coroutine.resume(f, {1,2,3}, {}, {1}, {'a', 'b', 'c'})
|
||||
assert(s and a == nil and coroutine.status(f) == "suspended")
|
||||
s,a,b,c,d = coroutine.resume(f)
|
||||
eqtab(_G.x, {})
|
||||
assert(s and a == 1 and b == nil)
|
||||
s,a,b,c,d = coroutine.resume(f, 1, 2, 3)
|
||||
eqtab(_G.x, {1, 2, 3})
|
||||
assert(s and a == 'a' and b == 'b' and c == 'c' and d == nil)
|
||||
s,a,b,c,d = coroutine.resume(f, "xuxu")
|
||||
eqtab(_G.x, {"xuxu"})
|
||||
assert(s and a == 1 and b == 2 and c == 3 and d == nil)
|
||||
assert(coroutine.status(f) == "dead")
|
||||
s, a = coroutine.resume(f, "xuxu")
|
||||
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
|
||||
|
||||
|
||||
-- yields in tail calls
|
||||
local function foo (i) return coroutine.yield(i) end
|
||||
f = coroutine.wrap(function ()
|
||||
for i=1,10 do
|
||||
assert(foo(i) == _G.x)
|
||||
end
|
||||
return 'a'
|
||||
end)
|
||||
for i=1,10 do _G.x = i; assert(f(i) == i) end
|
||||
_G.x = 'xuxu'; assert(f('xuxu') == 'a')
|
||||
|
||||
-- recursive
|
||||
function pf (n, i)
|
||||
coroutine.yield(n)
|
||||
pf(n*i, i+1)
|
||||
end
|
||||
|
||||
f = coroutine.wrap(pf)
|
||||
local s=1
|
||||
for i=1,10 do
|
||||
assert(f(1, 1) == s)
|
||||
s = s*i
|
||||
end
|
||||
|
||||
-- sieve
|
||||
function gen (n)
|
||||
return coroutine.wrap(function ()
|
||||
for i=2,n do coroutine.yield(i) end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
function filter (p, g)
|
||||
return coroutine.wrap(function ()
|
||||
while 1 do
|
||||
local n = g()
|
||||
if n == nil then return end
|
||||
if math.fmod(n, p) ~= 0 then coroutine.yield(n) end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local x = gen(100)
|
||||
local a = {}
|
||||
while 1 do
|
||||
local n = x()
|
||||
if n == nil then break end
|
||||
table.insert(a, n)
|
||||
x = filter(n, x)
|
||||
end
|
||||
|
||||
assert(#a == 25 and a[#a] == 97)
|
||||
x, a = nil
|
||||
|
||||
-- yielding across C boundaries
|
||||
|
||||
co = coroutine.wrap(function()
|
||||
assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
|
||||
assert(coroutine.isyieldable())
|
||||
coroutine.yield(20)
|
||||
return 30
|
||||
end)
|
||||
|
||||
assert(co() == 20)
|
||||
assert(co() == 30)
|
||||
|
||||
|
||||
local f = function (s, i) return coroutine.yield(i) end
|
||||
|
||||
local f1 = coroutine.wrap(function ()
|
||||
return xpcall(pcall, function (...) return ... end,
|
||||
function ()
|
||||
local s = 0
|
||||
for i in f, nil, 1 do pcall(function () s = s + i end) end
|
||||
error({s})
|
||||
end)
|
||||
end)
|
||||
|
||||
f1()
|
||||
for i = 1, 10 do assert(f1(i) == i) end
|
||||
local r1, r2, v = f1(nil)
|
||||
assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
|
||||
|
||||
|
||||
function f (a, b) a = coroutine.yield(a); error{a + b} end
|
||||
function g(x) return x[1]*2 end
|
||||
|
||||
co = coroutine.wrap(function ()
|
||||
coroutine.yield(xpcall(f, g, 10, 20))
|
||||
end)
|
||||
|
||||
assert(co() == 10)
|
||||
r, msg = co(100)
|
||||
assert(not r and msg == 240)
|
||||
|
||||
|
||||
-- unyieldable C call
|
||||
do
|
||||
local function f (c)
|
||||
assert(not coroutine.isyieldable())
|
||||
return c .. c
|
||||
end
|
||||
|
||||
local co = coroutine.wrap(function (c)
|
||||
assert(coroutine.isyieldable())
|
||||
local s = string.gsub("a", ".", f)
|
||||
return s
|
||||
end)
|
||||
assert(co() == "aa")
|
||||
end
|
||||
|
||||
|
||||
-- errors in coroutines
|
||||
function foo ()
|
||||
assert(debug.getinfo(1).currentline == debug.getinfo(foo).linedefined + 1)
|
||||
assert(debug.getinfo(2).currentline == debug.getinfo(goo).linedefined)
|
||||
coroutine.yield(3)
|
||||
error(foo)
|
||||
end
|
||||
|
||||
function goo() foo() end
|
||||
x = coroutine.wrap(goo)
|
||||
assert(x() == 3)
|
||||
local a,b = pcall(x)
|
||||
assert(not a and b == foo)
|
||||
|
||||
x = coroutine.create(goo)
|
||||
a,b = coroutine.resume(x)
|
||||
assert(a and b == 3)
|
||||
a,b = coroutine.resume(x)
|
||||
assert(not a and b == foo and coroutine.status(x) == "dead")
|
||||
a,b = coroutine.resume(x)
|
||||
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
|
||||
|
||||
|
||||
-- co-routines x for loop
|
||||
function all (a, n, k)
|
||||
if k == 0 then coroutine.yield(a)
|
||||
else
|
||||
for i=1,n do
|
||||
a[k] = i
|
||||
all(a, n, k-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local a = 0
|
||||
for t in coroutine.wrap(function () all({}, 5, 4) end) do
|
||||
a = a+1
|
||||
end
|
||||
assert(a == 5^4)
|
||||
|
||||
|
||||
-- access to locals of collected corroutines
|
||||
local C = {}; setmetatable(C, {__mode = "kv"})
|
||||
local x = coroutine.wrap (function ()
|
||||
local a = 10
|
||||
local function f () a = a+10; return a end
|
||||
while true do
|
||||
a = a+1
|
||||
coroutine.yield(f)
|
||||
end
|
||||
end)
|
||||
|
||||
C[1] = x;
|
||||
|
||||
local f = x()
|
||||
assert(f() == 21 and x()() == 32 and x() == f)
|
||||
x = nil
|
||||
collectgarbage()
|
||||
assert(C[1] == nil)
|
||||
assert(f() == 43 and f() == 53)
|
||||
|
||||
|
||||
-- old bug: attempt to resume itself
|
||||
|
||||
function co_func (current_co)
|
||||
assert(coroutine.running() == current_co)
|
||||
assert(coroutine.resume(current_co) == false)
|
||||
coroutine.yield(10, 20)
|
||||
assert(coroutine.resume(current_co) == false)
|
||||
coroutine.yield(23)
|
||||
return 10
|
||||
end
|
||||
|
||||
local co = coroutine.create(co_func)
|
||||
local a,b,c = coroutine.resume(co, co)
|
||||
assert(a == true and b == 10 and c == 20)
|
||||
a,b = coroutine.resume(co, co)
|
||||
assert(a == true and b == 23)
|
||||
a,b = coroutine.resume(co, co)
|
||||
assert(a == true and b == 10)
|
||||
assert(coroutine.resume(co, co) == false)
|
||||
assert(coroutine.resume(co, co) == false)
|
||||
|
||||
|
||||
-- other old bug when attempting to resume itself
|
||||
-- (trigger C-code assertions)
|
||||
do
|
||||
local A = coroutine.running()
|
||||
local B = coroutine.create(function() return coroutine.resume(A) end)
|
||||
local st, res = coroutine.resume(B)
|
||||
assert(st == true and res == false)
|
||||
|
||||
A = coroutine.wrap(function() return pcall(A, 1) end)
|
||||
st, res = A()
|
||||
assert(not st and string.find(res, "non%-suspended"))
|
||||
end
|
||||
|
||||
|
||||
-- attempt to resume 'normal' coroutine
|
||||
local co1, co2
|
||||
co1 = coroutine.create(function () return co2() end)
|
||||
co2 = coroutine.wrap(function ()
|
||||
assert(coroutine.status(co1) == 'normal')
|
||||
assert(not coroutine.resume(co1))
|
||||
coroutine.yield(3)
|
||||
end)
|
||||
|
||||
a,b = coroutine.resume(co1)
|
||||
assert(a and b == 3)
|
||||
assert(coroutine.status(co1) == 'dead')
|
||||
|
||||
-- infinite recursion of coroutines
|
||||
a = function(a) coroutine.wrap(a)(a) end
|
||||
assert(not pcall(a, a))
|
||||
a = nil
|
||||
|
||||
|
||||
-- access to locals of erroneous coroutines
|
||||
local x = coroutine.create (function ()
|
||||
local a = 10
|
||||
_G.f = function () a=a+1; return a end
|
||||
error('x')
|
||||
end)
|
||||
|
||||
assert(not coroutine.resume(x))
|
||||
-- overwrite previous position of local `a'
|
||||
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
|
||||
assert(_G.f() == 11)
|
||||
assert(_G.f() == 12)
|
||||
|
||||
|
||||
if not T then
|
||||
(Message or print)('\n >>> testC not active: skipping yield/hook tests <<<\n')
|
||||
else
|
||||
print "testing yields inside hooks"
|
||||
|
||||
local turn
|
||||
|
||||
function fact (t, x)
|
||||
assert(turn == t)
|
||||
if x == 0 then return 1
|
||||
else return x*fact(t, x-1)
|
||||
end
|
||||
end
|
||||
|
||||
local A, B = 0, 0
|
||||
|
||||
local x = coroutine.create(function ()
|
||||
T.sethook("yield 0", "", 2)
|
||||
A = fact("A", 6)
|
||||
end)
|
||||
|
||||
local y = coroutine.create(function ()
|
||||
T.sethook("yield 0", "", 3)
|
||||
B = fact("B", 7)
|
||||
end)
|
||||
|
||||
while A==0 or B==0 do -- A ~= 0 when 'x' finishes (similar for 'B','y')
|
||||
if A==0 then turn = "A"; assert(T.resume(x)) end
|
||||
if B==0 then turn = "B"; assert(T.resume(y)) end
|
||||
end
|
||||
|
||||
assert(B // A == 7) -- fact(7) // fact(6)
|
||||
|
||||
local line = debug.getinfo(1, "l").currentline + 2 -- get line number
|
||||
local function foo ()
|
||||
local x = 10 --<< this line is 'line'
|
||||
x = x + 10
|
||||
_G.XX = x
|
||||
end
|
||||
|
||||
-- testing yields in line hook
|
||||
local co = coroutine.wrap(function ()
|
||||
T.sethook("setglobal X; yield 0", "l", 0); foo(); return 10 end)
|
||||
|
||||
_G.XX = nil;
|
||||
_G.X = nil; co(); assert(_G.X == line)
|
||||
_G.X = nil; co(); assert(_G.X == line + 1)
|
||||
_G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
|
||||
_G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
|
||||
assert(co() == 10)
|
||||
|
||||
-- testing yields in count hook
|
||||
co = coroutine.wrap(function ()
|
||||
T.sethook("yield 0", "", 1); foo(); return 10 end)
|
||||
|
||||
_G.XX = nil;
|
||||
local c = 0
|
||||
repeat c = c + 1; local a = co() until a == 10
|
||||
assert(_G.XX == 20 and c >= 5)
|
||||
|
||||
co = coroutine.wrap(function ()
|
||||
T.sethook("yield 0", "", 2); foo(); return 10 end)
|
||||
|
||||
_G.XX = nil;
|
||||
local c = 0
|
||||
repeat c = c + 1; local a = co() until a == 10
|
||||
assert(_G.XX == 20 and c >= 5)
|
||||
_G.X = nil; _G.XX = nil
|
||||
|
||||
do
|
||||
-- testing debug library on a coroutine suspended inside a hook
|
||||
-- (bug in 5.2/5.3)
|
||||
c = coroutine.create(function (a, ...)
|
||||
T.sethook("yield 0", "l") -- will yield on next two lines
|
||||
assert(a == 10)
|
||||
return ...
|
||||
end)
|
||||
|
||||
assert(coroutine.resume(c, 1, 2, 3)) -- start coroutine
|
||||
local n,v = debug.getlocal(c, 0, 1) -- check its local
|
||||
assert(n == "a" and v == 1)
|
||||
n,v = debug.getlocal(c, 0, -1) -- check varargs
|
||||
assert(v == 2)
|
||||
n,v = debug.getlocal(c, 0, -2)
|
||||
assert(v == 3)
|
||||
assert(debug.setlocal(c, 0, 1, 10)) -- test 'setlocal'
|
||||
assert(debug.setlocal(c, 0, -2, 20))
|
||||
local t = debug.getinfo(c, 0) -- test 'getinfo'
|
||||
assert(t.currentline == t.linedefined + 1)
|
||||
assert(not debug.getinfo(c, 1)) -- no other level
|
||||
assert(coroutine.resume(c)) -- run next line
|
||||
v = {coroutine.resume(c)} -- finish coroutine
|
||||
assert(v[1] == true and v[2] == 2 and v[3] == 20 and v[4] == nil)
|
||||
assert(not coroutine.resume(c))
|
||||
end
|
||||
|
||||
do
|
||||
-- testing debug library on last function in a suspended coroutine
|
||||
-- (bug in 5.2/5.3)
|
||||
local c = coroutine.create(function () T.testC("yield 1", 10, 20) end)
|
||||
local a, b = coroutine.resume(c)
|
||||
assert(a and b == 20)
|
||||
assert(debug.getinfo(c, 0).linedefined == -1)
|
||||
a, b = debug.getlocal(c, 0, 2)
|
||||
assert(b == 10)
|
||||
end
|
||||
|
||||
|
||||
print "testing coroutine API"
|
||||
|
||||
-- reusing a thread
|
||||
assert(T.testC([[
|
||||
newthread # create thread
|
||||
pushvalue 2 # push body
|
||||
pushstring 'a a a' # push argument
|
||||
xmove 0 3 2 # move values to new thread
|
||||
resume -1, 1 # call it first time
|
||||
pushstatus
|
||||
xmove 3 0 0 # move results back to stack
|
||||
setglobal X # result
|
||||
setglobal Y # status
|
||||
pushvalue 2 # push body (to call it again)
|
||||
pushstring 'b b b'
|
||||
xmove 0 3 2
|
||||
resume -1, 1 # call it again
|
||||
pushstatus
|
||||
xmove 3 0 0
|
||||
return 1 # return result
|
||||
]], function (...) return ... end) == 'b b b')
|
||||
|
||||
assert(X == 'a a a' and Y == 'OK')
|
||||
|
||||
|
||||
-- resuming running coroutine
|
||||
C = coroutine.create(function ()
|
||||
return T.testC([[
|
||||
pushnum 10;
|
||||
pushnum 20;
|
||||
resume -3 2;
|
||||
pushstatus
|
||||
gettop;
|
||||
return 3]], C)
|
||||
end)
|
||||
local a, b, c, d = coroutine.resume(C)
|
||||
assert(a == true and string.find(b, "non%-suspended") and
|
||||
c == "ERRRUN" and d == 4)
|
||||
|
||||
a, b, c, d = T.testC([[
|
||||
rawgeti R 1 # get main thread
|
||||
pushnum 10;
|
||||
pushnum 20;
|
||||
resume -3 2;
|
||||
pushstatus
|
||||
gettop;
|
||||
return 4]])
|
||||
assert(a == coroutine.running() and string.find(b, "non%-suspended") and
|
||||
c == "ERRRUN" and d == 4)
|
||||
|
||||
|
||||
-- using a main thread as a coroutine
|
||||
local state = T.newstate()
|
||||
T.loadlib(state)
|
||||
|
||||
assert(T.doremote(state, [[
|
||||
coroutine = require'coroutine';
|
||||
X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
|
||||
return 'ok']]))
|
||||
|
||||
t = table.pack(T.testC(state, [[
|
||||
rawgeti R 1 # get main thread
|
||||
pushstring 'XX'
|
||||
getglobal X # get function for body
|
||||
pushstring AA # arg
|
||||
resume 1 1 # 'resume' shadows previous stack!
|
||||
gettop
|
||||
setglobal T # top
|
||||
setglobal B # second yielded value
|
||||
setglobal A # fist yielded value
|
||||
rawgeti R 1 # get main thread
|
||||
pushnum 5 # arg (noise)
|
||||
resume 1 1 # after coroutine ends, previous stack is back
|
||||
pushstatus
|
||||
return *
|
||||
]]))
|
||||
assert(t.n == 4 and t[2] == 'XX' and t[3] == 'CC' and t[4] == 'OK')
|
||||
assert(T.doremote(state, "return T") == '2')
|
||||
assert(T.doremote(state, "return A") == 'AA')
|
||||
assert(T.doremote(state, "return B") == 'BB')
|
||||
|
||||
T.closestate(state)
|
||||
|
||||
print'+'
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- leaving a pending coroutine open
|
||||
_X = coroutine.wrap(function ()
|
||||
local a = 10
|
||||
local x = function () a = a+1 end
|
||||
coroutine.yield()
|
||||
end)
|
||||
|
||||
_X()
|
||||
|
||||
|
||||
if not _soft then
|
||||
-- bug (stack overflow)
|
||||
local j = 2^9
|
||||
local lim = 1000000 -- (C stack limit; assume 32-bit machine)
|
||||
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1}
|
||||
for i = 1, #t do
|
||||
local j = t[i]
|
||||
co = coroutine.create(function()
|
||||
local t = {}
|
||||
for i = 1, j do t[i] = i end
|
||||
return table.unpack(t)
|
||||
end)
|
||||
local r, msg = coroutine.resume(co)
|
||||
assert(not r)
|
||||
end
|
||||
co = nil
|
||||
end
|
||||
|
||||
|
||||
assert(coroutine.running() == main)
|
||||
|
||||
print"+"
|
||||
|
||||
|
||||
print"testing yields inside metamethods"
|
||||
|
||||
local mt = {
|
||||
__eq = function(a,b) coroutine.yield(nil, "eq"); return a.x == b.x end,
|
||||
__lt = function(a,b) coroutine.yield(nil, "lt"); return a.x < b.x end,
|
||||
__le = function(a,b) coroutine.yield(nil, "le"); return a - b <= 0 end,
|
||||
__add = function(a,b) coroutine.yield(nil, "add"); return a.x + b.x end,
|
||||
__sub = function(a,b) coroutine.yield(nil, "sub"); return a.x - b.x end,
|
||||
__mod = function(a,b) coroutine.yield(nil, "mod"); return a.x % b.x end,
|
||||
__unm = function(a,b) coroutine.yield(nil, "unm"); return -a.x end,
|
||||
__bnot = function(a,b) coroutine.yield(nil, "bnot"); return ~a.x end,
|
||||
__shl = function(a,b) coroutine.yield(nil, "shl"); return a.x << b.x end,
|
||||
__shr = function(a,b) coroutine.yield(nil, "shr"); return a.x >> b.x end,
|
||||
__band = function(a,b)
|
||||
a = type(a) == "table" and a.x or a
|
||||
b = type(b) == "table" and b.x or b
|
||||
coroutine.yield(nil, "band")
|
||||
return a & b
|
||||
end,
|
||||
__bor = function(a,b) coroutine.yield(nil, "bor"); return a.x | b.x end,
|
||||
__bxor = function(a,b) coroutine.yield(nil, "bxor"); return a.x ~ b.x end,
|
||||
|
||||
__concat = function(a,b)
|
||||
coroutine.yield(nil, "concat");
|
||||
a = type(a) == "table" and a.x or a
|
||||
b = type(b) == "table" and b.x or b
|
||||
return a .. b
|
||||
end,
|
||||
__index = function (t,k) coroutine.yield(nil, "idx"); return t.k[k] end,
|
||||
__newindex = function (t,k,v) coroutine.yield(nil, "nidx"); t.k[k] = v end,
|
||||
}
|
||||
|
||||
|
||||
local function new (x)
|
||||
return setmetatable({x = x, k = {}}, mt)
|
||||
end
|
||||
|
||||
|
||||
local a = new(10)
|
||||
local b = new(12)
|
||||
local c = new"hello"
|
||||
|
||||
local function run (f, t)
|
||||
local i = 1
|
||||
local c = coroutine.wrap(f)
|
||||
while true do
|
||||
local res, stat = c()
|
||||
if res then assert(t[i] == nil); return res, t end
|
||||
assert(stat == t[i])
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
assert(run(function () if (a>=b) then return '>=' else return '<' end end,
|
||||
{"le", "sub"}) == "<")
|
||||
-- '<=' using '<'
|
||||
mt.__le = nil
|
||||
assert(run(function () if (a<=b) then return '<=' else return '>' end end,
|
||||
{"lt"}) == "<=")
|
||||
assert(run(function () if (a==b) then return '==' else return '~=' end end,
|
||||
{"eq"}) == "~=")
|
||||
|
||||
assert(run(function () return a & b + a end, {"add", "band"}) == 2)
|
||||
|
||||
assert(run(function () return a % b end, {"mod"}) == 10)
|
||||
|
||||
assert(run(function () return ~a & b end, {"bnot", "band"}) == ~10 & 12)
|
||||
assert(run(function () return a | b end, {"bor"}) == 10 | 12)
|
||||
assert(run(function () return a ~ b end, {"bxor"}) == 10 ~ 12)
|
||||
assert(run(function () return a << b end, {"shl"}) == 10 << 12)
|
||||
assert(run(function () return a >> b end, {"shr"}) == 10 >> 12)
|
||||
|
||||
assert(run(function () return a..b end, {"concat"}) == "1012")
|
||||
|
||||
assert(run(function() return a .. b .. c .. a end,
|
||||
{"concat", "concat", "concat"}) == "1012hello10")
|
||||
|
||||
assert(run(function() return "a" .. "b" .. a .. "c" .. c .. b .. "x" end,
|
||||
{"concat", "concat", "concat"}) == "ab10chello12x")
|
||||
|
||||
|
||||
do -- a few more tests for comparsion operators
|
||||
local mt1 = {
|
||||
__le = function (a,b)
|
||||
coroutine.yield(10)
|
||||
return
|
||||
(type(a) == "table" and a.x or a) <= (type(b) == "table" and b.x or b)
|
||||
end,
|
||||
__lt = function (a,b)
|
||||
coroutine.yield(10)
|
||||
return
|
||||
(type(a) == "table" and a.x or a) < (type(b) == "table" and b.x or b)
|
||||
end,
|
||||
}
|
||||
local mt2 = { __lt = mt1.__lt } -- no __le
|
||||
|
||||
local function run (f)
|
||||
local co = coroutine.wrap(f)
|
||||
local res
|
||||
repeat
|
||||
res = co()
|
||||
until res ~= 10
|
||||
return res
|
||||
end
|
||||
|
||||
local function test ()
|
||||
local a1 = setmetatable({x=1}, mt1)
|
||||
local a2 = setmetatable({x=2}, mt2)
|
||||
assert(a1 < a2)
|
||||
assert(a1 <= a2)
|
||||
assert(1 < a2)
|
||||
assert(1 <= a2)
|
||||
assert(2 > a1)
|
||||
assert(2 >= a2)
|
||||
return true
|
||||
end
|
||||
|
||||
run(test)
|
||||
|
||||
end
|
||||
|
||||
assert(run(function ()
|
||||
a.BB = print
|
||||
return a.BB
|
||||
end, {"nidx", "idx"}) == print)
|
||||
|
||||
-- getuptable & setuptable
|
||||
do local _ENV = _ENV
|
||||
f = function () AAA = BBB + 1; return AAA end
|
||||
end
|
||||
g = new(10); g.k.BBB = 10;
|
||||
debug.setupvalue(f, 1, g)
|
||||
assert(run(f, {"idx", "nidx", "idx"}) == 11)
|
||||
assert(g.k.AAA == 11)
|
||||
|
||||
print"+"
|
||||
|
||||
print"testing yields inside 'for' iterators"
|
||||
|
||||
local f = function (s, i)
|
||||
if i%2 == 0 then coroutine.yield(nil, "for") end
|
||||
if i < s then return i + 1 end
|
||||
end
|
||||
|
||||
assert(run(function ()
|
||||
local s = 0
|
||||
for i in f, 4, 0 do s = s + i end
|
||||
return s
|
||||
end, {"for", "for", "for"}) == 10)
|
||||
|
||||
|
||||
|
||||
-- tests for coroutine API
|
||||
if T==nil then
|
||||
(Message or print)('\n >>> testC not active: skipping coroutine API tests <<<\n')
|
||||
return
|
||||
end
|
||||
|
||||
print('testing coroutine API')
|
||||
|
||||
local function apico (...)
|
||||
local x = {...}
|
||||
return coroutine.wrap(function ()
|
||||
return T.testC(table.unpack(x))
|
||||
end)
|
||||
end
|
||||
|
||||
local a = {apico(
|
||||
[[
|
||||
pushstring errorcode
|
||||
pcallk 1 0 2;
|
||||
invalid command (should not arrive here)
|
||||
]],
|
||||
[[return *]],
|
||||
"stackmark",
|
||||
error
|
||||
)()}
|
||||
assert(#a == 4 and
|
||||
a[3] == "stackmark" and
|
||||
a[4] == "errorcode" and
|
||||
_G.status == "ERRRUN" and
|
||||
_G.ctx == 2) -- 'ctx' to pcallk
|
||||
|
||||
local co = apico(
|
||||
"pushvalue 2; pushnum 10; pcallk 1 2 3; invalid command;",
|
||||
coroutine.yield,
|
||||
"getglobal status; getglobal ctx; pushvalue 2; pushstring a; pcallk 1 0 4; invalid command",
|
||||
"getglobal status; getglobal ctx; return *")
|
||||
|
||||
assert(co() == 10)
|
||||
assert(co(20, 30) == 'a')
|
||||
a = {co()}
|
||||
assert(#a == 10 and
|
||||
a[2] == coroutine.yield and
|
||||
a[5] == 20 and a[6] == 30 and
|
||||
a[7] == "YIELD" and a[8] == 3 and
|
||||
a[9] == "YIELD" and a[10] == 4)
|
||||
assert(not pcall(co)) -- coroutine is dead now
|
||||
|
||||
|
||||
f = T.makeCfunc("pushnum 3; pushnum 5; yield 1;")
|
||||
co = coroutine.wrap(function ()
|
||||
assert(f() == 23); assert(f() == 23); return 10
|
||||
end)
|
||||
assert(co(23,16) == 5)
|
||||
assert(co(23,16) == 5)
|
||||
assert(co(23,16) == 10)
|
||||
|
||||
|
||||
-- testing coroutines with C bodies
|
||||
f = T.makeCfunc([[
|
||||
pushnum 102
|
||||
yieldk 1 U2
|
||||
cannot be here!
|
||||
]],
|
||||
[[ # continuation
|
||||
pushvalue U3 # accessing upvalues inside a continuation
|
||||
pushvalue U4
|
||||
return *
|
||||
]], 23, "huu")
|
||||
|
||||
x = coroutine.wrap(f)
|
||||
assert(x() == 102)
|
||||
eqtab({x()}, {23, "huu"})
|
||||
|
||||
|
||||
f = T.makeCfunc[[pushstring 'a'; pushnum 102; yield 2; ]]
|
||||
|
||||
a, b, c, d = T.testC([[newthread; pushvalue 2; xmove 0 3 1; resume 3 0;
|
||||
pushstatus; xmove 3 0 0; resume 3 0; pushstatus;
|
||||
return 4; ]], f)
|
||||
|
||||
assert(a == 'YIELD' and b == 'a' and c == 102 and d == 'OK')
|
||||
|
||||
|
||||
-- testing chain of suspendable C calls
|
||||
|
||||
local count = 3 -- number of levels
|
||||
|
||||
f = T.makeCfunc([[
|
||||
remove 1; # remove argument
|
||||
pushvalue U3; # get selection function
|
||||
call 0 1; # call it (result is 'f' or 'yield')
|
||||
pushstring hello # single argument for selected function
|
||||
pushupvalueindex 2; # index of continuation program
|
||||
callk 1 -1 .; # call selected function
|
||||
errorerror # should never arrive here
|
||||
]],
|
||||
[[
|
||||
# continuation program
|
||||
pushnum 34 # return value
|
||||
return * # return all results
|
||||
]],
|
||||
function () -- selection function
|
||||
count = count - 1
|
||||
if count == 0 then return coroutine.yield
|
||||
else return f
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
co = coroutine.wrap(function () return f(nil) end)
|
||||
assert(co() == "hello") -- argument to 'yield'
|
||||
a = {co()}
|
||||
-- three '34's (one from each pending C call)
|
||||
assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34)
|
||||
|
||||
|
||||
-- testing yields with continuations
|
||||
|
||||
co = coroutine.wrap(function (...) return
|
||||
T.testC([[ # initial function
|
||||
yieldk 1 2
|
||||
cannot be here!
|
||||
]],
|
||||
[[ # 1st continuation
|
||||
yieldk 0 3
|
||||
cannot be here!
|
||||
]],
|
||||
[[ # 2nd continuation
|
||||
yieldk 0 4
|
||||
cannot be here!
|
||||
]],
|
||||
[[ # 3th continuation
|
||||
pushvalue 6 # function which is last arg. to 'testC' here
|
||||
pushnum 10; pushnum 20;
|
||||
pcall 2 0 0 # call should throw an error and return to next line
|
||||
pop 1 # remove error message
|
||||
pushvalue 6
|
||||
getglobal status; getglobal ctx
|
||||
pcallk 2 2 5 # call should throw an error and jump to continuation
|
||||
cannot be here!
|
||||
]],
|
||||
[[ # 4th (and last) continuation
|
||||
return *
|
||||
]],
|
||||
-- function called by 3th continuation
|
||||
function (a,b) x=a; y=b; error("errmsg") end,
|
||||
...
|
||||
)
|
||||
end)
|
||||
|
||||
local a = {co(3,4,6)}
|
||||
assert(a[1] == 6 and a[2] == nil)
|
||||
a = {co()}; assert(a[1] == nil and _G.status == "YIELD" and _G.ctx == 2)
|
||||
a = {co()}; assert(a[1] == nil and _G.status == "YIELD" and _G.ctx == 3)
|
||||
a = {co(7,8)};
|
||||
-- original arguments
|
||||
assert(type(a[1]) == 'string' and type(a[2]) == 'string' and
|
||||
type(a[3]) == 'string' and type(a[4]) == 'string' and
|
||||
type(a[5]) == 'string' and type(a[6]) == 'function')
|
||||
-- arguments left from fist resume
|
||||
assert(a[7] == 3 and a[8] == 4)
|
||||
-- arguments to last resume
|
||||
assert(a[9] == 7 and a[10] == 8)
|
||||
-- error message and nothing more
|
||||
assert(a[11]:find("errmsg") and #a == 11)
|
||||
-- check arguments to pcallk
|
||||
assert(x == "YIELD" and y == 4)
|
||||
|
||||
assert(not pcall(co)) -- coroutine should be dead
|
||||
|
||||
|
||||
-- bug in nCcalls
|
||||
local co = coroutine.wrap(function ()
|
||||
local a = {pcall(pcall,pcall,pcall,pcall,pcall,pcall,pcall,error,"hi")}
|
||||
return pcall(assert, table.unpack(a))
|
||||
end)
|
||||
|
||||
local a = {co()}
|
||||
assert(a[10] == "hi")
|
||||
|
||||
print'OK'
|
857
06/parser-gen/parsers/lua-5.3.4-tests/db.lua
Normal file
857
06/parser-gen/parsers/lua-5.3.4-tests/db.lua
Normal file
|
@ -0,0 +1,857 @@
|
|||
-- $Id: db.lua,v 1.79 2016/11/07 13:02:34 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
-- testing debug library
|
||||
|
||||
local debug = require "debug"
|
||||
|
||||
local function dostring(s) return assert(load(s))() end
|
||||
|
||||
print"testing debug library and debug information"
|
||||
|
||||
do
|
||||
local a=1
|
||||
end
|
||||
|
||||
assert(not debug.gethook())
|
||||
|
||||
local testline = 19 -- line where 'test' is defined
|
||||
function test (s, l, p) -- this must be line 19
|
||||
collectgarbage() -- avoid gc during trace
|
||||
local function f (event, line)
|
||||
assert(event == 'line')
|
||||
local l = table.remove(l, 1)
|
||||
if p then print(l, line) end
|
||||
assert(l == line, "wrong trace!!")
|
||||
end
|
||||
debug.sethook(f,"l"); load(s)(); debug.sethook()
|
||||
assert(#l == 0)
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
assert(not pcall(debug.getinfo, print, "X")) -- invalid option
|
||||
assert(not debug.getinfo(1000)) -- out of range level
|
||||
assert(not debug.getinfo(-1)) -- out of range level
|
||||
local a = debug.getinfo(print)
|
||||
assert(a.what == "C" and a.short_src == "[C]")
|
||||
a = debug.getinfo(print, "L")
|
||||
assert(a.activelines == nil)
|
||||
local b = debug.getinfo(test, "SfL")
|
||||
assert(b.name == nil and b.what == "Lua" and b.linedefined == testline and
|
||||
b.lastlinedefined == b.linedefined + 10 and
|
||||
b.func == test and not string.find(b.short_src, "%["))
|
||||
assert(b.activelines[b.linedefined + 1] and
|
||||
b.activelines[b.lastlinedefined])
|
||||
assert(not b.activelines[b.linedefined] and
|
||||
not b.activelines[b.lastlinedefined + 1])
|
||||
end
|
||||
|
||||
|
||||
-- test file and string names truncation
|
||||
a = "function f () end"
|
||||
local function dostring (s, x) return load(s, x)() end
|
||||
dostring(a)
|
||||
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
|
||||
dostring(a..string.format("; %s\n=1", string.rep('p', 400)))
|
||||
assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
|
||||
dostring(a..string.format("; %s=1", string.rep('p', 400)))
|
||||
assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
|
||||
dostring("\n"..a)
|
||||
assert(debug.getinfo(f).short_src == '[string "..."]')
|
||||
dostring(a, "")
|
||||
assert(debug.getinfo(f).short_src == '[string ""]')
|
||||
dostring(a, "@xuxu")
|
||||
assert(debug.getinfo(f).short_src == "xuxu")
|
||||
dostring(a, "@"..string.rep('p', 1000)..'t')
|
||||
assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$"))
|
||||
dostring(a, "=xuxu")
|
||||
assert(debug.getinfo(f).short_src == "xuxu")
|
||||
dostring(a, string.format("=%s", string.rep('x', 500)))
|
||||
assert(string.find(debug.getinfo(f).short_src, "^x*$"))
|
||||
dostring(a, "=")
|
||||
assert(debug.getinfo(f).short_src == "")
|
||||
a = nil; f = nil;
|
||||
|
||||
|
||||
repeat
|
||||
local g = {x = function ()
|
||||
local a = debug.getinfo(2)
|
||||
assert(a.name == 'f' and a.namewhat == 'local')
|
||||
a = debug.getinfo(1)
|
||||
assert(a.name == 'x' and a.namewhat == 'field')
|
||||
return 'xixi'
|
||||
end}
|
||||
local f = function () return 1+1 and (not 1 or g.x()) end
|
||||
assert(f() == 'xixi')
|
||||
g = debug.getinfo(f)
|
||||
assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name)
|
||||
|
||||
function f (x, name) -- local!
|
||||
name = name or 'f'
|
||||
local a = debug.getinfo(1)
|
||||
assert(a.name == name and a.namewhat == 'local')
|
||||
return x
|
||||
end
|
||||
|
||||
-- breaks in different conditions
|
||||
if 3>4 then break end; f()
|
||||
if 3<4 then a=1 else break end; f()
|
||||
while 1 do local x=10; break end; f()
|
||||
local b = 1
|
||||
if 3>4 then return math.sin(1) end; f()
|
||||
a = 3<4; f()
|
||||
a = 3<4 or 1; f()
|
||||
repeat local x=20; if 4>3 then f() else break end; f() until 1
|
||||
g = {}
|
||||
f(g).x = f(2) and f(10)+f(9)
|
||||
assert(g.x == f(19))
|
||||
function g(x) if not x then return 3 end return (x('a', 'x')) end
|
||||
assert(g(f) == 'a')
|
||||
until 1
|
||||
|
||||
test([[if
|
||||
math.sin(1)
|
||||
then
|
||||
a=1
|
||||
else
|
||||
a=2
|
||||
end
|
||||
]], {2,3,4,7})
|
||||
|
||||
test([[--
|
||||
if nil then
|
||||
a=1
|
||||
else
|
||||
a=2
|
||||
end
|
||||
]], {2,5,6})
|
||||
|
||||
test([[a=1
|
||||
repeat
|
||||
a=a+1
|
||||
until a==3
|
||||
]], {1,3,4,3,4})
|
||||
|
||||
test([[ do
|
||||
return
|
||||
end
|
||||
]], {2})
|
||||
|
||||
test([[local a
|
||||
a=1
|
||||
while a<=3 do
|
||||
a=a+1
|
||||
end
|
||||
]], {1,2,3,4,3,4,3,4,3,5})
|
||||
|
||||
test([[while math.sin(1) do
|
||||
if math.sin(1)
|
||||
then break
|
||||
end
|
||||
end
|
||||
a=1]], {1,2,3,6})
|
||||
|
||||
test([[for i=1,3 do
|
||||
a=i
|
||||
end
|
||||
]], {1,2,1,2,1,2,1,3})
|
||||
|
||||
test([[for i,v in pairs{'a','b'} do
|
||||
a=tostring(i) .. v
|
||||
end
|
||||
]], {1,2,1,2,1,3})
|
||||
|
||||
test([[for i=1,4 do a=1 end]], {1,1,1,1,1})
|
||||
|
||||
|
||||
|
||||
print'+'
|
||||
|
||||
-- invalid levels in [gs]etlocal
|
||||
assert(not pcall(debug.getlocal, 20, 1))
|
||||
assert(not pcall(debug.setlocal, -1, 1, 10))
|
||||
|
||||
|
||||
-- parameter names
|
||||
local function foo (a,b,...) local d, e end
|
||||
local co = coroutine.create(foo)
|
||||
|
||||
assert(debug.getlocal(foo, 1) == 'a')
|
||||
assert(debug.getlocal(foo, 2) == 'b')
|
||||
assert(not debug.getlocal(foo, 3))
|
||||
assert(debug.getlocal(co, foo, 1) == 'a')
|
||||
assert(debug.getlocal(co, foo, 2) == 'b')
|
||||
assert(not debug.getlocal(co, foo, 3))
|
||||
|
||||
assert(not debug.getlocal(print, 1))
|
||||
|
||||
|
||||
-- varargs
|
||||
local function foo (a, ...)
|
||||
local t = table.pack(...)
|
||||
for i = 1, t.n do
|
||||
local n, v = debug.getlocal(1, -i)
|
||||
assert(n == "(*vararg)" and v == t[i])
|
||||
end
|
||||
assert(not debug.getlocal(1, -(t.n + 1)))
|
||||
assert(not debug.setlocal(1, -(t.n + 1), 30))
|
||||
if t.n > 0 then
|
||||
(function (x)
|
||||
assert(debug.setlocal(2, -1, x) == "(*vararg)")
|
||||
assert(debug.setlocal(2, -t.n, x) == "(*vararg)")
|
||||
end)(430)
|
||||
assert(... == 430)
|
||||
end
|
||||
end
|
||||
|
||||
foo()
|
||||
foo(print)
|
||||
foo(200, 3, 4)
|
||||
local a = {}
|
||||
for i = 1, (_soft and 100 or 1000) do a[i] = i end
|
||||
foo(table.unpack(a))
|
||||
a = nil
|
||||
|
||||
-- access to vararg in non-vararg function
|
||||
local function foo () return debug.getlocal(1, -1) end
|
||||
assert(not foo(10))
|
||||
|
||||
|
||||
do -- test hook presence in debug info
|
||||
assert(not debug.gethook())
|
||||
local count = 0
|
||||
local function f ()
|
||||
assert(debug.getinfo(1).namewhat == "hook")
|
||||
local sndline = string.match(debug.traceback(), "\n(.-)\n")
|
||||
assert(string.find(sndline, "hook"))
|
||||
count = count + 1
|
||||
end
|
||||
debug.sethook(f, "l")
|
||||
local a = 0
|
||||
_ENV.a = a
|
||||
a = 1
|
||||
debug.sethook()
|
||||
assert(count == 4)
|
||||
end
|
||||
|
||||
|
||||
a = {}; L = nil
|
||||
local glob = 1
|
||||
local oldglob = glob
|
||||
debug.sethook(function (e,l)
|
||||
collectgarbage() -- force GC during a hook
|
||||
local f, m, c = debug.gethook()
|
||||
assert(m == 'crl' and c == 0)
|
||||
if e == "line" then
|
||||
if glob ~= oldglob then
|
||||
L = l-1 -- get the first line where "glob" has changed
|
||||
oldglob = glob
|
||||
end
|
||||
elseif e == "call" then
|
||||
local f = debug.getinfo(2, "f").func
|
||||
a[f] = 1
|
||||
else assert(e == "return")
|
||||
end
|
||||
end, "crl")
|
||||
|
||||
|
||||
function f(a,b)
|
||||
collectgarbage()
|
||||
local _, x = debug.getlocal(1, 1)
|
||||
local _, y = debug.getlocal(1, 2)
|
||||
assert(x == a and y == b)
|
||||
assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
|
||||
assert(debug.setlocal(2, 4, "maçã") == "B")
|
||||
x = debug.getinfo(2)
|
||||
assert(x.func == g and x.what == "Lua" and x.name == 'g' and
|
||||
x.nups == 2 and string.find(x.source, "^@.*db%.lua$"))
|
||||
glob = glob+1
|
||||
assert(debug.getinfo(1, "l").currentline == L+1)
|
||||
assert(debug.getinfo(1, "l").currentline == L+2)
|
||||
end
|
||||
|
||||
function foo()
|
||||
glob = glob+1
|
||||
assert(debug.getinfo(1, "l").currentline == L+1)
|
||||
end; foo() -- set L
|
||||
-- check line counting inside strings and empty lines
|
||||
|
||||
_ = 'alo\
|
||||
alo' .. [[
|
||||
|
||||
]]
|
||||
--[[
|
||||
]]
|
||||
assert(debug.getinfo(1, "l").currentline == L+11) -- check count of lines
|
||||
|
||||
|
||||
function g(...)
|
||||
local arg = {...}
|
||||
do local a,b,c; a=math.sin(40); end
|
||||
local feijao
|
||||
local AAAA,B = "xuxu", "mamão"
|
||||
f(AAAA,B)
|
||||
assert(AAAA == "pera" and B == "maçã")
|
||||
do
|
||||
local B = 13
|
||||
local x,y = debug.getlocal(1,5)
|
||||
assert(x == 'B' and y == 13)
|
||||
end
|
||||
end
|
||||
|
||||
g()
|
||||
|
||||
|
||||
assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print])
|
||||
|
||||
|
||||
-- tests for manipulating non-registered locals (C and Lua temporaries)
|
||||
|
||||
local n, v = debug.getlocal(0, 1)
|
||||
assert(v == 0 and n == "(*temporary)")
|
||||
local n, v = debug.getlocal(0, 2)
|
||||
assert(v == 2 and n == "(*temporary)")
|
||||
assert(not debug.getlocal(0, 3))
|
||||
assert(not debug.getlocal(0, 0))
|
||||
|
||||
function f()
|
||||
assert(select(2, debug.getlocal(2,3)) == 1)
|
||||
assert(not debug.getlocal(2,4))
|
||||
debug.setlocal(2, 3, 10)
|
||||
return 20
|
||||
end
|
||||
|
||||
function g(a,b) return (a+1) + f() end
|
||||
|
||||
assert(g(0,0) == 30)
|
||||
|
||||
|
||||
debug.sethook(nil);
|
||||
assert(debug.gethook() == nil)
|
||||
|
||||
|
||||
-- testing access to function arguments
|
||||
|
||||
local function collectlocals (level)
|
||||
local tab = {}
|
||||
for i = 1, math.huge do
|
||||
local n, v = debug.getlocal(level + 1, i)
|
||||
if not (n and string.find(n, "^[a-zA-Z0-9_]+$")) then
|
||||
break -- consider only real variables
|
||||
end
|
||||
tab[n] = v
|
||||
end
|
||||
return tab
|
||||
end
|
||||
|
||||
|
||||
X = nil
|
||||
a = {}
|
||||
function a:f (a, b, ...) local arg = {...}; local c = 13 end
|
||||
debug.sethook(function (e)
|
||||
assert(e == "call")
|
||||
dostring("XX = 12") -- test dostring inside hooks
|
||||
-- testing errors inside hooks
|
||||
assert(not pcall(load("a='joao'+1")))
|
||||
debug.sethook(function (e, l)
|
||||
assert(debug.getinfo(2, "l").currentline == l)
|
||||
local f,m,c = debug.gethook()
|
||||
assert(e == "line")
|
||||
assert(m == 'l' and c == 0)
|
||||
debug.sethook(nil) -- hook is called only once
|
||||
assert(not X) -- check that
|
||||
X = collectlocals(2)
|
||||
end, "l")
|
||||
end, "c")
|
||||
|
||||
a:f(1,2,3,4,5)
|
||||
assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil)
|
||||
assert(XX == 12)
|
||||
assert(debug.gethook() == nil)
|
||||
|
||||
|
||||
-- testing access to local variables in return hook (bug in 5.2)
|
||||
do
|
||||
local function foo (a, b)
|
||||
do local x,y,z end
|
||||
local c, d = 10, 20
|
||||
return
|
||||
end
|
||||
|
||||
local function aux ()
|
||||
if debug.getinfo(2).name == "foo" then
|
||||
foo = nil -- to signal that it found 'foo'
|
||||
local tab = {a = 100, b = 200, c = 10, d = 20}
|
||||
for n, v in pairs(collectlocals(2)) do
|
||||
assert(tab[n] == v)
|
||||
tab[n] = nil
|
||||
end
|
||||
assert(next(tab) == nil) -- 'tab' must be empty
|
||||
end
|
||||
end
|
||||
|
||||
debug.sethook(aux, "r"); foo(100, 200); debug.sethook()
|
||||
assert(foo == nil)
|
||||
end
|
||||
|
||||
-- testing upvalue access
|
||||
local function getupvalues (f)
|
||||
local t = {}
|
||||
local i = 1
|
||||
while true do
|
||||
local name, value = debug.getupvalue(f, i)
|
||||
if not name then break end
|
||||
assert(not t[name])
|
||||
t[name] = value
|
||||
i = i + 1
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local a,b,c = 1,2,3
|
||||
local function foo1 (a) b = a; return c end
|
||||
local function foo2 (x) a = x; return c+b end
|
||||
assert(not debug.getupvalue(foo1, 3))
|
||||
assert(not debug.getupvalue(foo1, 0))
|
||||
assert(not debug.setupvalue(foo1, 3, "xuxu"))
|
||||
local t = getupvalues(foo1)
|
||||
assert(t.a == nil and t.b == 2 and t.c == 3)
|
||||
t = getupvalues(foo2)
|
||||
assert(t.a == 1 and t.b == 2 and t.c == 3)
|
||||
assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
|
||||
assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
|
||||
-- upvalues of C functions are allways "called" "" (the empty string)
|
||||
assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "")
|
||||
|
||||
|
||||
-- testing count hooks
|
||||
local a=0
|
||||
debug.sethook(function (e) a=a+1 end, "", 1)
|
||||
a=0; for i=1,1000 do end; assert(1000 < a and a < 1012)
|
||||
debug.sethook(function (e) a=a+1 end, "", 4)
|
||||
a=0; for i=1,1000 do end; assert(250 < a and a < 255)
|
||||
local f,m,c = debug.gethook()
|
||||
assert(m == "" and c == 4)
|
||||
debug.sethook(function (e) a=a+1 end, "", 4000)
|
||||
a=0; for i=1,1000 do end; assert(a == 0)
|
||||
|
||||
do
|
||||
debug.sethook(print, "", 2^24 - 1) -- count upperbound
|
||||
local f,m,c = debug.gethook()
|
||||
assert(({debug.gethook()})[3] == 2^24 - 1)
|
||||
end
|
||||
|
||||
debug.sethook()
|
||||
|
||||
|
||||
-- tests for tail calls
|
||||
local function f (x)
|
||||
if x then
|
||||
assert(debug.getinfo(1, "S").what == "Lua")
|
||||
assert(debug.getinfo(1, "t").istailcall == true)
|
||||
local tail = debug.getinfo(2)
|
||||
assert(tail.func == g1 and tail.istailcall == true)
|
||||
assert(debug.getinfo(3, "S").what == "main")
|
||||
print"+"
|
||||
end
|
||||
end
|
||||
|
||||
function g(x) return f(x) end
|
||||
|
||||
function g1(x) g(x) end
|
||||
|
||||
local function h (x) local f=g1; return f(x) end
|
||||
|
||||
h(true)
|
||||
|
||||
local b = {}
|
||||
debug.sethook(function (e) table.insert(b, e) end, "cr")
|
||||
h(false)
|
||||
debug.sethook()
|
||||
local res = {"return", -- first return (from sethook)
|
||||
"call", "tail call", "call", "tail call",
|
||||
"return", "return",
|
||||
"call", -- last call (to sethook)
|
||||
}
|
||||
for i = 1, #res do assert(res[i] == table.remove(b, 1)) end
|
||||
|
||||
b = 0
|
||||
debug.sethook(function (e)
|
||||
if e == "tail call" then
|
||||
b = b + 1
|
||||
assert(debug.getinfo(2, "t").istailcall == true)
|
||||
else
|
||||
assert(debug.getinfo(2, "t").istailcall == false)
|
||||
end
|
||||
end, "c")
|
||||
h(false)
|
||||
debug.sethook()
|
||||
assert(b == 2) -- two tail calls
|
||||
|
||||
lim = _soft and 3000 or 30000
|
||||
local function foo (x)
|
||||
if x==0 then
|
||||
assert(debug.getinfo(2).what == "main")
|
||||
local info = debug.getinfo(1)
|
||||
assert(info.istailcall == true and info.func == foo)
|
||||
else return foo(x-1)
|
||||
end
|
||||
end
|
||||
|
||||
foo(lim)
|
||||
|
||||
|
||||
print"+"
|
||||
|
||||
|
||||
-- testing local function information
|
||||
co = load[[
|
||||
local A = function ()
|
||||
return x
|
||||
end
|
||||
return
|
||||
]]
|
||||
|
||||
local a = 0
|
||||
-- 'A' should be visible to debugger only after its complete definition
|
||||
debug.sethook(function (e, l)
|
||||
if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(*temporary)")
|
||||
elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A")
|
||||
end
|
||||
end, "l")
|
||||
co() -- run local function definition
|
||||
debug.sethook() -- turn off hook
|
||||
assert(a == 2) -- ensure all two lines where hooked
|
||||
|
||||
-- testing traceback
|
||||
|
||||
assert(debug.traceback(print) == print)
|
||||
assert(debug.traceback(print, 4) == print)
|
||||
assert(string.find(debug.traceback("hi", 4), "^hi\n"))
|
||||
assert(string.find(debug.traceback("hi"), "^hi\n"))
|
||||
assert(not string.find(debug.traceback("hi"), "'debug.traceback'"))
|
||||
assert(string.find(debug.traceback("hi", 0), "'debug.traceback'"))
|
||||
assert(string.find(debug.traceback(), "^stack traceback:\n"))
|
||||
|
||||
do -- C-function names in traceback
|
||||
local st, msg = (function () return pcall end)()(debug.traceback)
|
||||
assert(st == true and string.find(msg, "pcall"))
|
||||
end
|
||||
|
||||
|
||||
-- testing nparams, nups e isvararg
|
||||
local t = debug.getinfo(print, "u")
|
||||
assert(t.isvararg == true and t.nparams == 0 and t.nups == 0)
|
||||
|
||||
t = debug.getinfo(function (a,b,c) end, "u")
|
||||
assert(t.isvararg == false and t.nparams == 3 and t.nups == 0)
|
||||
|
||||
t = debug.getinfo(function (a,b,...) return t[a] end, "u")
|
||||
assert(t.isvararg == true and t.nparams == 2 and t.nups == 1)
|
||||
|
||||
t = debug.getinfo(1) -- main
|
||||
assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
|
||||
debug.getupvalue(t.func, 1) == "_ENV")
|
||||
|
||||
|
||||
|
||||
|
||||
-- testing debugging of coroutines
|
||||
|
||||
local function checktraceback (co, p, level)
|
||||
local tb = debug.traceback(co, nil, level)
|
||||
local i = 0
|
||||
for l in string.gmatch(tb, "[^\n]+\n?") do
|
||||
assert(i == 0 or string.find(l, p[i]))
|
||||
i = i+1
|
||||
end
|
||||
assert(p[i] == nil)
|
||||
end
|
||||
|
||||
|
||||
local function f (n)
|
||||
if n > 0 then f(n-1)
|
||||
else coroutine.yield() end
|
||||
end
|
||||
|
||||
local co = coroutine.create(f)
|
||||
coroutine.resume(co, 3)
|
||||
checktraceback(co, {"yield", "db.lua", "db.lua", "db.lua", "db.lua"})
|
||||
checktraceback(co, {"db.lua", "db.lua", "db.lua", "db.lua"}, 1)
|
||||
checktraceback(co, {"db.lua", "db.lua", "db.lua"}, 2)
|
||||
checktraceback(co, {"db.lua"}, 4)
|
||||
checktraceback(co, {}, 40)
|
||||
|
||||
|
||||
co = coroutine.create(function (x)
|
||||
local a = 1
|
||||
coroutine.yield(debug.getinfo(1, "l"))
|
||||
coroutine.yield(debug.getinfo(1, "l").currentline)
|
||||
return a
|
||||
end)
|
||||
|
||||
local tr = {}
|
||||
local foo = function (e, l) if l then table.insert(tr, l) end end
|
||||
debug.sethook(co, foo, "lcr")
|
||||
|
||||
local _, l = coroutine.resume(co, 10)
|
||||
local x = debug.getinfo(co, 1, "lfLS")
|
||||
assert(x.currentline == l.currentline and x.activelines[x.currentline])
|
||||
assert(type(x.func) == "function")
|
||||
for i=x.linedefined + 1, x.lastlinedefined do
|
||||
assert(x.activelines[i])
|
||||
x.activelines[i] = nil
|
||||
end
|
||||
assert(next(x.activelines) == nil) -- no 'extra' elements
|
||||
assert(not debug.getinfo(co, 2))
|
||||
local a,b = debug.getlocal(co, 1, 1)
|
||||
assert(a == "x" and b == 10)
|
||||
a,b = debug.getlocal(co, 1, 2)
|
||||
assert(a == "a" and b == 1)
|
||||
debug.setlocal(co, 1, 2, "hi")
|
||||
assert(debug.gethook(co) == foo)
|
||||
assert(#tr == 2 and
|
||||
tr[1] == l.currentline-1 and tr[2] == l.currentline)
|
||||
|
||||
a,b,c = pcall(coroutine.resume, co)
|
||||
assert(a and b and c == l.currentline+1)
|
||||
checktraceback(co, {"yield", "in function <"})
|
||||
|
||||
a,b = coroutine.resume(co)
|
||||
assert(a and b == "hi")
|
||||
assert(#tr == 4 and tr[4] == l.currentline+2)
|
||||
assert(debug.gethook(co) == foo)
|
||||
assert(not debug.gethook())
|
||||
checktraceback(co, {})
|
||||
|
||||
|
||||
-- check get/setlocal in coroutines
|
||||
co = coroutine.create(function (x)
|
||||
local a, b = coroutine.yield(x)
|
||||
assert(a == 100 and b == nil)
|
||||
return x
|
||||
end)
|
||||
a, b = coroutine.resume(co, 10)
|
||||
assert(a and b == 10)
|
||||
a, b = debug.getlocal(co, 1, 1)
|
||||
assert(a == "x" and b == 10)
|
||||
assert(not debug.getlocal(co, 1, 5))
|
||||
assert(debug.setlocal(co, 1, 1, 30) == "x")
|
||||
assert(not debug.setlocal(co, 1, 5, 40))
|
||||
a, b = coroutine.resume(co, 100)
|
||||
assert(a and b == 30)
|
||||
|
||||
|
||||
-- check traceback of suspended (or dead with error) coroutines
|
||||
|
||||
function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end
|
||||
|
||||
co = coroutine.create(function (x) f(x) end)
|
||||
a, b = coroutine.resume(co, 3)
|
||||
t = {"'coroutine.yield'", "'f'", "in function <"}
|
||||
while coroutine.status(co) == "suspended" do
|
||||
checktraceback(co, t)
|
||||
a, b = coroutine.resume(co)
|
||||
table.insert(t, 2, "'f'") -- one more recursive call to 'f'
|
||||
end
|
||||
t[1] = "'error'"
|
||||
checktraceback(co, t)
|
||||
|
||||
|
||||
-- test acessing line numbers of a coroutine from a resume inside
|
||||
-- a C function (this is a known bug in Lua 5.0)
|
||||
|
||||
local function g(x)
|
||||
coroutine.yield(x)
|
||||
end
|
||||
|
||||
local function f (i)
|
||||
debug.sethook(function () end, "l")
|
||||
for j=1,1000 do
|
||||
g(i+j)
|
||||
end
|
||||
end
|
||||
|
||||
local co = coroutine.wrap(f)
|
||||
co(10)
|
||||
pcall(co)
|
||||
pcall(co)
|
||||
|
||||
|
||||
assert(type(debug.getregistry()) == "table")
|
||||
|
||||
|
||||
-- test tagmethod information
|
||||
local a = {}
|
||||
local function f (t)
|
||||
local info = debug.getinfo(1);
|
||||
assert(info.namewhat == "metamethod")
|
||||
a.op = info.name
|
||||
return info.name
|
||||
end
|
||||
setmetatable(a, {
|
||||
__index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f;
|
||||
__mul = f; __idiv = f; __unm = f; __len = f; __sub = f;
|
||||
__shl = f; __shr = f; __bor = f; __bxor = f;
|
||||
__eq = f; __le = f; __lt = f; __unm = f; __len = f; __band = f;
|
||||
__bnot = f;
|
||||
})
|
||||
|
||||
local b = setmetatable({}, getmetatable(a))
|
||||
|
||||
assert(a[3] == "__index" and a^3 == "__pow" and a..a == "__concat")
|
||||
assert(a/3 == "__div" and 3%a == "__mod")
|
||||
assert(a+3 == "__add" and 3-a == "__sub" and a*3 == "__mul" and
|
||||
-a == "__unm" and #a == "__len" and a&3 == "__band")
|
||||
assert(a|3 == "__bor" and 3~a == "__bxor" and a<<3 == "__shl" and
|
||||
a>>1 == "__shr")
|
||||
assert (a==b and a.op == "__eq")
|
||||
assert (a>=b and a.op == "__le")
|
||||
assert (a>b and a.op == "__lt")
|
||||
assert(~a == "__bnot")
|
||||
|
||||
do -- testing for-iterator name
|
||||
local function f()
|
||||
assert(debug.getinfo(1).name == "for iterator")
|
||||
end
|
||||
|
||||
for i in f do end
|
||||
end
|
||||
|
||||
|
||||
do -- testing debug info for finalizers
|
||||
local name = nil
|
||||
|
||||
-- create a piece of garbage with a finalizer
|
||||
setmetatable({}, {__gc = function ()
|
||||
local t = debug.getinfo(2) -- get callee information
|
||||
assert(t.namewhat == "metamethod")
|
||||
name = t.name
|
||||
end})
|
||||
|
||||
-- repeat until previous finalizer runs (setting 'name')
|
||||
repeat local a = {} until name
|
||||
assert(name == "__gc")
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
print("testing traceback sizes")
|
||||
|
||||
local function countlines (s)
|
||||
return select(2, string.gsub(s, "\n", ""))
|
||||
end
|
||||
|
||||
local function deep (lvl, n)
|
||||
if lvl == 0 then
|
||||
return (debug.traceback("message", n))
|
||||
else
|
||||
return (deep(lvl-1, n))
|
||||
end
|
||||
end
|
||||
|
||||
local function checkdeep (total, start)
|
||||
local s = deep(total, start)
|
||||
local rest = string.match(s, "^message\nstack traceback:\n(.*)$")
|
||||
local cl = countlines(rest)
|
||||
-- at most 10 lines in first part, 11 in second, plus '...'
|
||||
assert(cl <= 10 + 11 + 1)
|
||||
local brk = string.find(rest, "%.%.%.")
|
||||
if brk then -- does message have '...'?
|
||||
local rest1 = string.sub(rest, 1, brk)
|
||||
local rest2 = string.sub(rest, brk, #rest)
|
||||
assert(countlines(rest1) == 10 and countlines(rest2) == 11)
|
||||
else
|
||||
assert(cl == total - start + 2)
|
||||
end
|
||||
end
|
||||
|
||||
for d = 1, 51, 10 do
|
||||
for l = 1, d do
|
||||
-- use coroutines to ensure complete control of the stack
|
||||
coroutine.wrap(checkdeep)(d, l)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
print("testing debug functions on chunk without debug info")
|
||||
prog = [[-- program to be loaded without debug information
|
||||
local debug = require'debug'
|
||||
local a = 12 -- a local variable
|
||||
|
||||
local n, v = debug.getlocal(1, 1)
|
||||
assert(n == "(*temporary)" and v == debug) -- unkown name but known value
|
||||
n, v = debug.getlocal(1, 2)
|
||||
assert(n == "(*temporary)" and v == 12) -- unkown name but known value
|
||||
|
||||
-- a function with an upvalue
|
||||
local f = function () local x; return a end
|
||||
n, v = debug.getupvalue(f, 1)
|
||||
assert(n == "(*no name)" and v == 12)
|
||||
assert(debug.setupvalue(f, 1, 13) == "(*no name)")
|
||||
assert(a == 13)
|
||||
|
||||
local t = debug.getinfo(f)
|
||||
assert(t.name == nil and t.linedefined > 0 and
|
||||
t.lastlinedefined == t.linedefined and
|
||||
t.short_src == "?")
|
||||
assert(debug.getinfo(1).currentline == -1)
|
||||
|
||||
t = debug.getinfo(f, "L").activelines
|
||||
assert(next(t) == nil) -- active lines are empty
|
||||
|
||||
-- dump/load a function without debug info
|
||||
f = load(string.dump(f))
|
||||
|
||||
t = debug.getinfo(f)
|
||||
assert(t.name == nil and t.linedefined > 0 and
|
||||
t.lastlinedefined == t.linedefined and
|
||||
t.short_src == "?")
|
||||
assert(debug.getinfo(1).currentline == -1)
|
||||
|
||||
return a
|
||||
]]
|
||||
|
||||
|
||||
-- load 'prog' without debug info
|
||||
local f = assert(load(string.dump(load(prog), true)))
|
||||
|
||||
assert(f() == 13)
|
||||
|
||||
do -- tests for 'source' in binary dumps
|
||||
local prog = [[
|
||||
return function (x)
|
||||
return function (y)
|
||||
return x + y
|
||||
end
|
||||
end
|
||||
]]
|
||||
local name = string.rep("x", 1000)
|
||||
local p = assert(load(prog, name))
|
||||
-- load 'p' as a binary chunk with debug information
|
||||
local c = string.dump(p)
|
||||
assert(#c > 1000 and #c < 2000) -- no repetition of 'source' in dump
|
||||
local f = assert(load(c))
|
||||
local g = f()
|
||||
local h = g(3)
|
||||
assert(h(5) == 8)
|
||||
assert(debug.getinfo(f).source == name and -- all functions have 'source'
|
||||
debug.getinfo(g).source == name and
|
||||
debug.getinfo(h).source == name)
|
||||
-- again, without debug info
|
||||
local c = string.dump(p, true)
|
||||
assert(#c < 500) -- no 'source' in dump
|
||||
local f = assert(load(c))
|
||||
local g = f()
|
||||
local h = g(30)
|
||||
assert(h(50) == 80)
|
||||
assert(debug.getinfo(f).source == '=?' and -- no function has 'source'
|
||||
debug.getinfo(g).source == '=?' and
|
||||
debug.getinfo(h).source == '=?')
|
||||
end
|
||||
|
||||
print"OK"
|
||||
|
537
06/parser-gen/parsers/lua-5.3.4-tests/errors.lua
Normal file
537
06/parser-gen/parsers/lua-5.3.4-tests/errors.lua
Normal file
|
@ -0,0 +1,537 @@
|
|||
-- $Id: errors.lua,v 1.94 2016/12/21 19:23:02 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print("testing errors")
|
||||
|
||||
local debug = require"debug"
|
||||
|
||||
-- avoid problems with 'strict' module (which may generate other error messages)
|
||||
local mt = getmetatable(_G) or {}
|
||||
local oldmm = mt.__index
|
||||
mt.__index = nil
|
||||
|
||||
local function checkerr (msg, f, ...)
|
||||
local st, err = pcall(f, ...)
|
||||
assert(not st and string.find(err, msg))
|
||||
end
|
||||
|
||||
|
||||
local function doit (s)
|
||||
local f, msg = load(s)
|
||||
if f == nil then return msg end
|
||||
local cond, msg = pcall(f)
|
||||
return (not cond) and msg
|
||||
end
|
||||
|
||||
|
||||
local function checkmessage (prog, msg)
|
||||
local m = doit(prog)
|
||||
assert(string.find(m, msg, 1, true))
|
||||
end
|
||||
|
||||
local function checksyntax (prog, extra, token, line)
|
||||
local msg = doit(prog)
|
||||
if not string.find(token, "^<%a") and not string.find(token, "^char%(")
|
||||
then token = "'"..token.."'" end
|
||||
token = string.gsub(token, "(%p)", "%%%1")
|
||||
local pt = string.format([[^%%[string ".*"%%]:%d: .- near %s$]],
|
||||
line, token)
|
||||
assert(string.find(msg, pt))
|
||||
assert(string.find(msg, msg, 1, true))
|
||||
end
|
||||
|
||||
|
||||
-- test error message with no extra info
|
||||
assert(doit("error('hi', 0)") == 'hi')
|
||||
|
||||
-- test error message with no info
|
||||
assert(doit("error()") == nil)
|
||||
|
||||
|
||||
-- test common errors/errors that crashed in the past
|
||||
assert(doit("table.unpack({}, 1, n=2^30)"))
|
||||
assert(doit("a=math.sin()"))
|
||||
assert(not doit("tostring(1)") and doit("tostring()"))
|
||||
assert(doit"tonumber()")
|
||||
assert(doit"repeat until 1; a")
|
||||
assert(doit"return;;")
|
||||
assert(doit"assert(false)")
|
||||
assert(doit"assert(nil)")
|
||||
assert(doit("function a (... , ...) end"))
|
||||
assert(doit("function a (, ...) end"))
|
||||
assert(doit("local t={}; t = t[#t] + 1"))
|
||||
|
||||
checksyntax([[
|
||||
local a = {4
|
||||
|
||||
]], "'}' expected (to close '{' at line 1)", "<eof>", 3)
|
||||
|
||||
|
||||
-- tests for better error messages
|
||||
|
||||
checkmessage("a = {} + 1", "arithmetic")
|
||||
checkmessage("a = {} | 1", "bitwise operation")
|
||||
checkmessage("a = {} < 1", "attempt to compare")
|
||||
checkmessage("a = {} <= 1", "attempt to compare")
|
||||
|
||||
checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'")
|
||||
checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'")
|
||||
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
|
||||
assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'"))
|
||||
checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number")
|
||||
checkmessage("a=(1)..{}", "a table value")
|
||||
|
||||
checkmessage("a = #print", "length of a function value")
|
||||
checkmessage("a = #3", "length of a number value")
|
||||
|
||||
aaa = nil
|
||||
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
|
||||
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
|
||||
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
|
||||
checkmessage("local a,b,c; (function () a = b+1 end)()", "upvalue 'b'")
|
||||
assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)")
|
||||
|
||||
-- upvalues being indexed do not go to the stack
|
||||
checkmessage("local a,b,cc; (function () a = cc[1] end)()", "upvalue 'cc'")
|
||||
checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
|
||||
|
||||
checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
|
||||
|
||||
checkmessage("b=1; local aaa='a'; x=aaa+b", "local 'aaa'")
|
||||
checkmessage("aaa={}; x=3/aaa", "global 'aaa'")
|
||||
checkmessage("aaa='2'; b=nil;x=aaa*b", "global 'b'")
|
||||
checkmessage("aaa={}; x=-aaa", "global 'aaa'")
|
||||
|
||||
-- short circuit
|
||||
checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)",
|
||||
"local 'bbbb'")
|
||||
checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'")
|
||||
checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
|
||||
checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
|
||||
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
|
||||
assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'"))
|
||||
|
||||
checkmessage("print(print < 10)", "function with number")
|
||||
checkmessage("print(print < print)", "two function values")
|
||||
checkmessage("print('10' < 10)", "string with number")
|
||||
checkmessage("print(10 < '23')", "number with string")
|
||||
|
||||
-- float->integer conversions
|
||||
checkmessage("local a = 2.0^100; x = a << 2", "local a")
|
||||
checkmessage("local a = 1 >> 2.0^100", "has no integer representation")
|
||||
checkmessage("local a = '10' << 2.0^100", "has no integer representation")
|
||||
checkmessage("local a = 2.0^100 & 1", "has no integer representation")
|
||||
checkmessage("local a = 2.0^100 & '1'", "has no integer representation")
|
||||
checkmessage("local a = 2.0 | 1e40", "has no integer representation")
|
||||
checkmessage("local a = 2e100 ~ 1", "has no integer representation")
|
||||
checkmessage("string.sub('a', 2.0^100)", "has no integer representation")
|
||||
checkmessage("string.rep('a', 3.3)", "has no integer representation")
|
||||
checkmessage("return 6e40 & 7", "has no integer representation")
|
||||
checkmessage("return 34 << 7e30", "has no integer representation")
|
||||
checkmessage("return ~-3e40", "has no integer representation")
|
||||
checkmessage("return ~-3.009", "has no integer representation")
|
||||
checkmessage("return 3.009 & 1", "has no integer representation")
|
||||
checkmessage("return 34 >> {}", "table value")
|
||||
checkmessage("a = 24 // 0", "divide by zero")
|
||||
checkmessage("a = 1 % 0", "'n%0'")
|
||||
|
||||
|
||||
-- passing light userdata instead of full userdata
|
||||
_G.D = debug
|
||||
checkmessage([[
|
||||
-- create light udata
|
||||
local x = D.upvalueid(function () return debug end, 1)
|
||||
D.setuservalue(x, {})
|
||||
]], "light userdata")
|
||||
_G.D = nil
|
||||
|
||||
do -- named objects (field '__name')
|
||||
checkmessage("math.sin(io.input())", "(number expected, got FILE*)")
|
||||
_G.XX = setmetatable({}, {__name = "My Type"})
|
||||
assert(string.find(tostring(XX), "^My Type"))
|
||||
checkmessage("io.input(XX)", "(FILE* expected, got My Type)")
|
||||
checkmessage("return XX + 1", "on a My Type value")
|
||||
checkmessage("return ~io.stdin", "on a FILE* value")
|
||||
checkmessage("return XX < XX", "two My Type values")
|
||||
checkmessage("return {} < XX", "table with My Type")
|
||||
checkmessage("return XX < io.stdin", "My Type with FILE*")
|
||||
_G.XX = nil
|
||||
end
|
||||
|
||||
-- global functions
|
||||
checkmessage("(io.write or print){}", "io.write")
|
||||
checkmessage("(collectgarbage or print){}", "collectgarbage")
|
||||
|
||||
-- errors in functions without debug info
|
||||
do
|
||||
local f = function (a) return a + 1 end
|
||||
f = assert(load(string.dump(f, true)))
|
||||
assert(f(3) == 4)
|
||||
checkerr("^%?:%-1:", f, {})
|
||||
|
||||
-- code with a move to a local var ('OP_MOV A B' with A<B)
|
||||
f = function () local a; a = {}; return a + 2 end
|
||||
-- no debug info (so that 'a' is unknown)
|
||||
f = assert(load(string.dump(f, true)))
|
||||
-- symbolic execution should not get lost
|
||||
checkerr("^%?:%-1:.*table value", f)
|
||||
end
|
||||
|
||||
|
||||
-- tests for field accesses after RK limit
|
||||
local t = {}
|
||||
for i = 1, 1000 do
|
||||
t[i] = "a = x" .. i
|
||||
end
|
||||
local s = table.concat(t, "; ")
|
||||
t = nil
|
||||
checkmessage(s.."; a = bbb + 1", "global 'bbb'")
|
||||
checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'")
|
||||
checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'")
|
||||
checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'")
|
||||
|
||||
checkmessage([[aaa=9
|
||||
repeat until 3==3
|
||||
local x=math.sin(math.cos(3))
|
||||
if math.sin(1) == x then return math.sin(1) end -- tail call
|
||||
local a,b = 1, {
|
||||
{x='a'..'b'..'c', y='b', z=x},
|
||||
{1,2,3,4,5} or 3+3<=3+3,
|
||||
3+1>3+1,
|
||||
{d = x and aaa[x or y]}}
|
||||
]], "global 'aaa'")
|
||||
|
||||
checkmessage([[
|
||||
local x,y = {},1
|
||||
if math.sin(1) == 0 then return 3 end -- return
|
||||
x.a()]], "field 'a'")
|
||||
|
||||
checkmessage([[
|
||||
prefix = nil
|
||||
insert = nil
|
||||
while 1 do
|
||||
local a
|
||||
if nil then break end
|
||||
insert(prefix, a)
|
||||
end]], "global 'insert'")
|
||||
|
||||
checkmessage([[ -- tail call
|
||||
return math.sin("a")
|
||||
]], "'sin'")
|
||||
|
||||
checkmessage([[collectgarbage("nooption")]], "invalid option")
|
||||
|
||||
checkmessage([[x = print .. "a"]], "concatenate")
|
||||
checkmessage([[x = "a" .. false]], "concatenate")
|
||||
checkmessage([[x = {} .. 2]], "concatenate")
|
||||
|
||||
checkmessage("getmetatable(io.stdin).__gc()", "no value")
|
||||
|
||||
checkmessage([[
|
||||
local Var
|
||||
local function main()
|
||||
NoSuchName (function() Var=0 end)
|
||||
end
|
||||
main()
|
||||
]], "global 'NoSuchName'")
|
||||
print'+'
|
||||
|
||||
a = {}; setmetatable(a, {__index = string})
|
||||
checkmessage("a:sub()", "bad self")
|
||||
checkmessage("string.sub('a', {})", "#2")
|
||||
checkmessage("('a'):sub{}", "#1")
|
||||
|
||||
checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
|
||||
checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
|
||||
|
||||
-- tests for errors in coroutines
|
||||
|
||||
local function f (n)
|
||||
local c = coroutine.create(f)
|
||||
local a,b = coroutine.resume(c)
|
||||
return b
|
||||
end
|
||||
assert(string.find(f(), "C stack overflow"))
|
||||
|
||||
checkmessage("coroutine.yield()", "outside a coroutine")
|
||||
|
||||
f = coroutine.wrap(function () table.sort({1,2,3}, coroutine.yield) end)
|
||||
checkerr("yield across", f)
|
||||
|
||||
|
||||
-- testing size of 'source' info; size of buffer for that info is
|
||||
-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
|
||||
idsize = 60 - 1
|
||||
local function checksize (source)
|
||||
-- syntax error
|
||||
local _, msg = load("x", source)
|
||||
msg = string.match(msg, "^([^:]*):") -- get source (1st part before ':')
|
||||
assert(msg:len() <= idsize)
|
||||
end
|
||||
|
||||
for i = 60 - 10, 60 + 10 do -- check border cases around 60
|
||||
checksize("@" .. string.rep("x", i)) -- file names
|
||||
checksize(string.rep("x", i - 10)) -- string sources
|
||||
checksize("=" .. string.rep("x", i)) -- exact sources
|
||||
end
|
||||
|
||||
|
||||
-- testing line error
|
||||
|
||||
local function lineerror (s, l)
|
||||
local err,msg = pcall(load(s))
|
||||
local line = string.match(msg, ":(%d+):")
|
||||
assert((line and line+0) == l)
|
||||
end
|
||||
|
||||
lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2)
|
||||
lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3)
|
||||
lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4)
|
||||
lineerror("function a.x.y ()\na=a+1\nend", 1)
|
||||
|
||||
lineerror("a = \na\n+\n{}", 3)
|
||||
lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6)
|
||||
lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3)
|
||||
|
||||
lineerror("a\n=\n-\n\nprint\n;", 3)
|
||||
|
||||
lineerror([[
|
||||
a
|
||||
(
|
||||
23)
|
||||
]], 1)
|
||||
|
||||
lineerror([[
|
||||
local a = {x = 13}
|
||||
a
|
||||
.
|
||||
x
|
||||
(
|
||||
23
|
||||
)
|
||||
]], 2)
|
||||
|
||||
lineerror([[
|
||||
local a = {x = 13}
|
||||
a
|
||||
.
|
||||
x
|
||||
(
|
||||
23 + a
|
||||
)
|
||||
]], 6)
|
||||
|
||||
local p = [[
|
||||
function g() f() end
|
||||
function f(x) error('a', X) end
|
||||
g()
|
||||
]]
|
||||
X=3;lineerror((p), 3)
|
||||
X=0;lineerror((p), nil)
|
||||
X=1;lineerror((p), 2)
|
||||
X=2;lineerror((p), 1)
|
||||
|
||||
|
||||
if not _soft then
|
||||
-- several tests that exaust the Lua stack
|
||||
collectgarbage()
|
||||
print"testing stack overflow"
|
||||
C = 0
|
||||
local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end
|
||||
|
||||
local function checkstackmessage (m)
|
||||
return (string.find(m, "^.-:%d+: stack overflow"))
|
||||
end
|
||||
-- repeated stack overflows (to check stack recovery)
|
||||
assert(checkstackmessage(doit('y()')))
|
||||
print('+')
|
||||
assert(checkstackmessage(doit('y()')))
|
||||
print('+')
|
||||
assert(checkstackmessage(doit('y()')))
|
||||
print('+')
|
||||
|
||||
|
||||
-- error lines in stack overflow
|
||||
C = 0
|
||||
local l1
|
||||
local function g(x)
|
||||
l1 = debug.getinfo(x, "l").currentline; y()
|
||||
end
|
||||
local _, stackmsg = xpcall(g, debug.traceback, 1)
|
||||
print('+')
|
||||
local stack = {}
|
||||
for line in string.gmatch(stackmsg, "[^\n]*") do
|
||||
local curr = string.match(line, ":(%d+):")
|
||||
if curr then table.insert(stack, tonumber(curr)) end
|
||||
end
|
||||
local i=1
|
||||
while stack[i] ~= l1 do
|
||||
assert(stack[i] == l)
|
||||
i = i+1
|
||||
end
|
||||
assert(i > 15)
|
||||
|
||||
|
||||
-- error in error handling
|
||||
local res, msg = xpcall(error, error)
|
||||
assert(not res and type(msg) == 'string')
|
||||
print('+')
|
||||
|
||||
local function f (x)
|
||||
if x==0 then error('a\n')
|
||||
else
|
||||
local aux = function () return f(x-1) end
|
||||
local a,b = xpcall(aux, aux)
|
||||
return a,b
|
||||
end
|
||||
end
|
||||
f(3)
|
||||
|
||||
local function loop (x,y,z) return 1 + loop(x, y, z) end
|
||||
|
||||
local res, msg = xpcall(loop, function (m)
|
||||
assert(string.find(m, "stack overflow"))
|
||||
checkerr("error handling", loop)
|
||||
assert(math.sin(0) == 0)
|
||||
return 15
|
||||
end)
|
||||
assert(msg == 15)
|
||||
|
||||
local f = function ()
|
||||
for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end
|
||||
end
|
||||
checkerr("too many results", f)
|
||||
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
-- non string messages
|
||||
local t = {}
|
||||
local res, msg = pcall(function () error(t) end)
|
||||
assert(not res and msg == t)
|
||||
|
||||
res, msg = pcall(function () error(nil) end)
|
||||
assert(not res and msg == nil)
|
||||
|
||||
local function f() error{msg='x'} end
|
||||
res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
|
||||
assert(msg.msg == 'xy')
|
||||
|
||||
-- 'assert' with extra arguments
|
||||
res, msg = pcall(assert, false, "X", t)
|
||||
assert(not res and msg == "X")
|
||||
|
||||
-- 'assert' with no message
|
||||
res, msg = pcall(function () assert(false) end)
|
||||
local line = string.match(msg, "%w+%.lua:(%d+): assertion failed!$")
|
||||
assert(tonumber(line) == debug.getinfo(1, "l").currentline - 2)
|
||||
|
||||
-- 'assert' with non-string messages
|
||||
res, msg = pcall(assert, false, t)
|
||||
assert(not res and msg == t)
|
||||
|
||||
res, msg = pcall(assert, nil, nil)
|
||||
assert(not res and msg == nil)
|
||||
|
||||
-- 'assert' without arguments
|
||||
res, msg = pcall(assert)
|
||||
assert(not res and string.find(msg, "value expected"))
|
||||
end
|
||||
|
||||
-- xpcall with arguments
|
||||
a, b, c = xpcall(string.find, error, "alo", "al")
|
||||
assert(a and b == 1 and c == 2)
|
||||
a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
|
||||
assert(not a and type(b) == "table" and c == nil)
|
||||
|
||||
|
||||
print("testing tokens in error messages")
|
||||
checksyntax("syntax error", "", "error", 1)
|
||||
checksyntax("1.000", "", "1.000", 1)
|
||||
checksyntax("[[a]]", "", "[[a]]", 1)
|
||||
checksyntax("'aa'", "", "'aa'", 1)
|
||||
checksyntax("while << do end", "", "<<", 1)
|
||||
checksyntax("for >> do end", "", ">>", 1)
|
||||
|
||||
-- test invalid non-printable char in a chunk
|
||||
checksyntax("a\1a = 1", "", "<\\1>", 1)
|
||||
|
||||
-- test 255 as first char in a chunk
|
||||
checksyntax("\255a = 1", "", "<\\255>", 1)
|
||||
|
||||
doit('I = load("a=9+"); a=3')
|
||||
assert(a==3 and I == nil)
|
||||
print('+')
|
||||
|
||||
lim = 1000
|
||||
if _soft then lim = 100 end
|
||||
for i=1,lim do
|
||||
doit('a = ')
|
||||
doit('a = 4+nil')
|
||||
end
|
||||
|
||||
|
||||
-- testing syntax limits
|
||||
|
||||
local maxClevel = 200 -- LUAI_MAXCCALLS (in llimits.h)
|
||||
|
||||
local function testrep (init, rep, close, repc)
|
||||
local s = init .. string.rep(rep, maxClevel - 10) .. close ..
|
||||
string.rep(repc, maxClevel - 10)
|
||||
assert(load(s)) -- 190 levels is OK
|
||||
s = init .. string.rep(rep, maxClevel + 1)
|
||||
checkmessage(s, "too many C levels")
|
||||
end
|
||||
|
||||
testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment
|
||||
testrep("local a; a=", "{", "0", "}")
|
||||
testrep("local a; a=", "(", "2", ")")
|
||||
testrep("local a; ", "a(", "2", ")")
|
||||
testrep("", "do ", "", " end")
|
||||
testrep("", "while a do ", "", " end")
|
||||
testrep("local a; ", "if a then else ", "", " end")
|
||||
testrep("", "function foo () ", "", " end")
|
||||
testrep("local a; a=", "a..", "a", "")
|
||||
testrep("local a; a=", "a^", "a", "")
|
||||
|
||||
checkmessage("a = f(x" .. string.rep(",x", 260) .. ")", "too many registers")
|
||||
|
||||
|
||||
-- testing other limits
|
||||
|
||||
-- upvalues
|
||||
local lim = 127
|
||||
local s = "local function fooA ()\n local "
|
||||
for j = 1,lim do
|
||||
s = s.."a"..j..", "
|
||||
end
|
||||
s = s.."b,c\n"
|
||||
s = s.."local function fooB ()\n local "
|
||||
for j = 1,lim do
|
||||
s = s.."b"..j..", "
|
||||
end
|
||||
s = s.."b\n"
|
||||
s = s.."function fooC () return b+c"
|
||||
local c = 1+2
|
||||
for j = 1,lim do
|
||||
s = s.."+a"..j.."+b"..j
|
||||
c = c + 2
|
||||
end
|
||||
s = s.."\nend end end"
|
||||
local a,b = load(s)
|
||||
assert(c > 255 and string.find(b, "too many upvalues") and
|
||||
string.find(b, "line 5"))
|
||||
|
||||
-- local variables
|
||||
s = "\nfunction foo ()\n local "
|
||||
for j = 1,300 do
|
||||
s = s.."a"..j..", "
|
||||
end
|
||||
s = s.."b\n"
|
||||
local a,b = load(s)
|
||||
assert(string.find(b, "line 2") and string.find(b, "too many local variables"))
|
||||
|
||||
mt.__index = oldmm
|
||||
|
||||
print('OK')
|
456
06/parser-gen/parsers/lua-5.3.4-tests/events.lua
Normal file
456
06/parser-gen/parsers/lua-5.3.4-tests/events.lua
Normal file
|
@ -0,0 +1,456 @@
|
|||
-- $Id: events.lua,v 1.45 2016/12/21 19:23:02 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing metatables')
|
||||
|
||||
local debug = require'debug'
|
||||
|
||||
X = 20; B = 30
|
||||
|
||||
_ENV = setmetatable({}, {__index=_G})
|
||||
|
||||
collectgarbage()
|
||||
|
||||
X = X+10
|
||||
assert(X == 30 and _G.X == 20)
|
||||
B = false
|
||||
assert(B == false)
|
||||
B = nil
|
||||
assert(B == 30)
|
||||
|
||||
assert(getmetatable{} == nil)
|
||||
assert(getmetatable(4) == nil)
|
||||
assert(getmetatable(nil) == nil)
|
||||
a={name = "NAME"}; setmetatable(a, {__metatable = "xuxu",
|
||||
__tostring=function(x) return x.name end})
|
||||
assert(getmetatable(a) == "xuxu")
|
||||
assert(tostring(a) == "NAME")
|
||||
-- cannot change a protected metatable
|
||||
assert(pcall(setmetatable, a, {}) == false)
|
||||
a.name = "gororoba"
|
||||
assert(tostring(a) == "gororoba")
|
||||
|
||||
local a, t = {10,20,30; x="10", y="20"}, {}
|
||||
assert(setmetatable(a,t) == a)
|
||||
assert(getmetatable(a) == t)
|
||||
assert(setmetatable(a,nil) == a)
|
||||
assert(getmetatable(a) == nil)
|
||||
assert(setmetatable(a,t) == a)
|
||||
|
||||
|
||||
function f (t, i, e)
|
||||
assert(not e)
|
||||
local p = rawget(t, "parent")
|
||||
return (p and p[i]+3), "dummy return"
|
||||
end
|
||||
|
||||
t.__index = f
|
||||
|
||||
a.parent = {z=25, x=12, [4] = 24}
|
||||
assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10")
|
||||
|
||||
collectgarbage()
|
||||
|
||||
a = setmetatable({}, t)
|
||||
function f(t, i, v) rawset(t, i, v-3) end
|
||||
setmetatable(t, t) -- causes a bug in 5.1 !
|
||||
t.__newindex = f
|
||||
a[1] = 30; a.x = "101"; a[5] = 200
|
||||
assert(a[1] == 27 and a.x == 98 and a[5] == 197)
|
||||
|
||||
do -- bug in Lua 5.3.2
|
||||
local mt = {}
|
||||
mt.__newindex = mt
|
||||
local t = setmetatable({}, mt)
|
||||
t[1] = 10 -- will segfault on some machines
|
||||
assert(mt[1] == 10)
|
||||
end
|
||||
|
||||
|
||||
local c = {}
|
||||
a = setmetatable({}, t)
|
||||
t.__newindex = c
|
||||
a[1] = 10; a[2] = 20; a[3] = 90
|
||||
assert(c[1] == 10 and c[2] == 20 and c[3] == 90)
|
||||
|
||||
|
||||
do
|
||||
local a;
|
||||
a = setmetatable({}, {__index = setmetatable({},
|
||||
{__index = setmetatable({},
|
||||
{__index = function (_,n) return a[n-3]+4, "lixo" end})})})
|
||||
a[0] = 20
|
||||
for i=0,10 do
|
||||
assert(a[i*3] == 20 + i*4)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
do -- newindex
|
||||
local foi
|
||||
local a = {}
|
||||
for i=1,10 do a[i] = 0; a['a'..i] = 0; end
|
||||
setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end})
|
||||
foi = false; a[1]=0; assert(not foi)
|
||||
foi = false; a['a1']=0; assert(not foi)
|
||||
foi = false; a['a11']=0; assert(foi)
|
||||
foi = false; a[11]=0; assert(foi)
|
||||
foi = false; a[1]=nil; assert(not foi)
|
||||
foi = false; a[1]=nil; assert(foi)
|
||||
end
|
||||
|
||||
|
||||
setmetatable(t, nil)
|
||||
function f (t, ...) return t, {...} end
|
||||
t.__call = f
|
||||
|
||||
do
|
||||
local x,y = a(table.unpack{'a', 1})
|
||||
assert(x==a and y[1]=='a' and y[2]==1 and y[3]==nil)
|
||||
x,y = a()
|
||||
assert(x==a and y[1]==nil)
|
||||
end
|
||||
|
||||
|
||||
local b = setmetatable({}, t)
|
||||
setmetatable(b,t)
|
||||
|
||||
function f(op)
|
||||
return function (...) cap = {[0] = op, ...} ; return (...) end
|
||||
end
|
||||
t.__add = f("add")
|
||||
t.__sub = f("sub")
|
||||
t.__mul = f("mul")
|
||||
t.__div = f("div")
|
||||
t.__idiv = f("idiv")
|
||||
t.__mod = f("mod")
|
||||
t.__unm = f("unm")
|
||||
t.__pow = f("pow")
|
||||
t.__len = f("len")
|
||||
t.__band = f("band")
|
||||
t.__bor = f("bor")
|
||||
t.__bxor = f("bxor")
|
||||
t.__shl = f("shl")
|
||||
t.__shr = f("shr")
|
||||
t.__bnot = f("bnot")
|
||||
|
||||
assert(b+5 == b)
|
||||
assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==nil)
|
||||
assert(b+'5' == b)
|
||||
assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==nil)
|
||||
assert(5+b == 5)
|
||||
assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==nil)
|
||||
assert('5'+b == '5')
|
||||
assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==nil)
|
||||
b=b-3; assert(getmetatable(b) == t)
|
||||
assert(5-a == 5)
|
||||
assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==nil)
|
||||
assert('5'-a == '5')
|
||||
assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==nil)
|
||||
assert(a*a == a)
|
||||
assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==nil)
|
||||
assert(a/0 == a)
|
||||
assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==nil)
|
||||
assert(a%2 == a)
|
||||
assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==nil)
|
||||
assert(a // (1/0) == a)
|
||||
assert(cap[0] == "idiv" and cap[1] == a and cap[2] == 1/0 and cap[3]==nil)
|
||||
assert(a & "hi" == a)
|
||||
assert(cap[0] == "band" and cap[1] == a and cap[2] == "hi" and cap[3]==nil)
|
||||
assert(a | "hi" == a)
|
||||
assert(cap[0] == "bor" and cap[1] == a and cap[2] == "hi" and cap[3]==nil)
|
||||
assert("hi" ~ a == "hi")
|
||||
assert(cap[0] == "bxor" and cap[1] == "hi" and cap[2] == a and cap[3]==nil)
|
||||
assert(-a == a)
|
||||
assert(cap[0] == "unm" and cap[1] == a)
|
||||
assert(a^4 == a)
|
||||
assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==nil)
|
||||
assert(a^'4' == a)
|
||||
assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==nil)
|
||||
assert(4^a == 4)
|
||||
assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==nil)
|
||||
assert('4'^a == '4')
|
||||
assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==nil)
|
||||
assert(#a == a)
|
||||
assert(cap[0] == "len" and cap[1] == a)
|
||||
assert(~a == a)
|
||||
assert(cap[0] == "bnot" and cap[1] == a)
|
||||
assert(a << 3 == a)
|
||||
assert(cap[0] == "shl" and cap[1] == a and cap[2] == 3)
|
||||
assert(1.5 >> a == 1.5)
|
||||
assert(cap[0] == "shr" and cap[1] == 1.5 and cap[2] == a)
|
||||
|
||||
|
||||
-- test for rawlen
|
||||
t = setmetatable({1,2,3}, {__len = function () return 10 end})
|
||||
assert(#t == 10 and rawlen(t) == 3)
|
||||
assert(rawlen"abc" == 3)
|
||||
assert(not pcall(rawlen, io.stdin))
|
||||
assert(not pcall(rawlen, 34))
|
||||
assert(not pcall(rawlen))
|
||||
|
||||
-- rawlen for long strings
|
||||
assert(rawlen(string.rep('a', 1000)) == 1000)
|
||||
|
||||
|
||||
t = {}
|
||||
t.__lt = function (a,b,c)
|
||||
collectgarbage()
|
||||
assert(c == nil)
|
||||
if type(a) == 'table' then a = a.x end
|
||||
if type(b) == 'table' then b = b.x end
|
||||
return a<b, "dummy"
|
||||
end
|
||||
|
||||
function Op(x) return setmetatable({x=x}, t) end
|
||||
|
||||
local function test ()
|
||||
assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
|
||||
assert(not(1 < Op(1)) and (Op(1) < 2) and not(2 < Op(1)))
|
||||
assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
|
||||
assert(not('a' < Op('a')) and (Op('a') < 'b') and not(Op('b') < Op('a')))
|
||||
assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
|
||||
assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
|
||||
assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
|
||||
assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
|
||||
assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
|
||||
assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1))
|
||||
assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
|
||||
assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a')))
|
||||
end
|
||||
|
||||
test()
|
||||
|
||||
t.__le = function (a,b,c)
|
||||
assert(c == nil)
|
||||
if type(a) == 'table' then a = a.x end
|
||||
if type(b) == 'table' then b = b.x end
|
||||
return a<=b, "dummy"
|
||||
end
|
||||
|
||||
test() -- retest comparisons, now using both `lt' and `le'
|
||||
|
||||
|
||||
-- test `partial order'
|
||||
|
||||
local function rawSet(x)
|
||||
local y = {}
|
||||
for _,k in pairs(x) do y[k] = 1 end
|
||||
return y
|
||||
end
|
||||
|
||||
local function Set(x)
|
||||
return setmetatable(rawSet(x), t)
|
||||
end
|
||||
|
||||
t.__lt = function (a,b)
|
||||
for k in pairs(a) do
|
||||
if not b[k] then return false end
|
||||
b[k] = nil
|
||||
end
|
||||
return next(b) ~= nil
|
||||
end
|
||||
|
||||
t.__le = nil
|
||||
|
||||
assert(Set{1,2,3} < Set{1,2,3,4})
|
||||
assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
|
||||
assert((Set{1,2,3,4} <= Set{1,2,3,4}))
|
||||
assert((Set{1,2,3,4} >= Set{1,2,3,4}))
|
||||
assert((Set{1,3} <= Set{3,5})) -- wrong!! model needs a `le' method ;-)
|
||||
|
||||
t.__le = function (a,b)
|
||||
for k in pairs(a) do
|
||||
if not b[k] then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
assert(not (Set{1,3} <= Set{3,5})) -- now its OK!
|
||||
assert(not(Set{1,3} <= Set{3,5}))
|
||||
assert(not(Set{1,3} >= Set{3,5}))
|
||||
|
||||
t.__eq = function (a,b)
|
||||
for k in pairs(a) do
|
||||
if not b[k] then return false end
|
||||
b[k] = nil
|
||||
end
|
||||
return next(b) == nil
|
||||
end
|
||||
|
||||
local s = Set{1,3,5}
|
||||
assert(s == Set{3,5,1})
|
||||
assert(not rawequal(s, Set{3,5,1}))
|
||||
assert(rawequal(s, s))
|
||||
assert(Set{1,3,5,1} == rawSet{3,5,1})
|
||||
assert(rawSet{1,3,5,1} == Set{3,5,1})
|
||||
assert(Set{1,3,5} ~= Set{3,5,1,6})
|
||||
|
||||
-- '__eq' is not used for table accesses
|
||||
t[Set{1,3,5}] = 1
|
||||
assert(t[Set{1,3,5}] == nil)
|
||||
|
||||
|
||||
if not T then
|
||||
(Message or print)('\n >>> testC not active: skipping tests for \z
|
||||
userdata equality <<<\n')
|
||||
else
|
||||
local u1 = T.newuserdata(0)
|
||||
local u2 = T.newuserdata(0)
|
||||
local u3 = T.newuserdata(0)
|
||||
assert(u1 ~= u2 and u1 ~= u3)
|
||||
debug.setuservalue(u1, 1);
|
||||
debug.setuservalue(u2, 2);
|
||||
debug.setuservalue(u3, 1);
|
||||
debug.setmetatable(u1, {__eq = function (a, b)
|
||||
return debug.getuservalue(a) == debug.getuservalue(b)
|
||||
end})
|
||||
debug.setmetatable(u2, {__eq = function (a, b)
|
||||
return true
|
||||
end})
|
||||
assert(u1 == u3 and u3 == u1 and u1 ~= u2)
|
||||
assert(u2 == u1 and u2 == u3 and u3 == u2)
|
||||
assert(u2 ~= {}) -- different types cannot be equal
|
||||
end
|
||||
|
||||
|
||||
t.__concat = function (a,b,c)
|
||||
assert(c == nil)
|
||||
if type(a) == 'table' then a = a.val end
|
||||
if type(b) == 'table' then b = b.val end
|
||||
if A then return a..b
|
||||
else
|
||||
return setmetatable({val=a..b}, t)
|
||||
end
|
||||
end
|
||||
|
||||
c = {val="c"}; setmetatable(c, t)
|
||||
d = {val="d"}; setmetatable(d, t)
|
||||
|
||||
A = true
|
||||
assert(c..d == 'cd')
|
||||
assert(0 .."a".."b"..c..d.."e".."f"..(5+3).."g" == "0abcdef8g")
|
||||
|
||||
A = false
|
||||
assert((c..d..c..d).val == 'cdcd')
|
||||
x = c..d
|
||||
assert(getmetatable(x) == t and x.val == 'cd')
|
||||
x = 0 .."a".."b"..c..d.."e".."f".."g"
|
||||
assert(x.val == "0abcdefg")
|
||||
|
||||
|
||||
-- concat metamethod x numbers (bug in 5.1.1)
|
||||
c = {}
|
||||
local x
|
||||
setmetatable(c, {__concat = function (a,b)
|
||||
assert(type(a) == "number" and b == c or type(b) == "number" and a == c)
|
||||
return c
|
||||
end})
|
||||
assert(c..5 == c and 5 .. c == c)
|
||||
assert(4 .. c .. 5 == c and 4 .. 5 .. 6 .. 7 .. c == c)
|
||||
|
||||
|
||||
-- test comparison compatibilities
|
||||
local t1, t2, c, d
|
||||
t1 = {}; c = {}; setmetatable(c, t1)
|
||||
d = {}
|
||||
t1.__eq = function () return true end
|
||||
t1.__lt = function () return true end
|
||||
setmetatable(d, t1)
|
||||
assert(c == d and c < d and not(d <= c))
|
||||
t2 = {}
|
||||
t2.__eq = t1.__eq
|
||||
t2.__lt = t1.__lt
|
||||
setmetatable(d, t2)
|
||||
assert(c == d and c < d and not(d <= c))
|
||||
|
||||
|
||||
|
||||
-- test for several levels of calls
|
||||
local i
|
||||
local tt = {
|
||||
__call = function (t, ...)
|
||||
i = i+1
|
||||
if t.f then return t.f(...)
|
||||
else return {...}
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
local a = setmetatable({}, tt)
|
||||
local b = setmetatable({f=a}, tt)
|
||||
local c = setmetatable({f=b}, tt)
|
||||
|
||||
i = 0
|
||||
x = c(3,4,5)
|
||||
assert(i == 3 and x[1] == 3 and x[3] == 5)
|
||||
|
||||
|
||||
assert(_G.X == 20)
|
||||
|
||||
print'+'
|
||||
|
||||
local _g = _G
|
||||
_ENV = setmetatable({}, {__index=function (_,k) return _g[k] end})
|
||||
|
||||
|
||||
a = {}
|
||||
rawset(a, "x", 1, 2, 3)
|
||||
assert(a.x == 1 and rawget(a, "x", 3) == 1)
|
||||
|
||||
print '+'
|
||||
|
||||
-- testing metatables for basic types
|
||||
mt = {__index = function (a,b) return a+b end,
|
||||
__len = function (x) return math.floor(x) end}
|
||||
debug.setmetatable(10, mt)
|
||||
assert(getmetatable(-2) == mt)
|
||||
assert((10)[3] == 13)
|
||||
assert((10)["3"] == 13)
|
||||
assert(#3.45 == 3)
|
||||
debug.setmetatable(23, nil)
|
||||
assert(getmetatable(-2) == nil)
|
||||
|
||||
debug.setmetatable(true, mt)
|
||||
assert(getmetatable(false) == mt)
|
||||
mt.__index = function (a,b) return a or b end
|
||||
assert((true)[false] == true)
|
||||
assert((false)[false] == false)
|
||||
debug.setmetatable(false, nil)
|
||||
assert(getmetatable(true) == nil)
|
||||
|
||||
debug.setmetatable(nil, mt)
|
||||
assert(getmetatable(nil) == mt)
|
||||
mt.__add = function (a,b) return (a or 0) + (b or 0) end
|
||||
assert(10 + nil == 10)
|
||||
assert(nil + 23 == 23)
|
||||
assert(nil + nil == 0)
|
||||
debug.setmetatable(nil, nil)
|
||||
assert(getmetatable(nil) == nil)
|
||||
|
||||
debug.setmetatable(nil, {})
|
||||
|
||||
|
||||
-- loops in delegation
|
||||
a = {}; setmetatable(a, a); a.__index = a; a.__newindex = a
|
||||
assert(not pcall(function (a,b) return a[b] end, a, 10))
|
||||
assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true))
|
||||
|
||||
-- bug in 5.1
|
||||
T, K, V = nil
|
||||
grandparent = {}
|
||||
grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end
|
||||
|
||||
parent = {}
|
||||
parent.__newindex = parent
|
||||
setmetatable(parent, grandparent)
|
||||
|
||||
child = setmetatable({}, parent)
|
||||
child.foo = 10 --> CRASH (on some machines)
|
||||
assert(T == parent and K == "foo" and V == 10)
|
||||
|
||||
print 'OK'
|
||||
|
||||
return 12
|
||||
|
||||
|
793
06/parser-gen/parsers/lua-5.3.4-tests/files.lua
Normal file
793
06/parser-gen/parsers/lua-5.3.4-tests/files.lua
Normal file
|
@ -0,0 +1,793 @@
|
|||
-- $Id: files.lua,v 1.95 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
local debug = require "debug"
|
||||
|
||||
local maxint = math.maxinteger
|
||||
|
||||
assert(type(os.getenv"PATH") == "string")
|
||||
|
||||
assert(io.input(io.stdin) == io.stdin)
|
||||
assert(not pcall(io.input, "non-existent-file"))
|
||||
assert(io.output(io.stdout) == io.stdout)
|
||||
|
||||
|
||||
local function testerr (msg, f, ...)
|
||||
local stat, err = pcall(f, ...)
|
||||
return (not stat and string.find(err, msg, 1, true))
|
||||
end
|
||||
|
||||
|
||||
local function checkerr (msg, f, ...)
|
||||
assert(testerr(msg, f, ...))
|
||||
end
|
||||
|
||||
|
||||
-- cannot close standard files
|
||||
assert(not io.close(io.stdin) and
|
||||
not io.stdout:close() and
|
||||
not io.stderr:close())
|
||||
|
||||
|
||||
assert(type(io.input()) == "userdata" and io.type(io.output()) == "file")
|
||||
assert(type(io.stdin) == "userdata" and io.type(io.stderr) == "file")
|
||||
assert(not io.type(8))
|
||||
local a = {}; setmetatable(a, {})
|
||||
assert(not io.type(a))
|
||||
|
||||
assert(getmetatable(io.input()).__name == "FILE*")
|
||||
|
||||
local a,b,c = io.open('xuxu_nao_existe')
|
||||
assert(not a and type(b) == "string" and type(c) == "number")
|
||||
|
||||
a,b,c = io.open('/a/b/c/d', 'w')
|
||||
assert(not a and type(b) == "string" and type(c) == "number")
|
||||
|
||||
local file = os.tmpname()
|
||||
local f, msg = io.open(file, "w")
|
||||
if not f then
|
||||
(Message or print)("'os.tmpname' file cannot be open; skipping file tests")
|
||||
|
||||
else --{ most tests here need tmpname
|
||||
f:close()
|
||||
|
||||
print('testing i/o')
|
||||
|
||||
local otherfile = os.tmpname()
|
||||
|
||||
checkerr("invalid mode", io.open, file, "rw")
|
||||
checkerr("invalid mode", io.open, file, "rb+")
|
||||
checkerr("invalid mode", io.open, file, "r+bk")
|
||||
checkerr("invalid mode", io.open, file, "")
|
||||
checkerr("invalid mode", io.open, file, "+")
|
||||
checkerr("invalid mode", io.open, file, "b")
|
||||
assert(io.open(file, "r+b")):close()
|
||||
assert(io.open(file, "r+")):close()
|
||||
assert(io.open(file, "rb")):close()
|
||||
|
||||
assert(os.setlocale('C', 'all'))
|
||||
|
||||
io.input(io.stdin); io.output(io.stdout);
|
||||
|
||||
os.remove(file)
|
||||
assert(not loadfile(file))
|
||||
checkerr("", dofile, file)
|
||||
assert(not io.open(file))
|
||||
io.output(file)
|
||||
assert(io.output() ~= io.stdout)
|
||||
|
||||
if not _port then -- invalid seek
|
||||
local status, msg, code = io.stdin:seek("set", 1000)
|
||||
assert(not status and type(msg) == "string" and type(code) == "number")
|
||||
end
|
||||
|
||||
assert(io.output():seek() == 0)
|
||||
assert(io.write("alo alo"):seek() == string.len("alo alo"))
|
||||
assert(io.output():seek("cur", -3) == string.len("alo alo")-3)
|
||||
assert(io.write("joao"))
|
||||
assert(io.output():seek("end") == string.len("alo joao"))
|
||||
|
||||
assert(io.output():seek("set") == 0)
|
||||
|
||||
assert(io.write('"álo"', "{a}\n", "second line\n", "third line \n"))
|
||||
assert(io.write('çfourth_line'))
|
||||
io.output(io.stdout)
|
||||
collectgarbage() -- file should be closed by GC
|
||||
assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
|
||||
print('+')
|
||||
|
||||
-- test GC for files
|
||||
collectgarbage()
|
||||
for i=1,120 do
|
||||
for i=1,5 do
|
||||
io.input(file)
|
||||
assert(io.open(file, 'r'))
|
||||
io.lines(file)
|
||||
end
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
io.input():close()
|
||||
io.close()
|
||||
|
||||
assert(os.rename(file, otherfile))
|
||||
assert(not os.rename(file, otherfile))
|
||||
|
||||
io.output(io.open(otherfile, "ab"))
|
||||
assert(io.write("\n\n\t\t ", 3450, "\n"));
|
||||
io.close()
|
||||
|
||||
-- test writing/reading numbers
|
||||
f = assert(io.open(file, "w"))
|
||||
f:write(maxint, '\n')
|
||||
f:write(string.format("0X%x\n", maxint))
|
||||
f:write("0xABCp-3", '\n')
|
||||
f:write(0, '\n')
|
||||
f:write(-maxint, '\n')
|
||||
f:write(string.format("0x%X\n", -maxint))
|
||||
f:write("-0xABCp-3", '\n')
|
||||
assert(f:close())
|
||||
f = assert(io.open(file, "r"))
|
||||
assert(f:read("n") == maxint)
|
||||
assert(f:read("n") == maxint)
|
||||
assert(f:read("n") == 0xABCp-3)
|
||||
assert(f:read("n") == 0)
|
||||
assert(f:read("*n") == -maxint) -- test old format (with '*')
|
||||
assert(f:read("n") == -maxint)
|
||||
assert(f:read("*n") == -0xABCp-3) -- test old format (with '*')
|
||||
assert(f:close())
|
||||
assert(os.remove(file))
|
||||
|
||||
-- test yielding during 'dofile'
|
||||
f = assert(io.open(file, "w"))
|
||||
f:write[[
|
||||
local x, z = coroutine.yield(10)
|
||||
local y = coroutine.yield(20)
|
||||
return x + y * z
|
||||
]]
|
||||
assert(f:close())
|
||||
f = coroutine.wrap(dofile)
|
||||
assert(f(file) == 10)
|
||||
print(f(100, 101) == 20)
|
||||
assert(f(200) == 100 + 200 * 101)
|
||||
assert(os.remove(file))
|
||||
|
||||
|
||||
f = assert(io.open(file, "w"))
|
||||
-- test number termination
|
||||
f:write[[
|
||||
-12.3- -0xffff+ .3|5.E-3X +234e+13E 0xDEADBEEFDEADBEEFx
|
||||
0x1.13Ap+3e
|
||||
]]
|
||||
-- very long number
|
||||
f:write("1234"); for i = 1, 1000 do f:write("0") end; f:write("\n")
|
||||
-- invalid sequences (must read and discard valid prefixes)
|
||||
f:write[[
|
||||
.e+ 0.e; --; 0xX;
|
||||
]]
|
||||
assert(f:close())
|
||||
f = assert(io.open(file, "r"))
|
||||
assert(f:read("n") == -12.3); assert(f:read(1) == "-")
|
||||
assert(f:read("n") == -0xffff); assert(f:read(2) == "+ ")
|
||||
assert(f:read("n") == 0.3); assert(f:read(1) == "|")
|
||||
assert(f:read("n") == 5e-3); assert(f:read(1) == "X")
|
||||
assert(f:read("n") == 234e13); assert(f:read(1) == "E")
|
||||
assert(f:read("n") == 0Xdeadbeefdeadbeef); assert(f:read(2) == "x\n")
|
||||
assert(f:read("n") == 0x1.13aP3); assert(f:read(1) == "e")
|
||||
|
||||
do -- attempt to read too long number
|
||||
assert(f:read("n") == nil) -- fails
|
||||
local s = f:read("L") -- read rest of line
|
||||
assert(string.find(s, "^00*\n$")) -- lots of 0's left
|
||||
end
|
||||
|
||||
assert(not f:read("n")); assert(f:read(2) == "e+")
|
||||
assert(not f:read("n")); assert(f:read(1) == ";")
|
||||
assert(not f:read("n")); assert(f:read(2) == "-;")
|
||||
assert(not f:read("n")); assert(f:read(1) == "X")
|
||||
assert(not f:read("n")); assert(f:read(1) == ";")
|
||||
assert(not f:read("n")); assert(not f:read(0)) -- end of file
|
||||
assert(f:close())
|
||||
assert(os.remove(file))
|
||||
|
||||
|
||||
-- test line generators
|
||||
assert(not pcall(io.lines, "non-existent-file"))
|
||||
assert(os.rename(otherfile, file))
|
||||
io.output(otherfile)
|
||||
local n = 0
|
||||
local f = io.lines(file)
|
||||
while f() do n = n + 1 end;
|
||||
assert(n == 6) -- number of lines in the file
|
||||
checkerr("file is already closed", f)
|
||||
checkerr("file is already closed", f)
|
||||
-- copy from file to otherfile
|
||||
n = 0
|
||||
for l in io.lines(file) do io.write(l, "\n"); n = n + 1 end
|
||||
io.close()
|
||||
assert(n == 6)
|
||||
-- copy from otherfile back to file
|
||||
local f = assert(io.open(otherfile))
|
||||
assert(io.type(f) == "file")
|
||||
io.output(file)
|
||||
assert(not io.output():read())
|
||||
n = 0
|
||||
for l in f:lines() do io.write(l, "\n"); n = n + 1 end
|
||||
assert(tostring(f):sub(1, 5) == "file ")
|
||||
assert(f:close()); io.close()
|
||||
assert(n == 6)
|
||||
checkerr("closed file", io.close, f)
|
||||
assert(tostring(f) == "file (closed)")
|
||||
assert(io.type(f) == "closed file")
|
||||
io.input(file)
|
||||
f = io.open(otherfile):lines()
|
||||
n = 0
|
||||
for l in io.lines() do assert(l == f()); n = n + 1 end
|
||||
f = nil; collectgarbage()
|
||||
assert(n == 6)
|
||||
assert(os.remove(otherfile))
|
||||
|
||||
do -- bug in 5.3.1
|
||||
io.output(otherfile)
|
||||
io.write(string.rep("a", 300), "\n")
|
||||
io.close()
|
||||
local t ={}; for i = 1, 250 do t[i] = 1 end
|
||||
t = {io.lines(otherfile, table.unpack(t))()}
|
||||
-- everything ok here
|
||||
assert(#t == 250 and t[1] == 'a' and t[#t] == 'a')
|
||||
t[#t + 1] = 1 -- one too many
|
||||
checkerr("too many arguments", io.lines, otherfile, table.unpack(t))
|
||||
collectgarbage() -- ensure 'otherfile' is closed
|
||||
assert(os.remove(otherfile))
|
||||
end
|
||||
|
||||
io.input(file)
|
||||
do -- test error returns
|
||||
local a,b,c = io.input():write("xuxu")
|
||||
assert(not a and type(b) == "string" and type(c) == "number")
|
||||
end
|
||||
checkerr("invalid format", io.read, "x")
|
||||
assert(io.read(0) == "") -- not eof
|
||||
assert(io.read(5, 'l') == '"álo"')
|
||||
assert(io.read(0) == "")
|
||||
assert(io.read() == "second line")
|
||||
local x = io.input():seek()
|
||||
assert(io.read() == "third line ")
|
||||
assert(io.input():seek("set", x))
|
||||
assert(io.read('L') == "third line \n")
|
||||
assert(io.read(1) == "ç")
|
||||
assert(io.read(string.len"fourth_line") == "fourth_line")
|
||||
assert(io.input():seek("cur", -string.len"fourth_line"))
|
||||
assert(io.read() == "fourth_line")
|
||||
assert(io.read() == "") -- empty line
|
||||
assert(io.read('n') == 3450)
|
||||
assert(io.read(1) == '\n')
|
||||
assert(io.read(0) == nil) -- end of file
|
||||
assert(io.read(1) == nil) -- end of file
|
||||
assert(io.read(30000) == nil) -- end of file
|
||||
assert(({io.read(1)})[2] == nil)
|
||||
assert(io.read() == nil) -- end of file
|
||||
assert(({io.read()})[2] == nil)
|
||||
assert(io.read('n') == nil) -- end of file
|
||||
assert(({io.read('n')})[2] == nil)
|
||||
assert(io.read('a') == '') -- end of file (OK for 'a')
|
||||
assert(io.read('a') == '') -- end of file (OK for 'a')
|
||||
collectgarbage()
|
||||
print('+')
|
||||
io.close(io.input())
|
||||
checkerr(" input file is closed", io.read)
|
||||
|
||||
assert(os.remove(file))
|
||||
|
||||
local t = '0123456789'
|
||||
for i=1,10 do t = t..t; end
|
||||
assert(string.len(t) == 10*2^10)
|
||||
|
||||
io.output(file)
|
||||
io.write("alo"):write("\n")
|
||||
io.close()
|
||||
checkerr(" output file is closed", io.write)
|
||||
local f = io.open(file, "a+b")
|
||||
io.output(f)
|
||||
collectgarbage()
|
||||
|
||||
assert(io.write(' ' .. t .. ' '))
|
||||
assert(io.write(';', 'end of file\n'))
|
||||
f:flush(); io.flush()
|
||||
f:close()
|
||||
print('+')
|
||||
|
||||
io.input(file)
|
||||
assert(io.read() == "alo")
|
||||
assert(io.read(1) == ' ')
|
||||
assert(io.read(string.len(t)) == t)
|
||||
assert(io.read(1) == ' ')
|
||||
assert(io.read(0))
|
||||
assert(io.read('a') == ';end of file\n')
|
||||
assert(io.read(0) == nil)
|
||||
assert(io.close(io.input()))
|
||||
|
||||
|
||||
-- test errors in read/write
|
||||
do
|
||||
local function ismsg (m)
|
||||
-- error message is not a code number
|
||||
return (type(m) == "string" and tonumber(m) == nil)
|
||||
end
|
||||
|
||||
-- read
|
||||
local f = io.open(file, "w")
|
||||
local r, m, c = f:read()
|
||||
assert(not r and ismsg(m) and type(c) == "number")
|
||||
assert(f:close())
|
||||
-- write
|
||||
f = io.open(file, "r")
|
||||
r, m, c = f:write("whatever")
|
||||
assert(not r and ismsg(m) and type(c) == "number")
|
||||
assert(f:close())
|
||||
-- lines
|
||||
f = io.open(file, "w")
|
||||
r, m = pcall(f:lines())
|
||||
assert(r == false and ismsg(m))
|
||||
assert(f:close())
|
||||
end
|
||||
|
||||
assert(os.remove(file))
|
||||
|
||||
-- test for L format
|
||||
io.output(file); io.write"\n\nline\nother":close()
|
||||
io.input(file)
|
||||
assert(io.read"L" == "\n")
|
||||
assert(io.read"L" == "\n")
|
||||
assert(io.read"L" == "line\n")
|
||||
assert(io.read"L" == "other")
|
||||
assert(io.read"L" == nil)
|
||||
io.input():close()
|
||||
|
||||
local f = assert(io.open(file))
|
||||
local s = ""
|
||||
for l in f:lines("L") do s = s .. l end
|
||||
assert(s == "\n\nline\nother")
|
||||
f:close()
|
||||
|
||||
io.input(file)
|
||||
s = ""
|
||||
for l in io.lines(nil, "L") do s = s .. l end
|
||||
assert(s == "\n\nline\nother")
|
||||
io.input():close()
|
||||
|
||||
s = ""
|
||||
for l in io.lines(file, "L") do s = s .. l end
|
||||
assert(s == "\n\nline\nother")
|
||||
|
||||
s = ""
|
||||
for l in io.lines(file, "l") do s = s .. l end
|
||||
assert(s == "lineother")
|
||||
|
||||
io.output(file); io.write"a = 10 + 34\na = 2*a\na = -a\n":close()
|
||||
local t = {}
|
||||
load(io.lines(file, "L"), nil, nil, t)()
|
||||
assert(t.a == -((10 + 34) * 2))
|
||||
|
||||
|
||||
-- test for multipe arguments in 'lines'
|
||||
io.output(file); io.write"0123456789\n":close()
|
||||
for a,b in io.lines(file, 1, 1) do
|
||||
if a == "\n" then assert(b == nil)
|
||||
else assert(tonumber(a) == tonumber(b) - 1)
|
||||
end
|
||||
end
|
||||
|
||||
for a,b,c in io.lines(file, 1, 2, "a") do
|
||||
assert(a == "0" and b == "12" and c == "3456789\n")
|
||||
end
|
||||
|
||||
for a,b,c in io.lines(file, "a", 0, 1) do
|
||||
if a == "" then break end
|
||||
assert(a == "0123456789\n" and b == nil and c == nil)
|
||||
end
|
||||
collectgarbage() -- to close file in previous iteration
|
||||
|
||||
io.output(file); io.write"00\n10\n20\n30\n40\n":close()
|
||||
for a, b in io.lines(file, "n", "n") do
|
||||
if a == 40 then assert(b == nil)
|
||||
else assert(a == b - 10)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- test load x lines
|
||||
io.output(file);
|
||||
io.write[[
|
||||
local y
|
||||
= X
|
||||
X =
|
||||
X *
|
||||
2 +
|
||||
X;
|
||||
X =
|
||||
X
|
||||
- y;
|
||||
]]:close()
|
||||
_G.X = 1
|
||||
assert(not load(io.lines(file)))
|
||||
collectgarbage() -- to close file in previous iteration
|
||||
load(io.lines(file, "L"))()
|
||||
assert(_G.X == 2)
|
||||
load(io.lines(file, 1))()
|
||||
assert(_G.X == 4)
|
||||
load(io.lines(file, 3))()
|
||||
assert(_G.X == 8)
|
||||
|
||||
print('+')
|
||||
|
||||
local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
|
||||
io.output(file)
|
||||
assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1)))
|
||||
io.close()
|
||||
assert(loadfile(file))()
|
||||
assert(x1 == x2)
|
||||
print('+')
|
||||
assert(os.remove(file))
|
||||
assert(not os.remove(file))
|
||||
assert(not os.remove(otherfile))
|
||||
|
||||
-- testing loadfile
|
||||
local function testloadfile (s, expres)
|
||||
io.output(file)
|
||||
if s then io.write(s) end
|
||||
io.close()
|
||||
local res = assert(loadfile(file))()
|
||||
assert(os.remove(file))
|
||||
assert(res == expres)
|
||||
end
|
||||
|
||||
-- loading empty file
|
||||
testloadfile(nil, nil)
|
||||
|
||||
-- loading file with initial comment without end of line
|
||||
testloadfile("# a non-ending comment", nil)
|
||||
|
||||
|
||||
-- checking Unicode BOM in files
|
||||
testloadfile("\xEF\xBB\xBF# some comment\nreturn 234", 234)
|
||||
testloadfile("\xEF\xBB\xBFreturn 239", 239)
|
||||
testloadfile("\xEF\xBB\xBF", nil) -- empty file with a BOM
|
||||
|
||||
|
||||
-- checking line numbers in files with initial comments
|
||||
testloadfile("# a comment\nreturn require'debug'.getinfo(1).currentline", 2)
|
||||
|
||||
|
||||
-- loading binary file
|
||||
io.output(io.open(file, "wb"))
|
||||
assert(io.write(string.dump(function () return 10, '\0alo\255', 'hi' end)))
|
||||
io.close()
|
||||
a, b, c = assert(loadfile(file))()
|
||||
assert(a == 10 and b == "\0alo\255" and c == "hi")
|
||||
assert(os.remove(file))
|
||||
|
||||
-- bug in 5.2.1
|
||||
do
|
||||
io.output(io.open(file, "wb"))
|
||||
-- save function with no upvalues
|
||||
assert(io.write(string.dump(function () return 1 end)))
|
||||
io.close()
|
||||
f = assert(loadfile(file, "b", {}))
|
||||
assert(type(f) == "function" and f() == 1)
|
||||
assert(os.remove(file))
|
||||
end
|
||||
|
||||
-- loading binary file with initial comment
|
||||
io.output(io.open(file, "wb"))
|
||||
assert(io.write("#this is a comment for a binary file\0\n",
|
||||
string.dump(function () return 20, '\0\0\0' end)))
|
||||
io.close()
|
||||
a, b, c = assert(loadfile(file))()
|
||||
assert(a == 20 and b == "\0\0\0" and c == nil)
|
||||
assert(os.remove(file))
|
||||
|
||||
|
||||
-- 'loadfile' with 'env'
|
||||
do
|
||||
local f = io.open(file, 'w')
|
||||
f:write[[
|
||||
if (...) then a = 15; return b, c, d
|
||||
else return _ENV
|
||||
end
|
||||
]]
|
||||
f:close()
|
||||
local t = {b = 12, c = "xuxu", d = print}
|
||||
local f = assert(loadfile(file, 't', t))
|
||||
local b, c, d = f(1)
|
||||
assert(t.a == 15 and b == 12 and c == t.c and d == print)
|
||||
assert(f() == t)
|
||||
f = assert(loadfile(file, 't', nil))
|
||||
assert(f() == nil)
|
||||
f = assert(loadfile(file))
|
||||
assert(f() == _G)
|
||||
assert(os.remove(file))
|
||||
end
|
||||
|
||||
|
||||
-- 'loadfile' x modes
|
||||
do
|
||||
io.open(file, 'w'):write("return 10"):close()
|
||||
local s, m = loadfile(file, 'b')
|
||||
assert(not s and string.find(m, "a text chunk"))
|
||||
io.open(file, 'w'):write("\27 return 10"):close()
|
||||
local s, m = loadfile(file, 't')
|
||||
assert(not s and string.find(m, "a binary chunk"))
|
||||
assert(os.remove(file))
|
||||
end
|
||||
|
||||
|
||||
io.output(file)
|
||||
assert(io.write("qualquer coisa\n"))
|
||||
assert(io.write("mais qualquer coisa"))
|
||||
io.close()
|
||||
assert(io.output(assert(io.open(otherfile, 'wb')))
|
||||
:write("outra coisa\0\1\3\0\0\0\0\255\0")
|
||||
:close())
|
||||
|
||||
local filehandle = assert(io.open(file, 'r+'))
|
||||
local otherfilehandle = assert(io.open(otherfile, 'rb'))
|
||||
assert(filehandle ~= otherfilehandle)
|
||||
assert(type(filehandle) == "userdata")
|
||||
assert(filehandle:read('l') == "qualquer coisa")
|
||||
io.input(otherfilehandle)
|
||||
assert(io.read(string.len"outra coisa") == "outra coisa")
|
||||
assert(filehandle:read('l') == "mais qualquer coisa")
|
||||
filehandle:close();
|
||||
assert(type(filehandle) == "userdata")
|
||||
io.input(otherfilehandle)
|
||||
assert(io.read(4) == "\0\1\3\0")
|
||||
assert(io.read(3) == "\0\0\0")
|
||||
assert(io.read(0) == "") -- 255 is not eof
|
||||
assert(io.read(1) == "\255")
|
||||
assert(io.read('a') == "\0")
|
||||
assert(not io.read(0))
|
||||
assert(otherfilehandle == io.input())
|
||||
otherfilehandle:close()
|
||||
assert(os.remove(file))
|
||||
assert(os.remove(otherfile))
|
||||
collectgarbage()
|
||||
|
||||
io.output(file)
|
||||
:write[[
|
||||
123.4 -56e-2 not a number
|
||||
second line
|
||||
third line
|
||||
|
||||
and the rest of the file
|
||||
]]
|
||||
:close()
|
||||
io.input(file)
|
||||
local _,a,b,c,d,e,h,__ = io.read(1, 'n', 'n', 'l', 'l', 'l', 'a', 10)
|
||||
assert(io.close(io.input()))
|
||||
assert(_ == ' ' and __ == nil)
|
||||
assert(type(a) == 'number' and a==123.4 and b==-56e-2)
|
||||
assert(d=='second line' and e=='third line')
|
||||
assert(h==[[
|
||||
|
||||
and the rest of the file
|
||||
]])
|
||||
assert(os.remove(file))
|
||||
collectgarbage()
|
||||
|
||||
-- testing buffers
|
||||
do
|
||||
local f = assert(io.open(file, "w"))
|
||||
local fr = assert(io.open(file, "r"))
|
||||
assert(f:setvbuf("full", 2000))
|
||||
f:write("x")
|
||||
assert(fr:read("all") == "") -- full buffer; output not written yet
|
||||
f:close()
|
||||
fr:seek("set")
|
||||
assert(fr:read("all") == "x") -- `close' flushes it
|
||||
f = assert(io.open(file), "w")
|
||||
assert(f:setvbuf("no"))
|
||||
f:write("x")
|
||||
fr:seek("set")
|
||||
assert(fr:read("all") == "x") -- no buffer; output is ready
|
||||
f:close()
|
||||
f = assert(io.open(file, "a"))
|
||||
assert(f:setvbuf("line"))
|
||||
f:write("x")
|
||||
fr:seek("set", 1)
|
||||
assert(fr:read("all") == "") -- line buffer; no output without `\n'
|
||||
f:write("a\n"):seek("set", 1)
|
||||
assert(fr:read("all") == "xa\n") -- now we have a whole line
|
||||
f:close(); fr:close()
|
||||
assert(os.remove(file))
|
||||
end
|
||||
|
||||
|
||||
if not _soft then
|
||||
print("testing large files (> BUFSIZ)")
|
||||
io.output(file)
|
||||
for i=1,5001 do io.write('0123456789123') end
|
||||
io.write('\n12346'):close()
|
||||
io.input(file)
|
||||
local x = io.read('a')
|
||||
io.input():seek('set', 0)
|
||||
local y = io.read(30001)..io.read(1005)..io.read(0)..
|
||||
io.read(1)..io.read(100003)
|
||||
assert(x == y and string.len(x) == 5001*13 + 6)
|
||||
io.input():seek('set', 0)
|
||||
y = io.read() -- huge line
|
||||
assert(x == y..'\n'..io.read())
|
||||
assert(io.read() == nil)
|
||||
io.close(io.input())
|
||||
assert(os.remove(file))
|
||||
x = nil; y = nil
|
||||
end
|
||||
|
||||
if not _port then
|
||||
local progname
|
||||
do -- get name of running executable
|
||||
local arg = arg or _ARG
|
||||
local i = 0
|
||||
while arg[i] do i = i - 1 end
|
||||
progname = '"' .. arg[i + 1] .. '"'
|
||||
end
|
||||
print("testing popen/pclose and execute")
|
||||
local tests = {
|
||||
-- command, what, code
|
||||
{"ls > /dev/null", "ok"},
|
||||
{"not-to-be-found-command", "exit"},
|
||||
{"exit 3", "exit", 3},
|
||||
{"exit 129", "exit", 129},
|
||||
{"kill -s HUP $$", "signal", 1},
|
||||
{"kill -s KILL $$", "signal", 9},
|
||||
{"sh -c 'kill -s HUP $$'", "exit"},
|
||||
{progname .. ' -e " "', "ok"},
|
||||
{progname .. ' -e "os.exit(0, true)"', "ok"},
|
||||
{progname .. ' -e "os.exit(20, true)"', "exit", 20},
|
||||
}
|
||||
print("\n(some error messages are expected now)")
|
||||
for _, v in ipairs(tests) do
|
||||
local x, y, z = io.popen(v[1]):close()
|
||||
local x1, y1, z1 = os.execute(v[1])
|
||||
assert(x == x1 and y == y1 and z == z1)
|
||||
if v[2] == "ok" then
|
||||
assert(x and y == 'exit' and z == 0)
|
||||
else
|
||||
assert(not x and y == v[2]) -- correct status and 'what'
|
||||
-- correct code if known (but always different from 0)
|
||||
assert((v[3] == nil and z > 0) or v[3] == z)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- testing tmpfile
|
||||
f = io.tmpfile()
|
||||
assert(io.type(f) == "file")
|
||||
f:write("alo")
|
||||
f:seek("set")
|
||||
assert(f:read"a" == "alo")
|
||||
|
||||
end --}
|
||||
|
||||
print'+'
|
||||
|
||||
print("testing date/time")
|
||||
|
||||
assert(os.date("") == "")
|
||||
assert(os.date("!") == "")
|
||||
assert(os.date("\0\0") == "\0\0")
|
||||
assert(os.date("!\0\0") == "\0\0")
|
||||
local x = string.rep("a", 10000)
|
||||
assert(os.date(x) == x)
|
||||
local t = os.time()
|
||||
D = os.date("*t", t)
|
||||
assert(os.date(string.rep("%d", 1000), t) ==
|
||||
string.rep(os.date("%d", t), 1000))
|
||||
assert(os.date(string.rep("%", 200)) == string.rep("%", 100))
|
||||
|
||||
local t = os.time()
|
||||
D = os.date("*t", t)
|
||||
load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and
|
||||
D.hour==%H and D.min==%M and D.sec==%S and
|
||||
D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))()
|
||||
|
||||
checkerr("invalid conversion specifier", os.date, "%")
|
||||
checkerr("invalid conversion specifier", os.date, "%9")
|
||||
checkerr("invalid conversion specifier", os.date, "%")
|
||||
checkerr("invalid conversion specifier", os.date, "%O")
|
||||
checkerr("invalid conversion specifier", os.date, "%E")
|
||||
checkerr("invalid conversion specifier", os.date, "%Ea")
|
||||
|
||||
checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour='x'})
|
||||
checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour=1.5})
|
||||
|
||||
checkerr("missing", os.time, {hour = 12}) -- missing date
|
||||
|
||||
if not _port then
|
||||
-- test Posix-specific modifiers
|
||||
assert(type(os.date("%Ex")) == 'string')
|
||||
assert(type(os.date("%Oy")) == 'string')
|
||||
|
||||
|
||||
-- test out-of-range dates (at least for Unix)
|
||||
if maxint >= 2^62 then -- cannot do these tests in Small Lua
|
||||
-- no arith overflows
|
||||
checkerr("out-of-bound", os.time, {year = -maxint, month = 1, day = 1})
|
||||
if string.packsize("i") == 4 then -- 4-byte ints
|
||||
if testerr("out-of-bound", os.date, "%Y", 2^40) then
|
||||
-- time_t has 4 bytes and therefore cannot represent year 4000
|
||||
print(" 4-byte time_t")
|
||||
checkerr("cannot be represented", os.time, {year=4000, month=1, day=1})
|
||||
else
|
||||
-- time_t has 8 bytes; an int year cannot represent a huge time
|
||||
print(" 8-byte time_t")
|
||||
checkerr("cannot be represented", os.date, "%Y", 2^60)
|
||||
-- it should have no problems with year 4000
|
||||
assert(tonumber(os.time{year=4000, month=1, day=1}))
|
||||
end
|
||||
else -- 8-byte ints
|
||||
-- assume time_t has 8 bytes too
|
||||
print(" 8-byte time_t")
|
||||
assert(tonumber(os.date("%Y", 2^60)))
|
||||
-- but still cannot represent a huge year
|
||||
checkerr("cannot be represented", os.time, {year=2^60, month=1, day=1})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
D = os.date("!*t", t)
|
||||
load(os.date([[!assert(D.year==%Y and D.month==%m and D.day==%d and
|
||||
D.hour==%H and D.min==%M and D.sec==%S and
|
||||
D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))()
|
||||
|
||||
do
|
||||
local D = os.date("*t")
|
||||
local t = os.time(D)
|
||||
assert(type(D.isdst) == 'boolean')
|
||||
D.isdst = nil
|
||||
local t1 = os.time(D)
|
||||
assert(t == t1) -- if isdst is absent uses correct default
|
||||
end
|
||||
|
||||
t = os.time(D)
|
||||
D.year = D.year-1;
|
||||
local t1 = os.time(D)
|
||||
-- allow for leap years
|
||||
assert(math.abs(os.difftime(t,t1)/(24*3600) - 365) < 2)
|
||||
|
||||
-- should not take more than 1 second to execute these two lines
|
||||
t = os.time()
|
||||
t1 = os.time(os.date("*t"))
|
||||
local diff = os.difftime(t1,t)
|
||||
assert(0 <= diff and diff <= 1)
|
||||
diff = os.difftime(t,t1)
|
||||
assert(-1 <= diff and diff <= 0)
|
||||
|
||||
local t1 = os.time{year=2000, month=10, day=1, hour=23, min=12}
|
||||
local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19}
|
||||
assert(os.difftime(t1,t2) == 60*2-19)
|
||||
|
||||
-- since 5.3.3, 'os.time' normalizes table fields
|
||||
t1 = {year = 2005, month = 1, day = 1, hour = 1, min = 0, sec = -3602}
|
||||
os.time(t1)
|
||||
assert(t1.day == 31 and t1.month == 12 and t1.year == 2004 and
|
||||
t1.hour == 23 and t1.min == 59 and t1.sec == 58 and
|
||||
t1.yday == 366)
|
||||
|
||||
io.output(io.stdout)
|
||||
local t = os.date('%d %m %Y %H %M %S')
|
||||
local d, m, a, h, min, s = string.match(t,
|
||||
"(%d+) (%d+) (%d+) (%d+) (%d+) (%d+)")
|
||||
d = tonumber(d)
|
||||
m = tonumber(m)
|
||||
a = tonumber(a)
|
||||
h = tonumber(h)
|
||||
min = tonumber(min)
|
||||
s = tonumber(s)
|
||||
io.write(string.format('test done on %2.2d/%2.2d/%d', d, m, a))
|
||||
io.write(string.format(', at %2.2d:%2.2d:%2.2d\n', h, min, s))
|
||||
io.write(string.format('%s\n', _VERSION))
|
||||
|
||||
|
624
06/parser-gen/parsers/lua-5.3.4-tests/gc.lua
Normal file
624
06/parser-gen/parsers/lua-5.3.4-tests/gc.lua
Normal file
|
@ -0,0 +1,624 @@
|
|||
-- $Id: gc.lua,v 1.72 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing garbage collection')
|
||||
|
||||
local debug = require"debug"
|
||||
|
||||
collectgarbage()
|
||||
|
||||
assert(collectgarbage("isrunning"))
|
||||
|
||||
local function gcinfo () return collectgarbage"count" * 1024 end
|
||||
|
||||
|
||||
-- test weird parameters
|
||||
do
|
||||
-- save original parameters
|
||||
local a = collectgarbage("setpause", 200)
|
||||
local b = collectgarbage("setstepmul", 200)
|
||||
local t = {0, 2, 10, 90, 500, 5000, 30000, 0x7ffffffe}
|
||||
for i = 1, #t do
|
||||
local p = t[i]
|
||||
for j = 1, #t do
|
||||
local m = t[j]
|
||||
collectgarbage("setpause", p)
|
||||
collectgarbage("setstepmul", m)
|
||||
collectgarbage("step", 0)
|
||||
collectgarbage("step", 10000)
|
||||
end
|
||||
end
|
||||
-- restore original parameters
|
||||
collectgarbage("setpause", a)
|
||||
collectgarbage("setstepmul", b)
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
|
||||
_G["while"] = 234
|
||||
|
||||
limit = 5000
|
||||
|
||||
|
||||
local function GC1 ()
|
||||
local u
|
||||
local b -- must be declared after 'u' (to be above it in the stack)
|
||||
local finish = false
|
||||
u = setmetatable({}, {__gc = function () finish = true end})
|
||||
b = {34}
|
||||
repeat u = {} until finish
|
||||
assert(b[1] == 34) -- 'u' was collected, but 'b' was not
|
||||
|
||||
finish = false; local i = 1
|
||||
u = setmetatable({}, {__gc = function () finish = true end})
|
||||
repeat i = i + 1; u = tostring(i) .. tostring(i) until finish
|
||||
assert(b[1] == 34) -- 'u' was collected, but 'b' was not
|
||||
|
||||
finish = false
|
||||
u = setmetatable({}, {__gc = function () finish = true end})
|
||||
repeat local i; u = function () return i end until finish
|
||||
assert(b[1] == 34) -- 'u' was collected, but 'b' was not
|
||||
end
|
||||
|
||||
local function GC2 ()
|
||||
local u
|
||||
local finish = false
|
||||
u = {setmetatable({}, {__gc = function () finish = true end})}
|
||||
b = {34}
|
||||
repeat u = {{}} until finish
|
||||
assert(b[1] == 34) -- 'u' was collected, but 'b' was not
|
||||
|
||||
finish = false; local i = 1
|
||||
u = {setmetatable({}, {__gc = function () finish = true end})}
|
||||
repeat i = i + 1; u = {tostring(i) .. tostring(i)} until finish
|
||||
assert(b[1] == 34) -- 'u' was collected, but 'b' was not
|
||||
|
||||
finish = false
|
||||
u = {setmetatable({}, {__gc = function () finish = true end})}
|
||||
repeat local i; u = {function () return i end} until finish
|
||||
assert(b[1] == 34) -- 'u' was collected, but 'b' was not
|
||||
end
|
||||
|
||||
local function GC() GC1(); GC2() end
|
||||
|
||||
|
||||
contCreate = 0
|
||||
|
||||
print('tables')
|
||||
while contCreate <= limit do
|
||||
local a = {}; a = nil
|
||||
contCreate = contCreate+1
|
||||
end
|
||||
|
||||
a = "a"
|
||||
|
||||
contCreate = 0
|
||||
print('strings')
|
||||
while contCreate <= limit do
|
||||
a = contCreate .. "b";
|
||||
a = string.gsub(a, '(%d%d*)', string.upper)
|
||||
a = "a"
|
||||
contCreate = contCreate+1
|
||||
end
|
||||
|
||||
|
||||
contCreate = 0
|
||||
|
||||
a = {}
|
||||
|
||||
print('functions')
|
||||
function a:test ()
|
||||
while contCreate <= limit do
|
||||
load(string.format("function temp(a) return 'a%d' end", contCreate), "")()
|
||||
assert(temp() == string.format('a%d', contCreate))
|
||||
contCreate = contCreate+1
|
||||
end
|
||||
end
|
||||
|
||||
a:test()
|
||||
|
||||
-- collection of functions without locals, globals, etc.
|
||||
do local f = function () end end
|
||||
|
||||
|
||||
print("functions with errors")
|
||||
prog = [[
|
||||
do
|
||||
a = 10;
|
||||
function foo(x,y)
|
||||
a = sin(a+0.456-0.23e-12);
|
||||
return function (z) return sin(%x+z) end
|
||||
end
|
||||
local x = function (w) a=a+w; end
|
||||
end
|
||||
]]
|
||||
do
|
||||
local step = 1
|
||||
if _soft then step = 13 end
|
||||
for i=1, string.len(prog), step do
|
||||
for j=i, string.len(prog), step do
|
||||
pcall(load(string.sub(prog, i, j), ""))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
foo = nil
|
||||
print('long strings')
|
||||
x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
assert(string.len(x)==80)
|
||||
s = ''
|
||||
n = 0
|
||||
k = math.min(300, (math.maxinteger // 80) // 2)
|
||||
while n < k do s = s..x; n=n+1; j=tostring(n) end
|
||||
assert(string.len(s) == k*80)
|
||||
s = string.sub(s, 1, 10000)
|
||||
s, i = string.gsub(s, '(%d%d%d%d)', '')
|
||||
assert(i==10000 // 4)
|
||||
s = nil
|
||||
x = nil
|
||||
|
||||
assert(_G["while"] == 234)
|
||||
|
||||
|
||||
print("steps")
|
||||
|
||||
print("steps (2)")
|
||||
|
||||
local function dosteps (siz)
|
||||
assert(not collectgarbage("isrunning"))
|
||||
collectgarbage()
|
||||
assert(not collectgarbage("isrunning"))
|
||||
local a = {}
|
||||
for i=1,100 do a[i] = {{}}; local b = {} end
|
||||
local x = gcinfo()
|
||||
local i = 0
|
||||
repeat -- do steps until it completes a collection cycle
|
||||
i = i+1
|
||||
until collectgarbage("step", siz)
|
||||
assert(gcinfo() < x)
|
||||
return i
|
||||
end
|
||||
|
||||
collectgarbage"stop"
|
||||
|
||||
if not _port then
|
||||
-- test the "size" of basic GC steps (whatever they mean...)
|
||||
assert(dosteps(0) > 10)
|
||||
assert(dosteps(10) < dosteps(2))
|
||||
end
|
||||
|
||||
-- collector should do a full collection with so many steps
|
||||
assert(dosteps(20000) == 1)
|
||||
assert(collectgarbage("step", 20000) == true)
|
||||
assert(collectgarbage("step", 20000) == true)
|
||||
|
||||
assert(not collectgarbage("isrunning"))
|
||||
collectgarbage"restart"
|
||||
assert(collectgarbage("isrunning"))
|
||||
|
||||
|
||||
if not _port then
|
||||
-- test the pace of the collector
|
||||
collectgarbage(); collectgarbage()
|
||||
local x = gcinfo()
|
||||
collectgarbage"stop"
|
||||
assert(not collectgarbage("isrunning"))
|
||||
repeat
|
||||
local a = {}
|
||||
until gcinfo() > 3 * x
|
||||
collectgarbage"restart"
|
||||
assert(collectgarbage("isrunning"))
|
||||
repeat
|
||||
local a = {}
|
||||
until gcinfo() <= x * 2
|
||||
end
|
||||
|
||||
|
||||
print("clearing tables")
|
||||
lim = 15
|
||||
a = {}
|
||||
-- fill a with `collectable' indices
|
||||
for i=1,lim do a[{}] = i end
|
||||
b = {}
|
||||
for k,v in pairs(a) do b[k]=v end
|
||||
-- remove all indices and collect them
|
||||
for n in pairs(b) do
|
||||
a[n] = nil
|
||||
assert(type(n) == 'table' and next(n) == nil)
|
||||
collectgarbage()
|
||||
end
|
||||
b = nil
|
||||
collectgarbage()
|
||||
for n in pairs(a) do error'cannot be here' end
|
||||
for i=1,lim do a[i] = i end
|
||||
for i=1,lim do assert(a[i] == i) end
|
||||
|
||||
|
||||
print('weak tables')
|
||||
a = {}; setmetatable(a, {__mode = 'k'});
|
||||
-- fill a with some `collectable' indices
|
||||
for i=1,lim do a[{}] = i end
|
||||
-- and some non-collectable ones
|
||||
for i=1,lim do a[i] = i end
|
||||
for i=1,lim do local s=string.rep('@', i); a[s] = s..'#' end
|
||||
collectgarbage()
|
||||
local i = 0
|
||||
for k,v in pairs(a) do assert(k==v or k..'#'==v); i=i+1 end
|
||||
assert(i == 2*lim)
|
||||
|
||||
a = {}; setmetatable(a, {__mode = 'v'});
|
||||
a[1] = string.rep('b', 21)
|
||||
collectgarbage()
|
||||
assert(a[1]) -- strings are *values*
|
||||
a[1] = nil
|
||||
-- fill a with some `collectable' values (in both parts of the table)
|
||||
for i=1,lim do a[i] = {} end
|
||||
for i=1,lim do a[i..'x'] = {} end
|
||||
-- and some non-collectable ones
|
||||
for i=1,lim do local t={}; a[t]=t end
|
||||
for i=1,lim do a[i+lim]=i..'x' end
|
||||
collectgarbage()
|
||||
local i = 0
|
||||
for k,v in pairs(a) do assert(k==v or k-lim..'x' == v); i=i+1 end
|
||||
assert(i == 2*lim)
|
||||
|
||||
a = {}; setmetatable(a, {__mode = 'vk'});
|
||||
local x, y, z = {}, {}, {}
|
||||
-- keep only some items
|
||||
a[1], a[2], a[3] = x, y, z
|
||||
a[string.rep('$', 11)] = string.rep('$', 11)
|
||||
-- fill a with some `collectable' values
|
||||
for i=4,lim do a[i] = {} end
|
||||
for i=1,lim do a[{}] = i end
|
||||
for i=1,lim do local t={}; a[t]=t end
|
||||
collectgarbage()
|
||||
assert(next(a) ~= nil)
|
||||
local i = 0
|
||||
for k,v in pairs(a) do
|
||||
assert((k == 1 and v == x) or
|
||||
(k == 2 and v == y) or
|
||||
(k == 3 and v == z) or k==v);
|
||||
i = i+1
|
||||
end
|
||||
assert(i == 4)
|
||||
x,y,z=nil
|
||||
collectgarbage()
|
||||
assert(next(a) == string.rep('$', 11))
|
||||
|
||||
|
||||
-- 'bug' in 5.1
|
||||
a = {}
|
||||
local t = {x = 10}
|
||||
local C = setmetatable({key = t}, {__mode = 'v'})
|
||||
local C1 = setmetatable({[t] = 1}, {__mode = 'k'})
|
||||
a.x = t -- this should not prevent 't' from being removed from
|
||||
-- weak table 'C' by the time 'a' is finalized
|
||||
|
||||
setmetatable(a, {__gc = function (u)
|
||||
assert(C.key == nil)
|
||||
assert(type(next(C1)) == 'table')
|
||||
end})
|
||||
|
||||
a, t = nil
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
assert(next(C) == nil and next(C1) == nil)
|
||||
C, C1 = nil
|
||||
|
||||
|
||||
-- ephemerons
|
||||
local mt = {__mode = 'k'}
|
||||
a = {{10},{20},{30},{40}}; setmetatable(a, mt)
|
||||
x = nil
|
||||
for i = 1, 100 do local n = {}; a[n] = {k = {x}}; x = n end
|
||||
GC()
|
||||
local n = x
|
||||
local i = 0
|
||||
while n do n = a[n].k[1]; i = i + 1 end
|
||||
assert(i == 100)
|
||||
x = nil
|
||||
GC()
|
||||
for i = 1, 4 do assert(a[i][1] == i * 10); a[i] = nil end
|
||||
assert(next(a) == nil)
|
||||
|
||||
local K = {}
|
||||
a[K] = {}
|
||||
for i=1,10 do a[K][i] = {}; a[a[K][i]] = setmetatable({}, mt) end
|
||||
x = nil
|
||||
local k = 1
|
||||
for j = 1,100 do
|
||||
local n = {}; local nk = k%10 + 1
|
||||
a[a[K][nk]][n] = {x, k = k}; x = n; k = nk
|
||||
end
|
||||
GC()
|
||||
local n = x
|
||||
local i = 0
|
||||
while n do local t = a[a[K][k]][n]; n = t[1]; k = t.k; i = i + 1 end
|
||||
assert(i == 100)
|
||||
K = nil
|
||||
GC()
|
||||
-- assert(next(a) == nil)
|
||||
|
||||
|
||||
-- testing errors during GC
|
||||
do
|
||||
collectgarbage("stop") -- stop collection
|
||||
local u = {}
|
||||
local s = {}; setmetatable(s, {__mode = 'k'})
|
||||
setmetatable(u, {__gc = function (o)
|
||||
local i = s[o]
|
||||
s[i] = true
|
||||
assert(not s[i - 1]) -- check proper finalization order
|
||||
if i == 8 then error("here") end -- error during GC
|
||||
end})
|
||||
|
||||
for i = 6, 10 do
|
||||
local n = setmetatable({}, getmetatable(u))
|
||||
s[n] = i
|
||||
end
|
||||
|
||||
assert(not pcall(collectgarbage))
|
||||
for i = 8, 10 do assert(s[i]) end
|
||||
|
||||
for i = 1, 5 do
|
||||
local n = setmetatable({}, getmetatable(u))
|
||||
s[n] = i
|
||||
end
|
||||
|
||||
collectgarbage()
|
||||
for i = 1, 10 do assert(s[i]) end
|
||||
|
||||
getmetatable(u).__gc = false
|
||||
|
||||
|
||||
-- __gc errors with non-string messages
|
||||
setmetatable({}, {__gc = function () error{} end})
|
||||
local a, b = pcall(collectgarbage)
|
||||
assert(not a and type(b) == "string" and string.find(b, "error in __gc"))
|
||||
|
||||
end
|
||||
print '+'
|
||||
|
||||
|
||||
-- testing userdata
|
||||
if T==nil then
|
||||
(Message or print)('\n >>> testC not active: skipping userdata GC tests <<<\n')
|
||||
|
||||
else
|
||||
|
||||
local function newproxy(u)
|
||||
return debug.setmetatable(T.newuserdata(0), debug.getmetatable(u))
|
||||
end
|
||||
|
||||
collectgarbage("stop") -- stop collection
|
||||
local u = newproxy(nil)
|
||||
debug.setmetatable(u, {__gc = true})
|
||||
local s = 0
|
||||
local a = {[u] = 0}; setmetatable(a, {__mode = 'vk'})
|
||||
for i=1,10 do a[newproxy(u)] = i end
|
||||
for k in pairs(a) do assert(getmetatable(k) == getmetatable(u)) end
|
||||
local a1 = {}; for k,v in pairs(a) do a1[k] = v end
|
||||
for k,v in pairs(a1) do a[v] = k end
|
||||
for i =1,10 do assert(a[i]) end
|
||||
getmetatable(u).a = a1
|
||||
getmetatable(u).u = u
|
||||
do
|
||||
local u = u
|
||||
getmetatable(u).__gc = function (o)
|
||||
assert(a[o] == 10-s)
|
||||
assert(a[10-s] == nil) -- udata already removed from weak table
|
||||
assert(getmetatable(o) == getmetatable(u))
|
||||
assert(getmetatable(o).a[o] == 10-s)
|
||||
s=s+1
|
||||
end
|
||||
end
|
||||
a1, u = nil
|
||||
assert(next(a) ~= nil)
|
||||
collectgarbage()
|
||||
assert(s==11)
|
||||
collectgarbage()
|
||||
assert(next(a) == nil) -- finalized keys are removed in two cycles
|
||||
end
|
||||
|
||||
|
||||
-- __gc x weak tables
|
||||
local u = setmetatable({}, {__gc = true})
|
||||
-- __gc metamethod should be collected before running
|
||||
setmetatable(getmetatable(u), {__mode = "v"})
|
||||
getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen
|
||||
u = nil
|
||||
collectgarbage()
|
||||
|
||||
local u = setmetatable({}, {__gc = true})
|
||||
local m = getmetatable(u)
|
||||
m.x = {[{0}] = 1; [0] = {1}}; setmetatable(m.x, {__mode = "kv"});
|
||||
m.__gc = function (o)
|
||||
assert(next(getmetatable(o).x) == nil)
|
||||
m = 10
|
||||
end
|
||||
u, m = nil
|
||||
collectgarbage()
|
||||
assert(m==10)
|
||||
|
||||
|
||||
-- errors during collection
|
||||
u = setmetatable({}, {__gc = function () error "!!!" end})
|
||||
u = nil
|
||||
assert(not pcall(collectgarbage))
|
||||
|
||||
|
||||
if not _soft then
|
||||
print("deep structures")
|
||||
local a = {}
|
||||
for i = 1,200000 do
|
||||
a = {next = a}
|
||||
end
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
-- create many threads with self-references and open upvalues
|
||||
print("self-referenced threads")
|
||||
local thread_id = 0
|
||||
local threads = {}
|
||||
|
||||
local function fn (thread)
|
||||
local x = {}
|
||||
threads[thread_id] = function()
|
||||
thread = x
|
||||
end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
while thread_id < 1000 do
|
||||
local thread = coroutine.create(fn)
|
||||
coroutine.resume(thread, thread)
|
||||
thread_id = thread_id + 1
|
||||
end
|
||||
|
||||
|
||||
-- Create a closure (function inside 'f') with an upvalue ('param') that
|
||||
-- points (through a table) to the closure itself and to the thread
|
||||
-- ('co' and the initial value of 'param') where closure is running.
|
||||
-- Then, assert that table (and therefore everything else) will be
|
||||
-- collected.
|
||||
do
|
||||
local collected = false -- to detect collection
|
||||
collectgarbage(); collectgarbage("stop")
|
||||
do
|
||||
local function f (param)
|
||||
;(function ()
|
||||
assert(type(f) == 'function' and type(param) == 'thread')
|
||||
param = {param, f}
|
||||
setmetatable(param, {__gc = function () collected = true end})
|
||||
coroutine.yield(100)
|
||||
end)()
|
||||
end
|
||||
local co = coroutine.create(f)
|
||||
assert(coroutine.resume(co, co))
|
||||
end
|
||||
-- Now, thread and closure are not reacheable any more;
|
||||
-- two collections are needed to break cycle
|
||||
collectgarbage()
|
||||
assert(not collected)
|
||||
collectgarbage()
|
||||
assert(collected)
|
||||
collectgarbage("restart")
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
collectgarbage()
|
||||
collectgarbage"stop"
|
||||
local x = gcinfo()
|
||||
repeat
|
||||
for i=1,1000 do _ENV.a = {} end
|
||||
collectgarbage("step", 0) -- steps should not unblock the collector
|
||||
until gcinfo() > 2 * x
|
||||
collectgarbage"restart"
|
||||
end
|
||||
|
||||
|
||||
if T then -- tests for weird cases collecting upvalues
|
||||
|
||||
local function foo ()
|
||||
local a = {x = 20}
|
||||
coroutine.yield(function () return a.x end) -- will run collector
|
||||
assert(a.x == 20) -- 'a' is 'ok'
|
||||
a = {x = 30} -- create a new object
|
||||
assert(T.gccolor(a) == "white") -- of course it is new...
|
||||
coroutine.yield(100) -- 'a' is still local to this thread
|
||||
end
|
||||
|
||||
local t = setmetatable({}, {__mode = "kv"})
|
||||
collectgarbage(); collectgarbage('stop')
|
||||
-- create coroutine in a weak table, so it will never be marked
|
||||
t.co = coroutine.wrap(foo)
|
||||
local f = t.co() -- create function to access local 'a'
|
||||
T.gcstate("atomic") -- ensure all objects are traversed
|
||||
assert(T.gcstate() == "atomic")
|
||||
assert(t.co() == 100) -- resume coroutine, creating new table for 'a'
|
||||
assert(T.gccolor(t.co) == "white") -- thread was not traversed
|
||||
T.gcstate("pause") -- collect thread, but should mark 'a' before that
|
||||
assert(t.co == nil and f() == 30) -- ensure correct access to 'a'
|
||||
|
||||
collectgarbage("restart")
|
||||
|
||||
-- test barrier in sweep phase (advance cleaning of upvalue to white)
|
||||
local u = T.newuserdata(0) -- create a userdata
|
||||
collectgarbage()
|
||||
collectgarbage"stop"
|
||||
T.gcstate"atomic"
|
||||
T.gcstate"sweepallgc"
|
||||
local x = {}
|
||||
assert(T.gccolor(u) == "black") -- upvalue is "old" (black)
|
||||
assert(T.gccolor(x) == "white") -- table is "new" (white)
|
||||
debug.setuservalue(u, x) -- trigger barrier
|
||||
assert(T.gccolor(u) == "white") -- upvalue changed to white
|
||||
collectgarbage"restart"
|
||||
|
||||
print"+"
|
||||
end
|
||||
|
||||
|
||||
if T then
|
||||
local debug = require "debug"
|
||||
collectgarbage("stop")
|
||||
local x = T.newuserdata(0)
|
||||
local y = T.newuserdata(0)
|
||||
debug.setmetatable(y, {__gc = true}) -- bless the new udata before...
|
||||
debug.setmetatable(x, {__gc = true}) -- ...the old one
|
||||
assert(T.gccolor(y) == "white")
|
||||
T.checkmemory()
|
||||
collectgarbage("restart")
|
||||
end
|
||||
|
||||
|
||||
if T then
|
||||
print("emergency collections")
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
T.totalmem(T.totalmem() + 200)
|
||||
for i=1,200 do local a = {} end
|
||||
T.totalmem(0)
|
||||
collectgarbage()
|
||||
local t = T.totalmem("table")
|
||||
local a = {{}, {}, {}} -- create 4 new tables
|
||||
assert(T.totalmem("table") == t + 4)
|
||||
t = T.totalmem("function")
|
||||
a = function () end -- create 1 new closure
|
||||
assert(T.totalmem("function") == t + 1)
|
||||
t = T.totalmem("thread")
|
||||
a = coroutine.create(function () end) -- create 1 new coroutine
|
||||
assert(T.totalmem("thread") == t + 1)
|
||||
end
|
||||
|
||||
-- create an object to be collected when state is closed
|
||||
do
|
||||
local setmetatable,assert,type,print,getmetatable =
|
||||
setmetatable,assert,type,print,getmetatable
|
||||
local tt = {}
|
||||
tt.__gc = function (o)
|
||||
assert(getmetatable(o) == tt)
|
||||
-- create new objects during GC
|
||||
local a = 'xuxu'..(10+3)..'joao', {}
|
||||
___Glob = o -- ressurect object!
|
||||
setmetatable({}, tt) -- creates a new one with same metatable
|
||||
print(">>> closing state " .. "<<<\n")
|
||||
end
|
||||
local u = setmetatable({}, tt)
|
||||
___Glob = {u} -- avoid object being collected before program end
|
||||
end
|
||||
|
||||
-- create several objects to raise errors when collected while closing state
|
||||
do
|
||||
local mt = {__gc = function (o) return o + 1 end}
|
||||
for i = 1,10 do
|
||||
-- create object and preserve it until the end
|
||||
table.insert(___Glob, setmetatable({}, mt))
|
||||
end
|
||||
end
|
||||
|
||||
-- just to make sure
|
||||
assert(collectgarbage'isrunning')
|
||||
|
||||
print('OK')
|
232
06/parser-gen/parsers/lua-5.3.4-tests/goto.lua
Normal file
232
06/parser-gen/parsers/lua-5.3.4-tests/goto.lua
Normal file
|
@ -0,0 +1,232 @@
|
|||
-- $Id: goto.lua,v 1.13 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
collectgarbage()
|
||||
|
||||
local function errmsg (code, m)
|
||||
local st, msg = load(code)
|
||||
assert(not st and string.find(msg, m))
|
||||
end
|
||||
|
||||
-- cannot see label inside block
|
||||
errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'")
|
||||
errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'")
|
||||
|
||||
-- repeated label
|
||||
errmsg([[ ::l1:: ::l1:: ]], "label 'l1'")
|
||||
|
||||
|
||||
-- undefined label
|
||||
errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'")
|
||||
|
||||
-- jumping over variable definition
|
||||
errmsg([[
|
||||
do local bb, cc; goto l1; end
|
||||
local aa
|
||||
::l1:: print(3)
|
||||
]], "local 'aa'")
|
||||
|
||||
-- jumping into a block
|
||||
errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'")
|
||||
errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'")
|
||||
|
||||
-- cannot continue a repeat-until with variables
|
||||
errmsg([[
|
||||
repeat
|
||||
if x then goto cont end
|
||||
local xuxu = 10
|
||||
::cont::
|
||||
until xuxu < x
|
||||
]], "local 'xuxu'")
|
||||
|
||||
-- simple gotos
|
||||
local x
|
||||
do
|
||||
local y = 12
|
||||
goto l1
|
||||
::l2:: x = x + 1; goto l3
|
||||
::l1:: x = y; goto l2
|
||||
end
|
||||
::l3:: ::l3_1:: assert(x == 13)
|
||||
|
||||
|
||||
-- long labels
|
||||
do
|
||||
local prog = [[
|
||||
do
|
||||
local a = 1
|
||||
goto l%sa; a = a + 1
|
||||
::l%sa:: a = a + 10
|
||||
goto l%sb; a = a + 2
|
||||
::l%sb:: a = a + 20
|
||||
return a
|
||||
end
|
||||
]]
|
||||
local label = string.rep("0123456789", 40)
|
||||
prog = string.format(prog, label, label, label, label)
|
||||
assert(assert(load(prog))() == 31)
|
||||
end
|
||||
|
||||
-- goto to correct label when nested
|
||||
do goto l3; ::l3:: end -- does not loop jumping to previous label 'l3'
|
||||
|
||||
-- ok to jump over local dec. to end of block
|
||||
do
|
||||
goto l1
|
||||
local a = 23
|
||||
x = a
|
||||
::l1::;
|
||||
end
|
||||
|
||||
while true do
|
||||
goto l4
|
||||
goto l1 -- ok to jump over local dec. to end of block
|
||||
goto l1 -- multiple uses of same label
|
||||
local x = 45
|
||||
::l1:: ;;;
|
||||
end
|
||||
::l4:: assert(x == 13)
|
||||
|
||||
if print then
|
||||
goto l1 -- ok to jump over local dec. to end of block
|
||||
error("should not be here")
|
||||
goto l2 -- ok to jump over local dec. to end of block
|
||||
local x
|
||||
::l1:: ; ::l2:: ;;
|
||||
else end
|
||||
|
||||
-- to repeat a label in a different function is OK
|
||||
local function foo ()
|
||||
local a = {}
|
||||
goto l3
|
||||
::l1:: a[#a + 1] = 1; goto l2;
|
||||
::l2:: a[#a + 1] = 2; goto l5;
|
||||
::l3::
|
||||
::l3a:: a[#a + 1] = 3; goto l1;
|
||||
::l4:: a[#a + 1] = 4; goto l6;
|
||||
::l5:: a[#a + 1] = 5; goto l4;
|
||||
::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and
|
||||
a[4] == 5 and a[5] == 4)
|
||||
if not a[6] then a[6] = true; goto l3a end -- do it twice
|
||||
end
|
||||
|
||||
::l6:: foo()
|
||||
|
||||
|
||||
do -- bug in 5.2 -> 5.3.2
|
||||
local x
|
||||
::L1::
|
||||
local y -- cannot join this SETNIL with previous one
|
||||
assert(y == nil)
|
||||
y = true
|
||||
if x == nil then
|
||||
x = 1
|
||||
goto L1
|
||||
else
|
||||
x = x + 1
|
||||
end
|
||||
assert(x == 2 and y == true)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- testing closing of upvalues
|
||||
|
||||
local debug = require 'debug'
|
||||
|
||||
local function foo ()
|
||||
local t = {}
|
||||
do
|
||||
local i = 1
|
||||
local a, b, c, d
|
||||
t[1] = function () return a, b, c, d end
|
||||
::l1::
|
||||
local b
|
||||
do
|
||||
local c
|
||||
t[#t + 1] = function () return a, b, c, d end -- t[2], t[4], t[6]
|
||||
if i > 2 then goto l2 end
|
||||
do
|
||||
local d
|
||||
t[#t + 1] = function () return a, b, c, d end -- t[3], t[5]
|
||||
i = i + 1
|
||||
local a
|
||||
goto l1
|
||||
end
|
||||
end
|
||||
end
|
||||
::l2:: return t
|
||||
end
|
||||
|
||||
local a = foo()
|
||||
assert(#a == 6)
|
||||
|
||||
-- all functions share same 'a'
|
||||
for i = 2, 6 do
|
||||
assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1))
|
||||
end
|
||||
|
||||
-- 'b' and 'c' are shared among some of them
|
||||
for i = 2, 6 do
|
||||
-- only a[1] uses external 'b'/'b'
|
||||
assert(debug.upvalueid(a[1], 2) ~= debug.upvalueid(a[i], 2))
|
||||
assert(debug.upvalueid(a[1], 3) ~= debug.upvalueid(a[i], 3))
|
||||
end
|
||||
|
||||
for i = 3, 5, 2 do
|
||||
-- inner functions share 'b'/'c' with previous ones
|
||||
assert(debug.upvalueid(a[i], 2) == debug.upvalueid(a[i - 1], 2))
|
||||
assert(debug.upvalueid(a[i], 3) == debug.upvalueid(a[i - 1], 3))
|
||||
-- but not with next ones
|
||||
assert(debug.upvalueid(a[i], 2) ~= debug.upvalueid(a[i + 1], 2))
|
||||
assert(debug.upvalueid(a[i], 3) ~= debug.upvalueid(a[i + 1], 3))
|
||||
end
|
||||
|
||||
-- only external 'd' is shared
|
||||
for i = 2, 6, 2 do
|
||||
assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4))
|
||||
end
|
||||
|
||||
-- internal 'd's are all different
|
||||
for i = 3, 5, 2 do
|
||||
for j = 1, 6 do
|
||||
assert((debug.upvalueid(a[i], 4) == debug.upvalueid(a[j], 4))
|
||||
== (i == j))
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- testing if x goto optimizations
|
||||
|
||||
local function testG (a)
|
||||
if a == 1 then
|
||||
goto l1
|
||||
error("should never be here!")
|
||||
elseif a == 2 then goto l2
|
||||
elseif a == 3 then goto l3
|
||||
elseif a == 4 then
|
||||
goto l1 -- go to inside the block
|
||||
error("should never be here!")
|
||||
::l1:: a = a + 1 -- must go to 'if' end
|
||||
else
|
||||
goto l4
|
||||
::l4a:: a = a * 2; goto l4b
|
||||
error("should never be here!")
|
||||
::l4:: goto l4a
|
||||
error("should never be here!")
|
||||
::l4b::
|
||||
end
|
||||
do return a end
|
||||
::l2:: do return "2" end
|
||||
::l3:: do return "3" end
|
||||
::l1:: return "1"
|
||||
end
|
||||
|
||||
assert(testG(1) == "1")
|
||||
assert(testG(2) == "2")
|
||||
assert(testG(3) == "3")
|
||||
assert(testG(4) == 5)
|
||||
assert(testG(5) == 10)
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
print'OK'
|
302
06/parser-gen/parsers/lua-5.3.4-tests/literals.lua
Normal file
302
06/parser-gen/parsers/lua-5.3.4-tests/literals.lua
Normal file
|
@ -0,0 +1,302 @@
|
|||
-- $Id: literals.lua,v 1.36 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing scanner')
|
||||
|
||||
local debug = require "debug"
|
||||
|
||||
|
||||
local function dostring (x) return assert(load(x), "")() end
|
||||
|
||||
dostring("x \v\f = \t\r 'a\0a' \v\f\f")
|
||||
assert(x == 'a\0a' and string.len(x) == 3)
|
||||
|
||||
-- escape sequences
|
||||
assert('\n\"\'\\' == [[
|
||||
|
||||
"'\]])
|
||||
|
||||
assert(string.find("\a\b\f\n\r\t\v", "^%c%c%c%c%c%c%c$"))
|
||||
|
||||
-- assume ASCII just for tests:
|
||||
assert("\09912" == 'c12')
|
||||
assert("\99ab" == 'cab')
|
||||
assert("\099" == '\99')
|
||||
assert("\099\n" == 'c\10')
|
||||
assert('\0\0\0alo' == '\0' .. '\0\0' .. 'alo')
|
||||
|
||||
assert(010 .. 020 .. -030 == "1020-30")
|
||||
|
||||
-- hexadecimal escapes
|
||||
assert("\x00\x05\x10\x1f\x3C\xfF\xe8" == "\0\5\16\31\60\255\232")
|
||||
|
||||
local function lexstring (x, y, n)
|
||||
local f = assert(load('return ' .. x ..
|
||||
', require"debug".getinfo(1).currentline', ''))
|
||||
local s, l = f()
|
||||
assert(s == y and l == n)
|
||||
end
|
||||
|
||||
lexstring("'abc\\z \n efg'", "abcefg", 2)
|
||||
lexstring("'abc\\z \n\n\n'", "abc", 4)
|
||||
lexstring("'\\z \n\t\f\v\n'", "", 3)
|
||||
lexstring("[[\nalo\nalo\n\n]]", "alo\nalo\n\n", 5)
|
||||
lexstring("[[\nalo\ralo\n\n]]", "alo\nalo\n\n", 5)
|
||||
lexstring("[[\nalo\ralo\r\n]]", "alo\nalo\n", 4)
|
||||
lexstring("[[\ralo\n\ralo\r\n]]", "alo\nalo\n", 4)
|
||||
lexstring("[[alo]\n]alo]]", "alo]\n]alo", 2)
|
||||
|
||||
assert("abc\z
|
||||
def\z
|
||||
ghi\z
|
||||
" == 'abcdefghi')
|
||||
|
||||
|
||||
-- UTF-8 sequences
|
||||
assert("\u{0}\u{00000000}\x00\0" == string.char(0, 0, 0, 0))
|
||||
|
||||
-- limits for 1-byte sequences
|
||||
assert("\u{0}\u{7F}" == "\x00\z\x7F")
|
||||
|
||||
-- limits for 2-byte sequences
|
||||
assert("\u{80}\u{7FF}" == "\xC2\x80\z\xDF\xBF")
|
||||
|
||||
-- limits for 3-byte sequences
|
||||
assert("\u{800}\u{FFFF}" == "\xE0\xA0\x80\z\xEF\xBF\xBF")
|
||||
|
||||
-- limits for 4-byte sequences
|
||||
assert("\u{10000}\u{10FFFF}" == "\xF0\x90\x80\x80\z\xF4\x8F\xBF\xBF")
|
||||
|
||||
|
||||
-- Error in escape sequences
|
||||
local function lexerror (s, err)
|
||||
local st, msg = load('return ' .. s, '')
|
||||
if err ~= '<eof>' then err = err .. "'" end
|
||||
assert(not st and string.find(msg, "near .-" .. err))
|
||||
end
|
||||
|
||||
lexerror([["abc\x"]], [[\x"]])
|
||||
lexerror([["abc\x]], [[\x]])
|
||||
lexerror([["\x]], [[\x]])
|
||||
lexerror([["\x5"]], [[\x5"]])
|
||||
lexerror([["\x5]], [[\x5]])
|
||||
lexerror([["\xr"]], [[\xr]])
|
||||
lexerror([["\xr]], [[\xr]])
|
||||
lexerror([["\x.]], [[\x.]])
|
||||
lexerror([["\x8%"]], [[\x8%%]])
|
||||
lexerror([["\xAG]], [[\xAG]])
|
||||
lexerror([["\g"]], [[\g]])
|
||||
lexerror([["\g]], [[\g]])
|
||||
lexerror([["\."]], [[\%.]])
|
||||
|
||||
lexerror([["\999"]], [[\999"]])
|
||||
lexerror([["xyz\300"]], [[\300"]])
|
||||
lexerror([[" \256"]], [[\256"]])
|
||||
|
||||
-- errors in UTF-8 sequences
|
||||
lexerror([["abc\u{110000}"]], [[abc\u{110000]]) -- too large
|
||||
lexerror([["abc\u11r"]], [[abc\u1]]) -- missing '{'
|
||||
lexerror([["abc\u"]], [[abc\u"]]) -- missing '{'
|
||||
lexerror([["abc\u{11r"]], [[abc\u{11r]]) -- missing '}'
|
||||
lexerror([["abc\u{11"]], [[abc\u{11"]]) -- missing '}'
|
||||
lexerror([["abc\u{11]], [[abc\u{11]]) -- missing '}'
|
||||
lexerror([["abc\u{r"]], [[abc\u{r]]) -- no digits
|
||||
|
||||
-- unfinished strings
|
||||
lexerror("[=[alo]]", "<eof>")
|
||||
lexerror("[=[alo]=", "<eof>")
|
||||
lexerror("[=[alo]", "<eof>")
|
||||
lexerror("'alo", "<eof>")
|
||||
lexerror("'alo \\z \n\n", "<eof>")
|
||||
lexerror("'alo \\z", "<eof>")
|
||||
lexerror([['alo \98]], "<eof>")
|
||||
|
||||
-- valid characters in variable names
|
||||
for i = 0, 255 do
|
||||
local s = string.char(i)
|
||||
assert(not string.find(s, "[a-zA-Z_]") == not load(s .. "=1", ""))
|
||||
assert(not string.find(s, "[a-zA-Z_0-9]") ==
|
||||
not load("a" .. s .. "1 = 1", ""))
|
||||
end
|
||||
|
||||
|
||||
-- long variable names
|
||||
|
||||
var1 = string.rep('a', 15000) .. '1'
|
||||
var2 = string.rep('a', 15000) .. '2'
|
||||
prog = string.format([[
|
||||
%s = 5
|
||||
%s = %s + 1
|
||||
return function () return %s - %s end
|
||||
]], var1, var2, var1, var1, var2)
|
||||
local f = dostring(prog)
|
||||
assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1)
|
||||
var1, var2, f = nil
|
||||
print('+')
|
||||
|
||||
-- escapes --
|
||||
assert("\n\t" == [[
|
||||
|
||||
]])
|
||||
assert([[
|
||||
|
||||
$debug]] == "\n $debug")
|
||||
assert([[ [ ]] ~= [[ ] ]])
|
||||
-- long strings --
|
||||
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
|
||||
assert(string.len(b) == 960)
|
||||
prog = [=[
|
||||
print('+')
|
||||
|
||||
a1 = [["this is a 'string' with several 'quotes'"]]
|
||||
a2 = "'quotes'"
|
||||
|
||||
assert(string.find(a1, a2) == 34)
|
||||
print('+')
|
||||
|
||||
a1 = [==[temp = [[an arbitrary value]]; ]==]
|
||||
assert(load(a1))()
|
||||
assert(temp == 'an arbitrary value')
|
||||
-- long strings --
|
||||
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
|
||||
assert(string.len(b) == 960)
|
||||
print('+')
|
||||
|
||||
a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
00123456789012345678901234567890123456789123456789012345678901234567890123456789
|
||||
]]
|
||||
assert(string.len(a) == 1863)
|
||||
assert(string.sub(a, 1, 40) == string.sub(b, 1, 40))
|
||||
x = 1
|
||||
]=]
|
||||
|
||||
print('+')
|
||||
x = nil
|
||||
dostring(prog)
|
||||
assert(x)
|
||||
|
||||
prog = nil
|
||||
a = nil
|
||||
b = nil
|
||||
|
||||
|
||||
-- testing line ends
|
||||
prog = [[
|
||||
a = 1 -- a comment
|
||||
b = 2
|
||||
|
||||
|
||||
x = [=[
|
||||
hi
|
||||
]=]
|
||||
y = "\
|
||||
hello\r\n\
|
||||
"
|
||||
return require"debug".getinfo(1).currentline
|
||||
]]
|
||||
|
||||
for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do
|
||||
local prog, nn = string.gsub(prog, "\n", n)
|
||||
assert(dostring(prog) == nn)
|
||||
assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
|
||||
end
|
||||
|
||||
|
||||
-- testing comments and strings with long brackets
|
||||
a = [==[]=]==]
|
||||
assert(a == "]=")
|
||||
|
||||
a = [==[[===[[=[]]=][====[]]===]===]==]
|
||||
assert(a == "[===[[=[]]=][====[]]===]===")
|
||||
|
||||
a = [====[[===[[=[]]=][====[]]===]===]====]
|
||||
assert(a == "[===[[=[]]=][====[]]===]===")
|
||||
|
||||
a = [=[]]]]]]]]]=]
|
||||
assert(a == "]]]]]]]]")
|
||||
|
||||
|
||||
--[===[
|
||||
x y z [==[ blu foo
|
||||
]==
|
||||
]
|
||||
]=]==]
|
||||
error error]=]===]
|
||||
|
||||
-- generate all strings of four of these chars
|
||||
local x = {"=", "[", "]", "\n"}
|
||||
local len = 4
|
||||
local function gen (c, n)
|
||||
if n==0 then coroutine.yield(c)
|
||||
else
|
||||
for _, a in pairs(x) do
|
||||
gen(c..a, n-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for s in coroutine.wrap(function () gen("", len) end) do
|
||||
assert(s == load("return [====[\n"..s.."]====]", "")())
|
||||
end
|
||||
|
||||
|
||||
-- testing decimal point locale
|
||||
if os.setlocale("pt_BR") or os.setlocale("ptb") then
|
||||
assert(tonumber("3,4") == 3.4 and tonumber"3.4" == 3.4)
|
||||
assert(tonumber(" -.4 ") == -0.4)
|
||||
assert(tonumber(" +0x.41 ") == 0X0.41)
|
||||
assert(not load("a = (3,4)"))
|
||||
assert(assert(load("return 3.4"))() == 3.4)
|
||||
assert(assert(load("return .4,3"))() == .4)
|
||||
assert(assert(load("return 4."))() == 4.)
|
||||
assert(assert(load("return 4.+.5"))() == 4.5)
|
||||
|
||||
assert(" 0x.1 " + " 0x,1" + "-0X.1\t" == 0x0.1)
|
||||
|
||||
assert(tonumber"inf" == nil and tonumber"NAN" == nil)
|
||||
|
||||
assert(assert(load(string.format("return %q", 4.51)))() == 4.51)
|
||||
|
||||
local a,b = load("return 4.5.")
|
||||
assert(string.find(b, "'4%.5%.'"))
|
||||
|
||||
assert(os.setlocale("C"))
|
||||
else
|
||||
(Message or print)(
|
||||
'\n >>> pt_BR locale not available: skipping decimal point tests <<<\n')
|
||||
end
|
||||
|
||||
|
||||
-- testing %q x line ends
|
||||
local s = "a string with \r and \n and \r\n and \n\r"
|
||||
local c = string.format("return %q", s)
|
||||
assert(assert(load(c))() == s)
|
||||
|
||||
-- testing errors
|
||||
assert(not load"a = 'non-ending string")
|
||||
assert(not load"a = 'non-ending string\n'")
|
||||
assert(not load"a = '\\345'")
|
||||
assert(not load"a = [=x]")
|
||||
|
||||
print('OK')
|
162
06/parser-gen/parsers/lua-5.3.4-tests/locals.lua
Normal file
162
06/parser-gen/parsers/lua-5.3.4-tests/locals.lua
Normal file
|
@ -0,0 +1,162 @@
|
|||
-- $Id: locals.lua,v 1.37 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing local variables and environments')
|
||||
|
||||
local debug = require"debug"
|
||||
|
||||
|
||||
-- bug in 5.1:
|
||||
|
||||
local function f(x) x = nil; return x end
|
||||
assert(f(10) == nil)
|
||||
|
||||
local function f() local x; return x end
|
||||
assert(f(10) == nil)
|
||||
|
||||
local function f(x) x = nil; local y; return x, y end
|
||||
assert(f(10) == nil and select(2, f(20)) == nil)
|
||||
|
||||
do
|
||||
local i = 10
|
||||
do local i = 100; assert(i==100) end
|
||||
do local i = 1000; assert(i==1000) end
|
||||
assert(i == 10)
|
||||
if i ~= 10 then
|
||||
local i = 20
|
||||
else
|
||||
local i = 30
|
||||
assert(i == 30)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
f = nil
|
||||
|
||||
local f
|
||||
x = 1
|
||||
|
||||
a = nil
|
||||
load('local a = {}')()
|
||||
assert(a == nil)
|
||||
|
||||
function f (a)
|
||||
local _1, _2, _3, _4, _5
|
||||
local _6, _7, _8, _9, _10
|
||||
local x = 3
|
||||
local b = a
|
||||
local c,d = a,b
|
||||
if (d == b) then
|
||||
local x = 'q'
|
||||
x = b
|
||||
assert(x == 2)
|
||||
else
|
||||
assert(nil)
|
||||
end
|
||||
assert(x == 3)
|
||||
local f = 10
|
||||
end
|
||||
|
||||
local b=10
|
||||
local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
|
||||
|
||||
|
||||
assert(x == 1)
|
||||
|
||||
f(2)
|
||||
assert(type(f) == 'function')
|
||||
|
||||
|
||||
local function getenv (f)
|
||||
local a,b = debug.getupvalue(f, 1)
|
||||
assert(a == '_ENV')
|
||||
return b
|
||||
end
|
||||
|
||||
-- test for global table of loaded chunks
|
||||
assert(getenv(load"a=3") == _G)
|
||||
local c = {}; local f = load("a = 3", nil, nil, c)
|
||||
assert(getenv(f) == c)
|
||||
assert(c.a == nil)
|
||||
f()
|
||||
assert(c.a == 3)
|
||||
|
||||
-- old test for limits for special instructions (now just a generic test)
|
||||
do
|
||||
local i = 2
|
||||
local p = 4 -- p == 2^i
|
||||
repeat
|
||||
for j=-3,3 do
|
||||
assert(load(string.format([[local a=%s;
|
||||
a=a+%s;
|
||||
assert(a ==2^%s)]], j, p-j, i), '')) ()
|
||||
assert(load(string.format([[local a=%s;
|
||||
a=a-%s;
|
||||
assert(a==-2^%s)]], -j, p-j, i), '')) ()
|
||||
assert(load(string.format([[local a,b=0,%s;
|
||||
a=b-%s;
|
||||
assert(a==-2^%s)]], -j, p-j, i), '')) ()
|
||||
end
|
||||
p = 2 * p; i = i + 1
|
||||
until p <= 0
|
||||
end
|
||||
|
||||
print'+'
|
||||
|
||||
|
||||
if rawget(_G, "querytab") then
|
||||
-- testing clearing of dead elements from tables
|
||||
collectgarbage("stop") -- stop GC
|
||||
local a = {[{}] = 4, [3] = 0, alo = 1,
|
||||
a1234567890123456789012345678901234567890 = 10}
|
||||
|
||||
local t = querytab(a)
|
||||
|
||||
for k,_ in pairs(a) do a[k] = nil end
|
||||
collectgarbage() -- restore GC and collect dead fiels in `a'
|
||||
for i=0,t-1 do
|
||||
local k = querytab(a, i)
|
||||
assert(k == nil or type(k) == 'number' or k == 'alo')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- testing lexical environments
|
||||
|
||||
assert(_ENV == _G)
|
||||
|
||||
do
|
||||
local dummy
|
||||
local _ENV = (function (...) return ... end)(_G, dummy) -- {
|
||||
|
||||
do local _ENV = {assert=assert}; assert(true) end
|
||||
mt = {_G = _G}
|
||||
local foo,x
|
||||
A = false -- "declare" A
|
||||
do local _ENV = mt
|
||||
function foo (x)
|
||||
A = x
|
||||
do local _ENV = _G; A = 1000 end
|
||||
return function (x) return A .. x end
|
||||
end
|
||||
end
|
||||
assert(getenv(foo) == mt)
|
||||
x = foo('hi'); assert(mt.A == 'hi' and A == 1000)
|
||||
assert(x('*') == mt.A .. '*')
|
||||
|
||||
do local _ENV = {assert=assert, A=10};
|
||||
do local _ENV = {assert=assert, A=20};
|
||||
assert(A==20);x=A
|
||||
end
|
||||
assert(A==10 and x==20)
|
||||
end
|
||||
assert(x==20)
|
||||
|
||||
|
||||
print('OK')
|
||||
|
||||
return 5,f
|
||||
|
||||
end -- }
|
||||
|
381
06/parser-gen/parsers/lua-5.3.4-tests/main.lua
Normal file
381
06/parser-gen/parsers/lua-5.3.4-tests/main.lua
Normal file
|
@ -0,0 +1,381 @@
|
|||
#! testing special comment on first line
|
||||
-- $Id: main.lua,v 1.65 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
-- most (all?) tests here assume a reasonable "Unix-like" shell
|
||||
if _port then return end
|
||||
|
||||
-- use only "double quotes" inside shell scripts (better change to
|
||||
-- run on Windows)
|
||||
|
||||
|
||||
print ("testing stand-alone interpreter")
|
||||
|
||||
assert(os.execute()) -- machine has a system command
|
||||
|
||||
local arg = arg or _ARG
|
||||
|
||||
local prog = os.tmpname()
|
||||
local otherprog = os.tmpname()
|
||||
local out = os.tmpname()
|
||||
|
||||
local progname
|
||||
do
|
||||
local i = 0
|
||||
while arg[i] do i=i-1 end
|
||||
progname = arg[i+1]
|
||||
end
|
||||
print("progname: "..progname)
|
||||
|
||||
local prepfile = function (s, p)
|
||||
p = p or prog
|
||||
io.output(p)
|
||||
io.write(s)
|
||||
assert(io.close())
|
||||
end
|
||||
|
||||
local function getoutput ()
|
||||
io.input(out)
|
||||
local t = io.read("a")
|
||||
io.input():close()
|
||||
assert(os.remove(out))
|
||||
return t
|
||||
end
|
||||
|
||||
local function checkprogout (s)
|
||||
local t = getoutput()
|
||||
for line in string.gmatch(s, ".-\n") do
|
||||
assert(string.find(t, line, 1, true))
|
||||
end
|
||||
end
|
||||
|
||||
local function checkout (s)
|
||||
local t = getoutput()
|
||||
if s ~= t then print(string.format("'%s' - '%s'\n", s, t)) end
|
||||
assert(s == t)
|
||||
return t
|
||||
end
|
||||
|
||||
|
||||
local function RUN (p, ...)
|
||||
p = string.gsub(p, "lua", '"'..progname..'"', 1)
|
||||
local s = string.format(p, ...)
|
||||
assert(os.execute(s))
|
||||
end
|
||||
|
||||
local function NoRun (msg, p, ...)
|
||||
p = string.gsub(p, "lua", '"'..progname..'"', 1)
|
||||
local s = string.format(p, ...)
|
||||
s = string.format("%s 2> %s", s, out) -- will send error to 'out'
|
||||
assert(not os.execute(s))
|
||||
assert(string.find(getoutput(), msg, 1, true)) -- check error message
|
||||
end
|
||||
|
||||
RUN('lua -v')
|
||||
|
||||
print(string.format("(temporary program file used in these tests: %s)", prog))
|
||||
|
||||
-- running stdin as a file
|
||||
prepfile""
|
||||
RUN('lua - < %s > %s', prog, out)
|
||||
checkout("")
|
||||
|
||||
prepfile[[
|
||||
print(
|
||||
1, a
|
||||
)
|
||||
]]
|
||||
RUN('lua - < %s > %s', prog, out)
|
||||
checkout("1\tnil\n")
|
||||
|
||||
RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
|
||||
checkout("10\n2\n")
|
||||
|
||||
|
||||
-- test option '-'
|
||||
RUN('echo "print(arg[1])" | lua - -h > %s', out)
|
||||
checkout("-h\n")
|
||||
|
||||
-- test environment variables used by Lua
|
||||
|
||||
prepfile("print(package.path)")
|
||||
|
||||
-- test LUA_PATH
|
||||
RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out)
|
||||
checkout("x\n")
|
||||
|
||||
-- test LUA_PATH_version
|
||||
RUN('env LUA_INIT= LUA_PATH_5_3=y LUA_PATH=x lua %s > %s', prog, out)
|
||||
checkout("y\n")
|
||||
|
||||
-- test LUA_CPATH
|
||||
prepfile("print(package.cpath)")
|
||||
RUN('env LUA_INIT= LUA_CPATH=xuxu lua %s > %s', prog, out)
|
||||
checkout("xuxu\n")
|
||||
|
||||
-- test LUA_CPATH_version
|
||||
RUN('env LUA_INIT= LUA_CPATH_5_3=yacc LUA_CPATH=x lua %s > %s', prog, out)
|
||||
checkout("yacc\n")
|
||||
|
||||
-- test LUA_INIT (and its access to 'arg' table)
|
||||
prepfile("print(X)")
|
||||
RUN('env LUA_INIT="X=tonumber(arg[1])" lua %s 3.2 > %s', prog, out)
|
||||
checkout("3.2\n")
|
||||
|
||||
-- test LUA_INIT_version
|
||||
prepfile("print(X)")
|
||||
RUN('env LUA_INIT_5_3="X=10" LUA_INIT="X=3" lua %s > %s', prog, out)
|
||||
checkout("10\n")
|
||||
|
||||
-- test LUA_INIT for files
|
||||
prepfile("x = x or 10; print(x); x = x + 1")
|
||||
RUN('env LUA_INIT="@%s" lua %s > %s', prog, prog, out)
|
||||
checkout("10\n11\n")
|
||||
|
||||
-- test errors in LUA_INIT
|
||||
NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua')
|
||||
|
||||
-- test option '-E'
|
||||
local defaultpath, defaultCpath
|
||||
|
||||
do
|
||||
prepfile("print(package.path, package.cpath)")
|
||||
RUN('env LUA_INIT="error(10)" LUA_PATH=xxx LUA_CPATH=xxx lua -E %s > %s',
|
||||
prog, out)
|
||||
local out = getoutput()
|
||||
defaultpath = string.match(out, "^(.-)\t")
|
||||
defaultCpath = string.match(out, "\t(.-)$")
|
||||
end
|
||||
|
||||
-- paths did not changed
|
||||
assert(not string.find(defaultpath, "xxx") and
|
||||
string.find(defaultpath, "lua") and
|
||||
not string.find(defaultCpath, "xxx") and
|
||||
string.find(defaultCpath, "lua"))
|
||||
|
||||
|
||||
-- test replacement of ';;' to default path
|
||||
local function convert (p)
|
||||
prepfile("print(package.path)")
|
||||
RUN('env LUA_PATH="%s" lua %s > %s', p, prog, out)
|
||||
local expected = getoutput()
|
||||
expected = string.sub(expected, 1, -2) -- cut final end of line
|
||||
assert(string.gsub(p, ";;", ";"..defaultpath..";") == expected)
|
||||
end
|
||||
|
||||
convert(";")
|
||||
convert(";;")
|
||||
convert(";;;")
|
||||
convert(";;;;")
|
||||
convert(";;;;;")
|
||||
convert(";;a;;;bc")
|
||||
|
||||
|
||||
-- test -l over multiple libraries
|
||||
prepfile("print(1); a=2; return {x=15}")
|
||||
prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog)
|
||||
RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out)
|
||||
checkout("1\n2\n15\n2\n15\n")
|
||||
|
||||
-- test 'arg' table
|
||||
local a = [[
|
||||
assert(#arg == 3 and arg[1] == 'a' and
|
||||
arg[2] == 'b' and arg[3] == 'c')
|
||||
assert(arg[-1] == '--' and arg[-2] == "-e " and arg[-3] == '%s')
|
||||
assert(arg[4] == nil and arg[-4] == nil)
|
||||
local a, b, c = ...
|
||||
assert(... == 'a' and a == 'a' and b == 'b' and c == 'c')
|
||||
]]
|
||||
a = string.format(a, progname)
|
||||
prepfile(a)
|
||||
RUN('lua "-e " -- %s a b c', prog) -- "-e " runs an empty command
|
||||
|
||||
-- test 'arg' availability in libraries
|
||||
prepfile"assert(arg)"
|
||||
prepfile("assert(arg)", otherprog)
|
||||
RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog)
|
||||
|
||||
-- test messing up the 'arg' table
|
||||
RUN('echo "print(...)" | lua -e "arg[1] = 100" - > %s', out)
|
||||
checkout("100\n")
|
||||
NoRun("'arg' is not a table", 'echo "" | lua -e "arg = 1" -')
|
||||
|
||||
-- test error in 'print'
|
||||
RUN('echo 10 | lua -e "print=nil" -i > /dev/null 2> %s', out)
|
||||
assert(string.find(getoutput(), "error calling 'print'"))
|
||||
|
||||
-- test 'debug.debug'
|
||||
RUN('echo "io.stderr:write(1000)\ncont" | lua -e "require\'debug\'.debug()" 2> %s', out)
|
||||
checkout("lua_debug> 1000lua_debug> ")
|
||||
|
||||
-- test many arguments
|
||||
prepfile[[print(({...})[30])]]
|
||||
RUN('lua %s %s > %s', prog, string.rep(" a", 30), out)
|
||||
checkout("a\n")
|
||||
|
||||
RUN([[lua "-eprint(1)" -ea=3 -e "print(a)" > %s]], out)
|
||||
checkout("1\n3\n")
|
||||
|
||||
-- test iteractive mode
|
||||
prepfile[[
|
||||
(6*2-6) -- ===
|
||||
a =
|
||||
10
|
||||
print(a)
|
||||
a]]
|
||||
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
|
||||
checkprogout("6\n10\n10\n\n")
|
||||
|
||||
prepfile("a = [[b\nc\nd\ne]]\n=a")
|
||||
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
|
||||
checkprogout("b\nc\nd\ne\n\n")
|
||||
|
||||
prompt = "alo"
|
||||
prepfile[[ --
|
||||
a = 2
|
||||
]]
|
||||
RUN([[lua "-e_PROMPT='%s'" -i < %s > %s]], prompt, prog, out)
|
||||
local t = getoutput()
|
||||
assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt))
|
||||
|
||||
-- test for error objects
|
||||
prepfile[[
|
||||
debug = require "debug"
|
||||
m = {x=0}
|
||||
setmetatable(m, {__tostring = function(x)
|
||||
return tostring(debug.getinfo(4).currentline + x.x)
|
||||
end})
|
||||
error(m)
|
||||
]]
|
||||
NoRun(progname .. ": 6\n", [[lua %s]], prog)
|
||||
|
||||
prepfile("error{}")
|
||||
NoRun("error object is a table value", [[lua %s]], prog)
|
||||
|
||||
|
||||
-- chunk broken in many lines
|
||||
s = [=[ --
|
||||
function f ( x )
|
||||
local a = [[
|
||||
xuxu
|
||||
]]
|
||||
local b = "\
|
||||
xuxu\n"
|
||||
if x == 11 then return 1 + 12 , 2 + 20 end --[[ test multiple returns ]]
|
||||
return x + 1
|
||||
--\\
|
||||
end
|
||||
return( f( 100 ) )
|
||||
assert( a == b )
|
||||
do return f( 11 ) end ]=]
|
||||
s = string.gsub(s, ' ', '\n\n') -- change all spaces for newlines
|
||||
prepfile(s)
|
||||
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
|
||||
checkprogout("101\n13\t22\n\n")
|
||||
|
||||
prepfile[[#comment in 1st line without \n at the end]]
|
||||
RUN('lua %s', prog)
|
||||
|
||||
prepfile[[#test line number when file starts with comment line
|
||||
debug = require"debug"
|
||||
print(debug.getinfo(1).currentline)
|
||||
]]
|
||||
RUN('lua %s > %s', prog, out)
|
||||
checkprogout('3')
|
||||
|
||||
-- close Lua with an open file
|
||||
prepfile(string.format([[io.output(%q); io.write('alo')]], out))
|
||||
RUN('lua %s', prog)
|
||||
checkout('alo')
|
||||
|
||||
-- bug in 5.2 beta (extra \0 after version line)
|
||||
RUN([[lua -v -e"print'hello'" > %s]], out)
|
||||
t = getoutput()
|
||||
assert(string.find(t, "PUC%-Rio\nhello"))
|
||||
|
||||
|
||||
-- testing os.exit
|
||||
prepfile("os.exit(nil, true)")
|
||||
RUN('lua %s', prog)
|
||||
prepfile("os.exit(0, true)")
|
||||
RUN('lua %s', prog)
|
||||
prepfile("os.exit(true, true)")
|
||||
RUN('lua %s', prog)
|
||||
prepfile("os.exit(1, true)")
|
||||
NoRun("", "lua %s", prog) -- no message
|
||||
prepfile("os.exit(false, true)")
|
||||
NoRun("", "lua %s", prog) -- no message
|
||||
|
||||
-- remove temporary files
|
||||
assert(os.remove(prog))
|
||||
assert(os.remove(otherprog))
|
||||
assert(not os.remove(out))
|
||||
|
||||
-- invalid options
|
||||
NoRun("unrecognized option '-h'", "lua -h")
|
||||
NoRun("unrecognized option '---'", "lua ---")
|
||||
NoRun("unrecognized option '-Ex'", "lua -Ex")
|
||||
NoRun("unrecognized option '-vv'", "lua -vv")
|
||||
NoRun("unrecognized option '-iv'", "lua -iv")
|
||||
NoRun("'-e' needs argument", "lua -e")
|
||||
NoRun("syntax error", "lua -e a")
|
||||
NoRun("'-l' needs argument", "lua -l")
|
||||
|
||||
|
||||
if T then -- auxiliary library?
|
||||
print("testing 'not enough memory' to create a state")
|
||||
NoRun("not enough memory", "env MEMLIMIT=100 lua")
|
||||
end
|
||||
print('+')
|
||||
|
||||
print('testing Ctrl C')
|
||||
do
|
||||
-- interrupt a script
|
||||
local function kill (pid)
|
||||
return os.execute(string.format('kill -INT %d 2> /dev/null', pid))
|
||||
end
|
||||
|
||||
-- function to run a script in background, returning its output file
|
||||
-- descriptor and its pid
|
||||
local function runback (luaprg)
|
||||
-- shell script to run 'luaprg' in background and echo its pid
|
||||
local shellprg = string.format('%s -e "%s" & echo $!', progname, luaprg)
|
||||
local f = io.popen(shellprg, "r") -- run shell script
|
||||
local pid = f:read() -- get pid for Lua script
|
||||
print("(if test fails now, it may leave a Lua script running in \z
|
||||
background, pid " .. pid .. ")")
|
||||
return f, pid
|
||||
end
|
||||
|
||||
-- Lua script that runs protected infinite loop and then prints '42'
|
||||
local f, pid = runback[[
|
||||
pcall(function () print(12); while true do end end); print(42)]]
|
||||
-- wait until script is inside 'pcall'
|
||||
assert(f:read() == "12")
|
||||
kill(pid) -- send INT signal to Lua script
|
||||
-- check that 'pcall' captured the exception and script continued running
|
||||
assert(f:read() == "42") -- expected output
|
||||
assert(f:close())
|
||||
print("done")
|
||||
|
||||
-- Lua script in a long unbreakable search
|
||||
local f, pid = runback[[
|
||||
print(15); string.find(string.rep('a', 100000), '.*b')]]
|
||||
-- wait (so script can reach the loop)
|
||||
assert(f:read() == "15")
|
||||
assert(os.execute("sleep 1"))
|
||||
-- must send at least two INT signals to stop this Lua script
|
||||
local n = 100
|
||||
for i = 0, 100 do -- keep sending signals
|
||||
if not kill(pid) then -- until it fails
|
||||
n = i -- number of non-failed kills
|
||||
break
|
||||
end
|
||||
end
|
||||
assert(f:close())
|
||||
assert(n >= 2)
|
||||
print(string.format("done (with %d kills)", n))
|
||||
|
||||
end
|
||||
|
||||
print("OK")
|
824
06/parser-gen/parsers/lua-5.3.4-tests/math.lua
Normal file
824
06/parser-gen/parsers/lua-5.3.4-tests/math.lua
Normal file
|
@ -0,0 +1,824 @@
|
|||
-- $Id: math.lua,v 1.78 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print("testing numbers and math lib")
|
||||
|
||||
local minint = math.mininteger
|
||||
local maxint = math.maxinteger
|
||||
|
||||
local intbits = math.floor(math.log(maxint, 2) + 0.5) + 1
|
||||
assert((1 << intbits) == 0)
|
||||
|
||||
assert(minint == 1 << (intbits - 1))
|
||||
assert(maxint == minint - 1)
|
||||
|
||||
-- number of bits in the mantissa of a floating-point number
|
||||
local floatbits = 24
|
||||
do
|
||||
local p = 2.0^floatbits
|
||||
while p < p + 1.0 do
|
||||
p = p * 2.0
|
||||
floatbits = floatbits + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function isNaN (x)
|
||||
return (x ~= x)
|
||||
end
|
||||
|
||||
assert(isNaN(0/0))
|
||||
assert(not isNaN(1/0))
|
||||
|
||||
|
||||
do
|
||||
local x = 2.0^floatbits
|
||||
assert(x > x - 1.0 and x == x + 1.0)
|
||||
|
||||
print(string.format("%d-bit integers, %d-bit (mantissa) floats",
|
||||
intbits, floatbits))
|
||||
end
|
||||
|
||||
assert(math.type(0) == "integer" and math.type(0.0) == "float"
|
||||
and math.type("10") == nil)
|
||||
|
||||
|
||||
local function checkerror (msg, f, ...)
|
||||
local s, err = pcall(f, ...)
|
||||
assert(not s and string.find(err, msg))
|
||||
end
|
||||
|
||||
local msgf2i = "number.* has no integer representation"
|
||||
|
||||
-- float equality
|
||||
function eq (a,b,limit)
|
||||
if not limit then
|
||||
if floatbits >= 50 then limit = 1E-11
|
||||
else limit = 1E-5
|
||||
end
|
||||
end
|
||||
-- a == b needed for +inf/-inf
|
||||
return a == b or math.abs(a-b) <= limit
|
||||
end
|
||||
|
||||
|
||||
-- equality with types
|
||||
function eqT (a,b)
|
||||
return a == b and math.type(a) == math.type(b)
|
||||
end
|
||||
|
||||
|
||||
-- basic float notation
|
||||
assert(0e12 == 0 and .0 == 0 and 0. == 0 and .2e2 == 20 and 2.E-1 == 0.2)
|
||||
|
||||
do
|
||||
local a,b,c = "2", " 3e0 ", " 10 "
|
||||
assert(a+b == 5 and -b == -3 and b+"2" == 5 and "10"-c == 0)
|
||||
assert(type(a) == 'string' and type(b) == 'string' and type(c) == 'string')
|
||||
assert(a == "2" and b == " 3e0 " and c == " 10 " and -c == -" 10 ")
|
||||
assert(c%a == 0 and a^b == 08)
|
||||
a = 0
|
||||
assert(a == -a and 0 == -0)
|
||||
end
|
||||
|
||||
do
|
||||
local x = -1
|
||||
local mz = 0/x -- minus zero
|
||||
t = {[0] = 10, 20, 30, 40, 50}
|
||||
assert(t[mz] == t[0] and t[-0] == t[0])
|
||||
end
|
||||
|
||||
do -- tests for 'modf'
|
||||
local a,b = math.modf(3.5)
|
||||
assert(a == 3.0 and b == 0.5)
|
||||
a,b = math.modf(-2.5)
|
||||
assert(a == -2.0 and b == -0.5)
|
||||
a,b = math.modf(-3e23)
|
||||
assert(a == -3e23 and b == 0.0)
|
||||
a,b = math.modf(3e35)
|
||||
assert(a == 3e35 and b == 0.0)
|
||||
a,b = math.modf(-1/0) -- -inf
|
||||
assert(a == -1/0 and b == 0.0)
|
||||
a,b = math.modf(1/0) -- inf
|
||||
assert(a == 1/0 and b == 0.0)
|
||||
a,b = math.modf(0/0) -- NaN
|
||||
assert(isNaN(a) and isNaN(b))
|
||||
a,b = math.modf(3) -- integer argument
|
||||
assert(eqT(a, 3) and eqT(b, 0.0))
|
||||
a,b = math.modf(minint)
|
||||
assert(eqT(a, minint) and eqT(b, 0.0))
|
||||
end
|
||||
|
||||
assert(math.huge > 10e30)
|
||||
assert(-math.huge < -10e30)
|
||||
|
||||
|
||||
-- integer arithmetic
|
||||
assert(minint < minint + 1)
|
||||
assert(maxint - 1 < maxint)
|
||||
assert(0 - minint == minint)
|
||||
assert(minint * minint == 0)
|
||||
assert(maxint * maxint * maxint == maxint)
|
||||
|
||||
|
||||
-- testing floor division and conversions
|
||||
|
||||
for _, i in pairs{-16, -15, -3, -2, -1, 0, 1, 2, 3, 15} do
|
||||
for _, j in pairs{-16, -15, -3, -2, -1, 1, 2, 3, 15} do
|
||||
for _, ti in pairs{0, 0.0} do -- try 'i' as integer and as float
|
||||
for _, tj in pairs{0, 0.0} do -- try 'j' as integer and as float
|
||||
local x = i + ti
|
||||
local y = j + tj
|
||||
assert(i//j == math.floor(i/j))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert(1//0.0 == 1/0)
|
||||
assert(-1 // 0.0 == -1/0)
|
||||
assert(eqT(3.5 // 1.5, 2.0))
|
||||
assert(eqT(3.5 // -1.5, -3.0))
|
||||
|
||||
assert(maxint // maxint == 1)
|
||||
assert(maxint // 1 == maxint)
|
||||
assert((maxint - 1) // maxint == 0)
|
||||
assert(maxint // (maxint - 1) == 1)
|
||||
assert(minint // minint == 1)
|
||||
assert(minint // minint == 1)
|
||||
assert((minint + 1) // minint == 0)
|
||||
assert(minint // (minint + 1) == 1)
|
||||
assert(minint // 1 == minint)
|
||||
|
||||
assert(minint // -1 == -minint)
|
||||
assert(minint // -2 == 2^(intbits - 2))
|
||||
assert(maxint // -1 == -maxint)
|
||||
|
||||
|
||||
-- negative exponents
|
||||
do
|
||||
assert(2^-3 == 1 / 2^3)
|
||||
assert(eq((-3)^-3, 1 / (-3)^3))
|
||||
for i = -3, 3 do -- variables avoid constant folding
|
||||
for j = -3, 3 do
|
||||
-- domain errors (0^(-n)) are not portable
|
||||
if not _port or i ~= 0 or j > 0 then
|
||||
assert(eq(i^j, 1 / i^(-j)))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- comparison between floats and integers (border cases)
|
||||
if floatbits < intbits then
|
||||
assert(2.0^floatbits == (1 << floatbits))
|
||||
assert(2.0^floatbits - 1.0 == (1 << floatbits) - 1.0)
|
||||
assert(2.0^floatbits - 1.0 ~= (1 << floatbits))
|
||||
-- float is rounded, int is not
|
||||
assert(2.0^floatbits + 1.0 ~= (1 << floatbits) + 1)
|
||||
else -- floats can express all integers with full accuracy
|
||||
assert(maxint == maxint + 0.0)
|
||||
assert(maxint - 1 == maxint - 1.0)
|
||||
assert(minint + 1 == minint + 1.0)
|
||||
assert(maxint ~= maxint - 1.0)
|
||||
end
|
||||
assert(maxint + 0.0 == 2.0^(intbits - 1) - 1.0)
|
||||
assert(minint + 0.0 == minint)
|
||||
assert(minint + 0.0 == -2.0^(intbits - 1))
|
||||
|
||||
|
||||
-- order between floats and integers
|
||||
assert(1 < 1.1); assert(not (1 < 0.9))
|
||||
assert(1 <= 1.1); assert(not (1 <= 0.9))
|
||||
assert(-1 < -0.9); assert(not (-1 < -1.1))
|
||||
assert(1 <= 1.1); assert(not (-1 <= -1.1))
|
||||
assert(-1 < -0.9); assert(not (-1 < -1.1))
|
||||
assert(-1 <= -0.9); assert(not (-1 <= -1.1))
|
||||
assert(minint <= minint + 0.0)
|
||||
assert(minint + 0.0 <= minint)
|
||||
assert(not (minint < minint + 0.0))
|
||||
assert(not (minint + 0.0 < minint))
|
||||
assert(maxint < minint * -1.0)
|
||||
assert(maxint <= minint * -1.0)
|
||||
|
||||
do
|
||||
local fmaxi1 = 2^(intbits - 1)
|
||||
assert(maxint < fmaxi1)
|
||||
assert(maxint <= fmaxi1)
|
||||
assert(not (fmaxi1 <= maxint))
|
||||
assert(minint <= -2^(intbits - 1))
|
||||
assert(-2^(intbits - 1) <= minint)
|
||||
end
|
||||
|
||||
if floatbits < intbits then
|
||||
print("testing order (floats cannot represent all integers)")
|
||||
local fmax = 2^floatbits
|
||||
local ifmax = fmax | 0
|
||||
assert(fmax < ifmax + 1)
|
||||
assert(fmax - 1 < ifmax)
|
||||
assert(-(fmax - 1) > -ifmax)
|
||||
assert(not (fmax <= ifmax - 1))
|
||||
assert(-fmax > -(ifmax + 1))
|
||||
assert(not (-fmax >= -(ifmax - 1)))
|
||||
|
||||
assert(fmax/2 - 0.5 < ifmax//2)
|
||||
assert(-(fmax/2 - 0.5) > -ifmax//2)
|
||||
|
||||
assert(maxint < 2^intbits)
|
||||
assert(minint > -2^intbits)
|
||||
assert(maxint <= 2^intbits)
|
||||
assert(minint >= -2^intbits)
|
||||
else
|
||||
print("testing order (floats can represent all integers)")
|
||||
assert(maxint < maxint + 1.0)
|
||||
assert(maxint < maxint + 0.5)
|
||||
assert(maxint - 1.0 < maxint)
|
||||
assert(maxint - 0.5 < maxint)
|
||||
assert(not (maxint + 0.0 < maxint))
|
||||
assert(maxint + 0.0 <= maxint)
|
||||
assert(not (maxint < maxint + 0.0))
|
||||
assert(maxint + 0.0 <= maxint)
|
||||
assert(maxint <= maxint + 0.0)
|
||||
assert(not (maxint + 1.0 <= maxint))
|
||||
assert(not (maxint + 0.5 <= maxint))
|
||||
assert(not (maxint <= maxint - 1.0))
|
||||
assert(not (maxint <= maxint - 0.5))
|
||||
|
||||
assert(minint < minint + 1.0)
|
||||
assert(minint < minint + 0.5)
|
||||
assert(minint <= minint + 0.5)
|
||||
assert(minint - 1.0 < minint)
|
||||
assert(minint - 1.0 <= minint)
|
||||
assert(not (minint + 0.0 < minint))
|
||||
assert(not (minint + 0.5 < minint))
|
||||
assert(not (minint < minint + 0.0))
|
||||
assert(minint + 0.0 <= minint)
|
||||
assert(minint <= minint + 0.0)
|
||||
assert(not (minint + 1.0 <= minint))
|
||||
assert(not (minint + 0.5 <= minint))
|
||||
assert(not (minint <= minint - 1.0))
|
||||
end
|
||||
|
||||
do
|
||||
local NaN = 0/0
|
||||
assert(not (NaN < 0))
|
||||
assert(not (NaN > minint))
|
||||
assert(not (NaN <= -9))
|
||||
assert(not (NaN <= maxint))
|
||||
assert(not (NaN < maxint))
|
||||
assert(not (minint <= NaN))
|
||||
assert(not (minint < NaN))
|
||||
end
|
||||
|
||||
|
||||
-- avoiding errors at compile time
|
||||
local function checkcompt (msg, code)
|
||||
checkerror(msg, assert(load(code)))
|
||||
end
|
||||
checkcompt("divide by zero", "return 2 // 0")
|
||||
checkcompt(msgf2i, "return 2.3 >> 0")
|
||||
checkcompt(msgf2i, ("return 2.0^%d & 1"):format(intbits - 1))
|
||||
checkcompt("field 'huge'", "return math.huge << 1")
|
||||
checkcompt(msgf2i, ("return 1 | 2.0^%d"):format(intbits - 1))
|
||||
checkcompt(msgf2i, "return 2.3 ~ '0.0'")
|
||||
|
||||
|
||||
-- testing overflow errors when converting from float to integer (runtime)
|
||||
local function f2i (x) return x | x end
|
||||
checkerror(msgf2i, f2i, math.huge) -- +inf
|
||||
checkerror(msgf2i, f2i, -math.huge) -- -inf
|
||||
checkerror(msgf2i, f2i, 0/0) -- NaN
|
||||
|
||||
if floatbits < intbits then
|
||||
-- conversion tests when float cannot represent all integers
|
||||
assert(maxint + 1.0 == maxint + 0.0)
|
||||
assert(minint - 1.0 == minint + 0.0)
|
||||
checkerror(msgf2i, f2i, maxint + 0.0)
|
||||
assert(f2i(2.0^(intbits - 2)) == 1 << (intbits - 2))
|
||||
assert(f2i(-2.0^(intbits - 2)) == -(1 << (intbits - 2)))
|
||||
assert((2.0^(floatbits - 1) + 1.0) // 1 == (1 << (floatbits - 1)) + 1)
|
||||
-- maximum integer representable as a float
|
||||
local mf = maxint - (1 << (floatbits - intbits)) + 1
|
||||
assert(f2i(mf + 0.0) == mf) -- OK up to here
|
||||
mf = mf + 1
|
||||
assert(f2i(mf + 0.0) ~= mf) -- no more representable
|
||||
else
|
||||
-- conversion tests when float can represent all integers
|
||||
assert(maxint + 1.0 > maxint)
|
||||
assert(minint - 1.0 < minint)
|
||||
assert(f2i(maxint + 0.0) == maxint)
|
||||
checkerror("no integer rep", f2i, maxint + 1.0)
|
||||
checkerror("no integer rep", f2i, minint - 1.0)
|
||||
end
|
||||
|
||||
-- 'minint' should be representable as a float no matter the precision
|
||||
assert(f2i(minint + 0.0) == minint)
|
||||
|
||||
|
||||
-- testing numeric strings
|
||||
|
||||
assert("2" + 1 == 3)
|
||||
assert("2 " + 1 == 3)
|
||||
assert(" -2 " + 1 == -1)
|
||||
assert(" -0xa " + 1 == -9)
|
||||
|
||||
|
||||
-- Literal integer Overflows (new behavior in 5.3.3)
|
||||
do
|
||||
-- no overflows
|
||||
assert(eqT(tonumber(tostring(maxint)), maxint))
|
||||
assert(eqT(tonumber(tostring(minint)), minint))
|
||||
|
||||
-- add 1 to last digit as a string (it cannot be 9...)
|
||||
local function incd (n)
|
||||
local s = string.format("%d", n)
|
||||
s = string.gsub(s, "%d$", function (d)
|
||||
assert(d ~= '9')
|
||||
return string.char(string.byte(d) + 1)
|
||||
end)
|
||||
return s
|
||||
end
|
||||
|
||||
-- 'tonumber' with overflow by 1
|
||||
assert(eqT(tonumber(incd(maxint)), maxint + 1.0))
|
||||
assert(eqT(tonumber(incd(minint)), minint - 1.0))
|
||||
|
||||
-- large numbers
|
||||
assert(eqT(tonumber("1"..string.rep("0", 30)), 1e30))
|
||||
assert(eqT(tonumber("-1"..string.rep("0", 30)), -1e30))
|
||||
|
||||
-- hexa format still wraps around
|
||||
assert(eqT(tonumber("0x1"..string.rep("0", 30)), 0))
|
||||
|
||||
-- lexer in the limits
|
||||
assert(minint == load("return " .. minint)())
|
||||
assert(eqT(maxint, load("return " .. maxint)()))
|
||||
|
||||
assert(eqT(10000000000000000000000.0, 10000000000000000000000))
|
||||
assert(eqT(-10000000000000000000000.0, -10000000000000000000000))
|
||||
end
|
||||
|
||||
|
||||
-- testing 'tonumber'
|
||||
|
||||
-- 'tonumber' with numbers
|
||||
assert(tonumber(3.4) == 3.4)
|
||||
assert(eqT(tonumber(3), 3))
|
||||
assert(eqT(tonumber(maxint), maxint) and eqT(tonumber(minint), minint))
|
||||
assert(tonumber(1/0) == 1/0)
|
||||
|
||||
-- 'tonumber' with strings
|
||||
assert(tonumber("0") == 0)
|
||||
assert(tonumber("") == nil)
|
||||
assert(tonumber(" ") == nil)
|
||||
assert(tonumber("-") == nil)
|
||||
assert(tonumber(" -0x ") == nil)
|
||||
assert(tonumber{} == nil)
|
||||
assert(tonumber'+0.01' == 1/100 and tonumber'+.01' == 0.01 and
|
||||
tonumber'.01' == 0.01 and tonumber'-1.' == -1 and
|
||||
tonumber'+1.' == 1)
|
||||
assert(tonumber'+ 0.01' == nil and tonumber'+.e1' == nil and
|
||||
tonumber'1e' == nil and tonumber'1.0e+' == nil and
|
||||
tonumber'.' == nil)
|
||||
assert(tonumber('-012') == -010-2)
|
||||
assert(tonumber('-1.2e2') == - - -120)
|
||||
|
||||
assert(tonumber("0xffffffffffff") == (1 << (4*12)) - 1)
|
||||
assert(tonumber("0x"..string.rep("f", (intbits//4))) == -1)
|
||||
assert(tonumber("-0x"..string.rep("f", (intbits//4))) == 1)
|
||||
|
||||
-- testing 'tonumber' with base
|
||||
assert(tonumber(' 001010 ', 2) == 10)
|
||||
assert(tonumber(' 001010 ', 10) == 001010)
|
||||
assert(tonumber(' -1010 ', 2) == -10)
|
||||
assert(tonumber('10', 36) == 36)
|
||||
assert(tonumber(' -10 ', 36) == -36)
|
||||
assert(tonumber(' +1Z ', 36) == 36 + 35)
|
||||
assert(tonumber(' -1z ', 36) == -36 + -35)
|
||||
assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15)))))))
|
||||
assert(tonumber(string.rep('1', (intbits - 2)), 2) + 1 == 2^(intbits - 2))
|
||||
assert(tonumber('ffffFFFF', 16)+1 == (1 << 32))
|
||||
assert(tonumber('0ffffFFFF', 16)+1 == (1 << 32))
|
||||
assert(tonumber('-0ffffffFFFF', 16) - 1 == -(1 << 40))
|
||||
for i = 2,36 do
|
||||
local i2 = i * i
|
||||
local i10 = i2 * i2 * i2 * i2 * i2 -- i^10
|
||||
assert(tonumber('\t10000000000\t', i) == i10)
|
||||
end
|
||||
|
||||
if not _soft then
|
||||
-- tests with very long numerals
|
||||
assert(tonumber("0x"..string.rep("f", 13)..".0") == 2.0^(4*13) - 1)
|
||||
assert(tonumber("0x"..string.rep("f", 150)..".0") == 2.0^(4*150) - 1)
|
||||
assert(tonumber("0x"..string.rep("f", 300)..".0") == 2.0^(4*300) - 1)
|
||||
assert(tonumber("0x"..string.rep("f", 500)..".0") == 2.0^(4*500) - 1)
|
||||
assert(tonumber('0x3.' .. string.rep('0', 1000)) == 3)
|
||||
assert(tonumber('0x' .. string.rep('0', 1000) .. 'a') == 10)
|
||||
assert(tonumber('0x0.' .. string.rep('0', 13).."1") == 2.0^(-4*14))
|
||||
assert(tonumber('0x0.' .. string.rep('0', 150).."1") == 2.0^(-4*151))
|
||||
assert(tonumber('0x0.' .. string.rep('0', 300).."1") == 2.0^(-4*301))
|
||||
assert(tonumber('0x0.' .. string.rep('0', 500).."1") == 2.0^(-4*501))
|
||||
|
||||
assert(tonumber('0xe03' .. string.rep('0', 1000) .. 'p-4000') == 3587.0)
|
||||
assert(tonumber('0x.' .. string.rep('0', 1000) .. '74p4004') == 0x7.4)
|
||||
end
|
||||
|
||||
-- testing 'tonumber' for invalid formats
|
||||
|
||||
local function f (...)
|
||||
if select('#', ...) == 1 then
|
||||
return (...)
|
||||
else
|
||||
return "***"
|
||||
end
|
||||
end
|
||||
|
||||
assert(f(tonumber('fFfa', 15)) == nil)
|
||||
assert(f(tonumber('099', 8)) == nil)
|
||||
assert(f(tonumber('1\0', 2)) == nil)
|
||||
assert(f(tonumber('', 8)) == nil)
|
||||
assert(f(tonumber(' ', 9)) == nil)
|
||||
assert(f(tonumber(' ', 9)) == nil)
|
||||
assert(f(tonumber('0xf', 10)) == nil)
|
||||
|
||||
assert(f(tonumber('inf')) == nil)
|
||||
assert(f(tonumber(' INF ')) == nil)
|
||||
assert(f(tonumber('Nan')) == nil)
|
||||
assert(f(tonumber('nan')) == nil)
|
||||
|
||||
assert(f(tonumber(' ')) == nil)
|
||||
assert(f(tonumber('')) == nil)
|
||||
assert(f(tonumber('1 a')) == nil)
|
||||
assert(f(tonumber('1 a', 2)) == nil)
|
||||
assert(f(tonumber('1\0')) == nil)
|
||||
assert(f(tonumber('1 \0')) == nil)
|
||||
assert(f(tonumber('1\0 ')) == nil)
|
||||
assert(f(tonumber('e1')) == nil)
|
||||
assert(f(tonumber('e 1')) == nil)
|
||||
assert(f(tonumber(' 3.4.5 ')) == nil)
|
||||
|
||||
|
||||
-- testing 'tonumber' for invalid hexadecimal formats
|
||||
|
||||
assert(tonumber('0x') == nil)
|
||||
assert(tonumber('x') == nil)
|
||||
assert(tonumber('x3') == nil)
|
||||
assert(tonumber('0x3.3.3') == nil) -- two decimal points
|
||||
assert(tonumber('00x2') == nil)
|
||||
assert(tonumber('0x 2') == nil)
|
||||
assert(tonumber('0 x2') == nil)
|
||||
assert(tonumber('23x') == nil)
|
||||
assert(tonumber('- 0xaa') == nil)
|
||||
assert(tonumber('-0xaaP ') == nil) -- no exponent
|
||||
assert(tonumber('0x0.51p') == nil)
|
||||
assert(tonumber('0x5p+-2') == nil)
|
||||
|
||||
|
||||
-- testing hexadecimal numerals
|
||||
|
||||
assert(0x10 == 16 and 0xfff == 2^12 - 1 and 0XFB == 251)
|
||||
assert(0x0p12 == 0 and 0x.0p-3 == 0)
|
||||
assert(0xFFFFFFFF == (1 << 32) - 1)
|
||||
assert(tonumber('+0x2') == 2)
|
||||
assert(tonumber('-0xaA') == -170)
|
||||
assert(tonumber('-0xffFFFfff') == -(1 << 32) + 1)
|
||||
|
||||
-- possible confusion with decimal exponent
|
||||
assert(0E+1 == 0 and 0xE+1 == 15 and 0xe-1 == 13)
|
||||
|
||||
|
||||
-- floating hexas
|
||||
|
||||
assert(tonumber(' 0x2.5 ') == 0x25/16)
|
||||
assert(tonumber(' -0x2.5 ') == -0x25/16)
|
||||
assert(tonumber(' +0x0.51p+8 ') == 0x51)
|
||||
assert(0x.FfffFFFF == 1 - '0x.00000001')
|
||||
assert('0xA.a' + 0 == 10 + 10/16)
|
||||
assert(0xa.aP4 == 0XAA)
|
||||
assert(0x4P-2 == 1)
|
||||
assert(0x1.1 == '0x1.' + '+0x.1')
|
||||
assert(0Xabcdef.0 == 0x.ABCDEFp+24)
|
||||
|
||||
|
||||
assert(1.1 == 1.+.1)
|
||||
assert(100.0 == 1E2 and .01 == 1e-2)
|
||||
assert(1111111111 - 1111111110 == 1000.00e-03)
|
||||
assert(1.1 == '1.'+'.1')
|
||||
assert(tonumber'1111111111' - tonumber'1111111110' ==
|
||||
tonumber" +0.001e+3 \n\t")
|
||||
|
||||
assert(0.1e-30 > 0.9E-31 and 0.9E30 < 0.1e31)
|
||||
|
||||
assert(0.123456 > 0.123455)
|
||||
|
||||
assert(tonumber('+1.23E18') == 1.23*10.0^18)
|
||||
|
||||
-- testing order operators
|
||||
assert(not(1<1) and (1<2) and not(2<1))
|
||||
assert(not('a'<'a') and ('a'<'b') and not('b'<'a'))
|
||||
assert((1<=1) and (1<=2) and not(2<=1))
|
||||
assert(('a'<='a') and ('a'<='b') and not('b'<='a'))
|
||||
assert(not(1>1) and not(1>2) and (2>1))
|
||||
assert(not('a'>'a') and not('a'>'b') and ('b'>'a'))
|
||||
assert((1>=1) and not(1>=2) and (2>=1))
|
||||
assert(('a'>='a') and not('a'>='b') and ('b'>='a'))
|
||||
assert(1.3 < 1.4 and 1.3 <= 1.4 and not (1.3 < 1.3) and 1.3 <= 1.3)
|
||||
|
||||
-- testing mod operator
|
||||
assert(eqT(-4 % 3, 2))
|
||||
assert(eqT(4 % -3, -2))
|
||||
assert(eqT(-4.0 % 3, 2.0))
|
||||
assert(eqT(4 % -3.0, -2.0))
|
||||
assert(math.pi - math.pi % 1 == 3)
|
||||
assert(math.pi - math.pi % 0.001 == 3.141)
|
||||
|
||||
assert(eqT(minint % minint, 0))
|
||||
assert(eqT(maxint % maxint, 0))
|
||||
assert((minint + 1) % minint == minint + 1)
|
||||
assert((maxint - 1) % maxint == maxint - 1)
|
||||
assert(minint % maxint == maxint - 1)
|
||||
|
||||
assert(minint % -1 == 0)
|
||||
assert(minint % -2 == 0)
|
||||
assert(maxint % -2 == -1)
|
||||
|
||||
-- non-portable tests because Windows C library cannot compute
|
||||
-- fmod(1, huge) correctly
|
||||
if not _port then
|
||||
local function anan (x) assert(isNaN(x)) end -- assert Not a Number
|
||||
anan(0.0 % 0)
|
||||
anan(1.3 % 0)
|
||||
anan(math.huge % 1)
|
||||
anan(math.huge % 1e30)
|
||||
anan(-math.huge % 1e30)
|
||||
anan(-math.huge % -1e30)
|
||||
assert(1 % math.huge == 1)
|
||||
assert(1e30 % math.huge == 1e30)
|
||||
assert(1e30 % -math.huge == -math.huge)
|
||||
assert(-1 % math.huge == math.huge)
|
||||
assert(-1 % -math.huge == -1)
|
||||
end
|
||||
|
||||
|
||||
-- testing unsigned comparisons
|
||||
assert(math.ult(3, 4))
|
||||
assert(not math.ult(4, 4))
|
||||
assert(math.ult(-2, -1))
|
||||
assert(math.ult(2, -1))
|
||||
assert(not math.ult(-2, -2))
|
||||
assert(math.ult(maxint, minint))
|
||||
assert(not math.ult(minint, maxint))
|
||||
|
||||
|
||||
assert(eq(math.sin(-9.8)^2 + math.cos(-9.8)^2, 1))
|
||||
assert(eq(math.tan(math.pi/4), 1))
|
||||
assert(eq(math.sin(math.pi/2), 1) and eq(math.cos(math.pi/2), 0))
|
||||
assert(eq(math.atan(1), math.pi/4) and eq(math.acos(0), math.pi/2) and
|
||||
eq(math.asin(1), math.pi/2))
|
||||
assert(eq(math.deg(math.pi/2), 90) and eq(math.rad(90), math.pi/2))
|
||||
assert(math.abs(-10.43) == 10.43)
|
||||
assert(eqT(math.abs(minint), minint))
|
||||
assert(eqT(math.abs(maxint), maxint))
|
||||
assert(eqT(math.abs(-maxint), maxint))
|
||||
assert(eq(math.atan(1,0), math.pi/2))
|
||||
assert(math.fmod(10,3) == 1)
|
||||
assert(eq(math.sqrt(10)^2, 10))
|
||||
assert(eq(math.log(2, 10), math.log(2)/math.log(10)))
|
||||
assert(eq(math.log(2, 2), 1))
|
||||
assert(eq(math.log(9, 3), 2))
|
||||
assert(eq(math.exp(0), 1))
|
||||
assert(eq(math.sin(10), math.sin(10%(2*math.pi))))
|
||||
|
||||
|
||||
assert(tonumber(' 1.3e-2 ') == 1.3e-2)
|
||||
assert(tonumber(' -1.00000000000001 ') == -1.00000000000001)
|
||||
|
||||
-- testing constant limits
|
||||
-- 2^23 = 8388608
|
||||
assert(8388609 + -8388609 == 0)
|
||||
assert(8388608 + -8388608 == 0)
|
||||
assert(8388607 + -8388607 == 0)
|
||||
|
||||
|
||||
|
||||
do -- testing floor & ceil
|
||||
assert(eqT(math.floor(3.4), 3))
|
||||
assert(eqT(math.ceil(3.4), 4))
|
||||
assert(eqT(math.floor(-3.4), -4))
|
||||
assert(eqT(math.ceil(-3.4), -3))
|
||||
assert(eqT(math.floor(maxint), maxint))
|
||||
assert(eqT(math.ceil(maxint), maxint))
|
||||
assert(eqT(math.floor(minint), minint))
|
||||
assert(eqT(math.floor(minint + 0.0), minint))
|
||||
assert(eqT(math.ceil(minint), minint))
|
||||
assert(eqT(math.ceil(minint + 0.0), minint))
|
||||
assert(math.floor(1e50) == 1e50)
|
||||
assert(math.ceil(1e50) == 1e50)
|
||||
assert(math.floor(-1e50) == -1e50)
|
||||
assert(math.ceil(-1e50) == -1e50)
|
||||
for _, p in pairs{31,32,63,64} do
|
||||
assert(math.floor(2^p) == 2^p)
|
||||
assert(math.floor(2^p + 0.5) == 2^p)
|
||||
assert(math.ceil(2^p) == 2^p)
|
||||
assert(math.ceil(2^p - 0.5) == 2^p)
|
||||
end
|
||||
checkerror("number expected", math.floor, {})
|
||||
checkerror("number expected", math.ceil, print)
|
||||
assert(eqT(math.tointeger(minint), minint))
|
||||
assert(eqT(math.tointeger(minint .. ""), minint))
|
||||
assert(eqT(math.tointeger(maxint), maxint))
|
||||
assert(eqT(math.tointeger(maxint .. ""), maxint))
|
||||
assert(eqT(math.tointeger(minint + 0.0), minint))
|
||||
assert(math.tointeger(0.0 - minint) == nil)
|
||||
assert(math.tointeger(math.pi) == nil)
|
||||
assert(math.tointeger(-math.pi) == nil)
|
||||
assert(math.floor(math.huge) == math.huge)
|
||||
assert(math.ceil(math.huge) == math.huge)
|
||||
assert(math.tointeger(math.huge) == nil)
|
||||
assert(math.floor(-math.huge) == -math.huge)
|
||||
assert(math.ceil(-math.huge) == -math.huge)
|
||||
assert(math.tointeger(-math.huge) == nil)
|
||||
assert(math.tointeger("34.0") == 34)
|
||||
assert(math.tointeger("34.3") == nil)
|
||||
assert(math.tointeger({}) == nil)
|
||||
assert(math.tointeger(0/0) == nil) -- NaN
|
||||
end
|
||||
|
||||
|
||||
-- testing fmod for integers
|
||||
for i = -6, 6 do
|
||||
for j = -6, 6 do
|
||||
if j ~= 0 then
|
||||
local mi = math.fmod(i, j)
|
||||
local mf = math.fmod(i + 0.0, j)
|
||||
assert(mi == mf)
|
||||
assert(math.type(mi) == 'integer' and math.type(mf) == 'float')
|
||||
if (i >= 0 and j >= 0) or (i <= 0 and j <= 0) or mi == 0 then
|
||||
assert(eqT(mi, i % j))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
assert(eqT(math.fmod(minint, minint), 0))
|
||||
assert(eqT(math.fmod(maxint, maxint), 0))
|
||||
assert(eqT(math.fmod(minint + 1, minint), minint + 1))
|
||||
assert(eqT(math.fmod(maxint - 1, maxint), maxint - 1))
|
||||
|
||||
checkerror("zero", math.fmod, 3, 0)
|
||||
|
||||
|
||||
do -- testing max/min
|
||||
checkerror("value expected", math.max)
|
||||
checkerror("value expected", math.min)
|
||||
assert(eqT(math.max(3), 3))
|
||||
assert(eqT(math.max(3, 5, 9, 1), 9))
|
||||
assert(math.max(maxint, 10e60) == 10e60)
|
||||
assert(eqT(math.max(minint, minint + 1), minint + 1))
|
||||
assert(eqT(math.min(3), 3))
|
||||
assert(eqT(math.min(3, 5, 9, 1), 1))
|
||||
assert(math.min(3.2, 5.9, -9.2, 1.1) == -9.2)
|
||||
assert(math.min(1.9, 1.7, 1.72) == 1.7)
|
||||
assert(math.min(-10e60, minint) == -10e60)
|
||||
assert(eqT(math.min(maxint, maxint - 1), maxint - 1))
|
||||
assert(eqT(math.min(maxint - 2, maxint, maxint - 1), maxint - 2))
|
||||
end
|
||||
-- testing implicit convertions
|
||||
|
||||
local a,b = '10', '20'
|
||||
assert(a*b == 200 and a+b == 30 and a-b == -10 and a/b == 0.5 and -b == -20)
|
||||
assert(a == '10' and b == '20')
|
||||
|
||||
|
||||
do
|
||||
print("testing -0 and NaN")
|
||||
local mz, z = -0.0, 0.0
|
||||
assert(mz == z)
|
||||
assert(1/mz < 0 and 0 < 1/z)
|
||||
local a = {[mz] = 1}
|
||||
assert(a[z] == 1 and a[mz] == 1)
|
||||
a[z] = 2
|
||||
assert(a[z] == 2 and a[mz] == 2)
|
||||
local inf = math.huge * 2 + 1
|
||||
mz, z = -1/inf, 1/inf
|
||||
assert(mz == z)
|
||||
assert(1/mz < 0 and 0 < 1/z)
|
||||
local NaN = inf - inf
|
||||
assert(NaN ~= NaN)
|
||||
assert(not (NaN < NaN))
|
||||
assert(not (NaN <= NaN))
|
||||
assert(not (NaN > NaN))
|
||||
assert(not (NaN >= NaN))
|
||||
assert(not (0 < NaN) and not (NaN < 0))
|
||||
local NaN1 = 0/0
|
||||
assert(NaN ~= NaN1 and not (NaN <= NaN1) and not (NaN1 <= NaN))
|
||||
local a = {}
|
||||
assert(not pcall(rawset, a, NaN, 1))
|
||||
assert(a[NaN] == nil)
|
||||
a[1] = 1
|
||||
assert(not pcall(rawset, a, NaN, 1))
|
||||
assert(a[NaN] == nil)
|
||||
-- strings with same binary representation as 0.0 (might create problems
|
||||
-- for constant manipulation in the pre-compiler)
|
||||
local a1, a2, a3, a4, a5 = 0, 0, "\0\0\0\0\0\0\0\0", 0, "\0\0\0\0\0\0\0\0"
|
||||
assert(a1 == a2 and a2 == a4 and a1 ~= a3)
|
||||
assert(a3 == a5)
|
||||
end
|
||||
|
||||
|
||||
print("testing 'math.random'")
|
||||
math.randomseed(0)
|
||||
|
||||
do -- test random for floats
|
||||
local max = -math.huge
|
||||
local min = math.huge
|
||||
for i = 0, 20000 do
|
||||
local t = math.random()
|
||||
assert(0 <= t and t < 1)
|
||||
max = math.max(max, t)
|
||||
min = math.min(min, t)
|
||||
if eq(max, 1, 0.001) and eq(min, 0, 0.001) then
|
||||
goto ok
|
||||
end
|
||||
end
|
||||
-- loop ended without satisfing condition
|
||||
assert(false)
|
||||
::ok::
|
||||
end
|
||||
|
||||
do
|
||||
local function aux (p, lim) -- test random for small intervals
|
||||
local x1, x2
|
||||
if #p == 1 then x1 = 1; x2 = p[1]
|
||||
else x1 = p[1]; x2 = p[2]
|
||||
end
|
||||
local mark = {}; local count = 0 -- to check that all values appeared
|
||||
for i = 0, lim or 2000 do
|
||||
local t = math.random(table.unpack(p))
|
||||
assert(x1 <= t and t <= x2)
|
||||
if not mark[t] then -- new value
|
||||
mark[t] = true
|
||||
count = count + 1
|
||||
end
|
||||
if count == x2 - x1 + 1 then -- all values appeared; OK
|
||||
goto ok
|
||||
end
|
||||
end
|
||||
-- loop ended without satisfing condition
|
||||
assert(false)
|
||||
::ok::
|
||||
end
|
||||
|
||||
aux({-10,0})
|
||||
aux({6})
|
||||
aux({-10, 10})
|
||||
aux({minint, minint})
|
||||
aux({maxint, maxint})
|
||||
aux({minint, minint + 9})
|
||||
aux({maxint - 3, maxint})
|
||||
end
|
||||
|
||||
do
|
||||
local function aux(p1, p2) -- test random for large intervals
|
||||
local max = minint
|
||||
local min = maxint
|
||||
local n = 200
|
||||
local mark = {}; local count = 0 -- to count how many different values
|
||||
for _ = 1, n do
|
||||
local t = math.random(p1, p2)
|
||||
max = math.max(max, t)
|
||||
min = math.min(min, t)
|
||||
if not mark[t] then -- new value
|
||||
mark[t] = true
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
-- at least 80% of values are different
|
||||
assert(count >= n * 0.8)
|
||||
-- min and max not too far from formal min and max
|
||||
local diff = (p2 - p1) // 8
|
||||
assert(min < p1 + diff and max > p2 - diff)
|
||||
end
|
||||
aux(0, maxint)
|
||||
aux(1, maxint)
|
||||
aux(minint, -1)
|
||||
aux(minint // 2, maxint // 2)
|
||||
end
|
||||
|
||||
for i=1,100 do
|
||||
assert(math.random(maxint) > 0)
|
||||
assert(math.random(minint, -1) < 0)
|
||||
end
|
||||
|
||||
assert(not pcall(math.random, 1, 2, 3)) -- too many arguments
|
||||
|
||||
-- empty interval
|
||||
assert(not pcall(math.random, minint + 1, minint))
|
||||
assert(not pcall(math.random, maxint, maxint - 1))
|
||||
assert(not pcall(math.random, maxint, minint))
|
||||
|
||||
-- interval too large
|
||||
assert(not pcall(math.random, minint, 0))
|
||||
assert(not pcall(math.random, -1, maxint))
|
||||
assert(not pcall(math.random, minint // 2, maxint // 2 + 1))
|
||||
|
||||
|
||||
print('OK')
|
631
06/parser-gen/parsers/lua-5.3.4-tests/nextvar.lua
Normal file
631
06/parser-gen/parsers/lua-5.3.4-tests/nextvar.lua
Normal file
|
@ -0,0 +1,631 @@
|
|||
-- $Id: nextvar.lua,v 1.79 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing tables, next, and for')
|
||||
|
||||
local function checkerror (msg, f, ...)
|
||||
local s, err = pcall(f, ...)
|
||||
assert(not s and string.find(err, msg))
|
||||
end
|
||||
|
||||
|
||||
local a = {}
|
||||
|
||||
-- make sure table has lots of space in hash part
|
||||
for i=1,100 do a[i.."+"] = true end
|
||||
for i=1,100 do a[i.."+"] = nil end
|
||||
-- fill hash part with numeric indices testing size operator
|
||||
for i=1,100 do
|
||||
a[i] = true
|
||||
assert(#a == i)
|
||||
end
|
||||
|
||||
-- testing ipairs
|
||||
local x = 0
|
||||
for k,v in ipairs{10,20,30;x=12} do
|
||||
x = x + 1
|
||||
assert(k == x and v == x * 10)
|
||||
end
|
||||
|
||||
for _ in ipairs{x=12, y=24} do assert(nil) end
|
||||
|
||||
-- test for 'false' x ipair
|
||||
x = false
|
||||
local i = 0
|
||||
for k,v in ipairs{true,false,true,false} do
|
||||
i = i + 1
|
||||
x = not x
|
||||
assert(x == v)
|
||||
end
|
||||
assert(i == 4)
|
||||
|
||||
-- iterator function is always the same
|
||||
assert(type(ipairs{}) == 'function' and ipairs{} == ipairs{})
|
||||
|
||||
|
||||
if not T then
|
||||
(Message or print)
|
||||
('\n >>> testC not active: skipping tests for table sizes <<<\n')
|
||||
else --[
|
||||
-- testing table sizes
|
||||
|
||||
local function log2 (x) return math.log(x, 2) end
|
||||
|
||||
local function mp2 (n) -- minimum power of 2 >= n
|
||||
local mp = 2^math.ceil(log2(n))
|
||||
assert(n == 0 or (mp/2 < n and n <= mp))
|
||||
return mp
|
||||
end
|
||||
|
||||
local function fb (n)
|
||||
local r, nn = T.int2fb(n)
|
||||
assert(r < 256)
|
||||
return nn
|
||||
end
|
||||
|
||||
-- test fb function
|
||||
for a = 1, 10000 do -- all numbers up to 10^4
|
||||
local n = fb(a)
|
||||
assert(a <= n and n <= a*1.125)
|
||||
end
|
||||
local a = 1024 -- plus a few up to 2 ^30
|
||||
local lim = 2^30
|
||||
while a < lim do
|
||||
local n = fb(a)
|
||||
assert(a <= n and n <= a*1.125)
|
||||
a = math.ceil(a*1.3)
|
||||
end
|
||||
|
||||
|
||||
local function check (t, na, nh)
|
||||
local a, h = T.querytab(t)
|
||||
if a ~= na or h ~= nh then
|
||||
print(na, nh, a, h)
|
||||
assert(nil)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- testing C library sizes
|
||||
do
|
||||
local s = 0
|
||||
for _ in pairs(math) do s = s + 1 end
|
||||
check(math, 0, mp2(s))
|
||||
end
|
||||
|
||||
|
||||
-- testing constructor sizes
|
||||
local lim = 40
|
||||
local s = 'return {'
|
||||
for i=1,lim do
|
||||
s = s..i..','
|
||||
local s = s
|
||||
for k=0,lim do
|
||||
local t = load(s..'}', '')()
|
||||
assert(#t == i)
|
||||
check(t, fb(i), mp2(k))
|
||||
s = string.format('%sa%d=%d,', s, k, k)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- tests with unknown number of elements
|
||||
local a = {}
|
||||
for i=1,lim do a[i] = i end -- build auxiliary table
|
||||
for k=0,lim do
|
||||
local a = {table.unpack(a,1,k)}
|
||||
assert(#a == k)
|
||||
check(a, k, 0)
|
||||
a = {1,2,3,table.unpack(a,1,k)}
|
||||
check(a, k+3, 0)
|
||||
assert(#a == k + 3)
|
||||
end
|
||||
|
||||
|
||||
-- testing tables dynamically built
|
||||
local lim = 130
|
||||
local a = {}; a[2] = 1; check(a, 0, 1)
|
||||
a = {}; a[0] = 1; check(a, 0, 1); a[2] = 1; check(a, 0, 2)
|
||||
a = {}; a[0] = 1; a[1] = 1; check(a, 1, 1)
|
||||
a = {}
|
||||
for i = 1,lim do
|
||||
a[i] = 1
|
||||
assert(#a == i)
|
||||
check(a, mp2(i), 0)
|
||||
end
|
||||
|
||||
a = {}
|
||||
for i = 1,lim do
|
||||
a['a'..i] = 1
|
||||
assert(#a == 0)
|
||||
check(a, 0, mp2(i))
|
||||
end
|
||||
|
||||
a = {}
|
||||
for i=1,16 do a[i] = i end
|
||||
check(a, 16, 0)
|
||||
do
|
||||
for i=1,11 do a[i] = nil end
|
||||
for i=30,50 do a[i] = nil end -- force a rehash (?)
|
||||
check(a, 0, 8) -- only 5 elements in the table
|
||||
a[10] = 1
|
||||
for i=30,50 do a[i] = nil end -- force a rehash (?)
|
||||
check(a, 0, 8) -- only 6 elements in the table
|
||||
for i=1,14 do a[i] = nil end
|
||||
for i=18,50 do a[i] = nil end -- force a rehash (?)
|
||||
check(a, 0, 4) -- only 2 elements ([15] and [16])
|
||||
end
|
||||
|
||||
-- reverse filling
|
||||
for i=1,lim do
|
||||
local a = {}
|
||||
for i=i,1,-1 do a[i] = i end -- fill in reverse
|
||||
check(a, mp2(i), 0)
|
||||
end
|
||||
|
||||
-- size tests for vararg
|
||||
lim = 35
|
||||
function foo (n, ...)
|
||||
local arg = {...}
|
||||
check(arg, n, 0)
|
||||
assert(select('#', ...) == n)
|
||||
arg[n+1] = true
|
||||
check(arg, mp2(n+1), 0)
|
||||
arg.x = true
|
||||
check(arg, mp2(n+1), 1)
|
||||
end
|
||||
local a = {}
|
||||
for i=1,lim do a[i] = true; foo(i, table.unpack(a)) end
|
||||
|
||||
end --]
|
||||
|
||||
|
||||
-- test size operation on empty tables
|
||||
assert(#{} == 0)
|
||||
assert(#{nil} == 0)
|
||||
assert(#{nil, nil} == 0)
|
||||
assert(#{nil, nil, nil} == 0)
|
||||
assert(#{nil, nil, nil, nil} == 0)
|
||||
print'+'
|
||||
|
||||
|
||||
local nofind = {}
|
||||
|
||||
a,b,c = 1,2,3
|
||||
a,b,c = nil
|
||||
|
||||
|
||||
-- next uses always the same iteraction function
|
||||
assert(next{} == next{})
|
||||
|
||||
local function find (name)
|
||||
local n,v
|
||||
while 1 do
|
||||
n,v = next(_G, n)
|
||||
if not n then return nofind end
|
||||
assert(v ~= nil)
|
||||
if n == name then return v end
|
||||
end
|
||||
end
|
||||
|
||||
local function find1 (name)
|
||||
for n,v in pairs(_G) do
|
||||
if n==name then return v end
|
||||
end
|
||||
return nil -- not found
|
||||
end
|
||||
|
||||
|
||||
assert(print==find("print") and print == find1("print"))
|
||||
assert(_G["print"]==find("print"))
|
||||
assert(assert==find1("assert"))
|
||||
assert(nofind==find("return"))
|
||||
assert(not find1("return"))
|
||||
_G["ret" .. "urn"] = nil
|
||||
assert(nofind==find("return"))
|
||||
_G["xxx"] = 1
|
||||
assert(xxx==find("xxx"))
|
||||
|
||||
-- invalid key to 'next'
|
||||
checkerror("invalid key", next, {10,20}, 3)
|
||||
|
||||
-- both 'pairs' and 'ipairs' need an argument
|
||||
checkerror("bad argument", pairs)
|
||||
checkerror("bad argument", ipairs)
|
||||
|
||||
print('+')
|
||||
|
||||
a = {}
|
||||
for i=0,10000 do
|
||||
if math.fmod(i,10) ~= 0 then
|
||||
a['x'..i] = i
|
||||
end
|
||||
end
|
||||
|
||||
n = {n=0}
|
||||
for i,v in pairs(a) do
|
||||
n.n = n.n+1
|
||||
assert(i and v and a[i] == v)
|
||||
end
|
||||
assert(n.n == 9000)
|
||||
a = nil
|
||||
|
||||
do -- clear global table
|
||||
local a = {}
|
||||
for n,v in pairs(_G) do a[n]=v end
|
||||
for n,v in pairs(a) do
|
||||
if not package.loaded[n] and type(v) ~= "function" and
|
||||
not string.find(n, "^[%u_]") then
|
||||
_G[n] = nil
|
||||
end
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
|
||||
local function checknext (a)
|
||||
local b = {}
|
||||
do local k,v = next(a); while k do b[k] = v; k,v = next(a,k) end end
|
||||
for k,v in pairs(b) do assert(a[k] == v) end
|
||||
for k,v in pairs(a) do assert(b[k] == v) end
|
||||
end
|
||||
|
||||
checknext{1,x=1,y=2,z=3}
|
||||
checknext{1,2,x=1,y=2,z=3}
|
||||
checknext{1,2,3,x=1,y=2,z=3}
|
||||
checknext{1,2,3,4,x=1,y=2,z=3}
|
||||
checknext{1,2,3,4,5,x=1,y=2,z=3}
|
||||
|
||||
assert(#{} == 0)
|
||||
assert(#{[-1] = 2} == 0)
|
||||
assert(#{1,2,3,nil,nil} == 3)
|
||||
for i=0,40 do
|
||||
local a = {}
|
||||
for j=1,i do a[j]=j end
|
||||
assert(#a == i)
|
||||
end
|
||||
|
||||
-- 'maxn' is now deprecated, but it is easily defined in Lua
|
||||
function table.maxn (t)
|
||||
local max = 0
|
||||
for k in pairs(t) do
|
||||
max = (type(k) == 'number') and math.max(max, k) or max
|
||||
end
|
||||
return max
|
||||
end
|
||||
|
||||
assert(table.maxn{} == 0)
|
||||
assert(table.maxn{["1000"] = true} == 0)
|
||||
assert(table.maxn{["1000"] = true, [24.5] = 3} == 24.5)
|
||||
assert(table.maxn{[1000] = true} == 1000)
|
||||
assert(table.maxn{[10] = true, [100*math.pi] = print} == 100*math.pi)
|
||||
|
||||
table.maxn = nil
|
||||
|
||||
-- int overflow
|
||||
a = {}
|
||||
for i=0,50 do a[2^i] = true end
|
||||
assert(a[#a])
|
||||
|
||||
print('+')
|
||||
|
||||
|
||||
-- erasing values
|
||||
local t = {[{1}] = 1, [{2}] = 2, [string.rep("x ", 4)] = 3,
|
||||
[100.3] = 4, [4] = 5}
|
||||
|
||||
local n = 0
|
||||
for k, v in pairs( t ) do
|
||||
n = n+1
|
||||
assert(t[k] == v)
|
||||
t[k] = nil
|
||||
collectgarbage()
|
||||
assert(t[k] == nil)
|
||||
end
|
||||
assert(n == 5)
|
||||
|
||||
|
||||
local function test (a)
|
||||
assert(not pcall(table.insert, a, 2, 20));
|
||||
table.insert(a, 10); table.insert(a, 2, 20);
|
||||
table.insert(a, 1, -1); table.insert(a, 40);
|
||||
table.insert(a, #a+1, 50)
|
||||
table.insert(a, 2, -2)
|
||||
assert(not pcall(table.insert, a, 0, 20));
|
||||
assert(not pcall(table.insert, a, #a + 2, 20));
|
||||
assert(table.remove(a,1) == -1)
|
||||
assert(table.remove(a,1) == -2)
|
||||
assert(table.remove(a,1) == 10)
|
||||
assert(table.remove(a,1) == 20)
|
||||
assert(table.remove(a,1) == 40)
|
||||
assert(table.remove(a,1) == 50)
|
||||
assert(table.remove(a,1) == nil)
|
||||
assert(table.remove(a) == nil)
|
||||
assert(table.remove(a, #a) == nil)
|
||||
end
|
||||
|
||||
a = {n=0, [-7] = "ban"}
|
||||
test(a)
|
||||
assert(a.n == 0 and a[-7] == "ban")
|
||||
|
||||
a = {[-7] = "ban"};
|
||||
test(a)
|
||||
assert(a.n == nil and #a == 0 and a[-7] == "ban")
|
||||
|
||||
a = {[-1] = "ban"}
|
||||
test(a)
|
||||
assert(#a == 0 and table.remove(a) == nil and a[-1] == "ban")
|
||||
|
||||
a = {[0] = "ban"}
|
||||
assert(#a == 0 and table.remove(a) == "ban" and a[0] == nil)
|
||||
|
||||
table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1)
|
||||
assert(table.remove(a) == 10)
|
||||
assert(table.remove(a) == 20)
|
||||
assert(table.remove(a) == -1)
|
||||
assert(table.remove(a) == nil)
|
||||
|
||||
a = {'c', 'd'}
|
||||
table.insert(a, 3, 'a')
|
||||
table.insert(a, 'b')
|
||||
assert(table.remove(a, 1) == 'c')
|
||||
assert(table.remove(a, 1) == 'd')
|
||||
assert(table.remove(a, 1) == 'a')
|
||||
assert(table.remove(a, 1) == 'b')
|
||||
assert(table.remove(a, 1) == nil)
|
||||
assert(#a == 0 and a.n == nil)
|
||||
|
||||
a = {10,20,30,40}
|
||||
assert(table.remove(a, #a + 1) == nil)
|
||||
assert(not pcall(table.remove, a, 0))
|
||||
assert(a[#a] == 40)
|
||||
assert(table.remove(a, #a) == 40)
|
||||
assert(a[#a] == 30)
|
||||
assert(table.remove(a, 2) == 20)
|
||||
assert(a[#a] == 30 and #a == 2)
|
||||
|
||||
do -- testing table library with metamethods
|
||||
local function test (proxy, t)
|
||||
for i = 1, 10 do
|
||||
table.insert(proxy, 1, i)
|
||||
end
|
||||
assert(#proxy == 10 and #t == 10)
|
||||
for i = 1, 10 do
|
||||
assert(t[i] == 11 - i)
|
||||
end
|
||||
table.sort(proxy)
|
||||
for i = 1, 10 do
|
||||
assert(t[i] == i and proxy[i] == i)
|
||||
end
|
||||
assert(table.concat(proxy, ",") == "1,2,3,4,5,6,7,8,9,10")
|
||||
for i = 1, 8 do
|
||||
assert(table.remove(proxy, 1) == i)
|
||||
end
|
||||
assert(#proxy == 2 and #t == 2)
|
||||
local a, b, c = table.unpack(proxy)
|
||||
assert(a == 9 and b == 10 and c == nil)
|
||||
end
|
||||
|
||||
-- all virtual
|
||||
local t = {}
|
||||
local proxy = setmetatable({}, {
|
||||
__len = function () return #t end,
|
||||
__index = t,
|
||||
__newindex = t,
|
||||
})
|
||||
test(proxy, t)
|
||||
|
||||
-- only __newindex
|
||||
local count = 0
|
||||
t = setmetatable({}, {
|
||||
__newindex = function (t,k,v) count = count + 1; rawset(t,k,v) end})
|
||||
test(t, t)
|
||||
assert(count == 10) -- after first 10, all other sets are not new
|
||||
|
||||
-- no __newindex
|
||||
t = setmetatable({}, {
|
||||
__index = function (_,k) return k + 1 end,
|
||||
__len = function (_) return 5 end})
|
||||
assert(table.concat(t, ";") == "2;3;4;5;6")
|
||||
|
||||
end
|
||||
|
||||
|
||||
if not T then
|
||||
(Message or print)
|
||||
('\n >>> testC not active: skipping tests for table library on non-tables <<<\n')
|
||||
else --[
|
||||
local debug = require'debug'
|
||||
local tab = {10, 20, 30}
|
||||
local mt = {}
|
||||
local u = T.newuserdata(0)
|
||||
checkerror("table expected", table.insert, u, 40)
|
||||
checkerror("table expected", table.remove, u)
|
||||
debug.setmetatable(u, mt)
|
||||
checkerror("table expected", table.insert, u, 40)
|
||||
checkerror("table expected", table.remove, u)
|
||||
mt.__index = tab
|
||||
checkerror("table expected", table.insert, u, 40)
|
||||
checkerror("table expected", table.remove, u)
|
||||
mt.__newindex = tab
|
||||
checkerror("table expected", table.insert, u, 40)
|
||||
checkerror("table expected", table.remove, u)
|
||||
mt.__len = function () return #tab end
|
||||
table.insert(u, 40)
|
||||
assert(#u == 4 and #tab == 4 and u[4] == 40 and tab[4] == 40)
|
||||
assert(table.remove(u) == 40)
|
||||
table.insert(u, 1, 50)
|
||||
assert(#u == 4 and #tab == 4 and u[4] == 30 and tab[1] == 50)
|
||||
|
||||
mt.__newindex = nil
|
||||
mt.__len = nil
|
||||
local tab2 = {}
|
||||
local u2 = T.newuserdata(0)
|
||||
debug.setmetatable(u2, {__newindex = function (_, k, v) tab2[k] = v end})
|
||||
table.move(u, 1, 4, 1, u2)
|
||||
assert(#tab2 == 4 and tab2[1] == tab[1] and tab2[4] == tab[4])
|
||||
|
||||
end -- ]
|
||||
|
||||
print('+')
|
||||
|
||||
a = {}
|
||||
for i=1,1000 do
|
||||
a[i] = i; a[i-1] = nil
|
||||
end
|
||||
assert(next(a,nil) == 1000 and next(a,1000) == nil)
|
||||
|
||||
assert(next({}) == nil)
|
||||
assert(next({}, nil) == nil)
|
||||
|
||||
for a,b in pairs{} do error"not here" end
|
||||
for i=1,0 do error'not here' end
|
||||
for i=0,1,-1 do error'not here' end
|
||||
a = nil; for i=1,1 do assert(not a); a=1 end; assert(a)
|
||||
a = nil; for i=1,1,-1 do assert(not a); a=1 end; assert(a)
|
||||
|
||||
do
|
||||
print("testing floats in numeric for")
|
||||
local a
|
||||
-- integer count
|
||||
a = 0; for i=1, 1, 1 do a=a+1 end; assert(a==1)
|
||||
a = 0; for i=10000, 1e4, -1 do a=a+1 end; assert(a==1)
|
||||
a = 0; for i=1, 0.99999, 1 do a=a+1 end; assert(a==0)
|
||||
a = 0; for i=9999, 1e4, -1 do a=a+1 end; assert(a==0)
|
||||
a = 0; for i=1, 0.99999, -1 do a=a+1 end; assert(a==1)
|
||||
|
||||
-- float count
|
||||
a = 0; for i=0, 0.999999999, 0.1 do a=a+1 end; assert(a==10)
|
||||
a = 0; for i=1.0, 1, 1 do a=a+1 end; assert(a==1)
|
||||
a = 0; for i=-1.5, -1.5, 1 do a=a+1 end; assert(a==1)
|
||||
a = 0; for i=1e6, 1e6, -1 do a=a+1 end; assert(a==1)
|
||||
a = 0; for i=1.0, 0.99999, 1 do a=a+1 end; assert(a==0)
|
||||
a = 0; for i=99999, 1e5, -1.0 do a=a+1 end; assert(a==0)
|
||||
a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1)
|
||||
end
|
||||
|
||||
-- conversion
|
||||
a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)
|
||||
|
||||
do -- checking types
|
||||
local c
|
||||
local function checkfloat (i)
|
||||
assert(math.type(i) == "float")
|
||||
c = c + 1
|
||||
end
|
||||
|
||||
c = 0; for i = 1.0, 10 do checkfloat(i) end
|
||||
assert(c == 10)
|
||||
|
||||
c = 0; for i = -1, -10, -1.0 do checkfloat(i) end
|
||||
assert(c == 10)
|
||||
|
||||
local function checkint (i)
|
||||
assert(math.type(i) == "integer")
|
||||
c = c + 1
|
||||
end
|
||||
|
||||
local m = math.maxinteger
|
||||
c = 0; for i = m, m - 10, -1 do checkint(i) end
|
||||
assert(c == 11)
|
||||
|
||||
c = 0; for i = 1, 10.9 do checkint(i) end
|
||||
assert(c == 10)
|
||||
|
||||
c = 0; for i = 10, 0.001, -1 do checkint(i) end
|
||||
assert(c == 10)
|
||||
|
||||
c = 0; for i = 1, "10.8" do checkint(i) end
|
||||
assert(c == 10)
|
||||
|
||||
c = 0; for i = 9, "3.4", -1 do checkint(i) end
|
||||
assert(c == 6)
|
||||
|
||||
c = 0; for i = 0, " -3.4 ", -1 do checkint(i) end
|
||||
assert(c == 4)
|
||||
|
||||
c = 0; for i = 100, "96.3", -2 do checkint(i) end
|
||||
assert(c == 2)
|
||||
|
||||
c = 0; for i = 1, math.huge do if i > 10 then break end; checkint(i) end
|
||||
assert(c == 10)
|
||||
|
||||
c = 0; for i = -1, -math.huge, -1 do
|
||||
if i < -10 then break end; checkint(i)
|
||||
end
|
||||
assert(c == 10)
|
||||
|
||||
|
||||
for i = math.mininteger, -10e100 do assert(false) end
|
||||
for i = math.maxinteger, 10e100, -1 do assert(false) end
|
||||
|
||||
end
|
||||
|
||||
collectgarbage()
|
||||
|
||||
|
||||
-- testing generic 'for'
|
||||
|
||||
local function f (n, p)
|
||||
local t = {}; for i=1,p do t[i] = i*10 end
|
||||
return function (_,n)
|
||||
if n > 0 then
|
||||
n = n-1
|
||||
return n, table.unpack(t)
|
||||
end
|
||||
end, nil, n
|
||||
end
|
||||
|
||||
local x = 0
|
||||
for n,a,b,c,d in f(5,3) do
|
||||
x = x+1
|
||||
assert(a == 10 and b == 20 and c == 30 and d == nil)
|
||||
end
|
||||
assert(x == 5)
|
||||
|
||||
|
||||
|
||||
-- testing __pairs and __ipairs metamethod
|
||||
a = {}
|
||||
do
|
||||
local x,y,z = pairs(a)
|
||||
assert(type(x) == 'function' and y == a and z == nil)
|
||||
end
|
||||
|
||||
local function foo (e,i)
|
||||
assert(e == a)
|
||||
if i <= 10 then return i+1, i+2 end
|
||||
end
|
||||
|
||||
local function foo1 (e,i)
|
||||
i = i + 1
|
||||
assert(e == a)
|
||||
if i <= e.n then return i,a[i] end
|
||||
end
|
||||
|
||||
setmetatable(a, {__pairs = function (x) return foo, x, 0 end})
|
||||
|
||||
local i = 0
|
||||
for k,v in pairs(a) do
|
||||
i = i + 1
|
||||
assert(k == i and v == k+1)
|
||||
end
|
||||
|
||||
a.n = 5
|
||||
a[3] = 30
|
||||
|
||||
-- testing ipairs with metamethods
|
||||
a = {n=10}
|
||||
setmetatable(a, { __index = function (t,k)
|
||||
if k <= t.n then return k * 10 end
|
||||
end})
|
||||
i = 0
|
||||
for k,v in ipairs(a) do
|
||||
i = i + 1
|
||||
assert(k == i and v == i * 10)
|
||||
end
|
||||
assert(i == a.n)
|
||||
|
||||
print"OK"
|
374
06/parser-gen/parsers/lua-5.3.4-tests/pm.lua
Normal file
374
06/parser-gen/parsers/lua-5.3.4-tests/pm.lua
Normal file
|
@ -0,0 +1,374 @@
|
|||
-- $Id: pm.lua,v 1.48 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing pattern matching')
|
||||
|
||||
local function checkerror (msg, f, ...)
|
||||
local s, err = pcall(f, ...)
|
||||
assert(not s and string.find(err, msg))
|
||||
end
|
||||
|
||||
|
||||
function f(s, p)
|
||||
local i,e = string.find(s, p)
|
||||
if i then return string.sub(s, i, e) end
|
||||
end
|
||||
|
||||
a,b = string.find('', '') -- empty patterns are tricky
|
||||
assert(a == 1 and b == 0);
|
||||
a,b = string.find('alo', '')
|
||||
assert(a == 1 and b == 0)
|
||||
a,b = string.find('a\0o a\0o a\0o', 'a', 1) -- first position
|
||||
assert(a == 1 and b == 1)
|
||||
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 2) -- starts in the midle
|
||||
assert(a == 5 and b == 7)
|
||||
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 9) -- starts in the midle
|
||||
assert(a == 9 and b == 11)
|
||||
a,b = string.find('a\0a\0a\0a\0\0ab', '\0ab', 2); -- finds at the end
|
||||
assert(a == 9 and b == 11);
|
||||
a,b = string.find('a\0a\0a\0a\0\0ab', 'b') -- last position
|
||||
assert(a == 11 and b == 11)
|
||||
assert(string.find('a\0a\0a\0a\0\0ab', 'b\0') == nil) -- check ending
|
||||
assert(string.find('', '\0') == nil)
|
||||
assert(string.find('alo123alo', '12') == 4)
|
||||
assert(string.find('alo123alo', '^12') == nil)
|
||||
|
||||
assert(string.match("aaab", ".*b") == "aaab")
|
||||
assert(string.match("aaa", ".*a") == "aaa")
|
||||
assert(string.match("b", ".*b") == "b")
|
||||
|
||||
assert(string.match("aaab", ".+b") == "aaab")
|
||||
assert(string.match("aaa", ".+a") == "aaa")
|
||||
assert(not string.match("b", ".+b"))
|
||||
|
||||
assert(string.match("aaab", ".?b") == "ab")
|
||||
assert(string.match("aaa", ".?a") == "aa")
|
||||
assert(string.match("b", ".?b") == "b")
|
||||
|
||||
assert(f('aloALO', '%l*') == 'alo')
|
||||
assert(f('aLo_ALO', '%a*') == 'aLo')
|
||||
|
||||
assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu")
|
||||
|
||||
assert(f('aaab', 'a*') == 'aaa');
|
||||
assert(f('aaa', '^.*$') == 'aaa');
|
||||
assert(f('aaa', 'b*') == '');
|
||||
assert(f('aaa', 'ab*a') == 'aa')
|
||||
assert(f('aba', 'ab*a') == 'aba')
|
||||
assert(f('aaab', 'a+') == 'aaa')
|
||||
assert(f('aaa', '^.+$') == 'aaa')
|
||||
assert(f('aaa', 'b+') == nil)
|
||||
assert(f('aaa', 'ab+a') == nil)
|
||||
assert(f('aba', 'ab+a') == 'aba')
|
||||
assert(f('a$a', '.$') == 'a')
|
||||
assert(f('a$a', '.%$') == 'a$')
|
||||
assert(f('a$a', '.$.') == 'a$a')
|
||||
assert(f('a$a', '$$') == nil)
|
||||
assert(f('a$b', 'a$') == nil)
|
||||
assert(f('a$a', '$') == '')
|
||||
assert(f('', 'b*') == '')
|
||||
assert(f('aaa', 'bb*') == nil)
|
||||
assert(f('aaab', 'a-') == '')
|
||||
assert(f('aaa', '^.-$') == 'aaa')
|
||||
assert(f('aabaaabaaabaaaba', 'b.*b') == 'baaabaaabaaab')
|
||||
assert(f('aabaaabaaabaaaba', 'b.-b') == 'baaab')
|
||||
assert(f('alo xo', '.o$') == 'xo')
|
||||
assert(f(' \n isto é assim', '%S%S*') == 'isto')
|
||||
assert(f(' \n isto é assim', '%S*$') == 'assim')
|
||||
assert(f(' \n isto é assim', '[a-z]*$') == 'assim')
|
||||
assert(f('um caracter ? extra', '[^%sa-z]') == '?')
|
||||
assert(f('', 'a?') == '')
|
||||
assert(f('á', 'á?') == 'á')
|
||||
assert(f('ábl', 'á?b?l?') == 'ábl')
|
||||
assert(f(' ábl', 'á?b?l?') == '')
|
||||
assert(f('aa', '^aa?a?a') == 'aa')
|
||||
assert(f(']]]áb', '[^]]') == 'á')
|
||||
assert(f("0alo alo", "%x*") == "0a")
|
||||
assert(f("alo alo", "%C+") == "alo alo")
|
||||
print('+')
|
||||
|
||||
|
||||
function f1(s, p)
|
||||
p = string.gsub(p, "%%([0-9])", function (s)
|
||||
return "%" .. (tonumber(s)+1)
|
||||
end)
|
||||
p = string.gsub(p, "^(^?)", "%1()", 1)
|
||||
p = string.gsub(p, "($?)$", "()%1", 1)
|
||||
local t = {string.match(s, p)}
|
||||
return string.sub(s, t[1], t[#t] - 1)
|
||||
end
|
||||
|
||||
assert(f1('alo alx 123 b\0o b\0o', '(..*) %1') == "b\0o b\0o")
|
||||
assert(f1('axz123= 4= 4 34', '(.+)=(.*)=%2 %1') == '3= 4= 4 3')
|
||||
assert(f1('=======', '^(=*)=%1$') == '=======')
|
||||
assert(string.match('==========', '^([=]*)=%1$') == nil)
|
||||
|
||||
local function range (i, j)
|
||||
if i <= j then
|
||||
return i, range(i+1, j)
|
||||
end
|
||||
end
|
||||
|
||||
local abc = string.char(range(0, 255));
|
||||
|
||||
assert(string.len(abc) == 256)
|
||||
|
||||
function strset (p)
|
||||
local res = {s=''}
|
||||
string.gsub(abc, p, function (c) res.s = res.s .. c end)
|
||||
return res.s
|
||||
end;
|
||||
|
||||
assert(string.len(strset('[\200-\210]')) == 11)
|
||||
|
||||
assert(strset('[a-z]') == "abcdefghijklmnopqrstuvwxyz")
|
||||
assert(strset('[a-z%d]') == strset('[%da-uu-z]'))
|
||||
assert(strset('[a-]') == "-a")
|
||||
assert(strset('[^%W]') == strset('[%w]'))
|
||||
assert(strset('[]%%]') == '%]')
|
||||
assert(strset('[a%-z]') == '-az')
|
||||
assert(strset('[%^%[%-a%]%-b]') == '-[]^ab')
|
||||
assert(strset('%Z') == strset('[\1-\255]'))
|
||||
assert(strset('.') == strset('[\1-\255%z]'))
|
||||
print('+');
|
||||
|
||||
assert(string.match("alo xyzK", "(%w+)K") == "xyz")
|
||||
assert(string.match("254 K", "(%d*)K") == "")
|
||||
assert(string.match("alo ", "(%w*)$") == "")
|
||||
assert(string.match("alo ", "(%w+)$") == nil)
|
||||
assert(string.find("(álo)", "%(á") == 1)
|
||||
local a, b, c, d, e = string.match("âlo alo", "^(((.).).* (%w*))$")
|
||||
assert(a == 'âlo alo' and b == 'âl' and c == 'â' and d == 'alo' and e == nil)
|
||||
a, b, c, d = string.match('0123456789', '(.+(.?)())')
|
||||
assert(a == '0123456789' and b == '' and c == 11 and d == nil)
|
||||
print('+')
|
||||
|
||||
assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo')
|
||||
assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim
|
||||
assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim
|
||||
assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
|
||||
t = "abç d"
|
||||
a, b = string.gsub(t, '(.)', '%1@')
|
||||
assert('@'..a == string.gsub(t, '', '@') and b == 5)
|
||||
a, b = string.gsub('abçd', '(.)', '%0@', 2)
|
||||
assert(a == 'a@b@çd' and b == 2)
|
||||
assert(string.gsub('alo alo', '()[al]', '%1') == '12o 56o')
|
||||
assert(string.gsub("abc=xyz", "(%w*)(%p)(%w+)", "%3%2%1-%0") ==
|
||||
"xyz=abc-abc=xyz")
|
||||
assert(string.gsub("abc", "%w", "%1%0") == "aabbcc")
|
||||
assert(string.gsub("abc", "%w+", "%0%1") == "abcabc")
|
||||
assert(string.gsub('áéí', '$', '\0óú') == 'áéí\0óú')
|
||||
assert(string.gsub('', '^', 'r') == 'r')
|
||||
assert(string.gsub('', '$', 'r') == 'r')
|
||||
print('+')
|
||||
|
||||
|
||||
do -- new (5.3.3) semantics for empty matches
|
||||
assert(string.gsub("a b cd", " *", "-") == "-a-b-c-d-")
|
||||
|
||||
local res = ""
|
||||
local sub = "a \nbc\t\td"
|
||||
local i = 1
|
||||
for p, e in string.gmatch(sub, "()%s*()") do
|
||||
res = res .. string.sub(sub, i, p - 1) .. "-"
|
||||
i = e
|
||||
end
|
||||
assert(res == "-a-b-c-d-")
|
||||
end
|
||||
|
||||
|
||||
assert(string.gsub("um (dois) tres (quatro)", "(%(%w+%))", string.upper) ==
|
||||
"um (DOIS) tres (QUATRO)")
|
||||
|
||||
do
|
||||
local function setglobal (n,v) rawset(_G, n, v) end
|
||||
string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
|
||||
assert(_G.a=="roberto" and _G.roberto=="a")
|
||||
end
|
||||
|
||||
function f(a,b) return string.gsub(a,'.',b) end
|
||||
assert(string.gsub("trocar tudo em |teste|b| é |beleza|al|", "|([^|]*)|([^|]*)|", f) ==
|
||||
"trocar tudo em bbbbb é alalalalalal")
|
||||
|
||||
local function dostring (s) return load(s, "")() or "" end
|
||||
assert(string.gsub("alo $a='x'$ novamente $return a$",
|
||||
"$([^$]*)%$",
|
||||
dostring) == "alo novamente x")
|
||||
|
||||
x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
|
||||
"$([^$]*)%$", dostring)
|
||||
assert(x == ' assim vai para ALO')
|
||||
|
||||
t = {}
|
||||
s = 'a alo jose joao'
|
||||
r = string.gsub(s, '()(%w+)()', function (a,w,b)
|
||||
assert(string.len(w) == b-a);
|
||||
t[a] = b-a;
|
||||
end)
|
||||
assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
|
||||
|
||||
|
||||
function isbalanced (s)
|
||||
return string.find(string.gsub(s, "%b()", ""), "[()]") == nil
|
||||
end
|
||||
|
||||
assert(isbalanced("(9 ((8))(\0) 7) \0\0 a b ()(c)() a"))
|
||||
assert(not isbalanced("(9 ((8) 7) a b (\0 c) a"))
|
||||
assert(string.gsub("alo 'oi' alo", "%b''", '"') == 'alo " alo')
|
||||
|
||||
|
||||
local t = {"apple", "orange", "lime"; n=0}
|
||||
assert(string.gsub("x and x and x", "x", function () t.n=t.n+1; return t[t.n] end)
|
||||
== "apple and orange and lime")
|
||||
|
||||
t = {n=0}
|
||||
string.gsub("first second word", "%w%w*", function (w) t.n=t.n+1; t[t.n] = w end)
|
||||
assert(t[1] == "first" and t[2] == "second" and t[3] == "word" and t.n == 3)
|
||||
|
||||
t = {n=0}
|
||||
assert(string.gsub("first second word", "%w+",
|
||||
function (w) t.n=t.n+1; t[t.n] = w end, 2) == "first second word")
|
||||
assert(t[1] == "first" and t[2] == "second" and t[3] == nil)
|
||||
|
||||
checkerror("invalid replacement value %(a table%)",
|
||||
string.gsub, "alo", ".", {a = {}})
|
||||
checkerror("invalid capture index %%2", string.gsub, "alo", ".", "%2")
|
||||
checkerror("invalid capture index %%0", string.gsub, "alo", "(%0)", "a")
|
||||
checkerror("invalid capture index %%1", string.gsub, "alo", "(%1)", "a")
|
||||
checkerror("invalid use of '%%'", string.gsub, "alo", ".", "%x")
|
||||
|
||||
-- bug since 2.5 (C-stack overflow)
|
||||
do
|
||||
local function f (size)
|
||||
local s = string.rep("a", size)
|
||||
local p = string.rep(".?", size)
|
||||
return pcall(string.match, s, p)
|
||||
end
|
||||
local r, m = f(80)
|
||||
assert(r and #m == 80)
|
||||
r, m = f(200000)
|
||||
assert(not r and string.find(m, "too complex"))
|
||||
end
|
||||
|
||||
if not _soft then
|
||||
print("big strings")
|
||||
local a = string.rep('a', 300000)
|
||||
assert(string.find(a, '^a*.?$'))
|
||||
assert(not string.find(a, '^a*.?b$'))
|
||||
assert(string.find(a, '^a-.?$'))
|
||||
|
||||
-- bug in 5.1.2
|
||||
a = string.rep('a', 10000) .. string.rep('b', 10000)
|
||||
assert(not pcall(string.gsub, a, 'b'))
|
||||
end
|
||||
|
||||
-- recursive nest of gsubs
|
||||
function rev (s)
|
||||
return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
|
||||
end
|
||||
|
||||
local x = "abcdef"
|
||||
assert(rev(rev(x)) == x)
|
||||
|
||||
|
||||
-- gsub with tables
|
||||
assert(string.gsub("alo alo", ".", {}) == "alo alo")
|
||||
assert(string.gsub("alo alo", "(.)", {a="AA", l=""}) == "AAo AAo")
|
||||
assert(string.gsub("alo alo", "(.).", {a="AA", l="K"}) == "AAo AAo")
|
||||
assert(string.gsub("alo alo", "((.)(.?))", {al="AA", o=false}) == "AAo AAo")
|
||||
|
||||
assert(string.gsub("alo alo", "().", {'x','yy','zzz'}) == "xyyzzz alo")
|
||||
|
||||
t = {}; setmetatable(t, {__index = function (t,s) return string.upper(s) end})
|
||||
assert(string.gsub("a alo b hi", "%w%w+", t) == "a ALO b HI")
|
||||
|
||||
|
||||
-- tests for gmatch
|
||||
local a = 0
|
||||
for i in string.gmatch('abcde', '()') do assert(i == a+1); a=i end
|
||||
assert(a==6)
|
||||
|
||||
t = {n=0}
|
||||
for w in string.gmatch("first second word", "%w+") do
|
||||
t.n=t.n+1; t[t.n] = w
|
||||
end
|
||||
assert(t[1] == "first" and t[2] == "second" and t[3] == "word")
|
||||
|
||||
t = {3, 6, 9}
|
||||
for i in string.gmatch ("xuxx uu ppar r", "()(.)%2") do
|
||||
assert(i == table.remove(t, 1))
|
||||
end
|
||||
assert(#t == 0)
|
||||
|
||||
t = {}
|
||||
for i,j in string.gmatch("13 14 10 = 11, 15= 16, 22=23", "(%d+)%s*=%s*(%d+)") do
|
||||
t[tonumber(i)] = tonumber(j)
|
||||
end
|
||||
a = 0
|
||||
for k,v in pairs(t) do assert(k+1 == v+0); a=a+1 end
|
||||
assert(a == 3)
|
||||
|
||||
|
||||
-- tests for `%f' (`frontiers')
|
||||
|
||||
assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
|
||||
assert(string.gsub("[[]] [][] [[[[", "%f[[].", "x") == "x[]] x]x] x[[[")
|
||||
assert(string.gsub("01abc45de3", "%f[%d]", ".") == ".01abc.45de.3")
|
||||
assert(string.gsub("01abc45 de3x", "%f[%D]%w", ".") == "01.bc45 de3.")
|
||||
assert(string.gsub("function", "%f[\1-\255]%w", ".") == ".unction")
|
||||
assert(string.gsub("function", "%f[^\1-\255]", ".") == "function.")
|
||||
|
||||
assert(string.find("a", "%f[a]") == 1)
|
||||
assert(string.find("a", "%f[^%z]") == 1)
|
||||
assert(string.find("a", "%f[^%l]") == 2)
|
||||
assert(string.find("aba", "%f[a%z]") == 3)
|
||||
assert(string.find("aba", "%f[%z]") == 4)
|
||||
assert(not string.find("aba", "%f[%l%z]"))
|
||||
assert(not string.find("aba", "%f[^%l%z]"))
|
||||
|
||||
local i, e = string.find(" alo aalo allo", "%f[%S].-%f[%s].-%f[%S]")
|
||||
assert(i == 2 and e == 5)
|
||||
local k = string.match(" alo aalo allo", "%f[%S](.-%f[%s].-%f[%S])")
|
||||
assert(k == 'alo ')
|
||||
|
||||
local a = {1, 5, 9, 14, 17,}
|
||||
for k in string.gmatch("alo alo th02 is 1hat", "()%f[%w%d]") do
|
||||
assert(table.remove(a, 1) == k)
|
||||
end
|
||||
assert(#a == 0)
|
||||
|
||||
|
||||
-- malformed patterns
|
||||
local function malform (p, m)
|
||||
m = m or "malformed"
|
||||
local r, msg = pcall(string.find, "a", p)
|
||||
assert(not r and string.find(msg, m))
|
||||
end
|
||||
|
||||
malform("(.", "unfinished capture")
|
||||
malform(".)", "invalid pattern capture")
|
||||
malform("[a")
|
||||
malform("[]")
|
||||
malform("[^]")
|
||||
malform("[a%]")
|
||||
malform("[a%")
|
||||
malform("%b")
|
||||
malform("%ba")
|
||||
malform("%")
|
||||
malform("%f", "missing")
|
||||
|
||||
-- \0 in patterns
|
||||
assert(string.match("ab\0\1\2c", "[\0-\2]+") == "\0\1\2")
|
||||
assert(string.match("ab\0\1\2c", "[\0-\0]+") == "\0")
|
||||
assert(string.find("b$a", "$\0?") == 2)
|
||||
assert(string.find("abc\0efg", "%\0") == 4)
|
||||
assert(string.match("abc\0efg\0\1e\1g", "%b\0\1") == "\0efg\0\1e\1")
|
||||
assert(string.match("abc\0\0\0", "%\0+") == "\0\0\0")
|
||||
assert(string.match("abc\0\0\0", "%\0%\0?") == "\0\0")
|
||||
|
||||
-- magic char after \0
|
||||
assert(string.find("abc\0\0","\0.") == 4)
|
||||
assert(string.find("abcx\0\0abc\0abc","x\0\0abc\0a.") == 4)
|
||||
|
||||
print('OK')
|
||||
|
310
06/parser-gen/parsers/lua-5.3.4-tests/sort.lua
Normal file
310
06/parser-gen/parsers/lua-5.3.4-tests/sort.lua
Normal file
|
@ -0,0 +1,310 @@
|
|||
-- $Id: sort.lua,v 1.38 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print "testing (parts of) table library"
|
||||
|
||||
print "testing unpack"
|
||||
|
||||
local unpack = table.unpack
|
||||
|
||||
local maxI = math.maxinteger
|
||||
local minI = math.mininteger
|
||||
|
||||
|
||||
local function checkerror (msg, f, ...)
|
||||
local s, err = pcall(f, ...)
|
||||
assert(not s and string.find(err, msg))
|
||||
end
|
||||
|
||||
|
||||
checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4)
|
||||
|
||||
local x,y,z,a,n
|
||||
a = {}; lim = _soft and 200 or 2000
|
||||
for i=1, lim do a[i]=i end
|
||||
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
|
||||
x = unpack(a)
|
||||
assert(x == 1)
|
||||
x = {unpack(a)}
|
||||
assert(#x == lim and x[1] == 1 and x[lim] == lim)
|
||||
x = {unpack(a, lim-2)}
|
||||
assert(#x == 3 and x[1] == lim-2 and x[3] == lim)
|
||||
x = {unpack(a, 10, 6)}
|
||||
assert(next(x) == nil) -- no elements
|
||||
x = {unpack(a, 11, 10)}
|
||||
assert(next(x) == nil) -- no elements
|
||||
x,y = unpack(a, 10, 10)
|
||||
assert(x == 10 and y == nil)
|
||||
x,y,z = unpack(a, 10, 11)
|
||||
assert(x == 10 and y == 11 and z == nil)
|
||||
a,x = unpack{1}
|
||||
assert(a==1 and x==nil)
|
||||
a,x = unpack({1,2}, 1, 1)
|
||||
assert(a==1 and x==nil)
|
||||
|
||||
do
|
||||
local maxi = (1 << 31) - 1 -- maximum value for an int (usually)
|
||||
local mini = -(1 << 31) -- minimum value for an int (usually)
|
||||
checkerror("too many results", unpack, {}, 0, maxi)
|
||||
checkerror("too many results", unpack, {}, 1, maxi)
|
||||
checkerror("too many results", unpack, {}, 0, maxI)
|
||||
checkerror("too many results", unpack, {}, 1, maxI)
|
||||
checkerror("too many results", unpack, {}, mini, maxi)
|
||||
checkerror("too many results", unpack, {}, -maxi, maxi)
|
||||
checkerror("too many results", unpack, {}, minI, maxI)
|
||||
unpack({}, maxi, 0)
|
||||
unpack({}, maxi, 1)
|
||||
unpack({}, maxI, minI)
|
||||
pcall(unpack, {}, 1, maxi + 1)
|
||||
local a, b = unpack({[maxi] = 20}, maxi, maxi)
|
||||
assert(a == 20 and b == nil)
|
||||
a, b = unpack({[maxi] = 20}, maxi - 1, maxi)
|
||||
assert(a == nil and b == 20)
|
||||
local t = {[maxI - 1] = 12, [maxI] = 23}
|
||||
a, b = unpack(t, maxI - 1, maxI); assert(a == 12 and b == 23)
|
||||
a, b = unpack(t, maxI, maxI); assert(a == 23 and b == nil)
|
||||
a, b = unpack(t, maxI, maxI - 1); assert(a == nil and b == nil)
|
||||
t = {[minI] = 12.3, [minI + 1] = 23.5}
|
||||
a, b = unpack(t, minI, minI + 1); assert(a == 12.3 and b == 23.5)
|
||||
a, b = unpack(t, minI, minI); assert(a == 12.3 and b == nil)
|
||||
a, b = unpack(t, minI + 1, minI); assert(a == nil and b == nil)
|
||||
end
|
||||
|
||||
do -- length is not an integer
|
||||
local t = setmetatable({}, {__len = function () return 'abc' end})
|
||||
assert(#t == 'abc')
|
||||
checkerror("object length is not an integer", table.insert, t, 1)
|
||||
end
|
||||
|
||||
print "testing pack"
|
||||
|
||||
a = table.pack()
|
||||
assert(a[1] == nil and a.n == 0)
|
||||
|
||||
a = table.pack(table)
|
||||
assert(a[1] == table and a.n == 1)
|
||||
|
||||
a = table.pack(nil, nil, nil, nil)
|
||||
assert(a[1] == nil and a.n == 4)
|
||||
|
||||
|
||||
-- testing move
|
||||
do
|
||||
|
||||
checkerror("table expected", table.move, 1, 2, 3, 4)
|
||||
|
||||
local function eqT (a, b)
|
||||
for k, v in pairs(a) do assert(b[k] == v) end
|
||||
for k, v in pairs(b) do assert(a[k] == v) end
|
||||
end
|
||||
|
||||
local a = table.move({10,20,30}, 1, 3, 2) -- move forward
|
||||
eqT(a, {10,10,20,30})
|
||||
|
||||
-- move forward with overlap of 1
|
||||
a = table.move({10, 20, 30}, 1, 3, 3)
|
||||
eqT(a, {10, 20, 10, 20, 30})
|
||||
|
||||
-- moving to the same table (not being explicit about it)
|
||||
a = {10, 20, 30, 40}
|
||||
table.move(a, 1, 4, 2, a)
|
||||
eqT(a, {10, 10, 20, 30, 40})
|
||||
|
||||
a = table.move({10,20,30}, 2, 3, 1) -- move backward
|
||||
eqT(a, {20,30,30})
|
||||
|
||||
a = {} -- move to new table
|
||||
assert(table.move({10,20,30}, 1, 3, 1, a) == a)
|
||||
eqT(a, {10,20,30})
|
||||
|
||||
a = {}
|
||||
assert(table.move({10,20,30}, 1, 0, 3, a) == a) -- empty move (no move)
|
||||
eqT(a, {})
|
||||
|
||||
a = table.move({10,20,30}, 1, 10, 1) -- move to the same place
|
||||
eqT(a, {10,20,30})
|
||||
|
||||
-- moving on the fringes
|
||||
a = table.move({[maxI - 2] = 1, [maxI - 1] = 2, [maxI] = 3},
|
||||
maxI - 2, maxI, -10, {})
|
||||
eqT(a, {[-10] = 1, [-9] = 2, [-8] = 3})
|
||||
|
||||
a = table.move({[minI] = 1, [minI + 1] = 2, [minI + 2] = 3},
|
||||
minI, minI + 2, -10, {})
|
||||
eqT(a, {[-10] = 1, [-9] = 2, [-8] = 3})
|
||||
|
||||
a = table.move({45}, 1, 1, maxI)
|
||||
eqT(a, {45, [maxI] = 45})
|
||||
|
||||
a = table.move({[maxI] = 100}, maxI, maxI, minI)
|
||||
eqT(a, {[minI] = 100, [maxI] = 100})
|
||||
|
||||
a = table.move({[minI] = 100}, minI, minI, maxI)
|
||||
eqT(a, {[minI] = 100, [maxI] = 100})
|
||||
|
||||
a = setmetatable({}, {
|
||||
__index = function (_,k) return k * 10 end,
|
||||
__newindex = error})
|
||||
local b = table.move(a, 1, 10, 3, {})
|
||||
eqT(a, {})
|
||||
eqT(b, {nil,nil,10,20,30,40,50,60,70,80,90,100})
|
||||
|
||||
b = setmetatable({""}, {
|
||||
__index = error,
|
||||
__newindex = function (t,k,v)
|
||||
t[1] = string.format("%s(%d,%d)", t[1], k, v)
|
||||
end})
|
||||
table.move(a, 10, 13, 3, b)
|
||||
assert(b[1] == "(3,100)(4,110)(5,120)(6,130)")
|
||||
local stat, msg = pcall(table.move, b, 10, 13, 3, b)
|
||||
assert(not stat and msg == b)
|
||||
end
|
||||
|
||||
do
|
||||
-- for very long moves, just check initial accesses and interrupt
|
||||
-- move with an error
|
||||
local function checkmove (f, e, t, x, y)
|
||||
local pos1, pos2
|
||||
local a = setmetatable({}, {
|
||||
__index = function (_,k) pos1 = k end,
|
||||
__newindex = function (_,k) pos2 = k; error() end, })
|
||||
local st, msg = pcall(table.move, a, f, e, t)
|
||||
assert(not st and not msg and pos1 == x and pos2 == y)
|
||||
end
|
||||
checkmove(1, maxI, 0, 1, 0)
|
||||
checkmove(0, maxI - 1, 1, maxI - 1, maxI)
|
||||
checkmove(minI, -2, -5, -2, maxI - 6)
|
||||
checkmove(minI + 1, -1, -2, -1, maxI - 3)
|
||||
checkmove(minI, -2, 0, minI, 0) -- non overlapping
|
||||
checkmove(minI + 1, -1, 1, minI + 1, 1) -- non overlapping
|
||||
end
|
||||
|
||||
checkerror("too many", table.move, {}, 0, maxI, 1)
|
||||
checkerror("too many", table.move, {}, -1, maxI - 1, 1)
|
||||
checkerror("too many", table.move, {}, minI, -1, 1)
|
||||
checkerror("too many", table.move, {}, minI, maxI, 1)
|
||||
checkerror("wrap around", table.move, {}, 1, maxI, 2)
|
||||
checkerror("wrap around", table.move, {}, 1, 2, maxI)
|
||||
checkerror("wrap around", table.move, {}, minI, -2, 2)
|
||||
|
||||
|
||||
print"testing sort"
|
||||
|
||||
|
||||
-- strange lengths
|
||||
local a = setmetatable({}, {__len = function () return -1 end})
|
||||
assert(#a == -1)
|
||||
table.sort(a, error) -- should not compare anything
|
||||
a = setmetatable({}, {__len = function () return maxI end})
|
||||
checkerror("too big", table.sort, a)
|
||||
|
||||
-- test checks for invalid order functions
|
||||
local function check (t)
|
||||
local function f(a, b) assert(a and b); return true end
|
||||
checkerror("invalid order function", table.sort, t, f)
|
||||
end
|
||||
|
||||
check{1,2,3,4}
|
||||
check{1,2,3,4,5}
|
||||
check{1,2,3,4,5,6}
|
||||
|
||||
|
||||
function check (a, f)
|
||||
f = f or function (x,y) return x<y end;
|
||||
for n = #a, 2, -1 do
|
||||
assert(not f(a[n], a[n-1]))
|
||||
end
|
||||
end
|
||||
|
||||
a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
|
||||
"Oct", "Nov", "Dec"}
|
||||
|
||||
table.sort(a)
|
||||
check(a)
|
||||
|
||||
function perm (s, n)
|
||||
n = n or #s
|
||||
if n == 1 then
|
||||
local t = {unpack(s)}
|
||||
table.sort(t)
|
||||
check(t)
|
||||
else
|
||||
for i = 1, n do
|
||||
s[i], s[n] = s[n], s[i]
|
||||
perm(s, n - 1)
|
||||
s[i], s[n] = s[n], s[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
perm{}
|
||||
perm{1}
|
||||
perm{1,2}
|
||||
perm{1,2,3}
|
||||
perm{1,2,3,4}
|
||||
perm{2,2,3,4}
|
||||
perm{1,2,3,4,5}
|
||||
perm{1,2,3,3,5}
|
||||
perm{1,2,3,4,5,6}
|
||||
perm{2,2,3,3,5,6}
|
||||
|
||||
function timesort (a, n, func, msg, pre)
|
||||
local x = os.clock()
|
||||
table.sort(a, func)
|
||||
x = (os.clock() - x) * 1000
|
||||
pre = pre or ""
|
||||
print(string.format("%ssorting %d %s elements in %.2f msec.", pre, n, msg, x))
|
||||
check(a, func)
|
||||
end
|
||||
|
||||
limit = 50000
|
||||
if _soft then limit = 5000 end
|
||||
|
||||
a = {}
|
||||
for i=1,limit do
|
||||
a[i] = math.random()
|
||||
end
|
||||
|
||||
timesort(a, limit, nil, "random")
|
||||
|
||||
timesort(a, limit, nil, "sorted", "re-")
|
||||
|
||||
a = {}
|
||||
for i=1,limit do
|
||||
a[i] = math.random()
|
||||
end
|
||||
|
||||
x = os.clock(); i=0
|
||||
table.sort(a, function(x,y) i=i+1; return y<x end)
|
||||
x = (os.clock() - x) * 1000
|
||||
print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons",
|
||||
limit, x, i))
|
||||
check(a, function(x,y) return y<x end)
|
||||
|
||||
|
||||
table.sort{} -- empty array
|
||||
|
||||
for i=1,limit do a[i] = false end
|
||||
timesort(a, limit, function(x,y) return nil end, "equal")
|
||||
|
||||
for i,v in pairs(a) do assert(v == false) end
|
||||
|
||||
A = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
|
||||
table.sort(A)
|
||||
check(A)
|
||||
|
||||
table.sort(A, function (x, y)
|
||||
load(string.format("A[%q] = ''", x), "")()
|
||||
collectgarbage()
|
||||
return x<y
|
||||
end)
|
||||
|
||||
|
||||
tt = {__lt = function (a,b) return a.val < b.val end}
|
||||
a = {}
|
||||
for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
|
||||
table.sort(a)
|
||||
check(a, tt.__lt)
|
||||
check(a)
|
||||
|
||||
print"OK"
|
379
06/parser-gen/parsers/lua-5.3.4-tests/strings.lua
Normal file
379
06/parser-gen/parsers/lua-5.3.4-tests/strings.lua
Normal file
|
@ -0,0 +1,379 @@
|
|||
-- $Id: strings.lua,v 1.87 2016/12/21 19:23:02 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing strings and string library')
|
||||
|
||||
local maxi, mini = math.maxinteger, math.mininteger
|
||||
|
||||
|
||||
local function checkerror (msg, f, ...)
|
||||
local s, err = pcall(f, ...)
|
||||
assert(not s and string.find(err, msg))
|
||||
end
|
||||
|
||||
|
||||
-- testing string comparisons
|
||||
assert('alo' < 'alo1')
|
||||
assert('' < 'a')
|
||||
assert('alo\0alo' < 'alo\0b')
|
||||
assert('alo\0alo\0\0' > 'alo\0alo\0')
|
||||
assert('alo' < 'alo\0')
|
||||
assert('alo\0' > 'alo')
|
||||
assert('\0' < '\1')
|
||||
assert('\0\0' < '\0\1')
|
||||
assert('\1\0a\0a' <= '\1\0a\0a')
|
||||
assert(not ('\1\0a\0b' <= '\1\0a\0a'))
|
||||
assert('\0\0\0' < '\0\0\0\0')
|
||||
assert(not('\0\0\0\0' < '\0\0\0'))
|
||||
assert('\0\0\0' <= '\0\0\0\0')
|
||||
assert(not('\0\0\0\0' <= '\0\0\0'))
|
||||
assert('\0\0\0' <= '\0\0\0')
|
||||
assert('\0\0\0' >= '\0\0\0')
|
||||
assert(not ('\0\0b' < '\0\0a\0'))
|
||||
|
||||
-- testing string.sub
|
||||
assert(string.sub("123456789",2,4) == "234")
|
||||
assert(string.sub("123456789",7) == "789")
|
||||
assert(string.sub("123456789",7,6) == "")
|
||||
assert(string.sub("123456789",7,7) == "7")
|
||||
assert(string.sub("123456789",0,0) == "")
|
||||
assert(string.sub("123456789",-10,10) == "123456789")
|
||||
assert(string.sub("123456789",1,9) == "123456789")
|
||||
assert(string.sub("123456789",-10,-20) == "")
|
||||
assert(string.sub("123456789",-1) == "9")
|
||||
assert(string.sub("123456789",-4) == "6789")
|
||||
assert(string.sub("123456789",-6, -4) == "456")
|
||||
assert(string.sub("123456789", mini, -4) == "123456")
|
||||
assert(string.sub("123456789", mini, maxi) == "123456789")
|
||||
assert(string.sub("123456789", mini, mini) == "")
|
||||
assert(string.sub("\000123456789",3,5) == "234")
|
||||
assert(("\000123456789"):sub(8) == "789")
|
||||
|
||||
-- testing string.find
|
||||
assert(string.find("123456789", "345") == 3)
|
||||
a,b = string.find("123456789", "345")
|
||||
assert(string.sub("123456789", a, b) == "345")
|
||||
assert(string.find("1234567890123456789", "345", 3) == 3)
|
||||
assert(string.find("1234567890123456789", "345", 4) == 13)
|
||||
assert(string.find("1234567890123456789", "346", 4) == nil)
|
||||
assert(string.find("1234567890123456789", ".45", -9) == 13)
|
||||
assert(string.find("abcdefg", "\0", 5, 1) == nil)
|
||||
assert(string.find("", "") == 1)
|
||||
assert(string.find("", "", 1) == 1)
|
||||
assert(not string.find("", "", 2))
|
||||
assert(string.find('', 'aaa', 1) == nil)
|
||||
assert(('alo(.)alo'):find('(.)', 1, 1) == 4)
|
||||
|
||||
assert(string.len("") == 0)
|
||||
assert(string.len("\0\0\0") == 3)
|
||||
assert(string.len("1234567890") == 10)
|
||||
|
||||
assert(#"" == 0)
|
||||
assert(#"\0\0\0" == 3)
|
||||
assert(#"1234567890" == 10)
|
||||
|
||||
-- testing string.byte/string.char
|
||||
assert(string.byte("a") == 97)
|
||||
assert(string.byte("\xe4") > 127)
|
||||
assert(string.byte(string.char(255)) == 255)
|
||||
assert(string.byte(string.char(0)) == 0)
|
||||
assert(string.byte("\0") == 0)
|
||||
assert(string.byte("\0\0alo\0x", -1) == string.byte('x'))
|
||||
assert(string.byte("ba", 2) == 97)
|
||||
assert(string.byte("\n\n", 2, -1) == 10)
|
||||
assert(string.byte("\n\n", 2, 2) == 10)
|
||||
assert(string.byte("") == nil)
|
||||
assert(string.byte("hi", -3) == nil)
|
||||
assert(string.byte("hi", 3) == nil)
|
||||
assert(string.byte("hi", 9, 10) == nil)
|
||||
assert(string.byte("hi", 2, 1) == nil)
|
||||
assert(string.char() == "")
|
||||
assert(string.char(0, 255, 0) == "\0\255\0")
|
||||
assert(string.char(0, string.byte("\xe4"), 0) == "\0\xe4\0")
|
||||
assert(string.char(string.byte("\xe4l\0óu", 1, -1)) == "\xe4l\0óu")
|
||||
assert(string.char(string.byte("\xe4l\0óu", 1, 0)) == "")
|
||||
assert(string.char(string.byte("\xe4l\0óu", -10, 100)) == "\xe4l\0óu")
|
||||
|
||||
assert(string.upper("ab\0c") == "AB\0C")
|
||||
assert(string.lower("\0ABCc%$") == "\0abcc%$")
|
||||
assert(string.rep('teste', 0) == '')
|
||||
assert(string.rep('tés\00tê', 2) == 'tés\0têtés\000tê')
|
||||
assert(string.rep('', 10) == '')
|
||||
|
||||
if string.packsize("i") == 4 then
|
||||
-- result length would be 2^31 (int overflow)
|
||||
checkerror("too large", string.rep, 'aa', (1 << 30))
|
||||
checkerror("too large", string.rep, 'a', (1 << 30), ',')
|
||||
end
|
||||
|
||||
-- repetitions with separator
|
||||
assert(string.rep('teste', 0, 'xuxu') == '')
|
||||
assert(string.rep('teste', 1, 'xuxu') == 'teste')
|
||||
assert(string.rep('\1\0\1', 2, '\0\0') == '\1\0\1\0\0\1\0\1')
|
||||
assert(string.rep('', 10, '.') == string.rep('.', 9))
|
||||
assert(not pcall(string.rep, "aa", maxi // 2 + 10))
|
||||
assert(not pcall(string.rep, "", maxi // 2 + 10, "aa"))
|
||||
|
||||
assert(string.reverse"" == "")
|
||||
assert(string.reverse"\0\1\2\3" == "\3\2\1\0")
|
||||
assert(string.reverse"\0001234" == "4321\0")
|
||||
|
||||
for i=0,30 do assert(string.len(string.rep('a', i)) == i) end
|
||||
|
||||
assert(type(tostring(nil)) == 'string')
|
||||
assert(type(tostring(12)) == 'string')
|
||||
assert(string.find(tostring{}, 'table:'))
|
||||
assert(string.find(tostring(print), 'function:'))
|
||||
assert(#tostring('\0') == 1)
|
||||
assert(tostring(true) == "true")
|
||||
assert(tostring(false) == "false")
|
||||
assert(tostring(-1203) == "-1203")
|
||||
assert(tostring(1203.125) == "1203.125")
|
||||
assert(tostring(-0.5) == "-0.5")
|
||||
assert(tostring(-32767) == "-32767")
|
||||
if math.tointeger(2147483647) then -- no overflow? (32 bits)
|
||||
assert(tostring(-2147483647) == "-2147483647")
|
||||
end
|
||||
if math.tointeger(4611686018427387904) then -- no overflow? (64 bits)
|
||||
assert(tostring(4611686018427387904) == "4611686018427387904")
|
||||
assert(tostring(-4611686018427387904) == "-4611686018427387904")
|
||||
end
|
||||
|
||||
if tostring(0.0) == "0.0" then -- "standard" coercion float->string
|
||||
assert('' .. 12 == '12' and 12.0 .. '' == '12.0')
|
||||
assert(tostring(-1203 + 0.0) == "-1203.0")
|
||||
else -- compatible coercion
|
||||
assert(tostring(0.0) == "0")
|
||||
assert('' .. 12 == '12' and 12.0 .. '' == '12')
|
||||
assert(tostring(-1203 + 0.0) == "-1203")
|
||||
end
|
||||
|
||||
|
||||
x = '"ílo"\n\\'
|
||||
assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
|
||||
assert(string.format('%q', "\0") == [["\0"]])
|
||||
assert(load(string.format('return %q', x))() == x)
|
||||
x = "\0\1\0023\5\0009"
|
||||
assert(load(string.format('return %q', x))() == x)
|
||||
assert(string.format("\0%c\0%c%x\0", string.byte("\xe4"), string.byte("b"), 140) ==
|
||||
"\0\xe4\0b8c\0")
|
||||
assert(string.format('') == "")
|
||||
assert(string.format("%c",34)..string.format("%c",48)..string.format("%c",90)..string.format("%c",100) ==
|
||||
string.format("%c%c%c%c", 34, 48, 90, 100))
|
||||
assert(string.format("%s\0 is not \0%s", 'not be', 'be') == 'not be\0 is not \0be')
|
||||
assert(string.format("%%%d %010d", 10, 23) == "%10 0000000023")
|
||||
assert(tonumber(string.format("%f", 10.3)) == 10.3)
|
||||
x = string.format('"%-50s"', 'a')
|
||||
assert(#x == 52)
|
||||
assert(string.sub(x, 1, 4) == '"a ')
|
||||
|
||||
assert(string.format("-%.20s.20s", string.rep("%", 2000)) ==
|
||||
"-"..string.rep("%", 20)..".20s")
|
||||
assert(string.format('"-%20s.20s"', string.rep("%", 2000)) ==
|
||||
string.format("%q", "-"..string.rep("%", 2000)..".20s"))
|
||||
|
||||
do
|
||||
local function checkQ (v)
|
||||
local s = string.format("%q", v)
|
||||
local nv = load("return " .. s)()
|
||||
assert(v == nv and math.type(v) == math.type(nv))
|
||||
end
|
||||
checkQ("\0\0\1\255\u{234}")
|
||||
checkQ(math.maxinteger)
|
||||
checkQ(math.mininteger)
|
||||
checkQ(math.pi)
|
||||
checkQ(0.1)
|
||||
checkQ(true)
|
||||
checkQ(nil)
|
||||
checkQ(false)
|
||||
checkerror("no literal", string.format, "%q", {})
|
||||
end
|
||||
|
||||
assert(string.format("\0%s\0", "\0\0\1") == "\0\0\0\1\0")
|
||||
checkerror("contains zeros", string.format, "%10s", "\0")
|
||||
|
||||
-- format x tostring
|
||||
assert(string.format("%s %s", nil, true) == "nil true")
|
||||
assert(string.format("%s %.4s", false, true) == "false true")
|
||||
assert(string.format("%.3s %.3s", false, true) == "fal tru")
|
||||
local m = setmetatable({}, {__tostring = function () return "hello" end,
|
||||
__name = "hi"})
|
||||
assert(string.format("%s %.10s", m, m) == "hello hello")
|
||||
getmetatable(m).__tostring = nil -- will use '__name' from now on
|
||||
assert(string.format("%.4s", m) == "hi: ")
|
||||
|
||||
getmetatable(m).__tostring = function () return {} end
|
||||
checkerror("'__tostring' must return a string", tostring, m)
|
||||
|
||||
|
||||
assert(string.format("%x", 0.0) == "0")
|
||||
assert(string.format("%02x", 0.0) == "00")
|
||||
assert(string.format("%08X", 0xFFFFFFFF) == "FFFFFFFF")
|
||||
assert(string.format("%+08d", 31501) == "+0031501")
|
||||
assert(string.format("%+08d", -30927) == "-0030927")
|
||||
|
||||
|
||||
do -- longest number that can be formatted
|
||||
local i = 1
|
||||
local j = 10000
|
||||
while i + 1 < j do -- binary search for maximum finite float
|
||||
local m = (i + j) // 2
|
||||
if 10^m < math.huge then i = m else j = m end
|
||||
end
|
||||
assert(10^i < math.huge and 10^j == math.huge)
|
||||
local s = string.format('%.99f', -(10^i))
|
||||
assert(string.len(s) >= i + 101)
|
||||
assert(tonumber(s) == -(10^i))
|
||||
end
|
||||
|
||||
|
||||
-- testing large numbers for format
|
||||
do -- assume at least 32 bits
|
||||
local max, min = 0x7fffffff, -0x80000000 -- "large" for 32 bits
|
||||
assert(string.sub(string.format("%8x", -1), -8) == "ffffffff")
|
||||
assert(string.format("%x", max) == "7fffffff")
|
||||
assert(string.sub(string.format("%x", min), -8) == "80000000")
|
||||
assert(string.format("%d", max) == "2147483647")
|
||||
assert(string.format("%d", min) == "-2147483648")
|
||||
assert(string.format("%u", 0xffffffff) == "4294967295")
|
||||
assert(string.format("%o", 0xABCD) == "125715")
|
||||
|
||||
max, min = 0x7fffffffffffffff, -0x8000000000000000
|
||||
if max > 2.0^53 then -- only for 64 bits
|
||||
assert(string.format("%x", (2^52 | 0) - 1) == "fffffffffffff")
|
||||
assert(string.format("0x%8X", 0x8f000003) == "0x8F000003")
|
||||
assert(string.format("%d", 2^53) == "9007199254740992")
|
||||
assert(string.format("%i", -2^53) == "-9007199254740992")
|
||||
assert(string.format("%x", max) == "7fffffffffffffff")
|
||||
assert(string.format("%x", min) == "8000000000000000")
|
||||
assert(string.format("%d", max) == "9223372036854775807")
|
||||
assert(string.format("%d", min) == "-9223372036854775808")
|
||||
assert(string.format("%u", ~(-1 << 64)) == "18446744073709551615")
|
||||
assert(tostring(1234567890123) == '1234567890123')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
do print("testing 'format %a %A'")
|
||||
local function matchhexa (n)
|
||||
local s = string.format("%a", n)
|
||||
-- result matches ISO C requirements
|
||||
assert(string.find(s, "^%-?0x[1-9a-f]%.?[0-9a-f]*p[-+]?%d+$"))
|
||||
assert(tonumber(s) == n) -- and has full precision
|
||||
s = string.format("%A", n)
|
||||
assert(string.find(s, "^%-?0X[1-9A-F]%.?[0-9A-F]*P[-+]?%d+$"))
|
||||
assert(tonumber(s) == n)
|
||||
end
|
||||
for _, n in ipairs{0.1, -0.1, 1/3, -1/3, 1e30, -1e30,
|
||||
-45/247, 1, -1, 2, -2, 3e-20, -3e-20} do
|
||||
matchhexa(n)
|
||||
end
|
||||
|
||||
assert(string.find(string.format("%A", 0.0), "^0X0%.?0?P%+?0$"))
|
||||
assert(string.find(string.format("%a", -0.0), "^%-0x0%.?0?p%+?0$"))
|
||||
|
||||
if not _port then -- test inf, -inf, NaN, and -0.0
|
||||
assert(string.find(string.format("%a", 1/0), "^inf"))
|
||||
assert(string.find(string.format("%A", -1/0), "^%-INF"))
|
||||
assert(string.find(string.format("%a", 0/0), "^%-?nan"))
|
||||
assert(string.find(string.format("%a", -0.0), "^%-0x0"))
|
||||
end
|
||||
|
||||
if not pcall(string.format, "%.3a", 0) then
|
||||
(Message or print)("\n >>> modifiers for format '%a' not available <<<\n")
|
||||
else
|
||||
assert(string.find(string.format("%+.2A", 12), "^%+0X%x%.%x0P%+?%d$"))
|
||||
assert(string.find(string.format("%.4A", -12), "^%-0X%x%.%x000P%+?%d$"))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- errors in format
|
||||
|
||||
local function check (fmt, msg)
|
||||
checkerror(msg, string.format, fmt, 10)
|
||||
end
|
||||
|
||||
local aux = string.rep('0', 600)
|
||||
check("%100.3d", "too long")
|
||||
check("%1"..aux..".3d", "too long")
|
||||
check("%1.100d", "too long")
|
||||
check("%10.1"..aux.."004d", "too long")
|
||||
check("%t", "invalid option")
|
||||
check("%"..aux.."d", "repeated flags")
|
||||
check("%d %d", "no value")
|
||||
|
||||
|
||||
assert(load("return 1\n--comment without ending EOL")() == 1)
|
||||
|
||||
|
||||
checkerror("table expected", table.concat, 3)
|
||||
assert(table.concat{} == "")
|
||||
assert(table.concat({}, 'x') == "")
|
||||
assert(table.concat({'\0', '\0\1', '\0\1\2'}, '.\0.') == "\0.\0.\0\1.\0.\0\1\2")
|
||||
local a = {}; for i=1,300 do a[i] = "xuxu" end
|
||||
assert(table.concat(a, "123").."123" == string.rep("xuxu123", 300))
|
||||
assert(table.concat(a, "b", 20, 20) == "xuxu")
|
||||
assert(table.concat(a, "", 20, 21) == "xuxuxuxu")
|
||||
assert(table.concat(a, "x", 22, 21) == "")
|
||||
assert(table.concat(a, "3", 299) == "xuxu3xuxu")
|
||||
assert(table.concat({}, "x", maxi, maxi - 1) == "")
|
||||
assert(table.concat({}, "x", mini + 1, mini) == "")
|
||||
assert(table.concat({}, "x", maxi, mini) == "")
|
||||
assert(table.concat({[maxi] = "alo"}, "x", maxi, maxi) == "alo")
|
||||
assert(table.concat({[maxi] = "alo", [maxi - 1] = "y"}, "-", maxi - 1, maxi)
|
||||
== "y-alo")
|
||||
|
||||
assert(not pcall(table.concat, {"a", "b", {}}))
|
||||
|
||||
a = {"a","b","c"}
|
||||
assert(table.concat(a, ",", 1, 0) == "")
|
||||
assert(table.concat(a, ",", 1, 1) == "a")
|
||||
assert(table.concat(a, ",", 1, 2) == "a,b")
|
||||
assert(table.concat(a, ",", 2) == "b,c")
|
||||
assert(table.concat(a, ",", 3) == "c")
|
||||
assert(table.concat(a, ",", 4) == "")
|
||||
|
||||
if not _port then
|
||||
|
||||
local locales = { "ptb", "pt_BR.iso88591", "ISO-8859-1" }
|
||||
local function trylocale (w)
|
||||
for i = 1, #locales do
|
||||
if os.setlocale(locales[i], w) then
|
||||
print(string.format("'%s' locale set to '%s'", w, locales[i]))
|
||||
return locales[i]
|
||||
end
|
||||
end
|
||||
print(string.format("'%s' locale not found", w))
|
||||
return false
|
||||
end
|
||||
|
||||
if trylocale("collate") then
|
||||
assert("alo" < "álo" and "álo" < "amo")
|
||||
end
|
||||
|
||||
if trylocale("ctype") then
|
||||
assert(string.gsub("áéíóú", "%a", "x") == "xxxxx")
|
||||
assert(string.gsub("áÁéÉ", "%l", "x") == "xÁxÉ")
|
||||
assert(string.gsub("áÁéÉ", "%u", "x") == "áxéx")
|
||||
assert(string.upper"áÁé{xuxu}ção" == "ÁÁÉ{XUXU}ÇÃO")
|
||||
end
|
||||
|
||||
os.setlocale("C")
|
||||
assert(os.setlocale() == 'C')
|
||||
assert(os.setlocale(nil, "numeric") == 'C')
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- bug in Lua 5.3.2
|
||||
-- 'gmatch' iterator does not work across coroutines
|
||||
do
|
||||
local f = string.gmatch("1 2 3 4 5", "%d+")
|
||||
assert(f() == "1")
|
||||
co = coroutine.wrap(f)
|
||||
assert(co() == "2")
|
||||
end
|
||||
|
||||
print('OK')
|
||||
|
322
06/parser-gen/parsers/lua-5.3.4-tests/tpack.lua
Normal file
322
06/parser-gen/parsers/lua-5.3.4-tests/tpack.lua
Normal file
|
@ -0,0 +1,322 @@
|
|||
-- $Id: tpack.lua,v 1.13 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
local pack = string.pack
|
||||
local packsize = string.packsize
|
||||
local unpack = string.unpack
|
||||
|
||||
print "testing pack/unpack"
|
||||
|
||||
-- maximum size for integers
|
||||
local NB = 16
|
||||
|
||||
local sizeshort = packsize("h")
|
||||
local sizeint = packsize("i")
|
||||
local sizelong = packsize("l")
|
||||
local sizesize_t = packsize("T")
|
||||
local sizeLI = packsize("j")
|
||||
local sizefloat = packsize("f")
|
||||
local sizedouble = packsize("d")
|
||||
local sizenumber = packsize("n")
|
||||
local little = (pack("i2", 1) == "\1\0")
|
||||
local align = packsize("!xXi16")
|
||||
|
||||
assert(1 <= sizeshort and sizeshort <= sizeint and sizeint <= sizelong and
|
||||
sizefloat <= sizedouble)
|
||||
|
||||
print("platform:")
|
||||
print(string.format(
|
||||
"\tshort %d, int %d, long %d, size_t %d, float %d, double %d,\n\z
|
||||
\tlua Integer %d, lua Number %d",
|
||||
sizeshort, sizeint, sizelong, sizesize_t, sizefloat, sizedouble,
|
||||
sizeLI, sizenumber))
|
||||
print("\t" .. (little and "little" or "big") .. " endian")
|
||||
print("\talignment: " .. align)
|
||||
|
||||
|
||||
-- check errors in arguments
|
||||
function checkerror (msg, f, ...)
|
||||
local status, err = pcall(f, ...)
|
||||
-- print(status, err, msg)
|
||||
assert(not status and string.find(err, msg))
|
||||
end
|
||||
|
||||
-- minimum behavior for integer formats
|
||||
assert(unpack("B", pack("B", 0xff)) == 0xff)
|
||||
assert(unpack("b", pack("b", 0x7f)) == 0x7f)
|
||||
assert(unpack("b", pack("b", -0x80)) == -0x80)
|
||||
|
||||
assert(unpack("H", pack("H", 0xffff)) == 0xffff)
|
||||
assert(unpack("h", pack("h", 0x7fff)) == 0x7fff)
|
||||
assert(unpack("h", pack("h", -0x8000)) == -0x8000)
|
||||
|
||||
assert(unpack("L", pack("L", 0xffffffff)) == 0xffffffff)
|
||||
assert(unpack("l", pack("l", 0x7fffffff)) == 0x7fffffff)
|
||||
assert(unpack("l", pack("l", -0x80000000)) == -0x80000000)
|
||||
|
||||
|
||||
for i = 1, NB do
|
||||
-- small numbers with signal extension ("\xFF...")
|
||||
local s = string.rep("\xff", i)
|
||||
assert(pack("i" .. i, -1) == s)
|
||||
assert(packsize("i" .. i) == #s)
|
||||
assert(unpack("i" .. i, s) == -1)
|
||||
|
||||
-- small unsigned number ("\0...\xAA")
|
||||
s = "\xAA" .. string.rep("\0", i - 1)
|
||||
assert(pack("<I" .. i, 0xAA) == s)
|
||||
assert(unpack("<I" .. i, s) == 0xAA)
|
||||
assert(pack(">I" .. i, 0xAA) == s:reverse())
|
||||
assert(unpack(">I" .. i, s:reverse()) == 0xAA)
|
||||
end
|
||||
|
||||
do
|
||||
local lnum = 0x13121110090807060504030201
|
||||
local s = pack("<j", lnum)
|
||||
assert(unpack("<j", s) == lnum)
|
||||
assert(unpack("<i" .. sizeLI + 1, s .. "\0") == lnum)
|
||||
assert(unpack("<i" .. sizeLI + 1, s .. "\0") == lnum)
|
||||
|
||||
for i = sizeLI + 1, NB do
|
||||
local s = pack("<j", -lnum)
|
||||
assert(unpack("<j", s) == -lnum)
|
||||
-- strings with (correct) extra bytes
|
||||
assert(unpack("<i" .. i, s .. ("\xFF"):rep(i - sizeLI)) == -lnum)
|
||||
assert(unpack(">i" .. i, ("\xFF"):rep(i - sizeLI) .. s:reverse()) == -lnum)
|
||||
assert(unpack("<I" .. i, s .. ("\0"):rep(i - sizeLI)) == -lnum)
|
||||
|
||||
-- overflows
|
||||
checkerror("does not fit", unpack, "<I" .. i, ("\x00"):rep(i - 1) .. "\1")
|
||||
checkerror("does not fit", unpack, ">i" .. i, "\1" .. ("\x00"):rep(i - 1))
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, sizeLI do
|
||||
local lstr = "\1\2\3\4\5\6\7\8\9\10\11\12\13"
|
||||
local lnum = 0x13121110090807060504030201
|
||||
local n = lnum & (~(-1 << (i * 8)))
|
||||
local s = string.sub(lstr, 1, i)
|
||||
assert(pack("<i" .. i, n) == s)
|
||||
assert(pack(">i" .. i, n) == s:reverse())
|
||||
assert(unpack(">i" .. i, s:reverse()) == n)
|
||||
end
|
||||
|
||||
-- sign extension
|
||||
do
|
||||
local u = 0xf0
|
||||
for i = 1, sizeLI - 1 do
|
||||
assert(unpack("<i"..i, "\xf0"..("\xff"):rep(i - 1)) == -16)
|
||||
assert(unpack(">I"..i, "\xf0"..("\xff"):rep(i - 1)) == u)
|
||||
u = u * 256 + 0xff
|
||||
end
|
||||
end
|
||||
|
||||
-- mixed endianness
|
||||
do
|
||||
assert(pack(">i2 <i2", 10, 20) == "\0\10\20\0")
|
||||
local a, b = unpack("<i2 >i2", "\10\0\0\20")
|
||||
assert(a == 10 and b == 20)
|
||||
assert(pack("=i4", 2001) == pack("i4", 2001))
|
||||
end
|
||||
|
||||
print("testing invalid formats")
|
||||
|
||||
checkerror("out of limits", pack, "i0", 0)
|
||||
checkerror("out of limits", pack, "i" .. NB + 1, 0)
|
||||
checkerror("out of limits", pack, "!" .. NB + 1, 0)
|
||||
checkerror("%(17%) out of limits %[1,16%]", pack, "Xi" .. NB + 1)
|
||||
checkerror("invalid format option 'r'", pack, "i3r", 0)
|
||||
checkerror("16%-byte integer", unpack, "i16", string.rep('\3', 16))
|
||||
checkerror("not power of 2", pack, "!4i3", 0);
|
||||
checkerror("missing size", pack, "c", "")
|
||||
checkerror("variable%-length format", packsize, "s")
|
||||
checkerror("variable%-length format", packsize, "z")
|
||||
|
||||
-- overflow in option size (error will be in digit after limit)
|
||||
checkerror("invalid format", packsize, "c1" .. string.rep("0", 40))
|
||||
|
||||
if packsize("i") == 4 then
|
||||
-- result would be 2^31 (2^3 repetitions of 2^28 strings)
|
||||
local s = string.rep("c268435456", 2^3)
|
||||
checkerror("too large", packsize, s)
|
||||
-- one less is OK
|
||||
s = string.rep("c268435456", 2^3 - 1) .. "c268435455"
|
||||
assert(packsize(s) == 0x7fffffff)
|
||||
end
|
||||
|
||||
-- overflow in packing
|
||||
for i = 1, sizeLI - 1 do
|
||||
local umax = (1 << (i * 8)) - 1
|
||||
local max = umax >> 1
|
||||
local min = ~max
|
||||
checkerror("overflow", pack, "<I" .. i, -1)
|
||||
checkerror("overflow", pack, "<I" .. i, min)
|
||||
checkerror("overflow", pack, ">I" .. i, umax + 1)
|
||||
|
||||
checkerror("overflow", pack, ">i" .. i, umax)
|
||||
checkerror("overflow", pack, ">i" .. i, max + 1)
|
||||
checkerror("overflow", pack, "<i" .. i, min - 1)
|
||||
|
||||
assert(unpack(">i" .. i, pack(">i" .. i, max)) == max)
|
||||
assert(unpack("<i" .. i, pack("<i" .. i, min)) == min)
|
||||
assert(unpack(">I" .. i, pack(">I" .. i, umax)) == umax)
|
||||
end
|
||||
|
||||
-- Lua integer size
|
||||
assert(unpack(">j", pack(">j", math.maxinteger)) == math.maxinteger)
|
||||
assert(unpack("<j", pack("<j", math.mininteger)) == math.mininteger)
|
||||
assert(unpack("<J", pack("<j", -1)) == -1) -- maximum unsigned integer
|
||||
|
||||
if little then
|
||||
assert(pack("f", 24) == pack("<f", 24))
|
||||
else
|
||||
assert(pack("f", 24) == pack(">f", 24))
|
||||
end
|
||||
|
||||
print "testing pack/unpack of floating-point numbers"
|
||||
|
||||
for _, n in ipairs{0, -1.1, 1.9, 1/0, -1/0, 1e20, -1e20, 0.1, 2000.7} do
|
||||
assert(unpack("n", pack("n", n)) == n)
|
||||
assert(unpack("<n", pack("<n", n)) == n)
|
||||
assert(unpack(">n", pack(">n", n)) == n)
|
||||
assert(pack("<f", n) == pack(">f", n):reverse())
|
||||
assert(pack(">d", n) == pack("<d", n):reverse())
|
||||
end
|
||||
|
||||
-- for non-native precisions, test only with "round" numbers
|
||||
for _, n in ipairs{0, -1.5, 1/0, -1/0, 1e10, -1e9, 0.5, 2000.25} do
|
||||
assert(unpack("<f", pack("<f", n)) == n)
|
||||
assert(unpack(">f", pack(">f", n)) == n)
|
||||
assert(unpack("<d", pack("<d", n)) == n)
|
||||
assert(unpack(">d", pack(">d", n)) == n)
|
||||
end
|
||||
|
||||
print "testing pack/unpack of strings"
|
||||
do
|
||||
local s = string.rep("abc", 1000)
|
||||
assert(pack("zB", s, 247) == s .. "\0\xF7")
|
||||
local s1, b = unpack("zB", s .. "\0\xF9")
|
||||
assert(b == 249 and s1 == s)
|
||||
s1 = pack("s", s)
|
||||
assert(unpack("s", s1) == s)
|
||||
|
||||
checkerror("does not fit", pack, "s1", s)
|
||||
|
||||
checkerror("contains zeros", pack, "z", "alo\0");
|
||||
|
||||
for i = 2, NB do
|
||||
local s1 = pack("s" .. i, s)
|
||||
assert(unpack("s" .. i, s1) == s and #s1 == #s + i)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local x = pack("s", "alo")
|
||||
checkerror("too short", unpack, "s", x:sub(1, -2))
|
||||
checkerror("too short", unpack, "c5", "abcd")
|
||||
checkerror("out of limits", pack, "s100", "alo")
|
||||
end
|
||||
|
||||
do
|
||||
assert(pack("c0", "") == "")
|
||||
assert(packsize("c0") == 0)
|
||||
assert(unpack("c0", "") == "")
|
||||
assert(pack("<! c3", "abc") == "abc")
|
||||
assert(packsize("<! c3") == 3)
|
||||
assert(pack(">!4 c6", "abcdef") == "abcdef")
|
||||
assert(pack("c3", "123") == "123")
|
||||
assert(pack("c0", "") == "")
|
||||
assert(pack("c8", "123456") == "123456\0\0")
|
||||
assert(pack("c88", "") == string.rep("\0", 88))
|
||||
assert(pack("c188", "ab") == "ab" .. string.rep("\0", 188 - 2))
|
||||
local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz")
|
||||
assert(a == "abcdefghi" and b == "xyz" and c == 14)
|
||||
checkerror("longer than", pack, "c3", "1234")
|
||||
end
|
||||
|
||||
|
||||
-- testing multiple types and sequence
|
||||
do
|
||||
local x = pack("<b h b f d f n i", 1, 2, 3, 4, 5, 6, 7, 8)
|
||||
assert(#x == packsize("<b h b f d f n i"))
|
||||
local a, b, c, d, e, f, g, h = unpack("<b h b f d f n i", x)
|
||||
assert(a == 1 and b == 2 and c == 3 and d == 4 and e == 5 and f == 6 and
|
||||
g == 7 and h == 8)
|
||||
end
|
||||
|
||||
print "testing alignment"
|
||||
do
|
||||
assert(pack(" < i1 i2 ", 2, 3) == "\2\3\0") -- no alignment by default
|
||||
local x = pack(">!8 b Xh i4 i8 c1 Xi8", -12, 100, 200, "\xEC")
|
||||
assert(#x == packsize(">!8 b Xh i4 i8 c1 Xi8"))
|
||||
assert(x == "\xf4" .. "\0\0\0" ..
|
||||
"\0\0\0\100" ..
|
||||
"\0\0\0\0\0\0\0\xC8" ..
|
||||
"\xEC" .. "\0\0\0\0\0\0\0")
|
||||
local a, b, c, d, pos = unpack(">!8 c1 Xh i4 i8 b Xi8 XI XH", x)
|
||||
assert(a == "\xF4" and b == 100 and c == 200 and d == -20 and (pos - 1) == #x)
|
||||
|
||||
x = pack(">!4 c3 c4 c2 z i4 c5 c2 Xi4",
|
||||
"abc", "abcd", "xz", "hello", 5, "world", "xy")
|
||||
assert(x == "abcabcdxzhello\0\0\0\0\0\5worldxy\0")
|
||||
local a, b, c, d, e, f, g, pos = unpack(">!4 c3 c4 c2 z i4 c5 c2 Xh Xi4", x)
|
||||
assert(a == "abc" and b == "abcd" and c == "xz" and d == "hello" and
|
||||
e == 5 and f == "world" and g == "xy" and (pos - 1) % 4 == 0)
|
||||
|
||||
x = pack(" b b Xd b Xb x", 1, 2, 3)
|
||||
assert(packsize(" b b Xd b Xb x") == 4)
|
||||
assert(x == "\1\2\3\0")
|
||||
a, b, c, pos = unpack("bbXdb", x)
|
||||
assert(a == 1 and b == 2 and c == 3 and pos == #x)
|
||||
|
||||
-- only alignment
|
||||
assert(packsize("!8 xXi8") == 8)
|
||||
local pos = unpack("!8 xXi8", "0123456701234567"); assert(pos == 9)
|
||||
assert(packsize("!8 xXi2") == 2)
|
||||
local pos = unpack("!8 xXi2", "0123456701234567"); assert(pos == 3)
|
||||
assert(packsize("!2 xXi2") == 2)
|
||||
local pos = unpack("!2 xXi2", "0123456701234567"); assert(pos == 3)
|
||||
assert(packsize("!2 xXi8") == 2)
|
||||
local pos = unpack("!2 xXi8", "0123456701234567"); assert(pos == 3)
|
||||
assert(packsize("!16 xXi16") == 16)
|
||||
local pos = unpack("!16 xXi16", "0123456701234567"); assert(pos == 17)
|
||||
|
||||
checkerror("invalid next option", pack, "X")
|
||||
checkerror("invalid next option", unpack, "XXi", "")
|
||||
checkerror("invalid next option", unpack, "X i", "")
|
||||
checkerror("invalid next option", pack, "Xc1")
|
||||
end
|
||||
|
||||
do -- testing initial position
|
||||
local x = pack("i4i4i4i4", 1, 2, 3, 4)
|
||||
for pos = 1, 16, 4 do
|
||||
local i, p = unpack("i4", x, pos)
|
||||
assert(i == pos//4 + 1 and p == pos + 4)
|
||||
end
|
||||
|
||||
-- with alignment
|
||||
for pos = 0, 12 do -- will always round position to power of 2
|
||||
local i, p = unpack("!4 i4", x, pos + 1)
|
||||
assert(i == (pos + 3)//4 + 1 and p == i*4 + 1)
|
||||
end
|
||||
|
||||
-- negative indices
|
||||
local i, p = unpack("!4 i4", x, -4)
|
||||
assert(i == 4 and p == 17)
|
||||
local i, p = unpack("!4 i4", x, -7)
|
||||
assert(i == 4 and p == 17)
|
||||
local i, p = unpack("!4 i4", x, -#x)
|
||||
assert(i == 1 and p == 5)
|
||||
|
||||
-- limits
|
||||
for i = 1, #x + 1 do
|
||||
assert(unpack("c0", x, i) == "")
|
||||
end
|
||||
checkerror("out of string", unpack, "c0", x, 0)
|
||||
checkerror("out of string", unpack, "c0", x, #x + 2)
|
||||
checkerror("out of string", unpack, "c0", x, -(#x + 1))
|
||||
|
||||
end
|
||||
|
||||
print "OK"
|
||||
|
210
06/parser-gen/parsers/lua-5.3.4-tests/utf8.lua
Normal file
210
06/parser-gen/parsers/lua-5.3.4-tests/utf8.lua
Normal file
|
@ -0,0 +1,210 @@
|
|||
-- $Id: utf8.lua,v 1.12 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print "testing UTF-8 library"
|
||||
|
||||
local utf8 = require'utf8'
|
||||
|
||||
|
||||
local function checkerror (msg, f, ...)
|
||||
local s, err = pcall(f, ...)
|
||||
assert(not s and string.find(err, msg))
|
||||
end
|
||||
|
||||
|
||||
local function len (s)
|
||||
return #string.gsub(s, "[\x80-\xBF]", "")
|
||||
end
|
||||
|
||||
|
||||
local justone = "^" .. utf8.charpattern .. "$"
|
||||
|
||||
-- 't' is the list of codepoints of 's'
|
||||
local function checksyntax (s, t)
|
||||
local ts = {"return '"}
|
||||
for i = 1, #t do ts[i + 1] = string.format("\\u{%x}", t[i]) end
|
||||
ts[#t + 2] = "'"
|
||||
ts = table.concat(ts)
|
||||
assert(assert(load(ts))() == s)
|
||||
end
|
||||
|
||||
assert(utf8.offset("alo", 5) == nil)
|
||||
assert(utf8.offset("alo", -4) == nil)
|
||||
|
||||
-- 't' is the list of codepoints of 's'
|
||||
local function check (s, t)
|
||||
local l = utf8.len(s)
|
||||
assert(#t == l and len(s) == l)
|
||||
assert(utf8.char(table.unpack(t)) == s)
|
||||
|
||||
assert(utf8.offset(s, 0) == 1)
|
||||
|
||||
checksyntax(s, t)
|
||||
|
||||
local t1 = {utf8.codepoint(s, 1, -1)}
|
||||
assert(#t == #t1)
|
||||
for i = 1, #t do assert(t[i] == t1[i]) end
|
||||
|
||||
for i = 1, l do
|
||||
local pi = utf8.offset(s, i) -- position of i-th char
|
||||
local pi1 = utf8.offset(s, 2, pi) -- position of next char
|
||||
assert(string.find(string.sub(s, pi, pi1 - 1), justone))
|
||||
assert(utf8.offset(s, -1, pi1) == pi)
|
||||
assert(utf8.offset(s, i - l - 1) == pi)
|
||||
assert(pi1 - pi == #utf8.char(utf8.codepoint(s, pi)))
|
||||
for j = pi, pi1 - 1 do
|
||||
assert(utf8.offset(s, 0, j) == pi)
|
||||
end
|
||||
for j = pi + 1, pi1 - 1 do
|
||||
assert(not utf8.len(s, j))
|
||||
end
|
||||
assert(utf8.len(s, pi, pi) == 1)
|
||||
assert(utf8.len(s, pi, pi1 - 1) == 1)
|
||||
assert(utf8.len(s, pi) == l - i + 1)
|
||||
assert(utf8.len(s, pi1) == l - i)
|
||||
assert(utf8.len(s, 1, pi) == i)
|
||||
end
|
||||
|
||||
local i = 0
|
||||
for p, c in utf8.codes(s) do
|
||||
i = i + 1
|
||||
assert(c == t[i] and p == utf8.offset(s, i))
|
||||
assert(utf8.codepoint(s, p) == c)
|
||||
end
|
||||
assert(i == #t)
|
||||
|
||||
i = 0
|
||||
for p, c in utf8.codes(s) do
|
||||
i = i + 1
|
||||
assert(c == t[i] and p == utf8.offset(s, i))
|
||||
end
|
||||
assert(i == #t)
|
||||
|
||||
i = 0
|
||||
for c in string.gmatch(s, utf8.charpattern) do
|
||||
i = i + 1
|
||||
assert(c == utf8.char(t[i]))
|
||||
end
|
||||
assert(i == #t)
|
||||
|
||||
for i = 1, l do
|
||||
assert(utf8.offset(s, i) == utf8.offset(s, i - l - 1, #s + 1))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- error indication in utf8.len
|
||||
local function check (s, p)
|
||||
local a, b = utf8.len(s)
|
||||
assert(not a and b == p)
|
||||
end
|
||||
check("abc\xE3def", 4)
|
||||
check("汉字\x80", #("汉字") + 1)
|
||||
check("\xF4\x9F\xBF", 1)
|
||||
check("\xF4\x9F\xBF\xBF", 1)
|
||||
end
|
||||
|
||||
-- error in utf8.codes
|
||||
checkerror("invalid UTF%-8 code",
|
||||
function ()
|
||||
local s = "ab\xff"
|
||||
for c in utf8.codes(s) do assert(c) end
|
||||
end)
|
||||
|
||||
|
||||
-- error in initial position for offset
|
||||
checkerror("position out of range", utf8.offset, "abc", 1, 5)
|
||||
checkerror("position out of range", utf8.offset, "abc", 1, -4)
|
||||
checkerror("position out of range", utf8.offset, "", 1, 2)
|
||||
checkerror("position out of range", utf8.offset, "", 1, -1)
|
||||
checkerror("continuation byte", utf8.offset, "𦧺", 1, 2)
|
||||
checkerror("continuation byte", utf8.offset, "𦧺", 1, 2)
|
||||
checkerror("continuation byte", utf8.offset, "\x80", 1)
|
||||
|
||||
|
||||
|
||||
local s = "hello World"
|
||||
local t = {string.byte(s, 1, -1)}
|
||||
for i = 1, utf8.len(s) do assert(t[i] == string.byte(s, i)) end
|
||||
check(s, t)
|
||||
|
||||
check("汉字/漢字", {27721, 23383, 47, 28450, 23383,})
|
||||
|
||||
do
|
||||
local s = "áéí\128"
|
||||
local t = {utf8.codepoint(s,1,#s - 1)}
|
||||
assert(#t == 3 and t[1] == 225 and t[2] == 233 and t[3] == 237)
|
||||
checkerror("invalid UTF%-8 code", utf8.codepoint, s, 1, #s)
|
||||
checkerror("out of range", utf8.codepoint, s, #s + 1)
|
||||
t = {utf8.codepoint(s, 4, 3)}
|
||||
assert(#t == 0)
|
||||
checkerror("out of range", utf8.codepoint, s, -(#s + 1), 1)
|
||||
checkerror("out of range", utf8.codepoint, s, 1, #s + 1)
|
||||
end
|
||||
|
||||
assert(utf8.char() == "")
|
||||
assert(utf8.char(97, 98, 99) == "abc")
|
||||
|
||||
assert(utf8.codepoint(utf8.char(0x10FFFF)) == 0x10FFFF)
|
||||
|
||||
checkerror("value out of range", utf8.char, 0x10FFFF + 1)
|
||||
|
||||
local function invalid (s)
|
||||
checkerror("invalid UTF%-8 code", utf8.codepoint, s)
|
||||
assert(not utf8.len(s))
|
||||
end
|
||||
|
||||
-- UTF-8 representation for 0x11ffff (value out of valid range)
|
||||
invalid("\xF4\x9F\xBF\xBF")
|
||||
|
||||
-- overlong sequences
|
||||
invalid("\xC0\x80") -- zero
|
||||
invalid("\xC1\xBF") -- 0x7F (should be coded in 1 byte)
|
||||
invalid("\xE0\x9F\xBF") -- 0x7FF (should be coded in 2 bytes)
|
||||
invalid("\xF0\x8F\xBF\xBF") -- 0xFFFF (should be coded in 3 bytes)
|
||||
|
||||
|
||||
-- invalid bytes
|
||||
invalid("\x80") -- continuation byte
|
||||
invalid("\xBF") -- continuation byte
|
||||
invalid("\xFE") -- invalid byte
|
||||
invalid("\xFF") -- invalid byte
|
||||
|
||||
|
||||
-- empty string
|
||||
check("", {})
|
||||
|
||||
-- minimum and maximum values for each sequence size
|
||||
s = "\0 \x7F\z
|
||||
\xC2\x80 \xDF\xBF\z
|
||||
\xE0\xA0\x80 \xEF\xBF\xBF\z
|
||||
\xF0\x90\x80\x80 \xF4\x8F\xBF\xBF"
|
||||
s = string.gsub(s, " ", "")
|
||||
check(s, {0,0x7F, 0x80,0x7FF, 0x800,0xFFFF, 0x10000,0x10FFFF})
|
||||
|
||||
x = "日本語a-4\0éó"
|
||||
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})
|
||||
|
||||
|
||||
-- Supplementary Characters
|
||||
check("𣲷𠜎𠱓𡁻𠵼ab𠺢",
|
||||
{0x23CB7, 0x2070E, 0x20C53, 0x2107B, 0x20D7C, 0x61, 0x62, 0x20EA2,})
|
||||
|
||||
check("𨳊𩶘𦧺𨳒𥄫𤓓\xF4\x8F\xBF\xBF",
|
||||
{0x28CCA, 0x29D98, 0x269FA, 0x28CD2, 0x2512B, 0x244D3, 0x10ffff})
|
||||
|
||||
|
||||
local i = 0
|
||||
for p, c in string.gmatch(x, "()(" .. utf8.charpattern .. ")") do
|
||||
i = i + 1
|
||||
assert(utf8.offset(x, i) == p)
|
||||
assert(utf8.len(x, p) == utf8.len(x) - i + 1)
|
||||
assert(utf8.len(c) == 1)
|
||||
for j = 1, #c - 1 do
|
||||
assert(utf8.offset(x, 0, p + j - 1) == p)
|
||||
end
|
||||
end
|
||||
|
||||
print'ok'
|
||||
|
142
06/parser-gen/parsers/lua-5.3.4-tests/vararg.lua
Normal file
142
06/parser-gen/parsers/lua-5.3.4-tests/vararg.lua
Normal file
|
@ -0,0 +1,142 @@
|
|||
-- $Id: vararg.lua,v 1.25 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print('testing vararg')
|
||||
|
||||
function f(a, ...)
|
||||
local arg = {n = select('#', ...), ...}
|
||||
for i=1,arg.n do assert(a[i]==arg[i]) end
|
||||
return arg.n
|
||||
end
|
||||
|
||||
function c12 (...)
|
||||
assert(arg == _G.arg) -- no local 'arg'
|
||||
local x = {...}; x.n = #x
|
||||
local res = (x.n==2 and x[1] == 1 and x[2] == 2)
|
||||
if res then res = 55 end
|
||||
return res, 2
|
||||
end
|
||||
|
||||
function vararg (...) return {n = select('#', ...), ...} end
|
||||
|
||||
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
|
||||
|
||||
assert(f() == 0)
|
||||
assert(f({1,2,3}, 1, 2, 3) == 3)
|
||||
assert(f({"alo", nil, 45, f, nil}, "alo", nil, 45, f, nil) == 5)
|
||||
|
||||
assert(c12(1,2)==55)
|
||||
a,b = assert(call(c12, {1,2}))
|
||||
assert(a == 55 and b == 2)
|
||||
a = call(c12, {1,2;n=2})
|
||||
assert(a == 55 and b == 2)
|
||||
a = call(c12, {1,2;n=1})
|
||||
assert(not a)
|
||||
assert(c12(1,2,3) == false)
|
||||
local a = vararg(call(next, {_G,nil;n=2}))
|
||||
local b,c = next(_G)
|
||||
assert(a[1] == b and a[2] == c and a.n == 2)
|
||||
a = vararg(call(call, {c12, {1,2}}))
|
||||
assert(a.n == 2 and a[1] == 55 and a[2] == 2)
|
||||
a = call(print, {'+'})
|
||||
assert(a == nil)
|
||||
|
||||
local t = {1, 10}
|
||||
function t:f (...) local arg = {...}; return self[...]+#arg end
|
||||
assert(t:f(1,4) == 3 and t:f(2) == 11)
|
||||
print('+')
|
||||
|
||||
lim = 20
|
||||
local i, a = 1, {}
|
||||
while i <= lim do a[i] = i+0.3; i=i+1 end
|
||||
|
||||
function f(a, b, c, d, ...)
|
||||
local more = {...}
|
||||
assert(a == 1.3 and more[1] == 5.3 and
|
||||
more[lim-4] == lim+0.3 and not more[lim-3])
|
||||
end
|
||||
|
||||
function g(a,b,c)
|
||||
assert(a == 1.3 and b == 2.3 and c == 3.3)
|
||||
end
|
||||
|
||||
call(f, a)
|
||||
call(g, a)
|
||||
|
||||
a = {}
|
||||
i = 1
|
||||
while i <= lim do a[i] = i; i=i+1 end
|
||||
assert(call(math.max, a) == lim)
|
||||
|
||||
print("+")
|
||||
|
||||
|
||||
-- new-style varargs
|
||||
|
||||
function oneless (a, ...) return ... end
|
||||
|
||||
function f (n, a, ...)
|
||||
local b
|
||||
assert(arg == _G.arg) -- no local 'arg'
|
||||
if n == 0 then
|
||||
local b, c, d = ...
|
||||
return a, b, c, d, oneless(oneless(oneless(...)))
|
||||
else
|
||||
n, b, a = n-1, ..., a
|
||||
assert(b == ...)
|
||||
return f(n, a, ...)
|
||||
end
|
||||
end
|
||||
|
||||
a,b,c,d,e = assert(f(10,5,4,3,2,1))
|
||||
assert(a==5 and b==4 and c==3 and d==2 and e==1)
|
||||
|
||||
a,b,c,d,e = f(4)
|
||||
assert(a==nil and b==nil and c==nil and d==nil and e==nil)
|
||||
|
||||
|
||||
-- varargs for main chunks
|
||||
f = load[[ return {...} ]]
|
||||
x = f(2,3)
|
||||
assert(x[1] == 2 and x[2] == 3 and x[3] == nil)
|
||||
|
||||
|
||||
f = load[[
|
||||
local x = {...}
|
||||
for i=1,select('#', ...) do assert(x[i] == select(i, ...)) end
|
||||
assert(x[select('#', ...)+1] == nil)
|
||||
return true
|
||||
]]
|
||||
|
||||
assert(f("a", "b", nil, {}, assert))
|
||||
assert(f())
|
||||
|
||||
a = {select(3, table.unpack{10,20,30,40})}
|
||||
assert(#a == 2 and a[1] == 30 and a[2] == 40)
|
||||
a = {select(1)}
|
||||
assert(next(a) == nil)
|
||||
a = {select(-1, 3, 5, 7)}
|
||||
assert(a[1] == 7 and a[2] == nil)
|
||||
a = {select(-2, 3, 5, 7)}
|
||||
assert(a[1] == 5 and a[2] == 7 and a[3] == nil)
|
||||
pcall(select, 10000)
|
||||
pcall(select, -10000)
|
||||
|
||||
|
||||
-- bug in 5.2.2
|
||||
|
||||
function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
|
||||
p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
|
||||
p21, p22, p23, p24, p25, p26, p27, p28, p29, p30,
|
||||
p31, p32, p33, p34, p35, p36, p37, p38, p39, p40,
|
||||
p41, p42, p43, p44, p45, p46, p48, p49, p50, ...)
|
||||
local a1,a2,a3,a4,a5,a6,a7
|
||||
local a8,a9,a10,a11,a12,a13,a14
|
||||
end
|
||||
|
||||
-- assertion fail here
|
||||
f()
|
||||
|
||||
|
||||
print('OK')
|
||||
|
152
06/parser-gen/parsers/lua-5.3.4-tests/verybig.lua
Normal file
152
06/parser-gen/parsers/lua-5.3.4-tests/verybig.lua
Normal file
|
@ -0,0 +1,152 @@
|
|||
-- $Id: verybig.lua,v 1.25 2016/11/07 13:11:28 roberto Exp $
|
||||
-- See Copyright Notice in file all.lua
|
||||
|
||||
print "testing RK"
|
||||
|
||||
-- testing opcodes with RK arguments larger than K limit
|
||||
local function foo ()
|
||||
local dummy = {
|
||||
-- fill first 256 entries in table of constants
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
|
||||
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
|
||||
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
|
||||
97, 98, 99, 100, 101, 102, 103, 104,
|
||||
105, 106, 107, 108, 109, 110, 111, 112,
|
||||
113, 114, 115, 116, 117, 118, 119, 120,
|
||||
121, 122, 123, 124, 125, 126, 127, 128,
|
||||
129, 130, 131, 132, 133, 134, 135, 136,
|
||||
137, 138, 139, 140, 141, 142, 143, 144,
|
||||
145, 146, 147, 148, 149, 150, 151, 152,
|
||||
153, 154, 155, 156, 157, 158, 159, 160,
|
||||
161, 162, 163, 164, 165, 166, 167, 168,
|
||||
169, 170, 171, 172, 173, 174, 175, 176,
|
||||
177, 178, 179, 180, 181, 182, 183, 184,
|
||||
185, 186, 187, 188, 189, 190, 191, 192,
|
||||
193, 194, 195, 196, 197, 198, 199, 200,
|
||||
201, 202, 203, 204, 205, 206, 207, 208,
|
||||
209, 210, 211, 212, 213, 214, 215, 216,
|
||||
217, 218, 219, 220, 221, 222, 223, 224,
|
||||
225, 226, 227, 228, 229, 230, 231, 232,
|
||||
233, 234, 235, 236, 237, 238, 239, 240,
|
||||
241, 242, 243, 244, 245, 246, 247, 248,
|
||||
249, 250, 251, 252, 253, 254, 255, 256,
|
||||
}
|
||||
assert(24.5 + 0.6 == 25.1)
|
||||
local t = {foo = function (self, x) return x + self.x end, x = 10}
|
||||
t.t = t
|
||||
assert(t:foo(1.5) == 11.5)
|
||||
assert(t.t:foo(0.5) == 10.5) -- bug in 5.2 alpha
|
||||
assert(24.3 == 24.3)
|
||||
assert((function () return t.x end)() == 10)
|
||||
end
|
||||
|
||||
|
||||
foo()
|
||||
foo = nil
|
||||
|
||||
if _soft then return 10 end
|
||||
|
||||
print "testing large programs (>64k)"
|
||||
|
||||
-- template to create a very big test file
|
||||
prog = [[$
|
||||
|
||||
local a,b
|
||||
|
||||
b = {$1$
|
||||
b30009 = 65534,
|
||||
b30010 = 65535,
|
||||
b30011 = 65536,
|
||||
b30012 = 65537,
|
||||
b30013 = 16777214,
|
||||
b30014 = 16777215,
|
||||
b30015 = 16777216,
|
||||
b30016 = 16777217,
|
||||
b30017 = 0x7fffff,
|
||||
b30018 = -0x7fffff,
|
||||
b30019 = 0x1ffffff,
|
||||
b30020 = -0x1ffffd,
|
||||
b30021 = -65534,
|
||||
b30022 = -65535,
|
||||
b30023 = -65536,
|
||||
b30024 = -0xffffff,
|
||||
b30025 = 15012.5,
|
||||
$2$
|
||||
};
|
||||
|
||||
assert(b.a50008 == 25004 and b["a11"] == -5.5)
|
||||
assert(b.a33007 == -16503.5 and b.a50009 == -25004.5)
|
||||
assert(b["b"..30024] == -0xffffff)
|
||||
|
||||
function b:xxx (a,b) return a+b end
|
||||
assert(b:xxx(10, 12) == 22) -- pushself with non-constant index
|
||||
b.xxx = nil
|
||||
|
||||
s = 0; n=0
|
||||
for a,b in pairs(b) do s=s+b; n=n+1 end
|
||||
-- with 32-bit floats, exact value of 's' depends on summation order
|
||||
assert(81800000.0 < s and s < 81860000 and n == 70001)
|
||||
|
||||
a = nil; b = nil
|
||||
print'+'
|
||||
|
||||
function f(x) b=x end
|
||||
|
||||
a = f{$3$} or 10
|
||||
|
||||
assert(a==10)
|
||||
assert(b[1] == "a10" and b[2] == 5 and b[#b-1] == "a50009")
|
||||
|
||||
|
||||
function xxxx (x) return b[x] end
|
||||
|
||||
assert(xxxx(3) == "a11")
|
||||
|
||||
a = nil; b=nil
|
||||
xxxx = nil
|
||||
|
||||
return 10
|
||||
|
||||
]]
|
||||
|
||||
-- functions to fill in the $n$
|
||||
|
||||
local function sig (x)
|
||||
return (x % 2 == 0) and '' or '-'
|
||||
end
|
||||
|
||||
F = {
|
||||
function () -- $1$
|
||||
for i=10,50009 do
|
||||
io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n')
|
||||
end
|
||||
end,
|
||||
|
||||
function () -- $2$
|
||||
for i=30026,50009 do
|
||||
io.write('b', i, ' = ', sig(i), 15013+((i-30026)/2), ',\n')
|
||||
end
|
||||
end,
|
||||
|
||||
function () -- $3$
|
||||
for i=10,50009 do
|
||||
io.write('"a', i, '", ', sig(i), 5+((i-10)/2), ',\n')
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
file = os.tmpname()
|
||||
io.output(file)
|
||||
for s in string.gmatch(prog, "$([^$]+)") do
|
||||
local n = tonumber(s)
|
||||
if not n then io.write(s) else F[n]() end
|
||||
end
|
||||
io.close()
|
||||
result = dofile(file)
|
||||
assert(os.remove(file))
|
||||
print'OK'
|
||||
return result
|
||||
|
799
06/parser-gen/parsers/lua-parser-tests.lua
Normal file
799
06/parser-gen/parsers/lua-parser-tests.lua
Normal file
|
@ -0,0 +1,799 @@
|
|||
local lua = require "lua-parser"
|
||||
local peg = require "peg-parser"
|
||||
|
||||
local eq = require "equals"
|
||||
local equals = eq.equals
|
||||
print("\n\n [[ PARSING LUA TEST SUITE FILES ]] \n\n")
|
||||
local filenames = {
|
||||
'all.lua',
|
||||
'main.lua',
|
||||
'gc.lua',
|
||||
'db.lua',
|
||||
'calls.lua',
|
||||
'strings.lua',
|
||||
'literals.lua',
|
||||
'tpack.lua',
|
||||
'attrib.lua',
|
||||
'locals.lua',
|
||||
'constructs.lua',
|
||||
'code.lua',
|
||||
'big.lua',
|
||||
'nextvar.lua',
|
||||
'pm.lua',
|
||||
'utf8.lua',
|
||||
'api.lua',
|
||||
'events.lua',
|
||||
'vararg.lua',
|
||||
'closure.lua',
|
||||
'coroutine.lua',
|
||||
'goto.lua',
|
||||
'errors.lua',
|
||||
'math.lua',
|
||||
'sort.lua',
|
||||
'bitwise.lua',
|
||||
'verybig.lua',
|
||||
'files.lua',
|
||||
}
|
||||
local errs = 0
|
||||
for k,v in ipairs(filenames) do
|
||||
local filename = "lua-5.3.4-tests/"..v
|
||||
local f = assert(io.open(filename, "r"))
|
||||
|
||||
local t = f:read("*all")
|
||||
|
||||
local res, err = lua.parse(t)
|
||||
local s = "OK"
|
||||
if not res then s = "FAIL" end -- only check if succesful since grammar ensures whole file is read
|
||||
print("Testing file '"..v.."': ["..s.."]")
|
||||
if not res then
|
||||
errs = errs + 1
|
||||
print("Error: "..err[1]["msg"])
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
assert(errs == 0)
|
||||
|
||||
print("\n\n Test suite files compiled successfully")
|
||||
|
||||
|
||||
print("\n\n [[ TESTING ERROR LABELS ]] ")
|
||||
local pr = peg.print_r
|
||||
-- test errors
|
||||
local s,res, err
|
||||
local ErrExtra="unexpected character(s), expected EOF"
|
||||
s = [[ return; ! ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExtra)
|
||||
|
||||
local ErrInvalidStat="unexpected token, invalid start of statement"
|
||||
s = [[ ! ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrInvalidStat)
|
||||
|
||||
|
||||
local ErrEndIf="expected 'end' to close the if statement"
|
||||
|
||||
s = [[ if c then b=1 ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEndIf)
|
||||
|
||||
local ErrExprIf="expected a condition after 'if'"
|
||||
|
||||
s = [[ if then b=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprIf)
|
||||
|
||||
local ErrThenIf="expected 'then' after the condition"
|
||||
|
||||
s = [[ if c b=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrThenIf)
|
||||
|
||||
local ErrExprEIf="expected a condition after 'elseif'"
|
||||
|
||||
s = [[ if a then b=1 elseif then d=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprEIf)
|
||||
|
||||
local ErrThenEIf="expected 'then' after the condition"
|
||||
|
||||
s = [[ if a b=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrThenEIf)
|
||||
|
||||
local ErrEndDo="expected 'end' to close the do block"
|
||||
|
||||
s = [[ do x=1 ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEndDo)
|
||||
|
||||
local ErrExprWhile="expected a condition after 'while'"
|
||||
|
||||
s = [[ while do c=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprWhile)
|
||||
|
||||
local ErrDoWhile="expected 'do' after the condition"
|
||||
|
||||
s = [[ while a c=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrDoWhile)
|
||||
|
||||
local ErrEndWhile="expected 'end' to close the while loop"
|
||||
|
||||
s = [[ while a do b=1]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEndWhile)
|
||||
|
||||
local ErrUntilRep="expected 'until' at the end of the repeat loop"
|
||||
|
||||
s = [[ repeat c=1 ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrUntilRep)
|
||||
|
||||
local ErrExprRep="expected a conditions after 'until'"
|
||||
|
||||
s = [[ repeat c=1 until ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprRep)
|
||||
|
||||
local ErrForRange="expected a numeric or generic range after 'for'"
|
||||
|
||||
s = [[ for 3,4 do x=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrForRange)
|
||||
|
||||
local ErrEndFor="expected 'end' to close the for loop"
|
||||
|
||||
s = [[ for c=1,3 do a=1 ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEndFor)
|
||||
|
||||
local ErrExprFor1="expected a starting expression for the numeric range"
|
||||
|
||||
s = [[ for a=,4 do a=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprFor1)
|
||||
|
||||
local ErrCommaFor="expected ',' to split the start and end of the range"
|
||||
|
||||
s = [[ for a=4 5 do a=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCommaFor)
|
||||
|
||||
local ErrExprFor2="expected an ending expression for the numeric range"
|
||||
|
||||
s = [[ for a=4, do a=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprFor2)
|
||||
|
||||
local ErrExprFor3="expected a step expression for the numeric range after ','"
|
||||
|
||||
s = [[ for a=1,2, do a=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprFor3)
|
||||
|
||||
local ErrInFor="expected '=' or 'in' after the variable(s)"
|
||||
|
||||
s = [[ for a of 1 do a=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrInFor)
|
||||
|
||||
local ErrEListFor="expected one or more expressions after 'in'"
|
||||
|
||||
s = [[ for a in do a=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEListFor)
|
||||
|
||||
local ErrDoFor="expected 'do' after the range of the for loop"
|
||||
|
||||
s = [[ for a=1,2 a=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrDoFor)
|
||||
|
||||
local ErrDefLocal="expected a function definition or assignment after local"
|
||||
|
||||
s = [[ local return c ]]
|
||||
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
|
||||
assert(err[1]["msg"] == ErrDefLocal)
|
||||
|
||||
|
||||
local ErrNameLFunc="expected a function name after 'function'"
|
||||
|
||||
s = [[ local function() c=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrNameLFunc)
|
||||
|
||||
|
||||
local ErrEListLAssign="expected one or more expressions after '='"
|
||||
|
||||
s = [[ local a = return b ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEListLAssign)
|
||||
|
||||
local ErrEListAssign="expected one or more expressions after '='"
|
||||
|
||||
s = [[ a = return b ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEListAssign)
|
||||
|
||||
|
||||
local ErrFuncName="expected a function name after 'function'"
|
||||
|
||||
s = [[ function () a=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrFuncName)
|
||||
|
||||
local ErrNameFunc1="expected a function name after '.'"
|
||||
|
||||
s = [[ function a.() a=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrNameFunc1)
|
||||
|
||||
local ErrNameFunc2="expected a method name after ':'"
|
||||
|
||||
s = [[ function a:() a=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrNameFunc2)
|
||||
|
||||
local ErrOParenPList="expected '(' for the parameter list"
|
||||
|
||||
s = [[ function a b=1 end]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrOParenPList)
|
||||
|
||||
local ErrCParenPList="expected ')' to close the parameter list"
|
||||
|
||||
s = [[
|
||||
function a(
|
||||
b=1
|
||||
|
||||
end
|
||||
]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCParenPList)
|
||||
|
||||
local ErrEndFunc="expected 'end' to close the function body"
|
||||
|
||||
s = [[ function a() b=1 ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEndFunc)
|
||||
|
||||
local ErrParList="expected a variable name or '...' after ','"
|
||||
|
||||
s = [[ function a(b, ) b=1 end ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrParList)
|
||||
|
||||
|
||||
local ErrLabel="expected a label name after '::'"
|
||||
|
||||
s = [[ :: return b ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrLabel)
|
||||
|
||||
local ErrCloseLabel="expected '::' after the label"
|
||||
|
||||
s = [[ :: abc return a]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCloseLabel)
|
||||
|
||||
local ErrGoto="expected a label after 'goto'"
|
||||
|
||||
s = [[ goto return c]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrGoto)
|
||||
|
||||
|
||||
|
||||
local ErrVarList="expected a variable name after ','"
|
||||
|
||||
s = [[ abc,
|
||||
= 3]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
|
||||
assert(err[1]["msg"] == ErrVarList)
|
||||
|
||||
local ErrExprList="expected an expression after ','"
|
||||
|
||||
s = [[ return a,;]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprList)
|
||||
|
||||
|
||||
local ErrOrExpr="expected an expression after 'or'"
|
||||
|
||||
s = [[ return a or; ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrOrExpr)
|
||||
|
||||
local ErrAndExpr="expected an expression after 'and'"
|
||||
|
||||
s = [[ return a and;]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrAndExpr)
|
||||
|
||||
local ErrRelExpr="expected an expression after the relational operator"
|
||||
|
||||
s = [[ return a >;]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrRelExpr)
|
||||
|
||||
|
||||
local ErrBitwiseExpr="expected an expression after bitwise operator"
|
||||
|
||||
s = [[ return b & ; ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrBitwiseExpr)
|
||||
|
||||
local ErrConcatExpr="expected an expression after '..'"
|
||||
|
||||
s = [[ print(a..) ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrConcatExpr)
|
||||
|
||||
local ErrAddExpr="expected an expression after the additive operator"
|
||||
|
||||
s = [[ return a - ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrAddExpr)
|
||||
|
||||
local ErrMulExpr="expected an expression after the multiplicative operator"
|
||||
|
||||
s = [[ return a/ ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrMulExpr)
|
||||
|
||||
local ErrUnaryExpr="expected an expression after the unary operator"
|
||||
|
||||
s = [[ return # ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrUnaryExpr)
|
||||
|
||||
local ErrPowExpr="expected an expression after '^'"
|
||||
|
||||
s = [[ return a^ ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrPowExpr)
|
||||
|
||||
|
||||
local ErrExprParen="expected an expression after '('"
|
||||
|
||||
s = [[ return a + () ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprParen)
|
||||
|
||||
local ErrCParenExpr="expected ')' to close the expression"
|
||||
|
||||
s = [[ return a + (a ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCParenExpr)
|
||||
|
||||
local ErrNameIndex="expected a field name after '.'"
|
||||
|
||||
s = [[ return a. ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrNameIndex)
|
||||
|
||||
local ErrExprIndex="expected an expression after '['"
|
||||
|
||||
s = [[ return a [ ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprIndex)
|
||||
|
||||
local ErrCBracketIndex="expected ']' to close the indexing expression"
|
||||
|
||||
s = [[ return a[1 ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCBracketIndex)
|
||||
|
||||
local ErrNameMeth="expected a method name after ':'"
|
||||
|
||||
s = [[ return a: ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrNameMeth)
|
||||
|
||||
local ErrMethArgs="expected some arguments for the method call (or '()')"
|
||||
s = [[ a:b ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrMethArgs)
|
||||
|
||||
|
||||
|
||||
local ErrCParenArgs="expected ')' to close the argument list"
|
||||
|
||||
s = [[ return a(c ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCParenArgs)
|
||||
|
||||
|
||||
local ErrCBraceTable="expected '}' to close the table constructor"
|
||||
|
||||
s = [[ return { ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCBraceTable)
|
||||
|
||||
local ErrEqField="expected '=' after the table key"
|
||||
|
||||
s = [[ a = {[b] b} ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEqField)
|
||||
|
||||
local ErrExprField="expected an expression after '='"
|
||||
|
||||
s = [[ a = {[a] = } ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprField)
|
||||
|
||||
local ErrExprFKey="expected an expression after '[' for the table key"
|
||||
|
||||
s = [[ a = {[ = b} ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrExprFKey)
|
||||
|
||||
local ErrCBracketFKey="expected ']' to close the table key"
|
||||
|
||||
s = [[ a = {[a = b} ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCBracketFKey)
|
||||
|
||||
|
||||
local ErrDigitHex="expected one or more hexadecimal digits after '0x'"
|
||||
|
||||
s = [[ a = 0x ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrDigitHex)
|
||||
|
||||
local ErrDigitDeci="expected one or more digits after the decimal point"
|
||||
|
||||
s = [[ a = . ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrDigitDeci)
|
||||
|
||||
local ErrDigitExpo="expected one or more digits for the exponent"
|
||||
|
||||
|
||||
s = [[ a = 1.0e ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrDigitExpo)
|
||||
|
||||
local ErrQuote="unclosed string"
|
||||
|
||||
s = [[ a = ";]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrQuote)
|
||||
|
||||
local ErrHexEsc="expected exactly two hexadecimal digits after '\\x'"
|
||||
|
||||
s = [[ a = "a\x1" ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrHexEsc)
|
||||
|
||||
local ErrOBraceUEsc="expected '{' after '\\u'"
|
||||
|
||||
s = [[ a = "a\u" ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrOBraceUEsc)
|
||||
|
||||
local ErrDigitUEsc="expected one or more hexadecimal digits for the UTF-8 code point"
|
||||
|
||||
s = [[ a = "\u{}"]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrDigitUEsc)
|
||||
|
||||
local ErrCBraceUEsc="expected '}' after the code point"
|
||||
|
||||
s = [[ a = "\u{12" ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCBraceUEsc)
|
||||
|
||||
local ErrEscSeq="invalid escape sequence"
|
||||
|
||||
s = [[ a = "\;" ]]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrEscSeq)
|
||||
|
||||
local ErrCloseLStr="unclosed long string"
|
||||
|
||||
|
||||
s = [==[ a = [[ abc return; ]==]
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
assert(err[1]["msg"] == ErrCloseLStr)
|
||||
|
||||
print("\n\n All error labels generated successfully")
|
||||
|
||||
print("\n\n [[ TESTING AST GENERATION ]]\n\n ")
|
||||
|
||||
-- TODO: AST
|
||||
|
||||
s = [[
|
||||
if abc > 123 then
|
||||
abc=123
|
||||
end]]
|
||||
rez = {
|
||||
rule='chunk',
|
||||
pos=3,
|
||||
{
|
||||
rule='block',
|
||||
pos=3,
|
||||
{
|
||||
rule='stat',
|
||||
pos=3,
|
||||
'if',
|
||||
{
|
||||
rule='exp',
|
||||
pos=6,
|
||||
{
|
||||
rule='exp',
|
||||
{
|
||||
rule='exp',
|
||||
{
|
||||
rule='expTokens',
|
||||
pos=6,
|
||||
{
|
||||
rule='prefixexp',
|
||||
pos=6,
|
||||
{
|
||||
rule='varOrExp',
|
||||
pos=6,
|
||||
{
|
||||
rule='var',
|
||||
pos=6,
|
||||
{
|
||||
rule='NAME',
|
||||
pos=6,
|
||||
'abc',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rule='operatorComparison',
|
||||
pos=10,
|
||||
'>',
|
||||
},
|
||||
{
|
||||
rule='expTokens',
|
||||
pos=12,
|
||||
{
|
||||
rule='number',
|
||||
pos=12,
|
||||
{
|
||||
rule='INT',
|
||||
pos=12,
|
||||
'123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'then',
|
||||
{
|
||||
rule='block',
|
||||
pos=23,
|
||||
{
|
||||
rule='stat',
|
||||
pos=23,
|
||||
{
|
||||
rule='varlist',
|
||||
pos=23,
|
||||
{
|
||||
rule='var',
|
||||
pos=23,
|
||||
{
|
||||
rule='NAME',
|
||||
pos=23,
|
||||
'abc',
|
||||
},
|
||||
},
|
||||
},
|
||||
'=',
|
||||
{
|
||||
rule='explist',
|
||||
pos=27,
|
||||
{
|
||||
rule='exp',
|
||||
pos=27,
|
||||
{
|
||||
rule='expTokens',
|
||||
pos=27,
|
||||
{
|
||||
rule='number',
|
||||
pos=27,
|
||||
{
|
||||
rule='INT',
|
||||
pos=27,
|
||||
'123',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'end',
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
peg.print_t(res)
|
||||
assert(equals(res,rez))
|
||||
|
||||
s = [[
|
||||
local a = [=[ long string ]=]
|
||||
|
||||
-- aaa
|
||||
return a
|
||||
--[==[ hi
|
||||
|
||||
]==]
|
||||
]]
|
||||
rez = {
|
||||
|
||||
rule='chunk',
|
||||
pos=3,
|
||||
{
|
||||
rule='block',
|
||||
pos=3,
|
||||
{
|
||||
rule='stat',
|
||||
pos=3,
|
||||
'local',
|
||||
{
|
||||
rule='localAssign',
|
||||
pos=9,
|
||||
{
|
||||
rule='namelist',
|
||||
pos=9,
|
||||
{
|
||||
rule='NAME',
|
||||
pos=9,
|
||||
'a',
|
||||
},
|
||||
},
|
||||
'=',
|
||||
{
|
||||
rule='explist',
|
||||
pos=13,
|
||||
{
|
||||
rule='exp',
|
||||
pos=13,
|
||||
{
|
||||
rule='expTokens',
|
||||
pos=13,
|
||||
{
|
||||
rule='string',
|
||||
pos=13,
|
||||
' long string ',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rule='retstat',
|
||||
pos=41,
|
||||
'return',
|
||||
{
|
||||
rule='explist',
|
||||
pos=48,
|
||||
{
|
||||
rule='exp',
|
||||
pos=48,
|
||||
{
|
||||
rule='expTokens',
|
||||
pos=48,
|
||||
{
|
||||
rule='prefixexp',
|
||||
pos=48,
|
||||
{
|
||||
rule='varOrExp',
|
||||
pos=48,
|
||||
{
|
||||
rule='var',
|
||||
pos=48,
|
||||
{
|
||||
rule='NAME',
|
||||
pos=48,
|
||||
'a',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
|
||||
}
|
||||
print("Parsing '"..s.."'")
|
||||
res, err = lua.parse(s)
|
||||
peg.print_t(res)
|
||||
assert(equals(res,rez))
|
||||
|
||||
print("\n\n All AST's generated successfully")
|
||||
|
||||
print("\n\nAll tests passed!")
|
291
06/parser-gen/parsers/lua-parser.lua
Normal file
291
06/parser-gen/parsers/lua-parser.lua
Normal file
|
@ -0,0 +1,291 @@
|
|||
--[==[
|
||||
Parser for Lua 5.3
|
||||
Based on https://github.com/antlr/grammars-v4/blob/master/lua/Lua.g4 and https://github.com/andremm/lua-parser/blob/master/lua-parser/parser.lua
|
||||
]==]
|
||||
package.path = package.path .. ";../?.lua"
|
||||
local pg = require "parser-gen"
|
||||
function equals(s,i,a,b) return #a == #b end
|
||||
function fixexp (...)
|
||||
local exp = {...}
|
||||
local len = #exp
|
||||
if len > 1 then
|
||||
exp.rule = "exp"
|
||||
exp[len].rule = "exp"
|
||||
return exp
|
||||
elseif exp[1] then
|
||||
if exp[1].rule == "expTokens" then
|
||||
return exp[1]
|
||||
else
|
||||
return exp[1][1]
|
||||
end
|
||||
end
|
||||
end
|
||||
function fold (...)
|
||||
local exp = {...}
|
||||
local len = #exp
|
||||
if len > 1 then
|
||||
local folded = { rule = "exp", fixexp(exp[1]) }
|
||||
for i = 2, len, 2 do
|
||||
folded = { rule = "exp", folded, exp[i], fixexp(exp[i+1]) }
|
||||
end
|
||||
return folded
|
||||
elseif exp[1] then
|
||||
return exp[1][1]
|
||||
end
|
||||
end
|
||||
-- from https://github.com/andremm/lua-parser/blob/master/lua-parser/parser.lua
|
||||
local labels = {
|
||||
ErrExtra="unexpected character(s), expected EOF",
|
||||
ErrInvalidStat={"unexpected token, invalid start of statement",[[ (!%nl .)* ]]},
|
||||
|
||||
ErrEndIf="expected 'end' to close the if statement",
|
||||
ErrExprIf="expected a condition after 'if'",
|
||||
ErrThenIf="expected 'then' after the condition",
|
||||
ErrExprEIf="expected a condition after 'elseif'",
|
||||
ErrThenEIf="expected 'then' after the condition",
|
||||
|
||||
ErrEndDo="expected 'end' to close the do block",
|
||||
ErrExprWhile="expected a condition after 'while'",
|
||||
ErrDoWhile="expected 'do' after the condition",
|
||||
ErrEndWhile="expected 'end' to close the while loop",
|
||||
ErrUntilRep="expected 'until' at the end of the repeat loop",
|
||||
ErrExprRep="expected a conditions after 'until'",
|
||||
|
||||
ErrForRange="expected a numeric or generic range after 'for'",
|
||||
ErrEndFor="expected 'end' to close the for loop",
|
||||
ErrExprFor1="expected a starting expression for the numeric range",
|
||||
ErrCommaFor="expected ',' to split the start and end of the range",
|
||||
ErrExprFor2="expected an ending expression for the numeric range",
|
||||
ErrExprFor3={"expected a step expression for the numeric range after ','",[[ (!'do' !%nl .)* ]]},
|
||||
ErrInFor="expected '=' or 'in' after the variable(s)",
|
||||
ErrEListFor="expected one or more expressions after 'in'",
|
||||
ErrDoFor="expected 'do' after the range of the for loop",
|
||||
|
||||
ErrDefLocal="expected a function definition or assignment after local",
|
||||
ErrNameLFunc="expected a function name after 'function'",
|
||||
ErrEListLAssign="expected one or more expressions after '='",
|
||||
ErrEListAssign="expected one or more expressions after '='",
|
||||
|
||||
ErrFuncName="expected a function name after 'function'",
|
||||
ErrNameFunc1="expected a function name after '.'",
|
||||
ErrNameFunc2="expected a method name after ':'",
|
||||
ErrOParenPList="expected '(' for the parameter list",
|
||||
ErrCParenPList="expected ')' to close the parameter list",
|
||||
ErrEndFunc="expected 'end' to close the function body",
|
||||
ErrParList="expected a variable name or '...' after ','",
|
||||
|
||||
ErrLabel="expected a label name after '::'",
|
||||
ErrCloseLabel="expected '::' after the label",
|
||||
ErrGoto="expected a label after 'goto'",
|
||||
|
||||
ErrVarList={"expected a variable name after ','",[[ (!'=' !%nl .)* ]]},
|
||||
ErrExprList="expected an expression after ','",
|
||||
|
||||
ErrOrExpr="expected an expression after 'or'",
|
||||
ErrAndExpr="expected an expression after 'and'",
|
||||
ErrRelExpr="expected an expression after the relational operator",
|
||||
|
||||
ErrBitwiseExpr="expected an expression after bitwise operator",
|
||||
|
||||
ErrConcatExpr="expected an expression after '..'",
|
||||
ErrAddExpr="expected an expression after the additive operator",
|
||||
ErrMulExpr="expected an expression after the multiplicative operator",
|
||||
ErrUnaryExpr="expected an expression after the unary operator",
|
||||
ErrPowExpr="expected an expression after '^'",
|
||||
|
||||
ErrExprParen="expected an expression after '('",
|
||||
ErrCParenExpr="expected ')' to close the expression",
|
||||
ErrNameIndex="expected a field name after '.'",
|
||||
ErrExprIndex="expected an expression after '['",
|
||||
ErrCBracketIndex="expected ']' to close the indexing expression",
|
||||
ErrNameMeth="expected a method name after ':'",
|
||||
ErrMethArgs="expected some arguments for the method call (or '()')",
|
||||
|
||||
|
||||
ErrCParenArgs="expected ')' to close the argument list",
|
||||
|
||||
ErrCBraceTable="expected '}' to close the table constructor",
|
||||
ErrEqField="expected '=' after the table key",
|
||||
ErrExprField="expected an expression after '='",
|
||||
ErrExprFKey={"expected an expression after '[' for the table key",[[ (!']' !%nl .)* ]] },
|
||||
ErrCBracketFKey={"expected ']' to close the table key",[[ (!'=' !%nl .)* ]]},
|
||||
|
||||
ErrDigitHex="expected one or more hexadecimal digits after '0x'",
|
||||
ErrDigitDeci="expected one or more digits after the decimal point",
|
||||
ErrDigitExpo="expected one or more digits for the exponent",
|
||||
|
||||
ErrQuote="unclosed string",
|
||||
ErrHexEsc={"expected exactly two hexadecimal digits after '\\x'",[[ (!('"' / "'" / %nl) .)* ]]},
|
||||
ErrOBraceUEsc="expected '{' after '\\u'",
|
||||
ErrDigitUEsc={"expected one or more hexadecimal digits for the UTF-8 code point",[[ (!'}' !%nl .)* ]]},
|
||||
ErrCBraceUEsc={"expected '}' after the code point",[[ (!('"' / "'") .)* ]]},
|
||||
ErrEscSeq={"invalid escape sequence",[[ (!('"' / "'" / %nl) .)* ]]},
|
||||
ErrCloseLStr="unclosed long string",
|
||||
ErrEqAssign="expected '=' after variable list in assign statement"
|
||||
}
|
||||
pg.setlabels(labels)
|
||||
local grammar = pg.compile([==[
|
||||
chunk <- block (!.)^ErrExtra
|
||||
block <- stat* retstat?
|
||||
stat <- ';' /
|
||||
functioncall /
|
||||
varlist '='^ErrEqAssign explist^ErrEListAssign /
|
||||
'break' /
|
||||
'goto' NAME^ErrGoto /
|
||||
'do' block 'end'^ErrEndDo /
|
||||
'while' exp^ErrExprWhile 'do'^ErrDoWhile block 'end'^ErrEndWhile /
|
||||
'repeat' block 'until'^ErrUntilRep exp^ErrExprRep /
|
||||
'if' exp^ErrExprIf 'then'^ErrThenIf block ('elseif' exp^ErrExprEIf 'then'^ErrThenEIf block)* ('else' block)? 'end'^ErrEndIf /
|
||||
'for' (forNum / forIn)^ErrForRange 'do'^ErrDoFor block 'end'^ErrEndFor /
|
||||
|
||||
'function' funcname^ErrFuncName funcbody /
|
||||
'local' (localAssign / localFunc)^ErrDefLocal /
|
||||
label /
|
||||
!blockEnd %{ErrInvalidStat}
|
||||
blockEnd <- 'return' / 'end' / 'elseif' / 'else' / 'until' / !.
|
||||
retstat <- 'return' explist? ';'?
|
||||
forNum <- NAME '=' exp^ErrExprFor1 ','^ErrCommaFor exp^ErrExprFor2 (',' exp^ErrExprFor3)?
|
||||
forIn <- namelist 'in'^ErrInFor explist^ErrEListFor
|
||||
localFunc <- 'function' NAME^ErrNameLFunc funcbody
|
||||
localAssign <- namelist ('=' explist^ErrEListLAssign)?
|
||||
label <- '::' NAME^ErrLabel '::'^ErrCloseLabel
|
||||
funcname <- NAME ('.' NAME^ErrNameFunc1)* (':' NAME^ErrNameFunc2)?
|
||||
varlist <- var (',' var^ErrVarList)*
|
||||
namelist <- NAME (',' NAME)*
|
||||
explist <- exp (',' exp^ErrExprList )*
|
||||
|
||||
exp <- expOR -> fixexp
|
||||
expOR <- (expAND (operatorOr expAND^ErrOrExpr)*) -> fold
|
||||
expAND <- (expREL (operatorAnd expREL^ErrAndExpr)*) -> fold
|
||||
expREL <- (expBIT (operatorComparison expBIT^ErrRelExpr)*) -> fold
|
||||
expBIT <- (expCAT (operatorBitwise expCAT^ErrBitwiseExpr)*) -> fold
|
||||
expCAT <- (expADD (operatorStrcat expCAT^ErrConcatExpr)?) -> fixexp
|
||||
expADD <- (expMUL (operatorAddSub expMUL^ErrAddExpr)*) -> fold
|
||||
expMUL <- (expUNA (operatorMulDivMod expUNA^ErrMulExpr)*) -> fold
|
||||
expUNA <- ((operatorUnary expUNA^ErrUnaryExpr) / expPOW) -> fixexp
|
||||
expPOW <- (expTokens (operatorPower expUNA^ErrPowExpr)?) -> fixexp
|
||||
|
||||
expTokens <- 'nil' / 'false' / 'true' /
|
||||
number /
|
||||
string /
|
||||
'...' /
|
||||
'function' funcbody /
|
||||
tableconstructor /
|
||||
prefixexp
|
||||
|
||||
prefixexp <- varOrExp nameAndArgs*
|
||||
functioncall <- varOrExp nameAndArgs+
|
||||
varOrExp <- var / brackexp
|
||||
brackexp <- '(' exp^ErrExprParen ')'^ErrCParenExpr
|
||||
var <- (NAME / brackexp varSuffix) varSuffix*
|
||||
varSuffix <- nameAndArgs* ('[' exp^ErrExprIndex ']'^ErrCBracketIndex / '.' !'.' NAME^ErrNameIndex)
|
||||
nameAndArgs <- (':' !':' NAME^ErrNameMeth args^ErrMethArgs) /
|
||||
args
|
||||
args <- '(' explist? ')'^ErrCParenArgs / tableconstructor / string
|
||||
funcbody <- '('^ErrOParenPList parlist? ')'^ErrCParenPList block 'end'^ErrEndFunc
|
||||
parlist <- namelist (',' '...'^ErrParList)? / '...'
|
||||
tableconstructor<- '{' fieldlist? '}'^ErrCBraceTable
|
||||
fieldlist <- field (fieldsep field)* fieldsep?
|
||||
field <- !OPEN '[' exp^ErrExprFKey ']'^ErrCBracketFKey '='^ErrEqField exp^ErrExprField /
|
||||
NAME '=' exp /
|
||||
exp
|
||||
fieldsep <- ',' / ';'
|
||||
operatorOr <- 'or'
|
||||
operatorAnd <- 'and'
|
||||
operatorComparison<- '<=' / '>=' / '~=' / '==' / '<' !'<' / '>' !'>'
|
||||
operatorStrcat <- !'...' '..'
|
||||
operatorAddSub <- '+' / '-'
|
||||
operatorMulDivMod<- '*' / '%' / '//' / '/'
|
||||
operatorBitwise <- '&' / '|' / !'~=' '~' / '<<' / '>>'
|
||||
operatorUnary <- 'not' / '#' / '-' / !'~=' '~'
|
||||
operatorPower <- '^'
|
||||
number <- FLOAT / HEX_FLOAT / HEX / INT
|
||||
string <- NORMALSTRING / CHARSTRING / LONGSTRING
|
||||
-- lexer
|
||||
fragment
|
||||
RESERVED <- KEYWORDS !IDREST
|
||||
fragment
|
||||
IDREST <- [a-zA-Z_0-9]
|
||||
fragment
|
||||
KEYWORDS <- 'and' / 'break' / 'do' / 'elseif' / 'else' / 'end' /
|
||||
'false' / 'for' / 'function' / 'goto' / 'if' / 'in' /
|
||||
'local' / 'nil' / 'not' / 'or' / 'repeat' / 'return' /
|
||||
'then' / 'true' / 'until' / 'while'
|
||||
NAME <- !RESERVED [a-zA-Z_] [a-zA-Z_0-9]*
|
||||
fragment
|
||||
NORMALSTRING <- '"' {( ESC / [^"\] )*} '"'^ErrQuote
|
||||
fragment
|
||||
CHARSTRING <- "'" {( ESC / [^\'] )*} "'"^ErrQuote
|
||||
fragment
|
||||
LONGSTRING <- (OPEN {(!CLOSEEQ .)*} CLOSE^ErrCloseLStr) -> 1 -- capture only the string
|
||||
|
||||
fragment
|
||||
OPEN <- '[' {:openEq: EQUALS :} '[' %nl?
|
||||
fragment
|
||||
CLOSE <- ']' {EQUALS} ']'
|
||||
fragment
|
||||
EQUALS <- '='*
|
||||
fragment
|
||||
CLOSEEQ <- (CLOSE =openEq) => equals
|
||||
|
||||
INT <- DIGIT+
|
||||
HEX <- '0' [xX] HEXDIGIT+^ErrDigitHex
|
||||
FLOAT <- DIGIT+ '.' DIGIT* ExponentPart? /
|
||||
'.' !'.' DIGIT+^ErrDigitDeci ExponentPart? /
|
||||
DIGIT+ ExponentPart
|
||||
HEX_FLOAT <- '0' [xX] HEXDIGIT+ '.' HEXDIGIT* HexExponentPart? /
|
||||
'0' [xX] '.' HEXDIGIT+ HexExponentPart? /
|
||||
'0' [xX] HEXDIGIT+^ErrDigitHex HexExponentPart
|
||||
fragment
|
||||
ExponentPart <- [eE] [+-]? DIGIT+^ErrDigitExpo
|
||||
fragment
|
||||
HexExponentPart <- [pP] [+-]? DIGIT+^ErrDigitExpo
|
||||
fragment
|
||||
ESC <- '\' [abfnrtvz"'\] /
|
||||
'\' %nl /
|
||||
DECESC /
|
||||
HEXESC/
|
||||
UTFESC/
|
||||
'\' %{ErrEscSeq}
|
||||
fragment
|
||||
DECESC <- '\' ( DIGIT DIGIT? / [0-2] DIGIT DIGIT)
|
||||
fragment
|
||||
HEXESC <- '\' 'x' (HEXDIGIT HEXDIGIT)^ErrHexEsc
|
||||
fragment
|
||||
UTFESC <- '\' 'u' '{'^ErrOBraceUEsc HEXDIGIT+^ErrDigitUEsc '}'^ErrCBraceUEsc
|
||||
fragment
|
||||
DIGIT <- [0-9]
|
||||
fragment
|
||||
HEXDIGIT <- [0-9a-fA-F]
|
||||
|
||||
|
||||
fragment
|
||||
COMMENT <- '--' LONGSTRING -> 0 -- skip this
|
||||
fragment
|
||||
LINE_COMMENT <- '--' COM_TYPES ( %nl / !.)
|
||||
fragment
|
||||
COM_TYPES <- '[' '='* [^[=%nl] [^%nl]* /
|
||||
'[' '='* /
|
||||
[^[%nl] [^%nl]* /
|
||||
''
|
||||
fragment
|
||||
SHEBANG <- '#' '!' [^%nl]*
|
||||
|
||||
|
||||
SKIP <- %nl / %s / COMMENT / LINE_COMMENT / SHEBANG
|
||||
fragment
|
||||
HELPER <- RESERVED / '(' / ')' -- for sync expression
|
||||
SYNC <- ((!HELPER !SKIP .)+ / .?) SKIP* -- either sync to reserved keyword or skip characters and consume them
|
||||
|
||||
]==],{ equals = equals, fixexp = fixexp, fold = fold })
|
||||
local errnr = 1
|
||||
local function err (desc, line, col, sfail, recexp)
|
||||
print("Syntax error #"..errnr..": "..desc.." at line "..line.."(col "..col..")")
|
||||
errnr = errnr+1
|
||||
end
|
||||
local function parse (input)
|
||||
errnr = 1
|
||||
local ast, errs = pg.parse(input,grammar,err)
|
||||
return ast, errs
|
||||
end
|
||||
return {parse=parse}
|
55
06/parser-gen/parsers/tiny-parser.lua
Normal file
55
06/parser-gen/parsers/tiny-parser.lua
Normal file
|
@ -0,0 +1,55 @@
|
|||
package.path = package.path .. ";../?.lua"
|
||||
local pg = require "parser-gen"
|
||||
local peg = require "peg-parser"
|
||||
local errs = {errMissingThen = "Missing Then"}
|
||||
pg.setlabels(errs)
|
||||
|
||||
|
||||
local grammar = pg.compile([[
|
||||
|
||||
program <- stmtsequence !.
|
||||
stmtsequence <- statement (';' statement)*
|
||||
statement <- ifstmt / repeatstmt / assignstmt / readstmt / writestmt
|
||||
ifstmt <- 'if' exp 'then'^errMissingThen stmtsequence elsestmt? 'end'
|
||||
elsestmt <- ('else' stmtsequence)
|
||||
repeatstmt <- 'repeat' stmtsequence 'until' exp
|
||||
assignstmt <- IDENTIFIER ':=' exp
|
||||
readstmt <- 'read' IDENTIFIER
|
||||
writestmt <- 'write' exp
|
||||
exp <- simpleexp (COMPARISONOP simpleexp)*
|
||||
COMPARISONOP <- '<' / '='
|
||||
simpleexp <- term (ADDOP term)*
|
||||
ADDOP <- [+-]
|
||||
term <- factor (MULOP factor)*
|
||||
MULOP <- [*/]
|
||||
factor <- '(' exp ')' / NUMBER / IDENTIFIER
|
||||
|
||||
NUMBER <- '-'? [0-9]+
|
||||
KEYWORDS <- 'if' / 'repeat' / 'read' / 'write' / 'then' / 'else' / 'end' / 'until'
|
||||
RESERVED <- KEYWORDS ![a-zA-Z]
|
||||
IDENTIFIER <- !RESERVED [a-zA-Z]+
|
||||
HELPER <- ';' / %nl / %s / KEYWORDS / !.
|
||||
SYNC <- (!HELPER .)*
|
||||
|
||||
]], _, true)
|
||||
local errors = 0
|
||||
local function printerror(desc,line,col,sfail,trec)
|
||||
errors = errors+1
|
||||
print("Error #"..errors..": "..desc.." on line "..line.."(col "..col..")")
|
||||
end
|
||||
|
||||
|
||||
local function parse(input)
|
||||
errors = 0
|
||||
result, errors = pg.parse(input,grammar,printerror)
|
||||
return result, errors
|
||||
end
|
||||
|
||||
if arg[1] then
|
||||
-- argument must be in quotes if it contains spaces
|
||||
res, errs = parse(arg[1])
|
||||
peg.print_t(res)
|
||||
peg.print_r(errs)
|
||||
end
|
||||
local ret = {parse=parse}
|
||||
return ret
|
260
06/parser-gen/peg-parser-tests.lua
Normal file
260
06/parser-gen/peg-parser-tests.lua
Normal file
|
@ -0,0 +1,260 @@
|
|||
local peg = require "peg-parser"
|
||||
local f = peg.pegToAST
|
||||
|
||||
local eq = require "equals"
|
||||
local equals = eq.equals
|
||||
|
||||
|
||||
-- self-description of peg-parser:
|
||||
|
||||
--assert(f(peg.gram))
|
||||
|
||||
-- ( p ) grouping
|
||||
e = f("('a')")
|
||||
res = {t="a"}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
-- 'string' literal string
|
||||
|
||||
e = f("'string'")
|
||||
res = {t="string"}
|
||||
assert(equals(e,res))
|
||||
|
||||
-- "string" literal string
|
||||
e = f('"string"')
|
||||
res = {t="string"}
|
||||
|
||||
assert(equals(e,res))
|
||||
--[class] character class
|
||||
e = f("[^a-zA-Z01]")
|
||||
res = {
|
||||
action = "invert",
|
||||
op1 = {
|
||||
action = "or",
|
||||
op1 = {
|
||||
action = "or",
|
||||
op1 = {
|
||||
action = "or",
|
||||
op1 = {
|
||||
action = "range",
|
||||
op1 = {
|
||||
s = "az"
|
||||
}
|
||||
},
|
||||
op2 = {
|
||||
action = "range",
|
||||
op1 = {
|
||||
s = "AZ"
|
||||
}
|
||||
}
|
||||
},
|
||||
op2 = {
|
||||
t = "0"
|
||||
}
|
||||
},
|
||||
op2 = {
|
||||
t = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--. any character
|
||||
e = f(".")
|
||||
res = {action="anychar"}
|
||||
|
||||
assert(equals(e,res))
|
||||
--%name pattern defs[name] or a pre-defined pattern
|
||||
e = f("%name")
|
||||
res = {action="%", op1={s="name"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
--name non terminal
|
||||
e = f("name")
|
||||
res = {nt="name"}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--<name> non terminal
|
||||
e = f("<name>")
|
||||
res = {nt="name"}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--{} position capture
|
||||
e = f("{}")
|
||||
|
||||
res = {action="poscap"}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--{ p } simple capture
|
||||
e = f("{name}")
|
||||
res = {action="scap", op1= {nt="name"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--{: p :} anonymous group capture
|
||||
e = f("{:name:}")
|
||||
res = {action="gcap", op1= {nt="name"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--{:name: p :} named group capture
|
||||
e = f("{:g: name:}")
|
||||
res = {action="gcap", op1= {nt="name"} , op2={s="g"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
--{~ p ~} substitution capture
|
||||
e = f("{~ name ~}")
|
||||
|
||||
res = {action="subcap", op1= {nt="name"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--{| p |} table capture
|
||||
e = f("{| name |}")
|
||||
res = {action="tcap", op1= {nt="name"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--=name back reference
|
||||
e = f("=name")
|
||||
res = {action="bref", op1= {s="name"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p ? optional match
|
||||
e = f("name?")
|
||||
res = {action="?", op1= {nt="name"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p * zero or more repetitions
|
||||
e = f("name*")
|
||||
res = {action="*", op1= {nt="name"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p + one or more repetitions
|
||||
e = f("name+")
|
||||
res = {action="+", op1= {nt="name"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p^num exactly n repetitions
|
||||
e = f("name^3")
|
||||
res = {action="^", op1= {nt="name"}, op2 = {num="3"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p^+num at least n repetitions
|
||||
e = f("name^+3")
|
||||
res = {action="^", op1= {nt="name"}, op2 = {num="+3"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p^-num at most n repetitions
|
||||
e = f("name^-3")
|
||||
res = {action="^", op1= {nt="name"}, op2 = {num="-3"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p^LABEL error label
|
||||
e = f("name^err")
|
||||
res = {action = "^LABEL", op1= {nt="name"}, op2 = {s="err"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p -> 'string' string capture
|
||||
e = f("name -> 'a'")
|
||||
res = {action="->", op1= {nt="name"}, op2 = {s="a"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p -> "string" string capture
|
||||
e = f('name -> "a"')
|
||||
res = {action="->", op1= {nt="name"}, op2 = {s="a"}}
|
||||
assert(equals(e,res))
|
||||
|
||||
--p -> num numbered capture
|
||||
|
||||
e = f('name -> 3')
|
||||
|
||||
res = {action="->", op1= {nt="name"}, op2 = {num="3"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--p -> name function/query/string capture equivalent to p / defs[name]
|
||||
|
||||
e = f('name -> func')
|
||||
res = {action="->", op1= {nt="name"}, op2 = {func="func"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
|
||||
|
||||
--p => name match-time capture equivalent to lpeg.Cmt(p, defs[name])
|
||||
|
||||
e = f('name => func')
|
||||
res = {action="=>", op1= {nt="name"}, op2 = {func="func"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
|
||||
--& p and predicate
|
||||
|
||||
e = f('&name')
|
||||
res = {action="&", op1= {nt="name"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
|
||||
--! p not predicate
|
||||
|
||||
|
||||
e = f('!name')
|
||||
res = {action="!", op1= {nt="name"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
|
||||
--p1 p2 p3 concatenation with left association
|
||||
|
||||
e = f('name name2 name3')
|
||||
res = {action="and", op1= {action = "and", op1={nt="name"}, op2={nt="name2"}}, op2={nt="name3"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
--p1 / p2 / p3 ordered choice with left association
|
||||
|
||||
e = f('name / name2 / name3')
|
||||
res = {action="or", op1= {action = "or", op1={nt="name"}, op2={nt="name2"}}, op2={nt="name3"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
|
||||
--(name <- p)+ grammar
|
||||
|
||||
e = f('a <- b b <- c')
|
||||
res = {
|
||||
{rulename = "a", rule = {nt="b"}},
|
||||
{rulename = "b", rule = {nt="c"}}
|
||||
}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
-- error labels
|
||||
-- %{errName}
|
||||
|
||||
--peg.setlabels({errName=1})
|
||||
e = f('%{errName}')
|
||||
|
||||
res = {action="label", op1={s="errName"}}
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
-- a //{errName,errName2} b
|
||||
|
||||
--peg.setlabels({errName=1, errName2=2})
|
||||
e = f('a //{errName,errName2} b')
|
||||
|
||||
res = {action="or", condition={{s="errName"},{s="errName2"}}, op1={nt="a"}, op2={nt="b"}}
|
||||
|
||||
|
||||
assert(equals(e,res))
|
||||
|
||||
print("all tests succesful")
|
334
06/parser-gen/peg-parser.lua
Normal file
334
06/parser-gen/peg-parser.lua
Normal file
|
@ -0,0 +1,334 @@
|
|||
local re = require "lpeglabel.relabel"
|
||||
|
||||
local peg = {}
|
||||
|
||||
-- from relabel.lua
|
||||
|
||||
local errinfo = {
|
||||
{"NoPatt", "no pattern found"},
|
||||
{"ExtraChars", "unexpected characters after the pattern"},
|
||||
|
||||
{"ExpPatt1", "expected a pattern after '/' or '//{...}'"},
|
||||
|
||||
{"ExpPatt2", "expected a pattern after '&'"},
|
||||
{"ExpPatt3", "expected a pattern after '!'"},
|
||||
|
||||
{"ExpPatt4", "expected a pattern after '('"},
|
||||
{"ExpPatt5", "expected a pattern after ':'"},
|
||||
{"ExpPatt6", "expected a pattern after '{~'"},
|
||||
{"ExpPatt7", "expected a pattern after '{|'"},
|
||||
|
||||
{"ExpPatt8", "expected a pattern after '<-'"},
|
||||
|
||||
{"ExpPattOrClose", "expected a pattern or closing '}' after '{'"},
|
||||
|
||||
{"ExpNum", "expected a number after '^', '+' or '-' (no space)"},
|
||||
{"ExpNumOrLab", "expected a number or a label after ^"},
|
||||
{"ExpCap", "expected a string, number, '{}' or name after '->'"},
|
||||
|
||||
{"ExpName1", "expected the name of a rule after '=>'"},
|
||||
{"ExpName2", "expected the name of a rule after '=' (no space)"},
|
||||
{"ExpName3", "expected the name of a rule after '<' (no space)"},
|
||||
|
||||
{"ExpLab1", "expected at least one label after '{'"},
|
||||
{"ExpLab2", "expected a label after the comma"},
|
||||
|
||||
{"ExpNameOrLab", "expected a name or label after '%' (no space)"},
|
||||
|
||||
{"ExpItem", "expected at least one item after '[' or '^'"},
|
||||
|
||||
{"MisClose1", "missing closing ')'"},
|
||||
{"MisClose2", "missing closing ':}'"},
|
||||
{"MisClose3", "missing closing '~}'"},
|
||||
{"MisClose4", "missing closing '|}'"},
|
||||
{"MisClose5", "missing closing '}'"}, -- for the captures
|
||||
|
||||
{"MisClose6", "missing closing '>'"},
|
||||
{"MisClose7", "missing closing '}'"}, -- for the labels
|
||||
|
||||
{"MisClose8", "missing closing ']'"},
|
||||
|
||||
{"MisTerm1", "missing terminating single quote"},
|
||||
{"MisTerm2", "missing terminating double quote"},
|
||||
}
|
||||
|
||||
local errmsgs = {}
|
||||
local labels = {}
|
||||
|
||||
for i, err in ipairs(errinfo) do
|
||||
errmsgs[i] = err[2]
|
||||
labels[err[1]] = i
|
||||
end
|
||||
|
||||
re.setlabels(labels)
|
||||
|
||||
local function concat(a,b)
|
||||
return a..b
|
||||
end
|
||||
local function foldtable(action,t)
|
||||
local re
|
||||
local first = true
|
||||
for key,value in pairs(t) do
|
||||
if first then
|
||||
re = value
|
||||
first = false
|
||||
else
|
||||
|
||||
local temp = re
|
||||
if action == "suf" then -- suffix actions
|
||||
local act = value[1]
|
||||
if act == "*" or act == "?" or act == "+" then
|
||||
re = {action=act, op1=temp}
|
||||
else
|
||||
re = {action=act, op1=temp, op2=value[2]}
|
||||
end
|
||||
elseif action == "or" and #value == 2 then -- recovery expression
|
||||
local labels = value[1]
|
||||
local op2 = value[2]
|
||||
re = {action=action, op1=temp, op2=op2, condition=labels}
|
||||
else
|
||||
re = {action=action, op1=temp, op2=value}
|
||||
end
|
||||
end
|
||||
end
|
||||
return re
|
||||
end
|
||||
|
||||
|
||||
local gram = [=[
|
||||
|
||||
pattern <- (exp / %{NoPatt}) (!. / %{ExtraChars})
|
||||
exp <- S (grammar / alternative)
|
||||
|
||||
labels <- {| '{' {: (label / %{ExpLab1}) :} (',' {: (label / %{ExpLab2}) :})* ('}' / %{MisClose7}) |}
|
||||
|
||||
|
||||
alternative <- ( {:''->'or':} {| {: seq :} ('/' (('/' {| {: labels :} S {: (seq / %{ExpPatt1}) :} |}) / (S {: (seq / %{ExpPatt1}) :} ) ) )* |} ) -> foldtable
|
||||
|
||||
|
||||
seq <- ( {:''->'and':} {| {: prefix :}+ |} ) -> foldtable
|
||||
|
||||
|
||||
prefix <- {| {:action: '&' :} S {:op1: (prefix / %{ExpPatt2}) :} |}
|
||||
/ {| {:action: '!' :} S {:op1: (prefix / %{ExpPatt3}) :} |}
|
||||
/ suffix
|
||||
|
||||
suffix <- ( {:''->'suf':} {| primary S {| suffixaction S |}* |} ) -> foldtable
|
||||
|
||||
|
||||
suffixaction <- {[+*?]}
|
||||
/ {'^'} {| {:num: [+-]? NUM:} |}
|
||||
/ '^'->'^LABEL' (label / %{ExpNumOrLab})
|
||||
/ {'->'} S ((string / {| {:action:'{}'->'poscap':} |} / funcname / {|{:num: NUM :} |}) / %{ExpCap})
|
||||
/ {'=>'} S (funcname / %{ExpName1})
|
||||
|
||||
|
||||
|
||||
|
||||
primary <- '(' (exp / %{ExpPatt4}) (')' / %{MisClose1})
|
||||
/ term
|
||||
/ class
|
||||
/ defined
|
||||
/ {| {:action: '%'->'label':} ('{' / %{ExpNameOrLab}) S ({:op1: label:} / %{ExpLab1}) S ('}' / %{MisClose7}) |}
|
||||
/ {| {:action: '{:'->'gcap':} {:op2: defname:} ':' !'}' ({:op1:exp:} / %{ExpPatt5}) (':}' / %{MisClose2}) |}
|
||||
/ {| {:action: '{:'->'gcap':} ({:op1:exp:} / %{ExpPatt5}) (':}' / %{MisClose2}) |}
|
||||
/ {| {:action: '='->'bref':} ({:op1: defname:} / %{ExpName2}) |}
|
||||
/ {| {:action: '{}'->'poscap':} |}
|
||||
/ {| {:action: '{~'->'subcap':} ({:op1: exp:} / %{ExpPatt6}) ('~}' / %{MisClose3}) |}
|
||||
/ {| {:action: '{|'->'tcap':} ({:op1: exp:} / %{ExpPatt7}) ('|}' / %{MisClose4}) |}
|
||||
/ {| {:action: '{'->'scap':} ({:op1: exp:} / %{ExpPattOrClose}) ('}' / %{MisClose5}) |}
|
||||
/ {| {:action: '.'->'anychar':} |}
|
||||
/ !frag !nodee name S !ARROW
|
||||
/ '<' (name / %{ExpName3}) ('>' / %{MisClose6}) -- old-style non terminals
|
||||
|
||||
grammar <- {| definition+ |}
|
||||
definition <- {| (frag / nodee)? (token / nontoken) S ARROW ({:rule: exp :} / %{ExpPatt8}) |}
|
||||
|
||||
label <- {| {:s: ERRORNAME :} |}
|
||||
|
||||
frag <- {:fragment: 'fragment'->'1' :} ![0-9_a-z] S !ARROW
|
||||
nodee <- {:node: 'node'->'1' :} ![0-9_a-z] S !ARROW
|
||||
token <- {:rulename: TOKENNAME :} {:token:''->'1':}
|
||||
nontoken <- {:rulename: NAMESTRING :}
|
||||
|
||||
class <- '[' ( ('^' {| {:action:''->'invert':} {:op1: classset :} |} ) / classset ) (']' / %{MisClose8})
|
||||
classset <- ( {:''->'or':} {| {: (item / %{ExpItem}) :} (!']' {: (item / %{ExpItem}) :})* |} ) -> foldtable
|
||||
item <- defined / range / {| {:t: . :} |}
|
||||
range <- {| {:action:''->'range':} {:op1: {| {:s: ({: . :} ('-') {: [^]] :} ) -> concat :} |} :} |}
|
||||
|
||||
S <- (%s / '--' [^%nl]*)* -- spaces and comments
|
||||
name <- {| {:nt: TOKENNAME :} {:token:''->'1':} / {:nt: NAMESTRING :} |}
|
||||
|
||||
funcname <- {| {:func: NAMESTRING :} |}
|
||||
ERRORNAME <- NAMESTRING
|
||||
NAMESTRING <- [A-Za-z][A-Za-z0-9_]*
|
||||
TOKENNAME <- [A-Z_]+ ![0-9a-z]
|
||||
defname <- {| {:s: NAMESTRING :} |}
|
||||
ARROW <- '<-'
|
||||
NUM <- [0-9]+
|
||||
term <- {| '"' {:t: [^"]* :} ('"' / %{MisTerm2}) / "'" {:t: [^']* :} ("'" / %{MisTerm1}) |}
|
||||
string <- {| '"' {:s: [^"]* :} ('"' / %{MisTerm2}) / "'" {:s: [^']* :} ("'" / %{MisTerm1}) |}
|
||||
defined <- {| {:action: '%':} {:op1: defname :} |}
|
||||
]=]
|
||||
|
||||
local defs = {foldtable=foldtable, concat=concat}
|
||||
peg.gram = gram
|
||||
peg.defs = defs
|
||||
peg.labels = labels
|
||||
local p = re.compile ( gram, defs)
|
||||
|
||||
|
||||
|
||||
|
||||
--[[
|
||||
Function: pegToAST(input)
|
||||
|
||||
Input: a grammar in PEG format, described in https://github.com/vsbenas/parser-gen
|
||||
|
||||
Output: if parsing successful - a table of grammar rules, else - runtime error
|
||||
|
||||
Example input: "
|
||||
|
||||
Program <- stmt* / SPACE
|
||||
stmt <- ('a' / 'b')+
|
||||
SPACE <- ''
|
||||
|
||||
"
|
||||
|
||||
Example output: {
|
||||
{rulename = "Program", rule = {action = "or", op1 = {action = "*", op1 = {nt = "stmt"}}, op2 = {nt = "SPACE", token="1"}}},
|
||||
{rulename = "stmt", rule = {action = "+", op1 = {action="or", op1 = {t = "a"}, op2 = {t = "b"}}}},
|
||||
{rulename = "SPACE", rule = {t=""}, token=1},
|
||||
}
|
||||
|
||||
The rules are further processed and turned into lpeg compatible format in parser-gen.lua
|
||||
|
||||
Action names:
|
||||
or (has parameter condition for recovery expresions)
|
||||
and
|
||||
&
|
||||
!
|
||||
+
|
||||
*
|
||||
?
|
||||
^num (num is a number with an optional plus or minus sign)
|
||||
^label (label is an error label set with setlabels)
|
||||
->
|
||||
=>
|
||||
tcap
|
||||
gcap (op2= name, anonymous otherwise)
|
||||
bref
|
||||
poscap
|
||||
subcap
|
||||
scap
|
||||
anychar
|
||||
label
|
||||
%
|
||||
range
|
||||
|
||||
Final token actions:
|
||||
t - terminal
|
||||
nt - non terminal
|
||||
func - function definition
|
||||
s - literal string
|
||||
num - literal number
|
||||
]]--
|
||||
local function splitlines(str)
|
||||
local t = {}
|
||||
local function helper(line) table.insert(t, line) return "" end
|
||||
helper((str:gsub("(.-)\r?\n", helper)))
|
||||
return t
|
||||
end
|
||||
function peg.pegToAST(input, defs)
|
||||
local r, e, sfail = p:match(input, defs)
|
||||
if not r then
|
||||
local lab
|
||||
if e == 0 then
|
||||
lab = "Syntax error"
|
||||
else
|
||||
lab = errmsgs[e]
|
||||
end
|
||||
local lines = splitlines(input)
|
||||
local line, col = re.calcline(input, #input - #sfail + 1)
|
||||
local err = {}
|
||||
table.insert(err, "L" .. line .. ":C" .. col .. ": " .. lab)
|
||||
table.insert(err, lines[line])
|
||||
table.insert(err, string.rep(" ", col-1) .. "^")
|
||||
error("syntax error(s) in pattern\n" .. table.concat(err, "\n"), 3)
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
function peg.print_r ( t ) -- for debugging
|
||||
local print_r_cache={}
|
||||
local function sub_print_r(t,indent)
|
||||
if (print_r_cache[tostring(t)]) then
|
||||
print(indent.."*"..tostring(t))
|
||||
else
|
||||
print_r_cache[tostring(t)]=true
|
||||
if (type(t)=="table") then
|
||||
for pos,val in pairs(t) do
|
||||
if (type(val)=="table") then
|
||||
print(indent.."["..pos.."] => {")
|
||||
sub_print_r(val,indent..string.rep(" ",string.len(pos)+8))
|
||||
print(indent..string.rep(" ",string.len(pos)+6).."}")
|
||||
else
|
||||
print(indent.."["..pos.."] => '"..tostring(val).."'")
|
||||
end
|
||||
end
|
||||
else
|
||||
print(indent..tostring(t))
|
||||
end
|
||||
end
|
||||
end
|
||||
sub_print_r(t,"")
|
||||
end
|
||||
function peg.print_t ( t ) -- for debugging
|
||||
local print_r_cache={}
|
||||
local function sub_print_r (t,indent)
|
||||
if (print_r_cache[tostring(t)]) then
|
||||
print(indent.."*"..tostring(t))
|
||||
else
|
||||
print_r_cache[tostring(t)]=true
|
||||
if (type(t)=="table") then
|
||||
local function subprint (pos,val,indent)
|
||||
if (type(val)=="table") then
|
||||
print(indent.."{")
|
||||
sub_print_r(val,indent..string.rep(" ",string.len(pos)+8))
|
||||
print(indent..string.rep(" ",string.len(pos)-1).."},")
|
||||
else
|
||||
if type(val) ~= "number" then
|
||||
val = "'"..tostring(val).."'"
|
||||
end
|
||||
|
||||
if tonumber(pos) then
|
||||
print(indent..val..",")
|
||||
else
|
||||
print(indent..pos.."="..val..",")
|
||||
end
|
||||
end
|
||||
end
|
||||
if t["rule"] then
|
||||
subprint("rule",t["rule"],indent)
|
||||
end
|
||||
if t["pos"] then
|
||||
subprint("pos",t["pos"],indent)
|
||||
end
|
||||
for pos,val in pairs(t) do
|
||||
if pos ~= "rule" and pos ~= "pos" then
|
||||
subprint(pos,val,indent)
|
||||
end
|
||||
end
|
||||
else
|
||||
print(indent..tostring(t))
|
||||
end
|
||||
end
|
||||
end
|
||||
sub_print_r(t,"")
|
||||
end
|
||||
|
||||
function peg.calcline(subject, pos)
|
||||
return re.calcline(subject,pos)
|
||||
end
|
||||
return peg
|
27
06/parser-gen/rockspecs/parser-gen-1.0.rockspec
Normal file
27
06/parser-gen/rockspecs/parser-gen-1.0.rockspec
Normal file
|
@ -0,0 +1,27 @@
|
|||
package = "parser-gen"
|
||||
version = "1.0-7"
|
||||
source = {
|
||||
url = "git://github.com/vsbenas/parser-gen",
|
||||
tag = "v1.0"
|
||||
}
|
||||
description = {
|
||||
summary = "A PEG parser generator that handles space characters, generates ASTs and adds error labels automatically.",
|
||||
homepage = "https://github.com/vsbenas/parser-gen",
|
||||
license = "MIT/X11"
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1, < 5.4",
|
||||
"lpeglabel >= 0.12.2"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["parser-gen"] = "parser-gen.lua",
|
||||
["peg-parser"] = "peg-parser.lua",
|
||||
["stack"] = "stack.lua",
|
||||
["equals"] = "equals.lua",
|
||||
["errorgen"] = "errorgen.lua",
|
||||
|
||||
|
||||
}
|
||||
}
|
27
06/parser-gen/rockspecs/parser-gen-1.1.rockspec
Normal file
27
06/parser-gen/rockspecs/parser-gen-1.1.rockspec
Normal file
|
@ -0,0 +1,27 @@
|
|||
package = "parser-gen"
|
||||
version = "1.1-0"
|
||||
source = {
|
||||
url = "git://github.com/vsbenas/parser-gen",
|
||||
tag = "v1.1"
|
||||
}
|
||||
description = {
|
||||
summary = "A PEG parser generator that handles space characters, generates ASTs and adds error labels automatically.",
|
||||
homepage = "https://github.com/vsbenas/parser-gen",
|
||||
license = "MIT/X11"
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1, < 5.4",
|
||||
"lpeglabel >= 0.12.2"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["parser-gen"] = "parser-gen.lua",
|
||||
["peg-parser"] = "peg-parser.lua",
|
||||
["stack"] = "stack.lua",
|
||||
["equals"] = "equals.lua",
|
||||
["errorgen"] = "errorgen.lua",
|
||||
|
||||
|
||||
}
|
||||
}
|
27
06/parser-gen/rockspecs/parser-gen-1.2.rockspec
Normal file
27
06/parser-gen/rockspecs/parser-gen-1.2.rockspec
Normal file
|
@ -0,0 +1,27 @@
|
|||
package = "parser-gen"
|
||||
version = "1.2-0"
|
||||
source = {
|
||||
url = "git://github.com/vsbenas/parser-gen",
|
||||
tag = "v1.2"
|
||||
}
|
||||
description = {
|
||||
summary = "A PEG parser generator that handles space characters, generates ASTs and adds error labels automatically.",
|
||||
homepage = "https://github.com/vsbenas/parser-gen",
|
||||
license = "MIT/X11"
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1, < 5.4",
|
||||
"lpeglabel >= 0.12.2"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["parser-gen"] = "parser-gen.lua",
|
||||
["peg-parser"] = "peg-parser.lua",
|
||||
["stack"] = "stack.lua",
|
||||
["equals"] = "equals.lua",
|
||||
["errorgen"] = "errorgen.lua",
|
||||
|
||||
|
||||
}
|
||||
}
|
67
06/parser-gen/stack.lua
Normal file
67
06/parser-gen/stack.lua
Normal file
|
@ -0,0 +1,67 @@
|
|||
-- Stack Table
|
||||
-- Uses a table as stack, use <table>:push(value) and <table>:pop()
|
||||
-- Lua 5.1 compatible
|
||||
local unpack = unpack or table.unpack
|
||||
-- GLOBAL
|
||||
local Stack = {}
|
||||
|
||||
-- Create a Table with stack functions
|
||||
function Stack:Create()
|
||||
|
||||
-- stack table
|
||||
local t = {}
|
||||
-- entry table
|
||||
t._et = {}
|
||||
|
||||
-- push a value on to the stack
|
||||
function t:push(...)
|
||||
if ... then
|
||||
local targs = {...}
|
||||
-- add values
|
||||
for _,v in ipairs(targs) do
|
||||
table.insert(self._et, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- pop a value from the stack
|
||||
function t:pop(num)
|
||||
|
||||
-- get num values from stack
|
||||
local num = num or 1
|
||||
|
||||
-- return table
|
||||
local entries = {}
|
||||
|
||||
-- get values into entries
|
||||
for i = 1, num do
|
||||
-- get last entry
|
||||
if #self._et ~= 0 then
|
||||
table.insert(entries, self._et[#self._et])
|
||||
-- remove last value
|
||||
table.remove(self._et)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
-- return unpacked entries
|
||||
return unpack(entries)
|
||||
end
|
||||
|
||||
-- get entries
|
||||
function t:getn()
|
||||
return #self._et
|
||||
end
|
||||
|
||||
-- list values
|
||||
function t:list()
|
||||
for i,v in pairs(self._et) do
|
||||
print(i, v)
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
return {Stack=Stack}
|
||||
|
||||
-- CHILLCODE™
|
Loading…
Add table
Add a link
Reference in a new issue