mirror of
https://git.freebsd.org/src.git
synced 2026-01-16 23:02:24 +00:00
lyaml: vendor import lyaml bindings for libyaml version 6.2.8
This commit is contained in:
commit
95286bbb79
31 changed files with 7317 additions and 0 deletions
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
*~
|
||||
*.o
|
||||
*.so
|
||||
*.src.rock
|
||||
/ChangeLog
|
||||
/build-aux/config.ld
|
||||
/luacov.*.out
|
||||
/lyaml-*.tar.gz
|
||||
/TAGS
|
||||
8
.luacov
Normal file
8
.luacov
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
modules = {
|
||||
['lyaml'] = 'lib/lyaml/init.lua',
|
||||
['lyaml.*'] = 'lib',
|
||||
}
|
||||
|
||||
runreport = true
|
||||
|
||||
tick = true
|
||||
6
AUTHORS
Normal file
6
AUTHORS
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
lyaml is the work of several authors (see git history for
|
||||
contributors).
|
||||
|
||||
There is an earlier C LibYAML binding
|
||||
|
||||
Copyright Andrew Danforth <acd@weirdness.net>
|
||||
27
LICENSE
Normal file
27
LICENSE
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
This software comprises files that are copyright their respective
|
||||
authors (see the AUTHORS file for details), and distributed under
|
||||
the terms of the MIT license (the same license as Lua itself),
|
||||
unless noted otherwise in the body of that file.
|
||||
|
||||
====================================================================
|
||||
Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
|
||||
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 NONINFRINGE-
|
||||
MENT. 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.
|
||||
====================================================================
|
||||
352
NEWS.md
Normal file
352
NEWS.md
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
# lyaml NEWS - User visible changes
|
||||
|
||||
## Noteworthy changes in release 6.2.8 (2022-10-22) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `luke` no longer crashes in `std.normalize` require loops
|
||||
occasionally in Lua 5.4.
|
||||
|
||||
- lyaml emitter no longer leaks at least six bytes for every
|
||||
map, sequence and scalar emitted.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2.7 (2020-11-27) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Don't skip YAML entries from mixed key Lua tables.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2.6 (2020-08-28) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `luke` really propagates `LDFLAGS` to module compilation
|
||||
commands.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2.5 (2020-04-15) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `luke` really propagates `YAML_BINDIR`, `YAML_DIR`,
|
||||
`YAML_INCDIR` and `YAML_LIBDIR` to checksymbol test in lukefile
|
||||
given the change to `external_dependencies` layout in 6.1.2.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2.4 (2019-07-20) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `luke` works with upgraded bootstrap luarocks version of
|
||||
`require`.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2.3 (2018-09-16) [stable]
|
||||
|
||||
### New Features
|
||||
|
||||
- Initial support for Lua 5.4.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2.2 (2018-03-28) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Remove spurious dependency on `std.normalize` and `std._debug`
|
||||
libraries.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2.1 (2018-02-20) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `spec/spec_helper.lua` now looks in the correct objdir
|
||||
for object modules built by luke, instead of adding unused
|
||||
paths from old Autotools objdirs. So now specl is properly
|
||||
running examples against the not yet installed lyaml objects.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.2 (2017-11-26) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `luke` uses the correct spelling of LIBFLAG to match luarocks now.
|
||||
|
||||
- `luke` no longer throws spurious `cp: file exists` errors.
|
||||
|
||||
- `luke` works on luajit again.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.1.3 (2017-05-29) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `luke` no longer bombs out with a nil concat error.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.1.2 (2017-04-30) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `luke` now propagates `LUA_DIR`, `YAML_INCDIR` and `YAML_LIBDIR`
|
||||
correctly.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.1.1 (2017-01-22) [stable]
|
||||
|
||||
### New Features
|
||||
|
||||
- Builds and installs with `luke` instead of Autotools.
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.1 (2016-10-08) [stable]
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- `lyaml.load` now correctly reads implicit null scalars in a YAML
|
||||
document as an `lyaml.null` reference, identical to the "~"
|
||||
shorthand syntax, according to [the specification][nullspec].
|
||||
|
||||
```yaml
|
||||
empty:
|
||||
canonical: ~
|
||||
english: null
|
||||
~: null key
|
||||
```
|
||||
|
||||
|
||||
## Noteworthy changes in release 6.0 (2015-07-27) [stable]
|
||||
|
||||
### New Features
|
||||
|
||||
- `lyaml.load` now correctly reads a !!bool tagged scalar from a
|
||||
YAML document, or an implicit bool value, according to
|
||||
[the specification][boolspec].
|
||||
|
||||
```yaml
|
||||
%TAG ! tag:yaml.org,2002:
|
||||
---
|
||||
truthy:
|
||||
- !bool Y
|
||||
- !bool y
|
||||
- !bool True
|
||||
- !bool "on"
|
||||
falsey:
|
||||
- !bool n
|
||||
- !bool OFF
|
||||
- !bool garbage
|
||||
```
|
||||
|
||||
- `lyaml.load` now correctly reads a !!float tagged scalar from a
|
||||
YAML document, or an implicit float value, according to
|
||||
[the specification][floatspec].
|
||||
|
||||
- `lyaml.load` now correctly reads a !!int tagged scalar from a
|
||||
YAML document, or an implicit integer value, according to
|
||||
[the specification][intspec].
|
||||
|
||||
- `lyaml.load` now supports the !!merge key type according to
|
||||
[the specification][mergespec].
|
||||
|
||||
```yaml
|
||||
- &MERGE { x: 1, y: 2 }
|
||||
- &OVERRIDE { x: 0, z: 1 }
|
||||
-
|
||||
<< : [&MERGE, &OVERRIDE]
|
||||
z: 3
|
||||
```
|
||||
|
||||
The anchored tables remain in the document too, so this results in
|
||||
the following Lua table:
|
||||
|
||||
```lua
|
||||
{ -- START_STREAM
|
||||
{ -- START_DOCUMENT
|
||||
{ x = 1, y = 2 }, -- MERGE
|
||||
{ x = 0, z = 1 }, -- OVERRIDE
|
||||
{ x = 1, y = 2, z = 3}, -- <<<
|
||||
} -- END_DOCUMENT
|
||||
} -- END_STREAM
|
||||
```
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Multi-line strings were previously being dumped using single quotes
|
||||
which caused the dumped YAML to break.
|
||||
|
||||
For example, { foo = "a\nmultiline\nstring" } would get dumped as:
|
||||
|
||||
```yaml
|
||||
foo: 'a
|
||||
|
||||
multiline
|
||||
|
||||
string'
|
||||
```
|
||||
|
||||
Note the extra line-breaks in between each line. This also causes
|
||||
YAML parsing to fail (since the blank lines didn't have the expected
|
||||
indentation).
|
||||
|
||||
This patch fixes the dump to use the YAML literal syntax for any
|
||||
multi-line strings so the same example gets dumped as:
|
||||
|
||||
```yaml
|
||||
foo: |-
|
||||
a
|
||||
multiline
|
||||
string
|
||||
```
|
||||
|
||||
- `lyaml.load` now correctly reads the !!null tag in a YAML
|
||||
document as an `lyaml.null` reference, identical to the "~"
|
||||
shorthand syntax, according to [the specification][nullspec].
|
||||
|
||||
### Incompatible Changes
|
||||
|
||||
- `lyaml.load` now takes a table of options as an optional second
|
||||
argument, not a simple boolean to determine whether all documents
|
||||
should be returned from the stream. For now, a `true` second
|
||||
argument will be converted to the modern equivalent:
|
||||
|
||||
```lua
|
||||
lyaml.load (document, { all = true })
|
||||
```
|
||||
|
||||
- `lyaml.dump` now takes a table of options as an optional second
|
||||
argument, not an initial table of anchors. For now, a second
|
||||
argument without any new API keys will be converted to the modern
|
||||
equivalent:
|
||||
|
||||
```lua
|
||||
lyaml.dump (t, { anchors = arg2 })
|
||||
```
|
||||
|
||||
[boolspec]: http://yaml.org/type/bool.html
|
||||
[floatspec]: http://yaml.org/type/float.html
|
||||
[intspec]: http://yaml.org/type/int.html
|
||||
[mergespec]: http://yaml.org/type/merge.html
|
||||
[nullspec]: http://yaml.org/type/null.html
|
||||
|
||||
|
||||
## Noteworthy changes in release 5.1.4 (2015-01-01) [stable]
|
||||
|
||||
- This release is functionally identical to the last.
|
||||
|
||||
|
||||
## Noteworthy changes in release 5.1.3 (2015-01-01) [stable]
|
||||
|
||||
- This release is functionally identical to the last.
|
||||
|
||||
|
||||
## Noteworthy changes in release 5.1.2 (2014-12-27) [stable]
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
- No more spurious .travis.yml is out of date warnings during
|
||||
`luarocks install lyaml`.
|
||||
|
||||
|
||||
## Noteworthy changes in release 5.1.1 (2014-12-19) [stable]
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
- When using `sudo make install` instead of LuaRocks, `lyaml.so`
|
||||
is now correctly installed to `$luaexecdir`.
|
||||
|
||||
|
||||
## Noteworthy changes in release 5.1.0 (2014-12-17) [stable]
|
||||
|
||||
### New Features
|
||||
|
||||
- Lua 5.3.0 compatibility.
|
||||
|
||||
|
||||
## Noteworthy changes in release 5 (2014-09-25) [beta]
|
||||
|
||||
### Build
|
||||
|
||||
- Significantly reduced pointer mismatch warnings from modern GNU
|
||||
compilers.
|
||||
|
||||
### New Features
|
||||
|
||||
- `lyaml.dump` now takes a second argument containing a table of
|
||||
potential anchor values in `ANCHOR_NAME = { "match", "elements" }`
|
||||
pairs format. The first time any are matched in the table being
|
||||
dumped, they are preceded by `&ANCHOR_NAME` in the output YAML
|
||||
document; subsequent matches are not written out in full, but
|
||||
shortened to the appropriate `*ANCHOR_NAME` alias.
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
- `yaml.emitter` no longer emits numbers in SINGLE_QUOTE style by
|
||||
default.
|
||||
|
||||
- `yaml.emitter ().emit` returns error strings correctly for invalid
|
||||
STREAM_START encoding, and MAPPING_START, SEQUENCE_START & SCALAR
|
||||
style fields.
|
||||
|
||||
|
||||
## Noteworthy changes in release 4 (2013-09-11) [beta]
|
||||
|
||||
### New Features
|
||||
|
||||
- New yaml.emitter API returns an object with an emit method for
|
||||
adding events using yaml_*_event_initialize() calls.
|
||||
|
||||
- New yaml.parser API returns a Lua iterator that fetches the next
|
||||
event using yaml_parser_parse().
|
||||
|
||||
- New yaml.scanner API returns a Lua iterator that fetches the next
|
||||
token using yaml_parser_scan().
|
||||
|
||||
- Beginnings of Specl specs, starting with a reasonably comprehensive
|
||||
specifications for the new APIs above.
|
||||
|
||||
- C implementation of lyaml.dump has moved to Lua implementation as
|
||||
yaml.dump.
|
||||
|
||||
- C implementation of lyaml.load has moved to Lua implementation as
|
||||
yaml.load.
|
||||
|
||||
- The new Lua implementation of lyaml.load () handles multi-document
|
||||
streams, and returns a table of documents when the new second
|
||||
argument is `true`.
|
||||
|
||||
|
||||
## Noteworthy changes in release 3 (2013-04-27) [beta]
|
||||
|
||||
- This release is functionally identical to the last.
|
||||
|
||||
### New Features
|
||||
|
||||
- lyaml builds are now made against Lua 5.1, Lua 5.2 and luajit 2.0.0
|
||||
automatically, with every commit.
|
||||
|
||||
- move to a cleaner, automated release system.
|
||||
|
||||
|
||||
## Noteworthy changes in release 2 (2013-03-18) [beta]
|
||||
|
||||
- This release is functionally identical to the last.
|
||||
|
||||
- Use correct MIT license attribution, relicensing build files to match
|
||||
Andrew Danforth''s MIT licensed lyaml.c too.
|
||||
|
||||
|
||||
## Noteworthy changes in release 1 (2013-03-17) [beta]
|
||||
|
||||
### New Features
|
||||
|
||||
- A binding for libYAML, by Andrew Danforth: Updated for Lua 5.1 and
|
||||
5.2, and packaged as a luarock.
|
||||
|
||||
- I spun this out of Specl (http://github.com/gvvaughan/specl) so that
|
||||
other projects may use it, and to simplify the Specl build.
|
||||
|
||||
### Known Issues
|
||||
|
||||
- There's not really any documentation, sorry. Contributions welcome!
|
||||
232
README.md
Normal file
232
README.md
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
LYAML
|
||||
=====
|
||||
|
||||
Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
|
||||
[](https://mit-license.org)
|
||||
[](https://github.com/gvvaughan/lyaml/actions)
|
||||
[](https://codecov.io/github/gvvaughan/lyaml?branch=release-v6.2.8)
|
||||
|
||||
[LibYAML] binding for [Lua], with a fast C implementation
|
||||
for converting between [%YAML 1.1][yaml11] and [Lua] tables,
|
||||
and a low-level [YAML] event parser for implementing more
|
||||
intricate [YAML] document loading.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
### High Level API
|
||||
|
||||
These functions quickly convert back and forth between Lua tables
|
||||
and [%YAML 1.1][yaml11] format strings.
|
||||
|
||||
```lua
|
||||
local lyaml = require "lyaml"
|
||||
local t = lyaml.load (YAML-STRING, [OPTS-TABLE])
|
||||
local yamlstr = lyaml.dump (LUA-TABLE, [OPTS-TABLE])
|
||||
local null = lyaml.null ()
|
||||
```
|
||||
|
||||
#### `lyaml.load`
|
||||
|
||||
`lyaml.load` accepts a YAML string for parsing. If the YAML string contains
|
||||
multiple documents, only the first document will be returned by default. To
|
||||
return multiple documents as a table, set `all = true` in the second
|
||||
argument OPTS-TABLE.
|
||||
|
||||
```lua
|
||||
lyaml.load("foo: bar")
|
||||
--> { foo = "bar" }
|
||||
|
||||
lyaml.load("foo: bar", { all = true })
|
||||
--> { { foo = "bar" } }
|
||||
|
||||
multi_doc_yaml = [[
|
||||
---
|
||||
one
|
||||
...
|
||||
---
|
||||
two
|
||||
...
|
||||
]]
|
||||
|
||||
lyaml.load(multi_doc_yaml)
|
||||
--> "one"
|
||||
|
||||
lyaml.load(multi_doc_yaml, { all = true })
|
||||
--> { "one", "two" }
|
||||
```
|
||||
|
||||
You can supply an alternative function for converting implicit plain
|
||||
scalar values in the `implicit_scalar` field of the OPTS-TABLE argument;
|
||||
otherwise a default is composed from the functions in the `lyaml.implicit`
|
||||
module.
|
||||
|
||||
You can also supply an alternative table for coverting explicitly tagged
|
||||
scalar values in the `explicit_scalar` field of the OPTS-TABLE argument;
|
||||
otherwise all supported tags are parsed by default using the functions
|
||||
from the `lyaml.explicit` module.
|
||||
|
||||
#### `lyaml.dump`
|
||||
|
||||
`lyaml.dump` accepts a table of values to dump. Each value in the table
|
||||
represents a single YAML document. To dump a table of lua values this means
|
||||
the table must be wrapped in another table (the outer table represents the
|
||||
YAML documents, the inner table is the single document table to dump).
|
||||
|
||||
```lua
|
||||
lyaml.dump({ { foo = "bar" } })
|
||||
--> ---
|
||||
--> foo: bar
|
||||
--> ...
|
||||
|
||||
lyaml.dump({ "one", "two" })
|
||||
--> --- one
|
||||
--> ...
|
||||
--> --- two
|
||||
--> ...
|
||||
```
|
||||
|
||||
If you need to round-trip load a dumped document, and you used a custom
|
||||
function for converting implicit scalars, then you should pass that same
|
||||
function in the `implicit_scalar` field of the OPTS-TABLE argument to
|
||||
`lyaml.dump` so that it can quote strings that might otherwise be
|
||||
implicitly converted on reload.
|
||||
|
||||
#### Nil Values
|
||||
|
||||
[Lua] tables treat `nil` valued keys as if they were not there,
|
||||
where [YAML] explicitly supports `null` values (and keys!). Lyaml
|
||||
will retain [YAML] `null` values as `lyaml.null ()` by default,
|
||||
though it is straight forward to wrap the low level APIs to use `nil`,
|
||||
subject to the usual caveats of how nil values work in [Lua] tables.
|
||||
|
||||
|
||||
### Low Level APIs
|
||||
|
||||
```lua
|
||||
local emitter = require ("yaml").emitter ()
|
||||
|
||||
emitter.emit {type = "STREAM_START"}
|
||||
for _, event in ipairs (event_list) do
|
||||
emitter.emit (event)
|
||||
end
|
||||
str = emitter.emit {type = "STREAM_END"}
|
||||
```
|
||||
|
||||
The `yaml.emitter` function returns an emitter object that has a
|
||||
single emit function, which you call with event tables, the last
|
||||
`STREAM_END` event returns a string formatted as a [YAML 1.1][yaml11]
|
||||
document.
|
||||
|
||||
```lua
|
||||
local iter = require ("yaml").scanner (YAML-STRING)
|
||||
|
||||
for token_table in iter () do
|
||||
-- process token table
|
||||
end
|
||||
```
|
||||
|
||||
Each time the iterator returned by `scanner` is called, it returns
|
||||
a table describing the next token of YAML-STRING. See LibYAML's
|
||||
[yaml.h] for details of the contents and semantics of the various
|
||||
tokens produced by `yaml_parser_scan`, the underlying call made by
|
||||
the iterator.
|
||||
|
||||
[LibYAML] implements a fast parser in C using `yaml_parser_scan`, which
|
||||
is also bound to lyaml, and easier to use than the token API above:
|
||||
|
||||
```lua
|
||||
local iter = require ("yaml").parser (YAML-STRING)
|
||||
|
||||
for event_table in iter () do
|
||||
-- process event table
|
||||
end
|
||||
```
|
||||
|
||||
Each time the iterator returned by `parser` is called, it returns
|
||||
a table describing the next event from the "Parse" process of the
|
||||
"Parse, Compose, Construct" processing model described in the
|
||||
[YAML 1.1][yaml11] specification using [LibYAML].
|
||||
|
||||
Implementing the remaining "Compose" and "Construct" processes in
|
||||
[Lua] is left as an exercise for the reader -- though, unlike the
|
||||
high-level API, `lyaml.parser` exposes all details of the input
|
||||
stream events, such as line and column numbers.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
There's no need to download an [lyaml] release, or clone the git repo,
|
||||
unless you want to modify the code. If you use [LuaRocks], you can
|
||||
use it to install the latest release from its repository:
|
||||
|
||||
luarocks --server=http://rocks.moonscript.org install lyaml
|
||||
|
||||
Or from the rockspec in a release tarball:
|
||||
|
||||
luarocks make lyaml-?-1.rockspec
|
||||
|
||||
To install current git master from [GitHub][lyaml] (for testing):
|
||||
|
||||
luarocks install http://raw.github.com/gvvaughan/lyaml/master/lyaml-git-1.rockspec
|
||||
|
||||
To install without [LuaRocks], clone the sources from the
|
||||
[repository][lyaml], and then run the following commands:
|
||||
|
||||
```sh
|
||||
cd lyaml
|
||||
build-aux/luke LYAML_DIR=LIBYAML-INSTALL-PREFIX
|
||||
sudo build-aux/luke PREFIX=LYAML-INSTALL-PREFIX install
|
||||
specl -v1freport spec/*_spec.yaml
|
||||
```
|
||||
|
||||
The dependencies are listed in the dependencies entry of the file
|
||||
[rockspec][L15].
|
||||
|
||||
|
||||
Bug reports and code contributions
|
||||
----------------------------------
|
||||
|
||||
This library is maintained by its users.
|
||||
|
||||
Please make bug reports and suggestions as [GitHub Issues][issues].
|
||||
Pull requests are especially appreciated.
|
||||
|
||||
But first, please check that your issue has not already been reported by
|
||||
someone else, and that it is not already fixed by [master][lyaml] in
|
||||
preparation for the next release (see Installation section above for how
|
||||
to temporarily install master with [LuaRocks][]).
|
||||
|
||||
There is no strict coding style, but please bear in mind the following
|
||||
points when proposing changes:
|
||||
|
||||
0. Follow existing code. There are a lot of useful patterns and avoided
|
||||
traps there.
|
||||
|
||||
1. 3-character indentation using SPACES in Lua sources: It makes rogue
|
||||
TABs easier to see, and lines up nicely with 'if' and 'end' keywords.
|
||||
|
||||
2. Simple strings are easiest to type using single-quote delimiters,
|
||||
saving double-quotes for where a string contains apostrophes.
|
||||
|
||||
3. Save horizontal space by only using SPACEs where the parser requires
|
||||
them.
|
||||
|
||||
4. Use vertical space to separate out compound statements to help the
|
||||
coverage reports discover untested lines.
|
||||
|
||||
5. Prefer explicit string function calls over object methods, to mitigate
|
||||
issues with monkey-patching in caller environment.
|
||||
|
||||
|
||||
[issues]: http://github.com/gvvaughas/lyaml/issues
|
||||
[libyaml]: http://pyyaml.org/wiki/LibYAML
|
||||
[lua]: http://www.lua.org
|
||||
[luarocks]: http://www.luarocks.org
|
||||
[lyaml]: http://github.com/gvvaughan/lyaml
|
||||
[L15]: http://github.com/gvvaughan/lyaml/blob/master/lyaml-git-1.rockspec#L15
|
||||
[yaml.h]: http://pyyaml.org/browser/libyaml/branches/stable/include/yaml.h
|
||||
[yaml]: http://yaml.org
|
||||
[yaml11]: http://yaml.org/spec/1.1/
|
||||
34
build-aux/config.ld.in
Normal file
34
build-aux/config.ld.in
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
--[[
|
||||
LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
]]
|
||||
|
||||
title = '@package@ @version@ Reference'
|
||||
project = '@package@ @version@'
|
||||
description = [[
|
||||
# LYAML binding for Lua
|
||||
|
||||
This is a Lua binding for the fast libYAML C library for converting
|
||||
between `%YAML 1.1` and Lua tables, with a flexible Lua language
|
||||
API to load and save YAML documents.
|
||||
|
||||
It works with Lua 5.1 (including LuaJIT), 5.2, 5.3 and 5.4.
|
||||
|
||||
## LICENSE
|
||||
|
||||
The code is copyright by its respective authors, and released under the
|
||||
MIT license (the same license as Lua itself). There is no warranty.
|
||||
]]
|
||||
|
||||
dir = '../doc'
|
||||
|
||||
file = {
|
||||
'../lib/lyaml/init.lua',
|
||||
'../lib/lyaml/explicit.lua',
|
||||
'../lib/lyaml/functional.lua',
|
||||
'../lib/lyaml/implicit.lua',
|
||||
}
|
||||
|
||||
format = 'markdown'
|
||||
backtick_references = false
|
||||
sort = false
|
||||
672
build-aux/luke
Executable file
672
build-aux/luke
Executable file
|
|
@ -0,0 +1,672 @@
|
|||
#!/usr/bin/env lua
|
||||
--[[ minified code follows, see --help text for source location! ]]
|
||||
local require=function(modname)if package.loaded[modname]==nil then
|
||||
if type(package.preload[modname])~="function"then
|
||||
io.stderr:write("module '" .. modname .. "' not found:\n no valid field package.preload['" .. modname .. "']\n")
|
||||
return nil
|
||||
end
|
||||
package.loaded[modname]=package.preload[modname](modname,"package.preload")end
|
||||
return package.loaded[modname]end
|
||||
package.preload['luke._base']=function()
|
||||
local _ENV=require'std.normalize'{}local function fatal(...)local msg=(...)if select('#',...)>1 then
|
||||
msg=format(...)end
|
||||
stderr:write('luke: fatal: '..msg..'\n')exit(1)end
|
||||
return{diagnose=function(predicate,...)if not predicate then
|
||||
fatal(...)end
|
||||
end,fatal=fatal,}
|
||||
end
|
||||
package.preload['luke.cli']=function()
|
||||
local _ENV=require'std.normalize'{'luke._base','luke.lukefile','luke.platforms','std.functional',}local function version()print[[
|
||||
luke (Luke) 0.2.3
|
||||
Written by Gary V. Vaughan <gary@gnu.org>, 2014
|
||||
|
||||
Copyright (C) 2022, Gary V. Vaughan
|
||||
Luke comes with ABSOLUTELY NO WARRANTY.
|
||||
You may redistribute copies of Luke under the terms of the MIT license;
|
||||
it may be used for any purpose at absolutely no cost, without permission.
|
||||
See <https://mit-license.org> for details.
|
||||
]]exit(0)end
|
||||
local function help()print[[
|
||||
Usage: luke [OPTION]... [VAR=VALUE]... [TARGET]
|
||||
|
||||
Use the source, Luke!
|
||||
|
||||
--help print this help, then exit
|
||||
--version print version number, then exit
|
||||
--file=FILE use FILE instead of lukefile
|
||||
--value=NAME print the value of variable NAME
|
||||
--quiet without any output
|
||||
--verbose provide more progress output
|
||||
|
||||
Each TARGET can be one of the module table keys from lukefile, or:
|
||||
|
||||
all build all targets in lukefile
|
||||
install copy all built targets to $PREFIX
|
||||
|
||||
If no TARGET is given, 'all' is implied.
|
||||
|
||||
Report bugs to https://github.com/gvvaughan/luke/issues.]]exit(0)end
|
||||
local function opterr(...)local msg=(...)if select('#',...)>1 then
|
||||
msg=format(...)end
|
||||
msg=gsub(msg,'%.$','')stderr:write('luke: error: '..msg..'.\n')stderr:write("luke: try '"..arg[0].." --help' for help.\n")exit(2)end
|
||||
local function display(...)return stdout:write(concat{...})end
|
||||
local function dump(...)local s=concat(map(list(...),str))if len(s)>0 then
|
||||
gsub(concat(map(list(...),str)),'\n*$','\n'):gsub('(.-)\n',function(line)stderr:write(' DEBUG: '..line..'\n')end)end
|
||||
end
|
||||
local function interpolate_to_substitute(s)return(gsub(s,'%$([%w_]+)','@%1@'))end
|
||||
return{parse_arguments=function(args)local r={clidefs={},valreqs={},fname='lukefile',install={},log=nop,targets={},verbose=nop,write=display,}map(args,function(opt)case(opt,{['--debug']=function()r.log=dump
|
||||
end,['%-%-file=(.+)']=function(optarg)r.fname=optarg
|
||||
end,['%-%-value=(.+)']=function(optarg)r.valreqs[#r.valreqs+1]=optarg
|
||||
end,['--quiet']=function()r.write=nop
|
||||
end,['--verbose']=function()r.verbose=display
|
||||
end,['--help']=help,['--version']=version,['([^-][^=]-)=(.+)']=function(name,value)r.clidefs[name]=value
|
||||
end,function(opt)if match(opt,'^-')~=nil then
|
||||
opterr("unrecognized option '%s'",opt)end
|
||||
append(r.targets,opt)end,})end)return r
|
||||
end,validate_arguments=function(parsed)local luke,err=loadluke(parsed.fname)diagnose(luke~=nil,'bad %s: %s',parsed.fname,err)if isempty(luke.modules or{})then
|
||||
fatal("no modules table in '%s', nothing to build",parsed.fname)end
|
||||
local targets=call(function()if isempty(parsed.targets)or contains(parsed.targets,'all')then
|
||||
return except(flatten(parsed.targets,keys(luke.modules)),'all')end
|
||||
local r=filter(parsed.targets,function(target)if target~='install'and luke.modules[target]==nil then
|
||||
fatal("no rule to make target '%s'",target)end
|
||||
return true
|
||||
end)assert(len(r)>0,"no build targets specified")return r
|
||||
end)local install
|
||||
local build=pluck(targets,luke.modules)if contains(targets,'install')then
|
||||
install=build or luke.modules
|
||||
end
|
||||
luke.modules=build
|
||||
if isempty(luke.modules)then
|
||||
luke.external_dependencies=nil
|
||||
end
|
||||
luke.substitute=merge(luke.substitute or{},{package=interpolate_to_substitute(luke.package),version=interpolate_to_substitute(luke.version),})luke.variables=merge(luke.variables or{},collect_variables(luke),{LUA_DIR='/usr',LUA_BINDIR='$LUA_DIR/bin',LUA_INCDIR='$LUA_DIR/include/lua$LUAVERSION',LUA_LIBDIR='$LUA_DIR/lib',objdir=platforms[1],package=luke.package,version=luke.version,})return{clidefs=parsed.clidefs,install=install,log=parsed.log,luke=luke,valreqs=parsed.valreqs,verbose=parsed.verbose,write=parsed.write,}end,}
|
||||
end
|
||||
package.preload['luke.compile']=function()
|
||||
local _ENV=require'std.normalize'{'luke._base','luke.environment','std.functional','type.context-manager','type.path',SHELLMETACHARS='[%s%$"]',}local function spawn(env,...)local command=interpolate(env,concat({...},' '))return with(TmpFile(),TmpFile(),function(out,err)local pipe=concat{command,' >',out.filename,' 2>',err.filename,'; printf $?'}return tonumber(slurp(Pipe(pipe))),slurp(File(err.filename)),slurp(File(out.filename))end)end
|
||||
local function run(L,env,command)L.write(interpolate(env,concat(command,' ')),'\n')local status,err,out=spawn(env,unpack(command))if status~=0 then
|
||||
if L.write==nop then
|
||||
stdout:write(concat(command,' ')..'\n')end
|
||||
stderr:write(err..'\n')end
|
||||
return status,out,err
|
||||
end
|
||||
local function defines(env,deftables)return zip_with(merge({},unpack(deftables)),function(name,value)local fmt=cond({[int(value)==1]='-D%s'},{[match(value,SHELLMETACHARS)~=nil]="-D%s='%s'"},{[true]='-D%s=%s'})return format(fmt,name,value)end)end
|
||||
local function incdirs(...)return map(flatten(...),function(v)return'-I'..v
|
||||
end)end
|
||||
local function libdirs(...)return map(flatten(...),function(v)return'-L'..v
|
||||
end)end
|
||||
local function c_module_path(objdir,name)return format('%s/%s.$LIB_EXTENSION',objdir,gsub(name,'%.','/'))end
|
||||
local function c_source(module,objdir)local path=gsub(module,'%.','/')local src=c_module_path(objdir,path)return src,(gsub('$INST_LIBDIR/'..path,'/[^/]+$',''))end
|
||||
local function lua_source(module,src)local abspath='$INST_LUADIR/'..gsub(module,'%.','/')if match(src,'/init%.lua$')then
|
||||
abspath=abspath..'/init'end
|
||||
abspath=abspath..'.lua'return src,(gsub(abspath,'/[^/]+%.lua$',''))end
|
||||
local function module_to_path(module,sources,objdir)return dropuntil(sources,function(source)return case(source,{['.*%.[ch]']=bind(c_source,{module,objdir}),['(.*%.[ch])%.in']=bind(c_source,{module,objdir}),['.*%.lua']=bind(lua_source,{module}),['(.*%.lua)%.in']=bind(lua_source,{module}),function(src)fatal("unsupported source type '%s'",src)end,})end)end
|
||||
return{build_c_module=function(L,env,luke,name)local rules=luke.modules[name]local c_module=c_module_path(luke.variables.objdir,name)local command={'$MAKEDIRS',dirname(c_module)}local status,err,out=spawn(env,unpack(command))if status~=0 then
|
||||
stdout:write(concat(command,' ')..'\n')stderr:write(err..'\n')exit(status)end
|
||||
return run(L,env,flatten('$CC $CFLAGS $LIBFLAG $PKGFLAGS $CPPFLAGS',defines(env,except(list(rules.defines,luke.defines),nil)),incdirs(rules.incdirs,luke.incdirs),rules.sources,'-o',c_module,'$LDFLAGS',libdirs(rules.libdirs,luke.libdirs),'$LIBS',rules.libraries,luke.libraries))end,c_modules=function(modules)return filter(keys(modules),function(name)return dropuntil(modules[name].sources,bind(match,{[2]='%.[ch]$'}))end)end,incdirs=incdirs,install_modules=function(L,env,luke,modules)return reduce(keys(modules),0,function(status,name)if status==0 then
|
||||
local src,dir=module_to_path(name,modules[name].sources,luke.variables.objdir)if not exists(interpolate(env,dir))then
|
||||
status=run(L,env,{'$MAKEDIRS',dir})end
|
||||
if status==0 then
|
||||
status=run(L,env,{'$INSTALL',src,dir..'/'})end
|
||||
end
|
||||
return status
|
||||
end)end,libdirs=libdirs,run_command=run,spawn=spawn,}
|
||||
end
|
||||
package.preload['luke.configure']=function()
|
||||
local _ENV=require'std.normalize'{'luke._base','luke.compile','luke.environment','std.functional','type.context-manager','type.dict',CCPROGS={'cc','gcc','clang'},}local function logspawn(L,env,...)local status,err=spawn(env,...)if status~=0 and err~=''then
|
||||
L.log(err)end
|
||||
return status
|
||||
end
|
||||
local function checking(L,...)L.verbose('checking ',concat({...},' '),'... ')end
|
||||
local function found_library(L,x)if x==nil or x==''then
|
||||
L.verbose'none required'elseif isempty(x)then
|
||||
L.verbose'not supported'else
|
||||
L.verbose(x)end
|
||||
L.verbose'\n'return x
|
||||
end
|
||||
local function found_prog(L,x)L.verbose(x and'yes\n'or'no\n')return x
|
||||
end
|
||||
local function found_result(L,x)L.verbose(x==0 and'yes\n'or'no\n')return x~=0 and 0 or 1
|
||||
end
|
||||
local function bindirs(...)return map(flatten(...),function(v)return v..':'end)end
|
||||
local function compile_command(L,env,config,filename)local command=flatten('$CC','-c','$CFLAGS',incdirs(config.incdir),'$CPPFLAGS',filename)L.log(interpolate(env,concat(command,' ')))return unpack(command)end
|
||||
local function link_command(L,env,config,a_out,source,lib)local command=flatten('$CC','$CFLAGS',incdirs(config.incdir),'$CPPFLAGS','-o',a_out,source,libdirs(config.libdir),'$LDFLAGS',lib,'$libs',CONFIGENV.libs)L.log(interpolate(env,concat(command,' ')))return unpack(command)end
|
||||
local function check_executable_in_path(L,env,config,prog)local PATH=concat(bindirs(config.bindir))..getenv('PATH')local found=dropuntil(gmatch(PATH,'[^:]+'),function(path)local progpath=path..'/'..prog
|
||||
return with(File(progpath,'r'),function(h)return h and isfile(h.context)and progpath or nil
|
||||
end)end)L.log(found and'found '..found or prog..' not found')return found~=nil
|
||||
end
|
||||
local function check_header_compile(L,env,config,header,extra_hdrs)return with(CTest(),function(conftest)conftest:write(format('%s\n#include "%s"\n',extra_hdrs,header))return logspawn(L,env,compile_command(L,env,config,conftest.filename))end)end
|
||||
local function check_struct_member_compile(L,env,config,structname,member,extra_hdrs)return with(CTest(),function(conftest)conftest:write(format([[
|
||||
%s
|
||||
int main () {
|
||||
static %s aggr;
|
||||
if (sizeof aggr.%s)
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
]],extra_hdrs,structname,member))return logspawn(L,env,compile_command(L,env,config,conftest.filename))end)end
|
||||
local function try_link(L,env,config,lib,symbol)return with(CTest(),TmpFile(),function(conftest,a_out)conftest:write(format([[
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char %s ();
|
||||
int main () {
|
||||
return %s ();
|
||||
}
|
||||
]],symbol,symbol))return logspawn(L,env,link_command(L,env,config,a_out.filename,conftest.filename,lib))end)end
|
||||
local function try_compile(L,env,config,headers)return with(CTest(),TmpFile(),function(conftest,a_out)conftest:write(format([[
|
||||
%s
|
||||
#if !defined %s || %s == -1
|
||||
choke me
|
||||
#endif
|
||||
int
|
||||
main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
]],headers,config.ifdef,config.ifdef))return logspawn(L,env,link_command(L,env,config,a_out.filename,conftest.filename))end)end
|
||||
local function check_func_decl(L,env,config,fname,extra_hdrs)return with(CTest(),function(conftest)conftest:write(format([[
|
||||
%s
|
||||
int
|
||||
main()
|
||||
{
|
||||
#ifndef %s
|
||||
(void) %s;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
]],extra_hdrs,fname,fname))return logspawn(L,env,compile_command(L,env,config,conftest.filename))end)end
|
||||
local function check_func_link(L,env,config,fname)return with(CTest(),TmpFile(),function(conftest,a_out)conftest:write(format([[
|
||||
/* Define to an innocous variant, in case <limits.h> declares it.
|
||||
For example, HP-UX 11i <limits,h> declares gettimeofday. */
|
||||
#define %s innocuous_%s
|
||||
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with declaration below.
|
||||
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
|
||||
<limits.h> exists even on freestanding compilers. */
|
||||
|
||||
#ifdef __STDC__
|
||||
# include <limits.h>
|
||||
#else
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#undef %s
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char %s ();
|
||||
|
||||
/* The GNU C library defines this for functions which it implements
|
||||
to always fail with ENOSYS. Some functions are actually named
|
||||
something starting with __ and the normal name is an alias. */
|
||||
#if defined __stub_%s || defined __stub__%s
|
||||
choke me
|
||||
#endif
|
||||
|
||||
int main () {
|
||||
return %s ();
|
||||
}
|
||||
]],fname,fname,fname,fname,fname,fname,fname))return logspawn(L,env,link_command(L,env,config,a_out.filename,conftest.filename))end)end
|
||||
local function add_external_deps(env,config,prefix)if prefix~=nil then
|
||||
for k,v in next,{bindir='$%s_BINDIR',incdir='$%s_INCDIR',libdir='$%s_LIBDIR'}do
|
||||
local envvar=interpolate(env,format(v,prefix))if envvar~=''then
|
||||
config[k]=envvar
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local function format_includes(includes)return map(includes or{},function(include)return format('#include "%s"',include)end)end
|
||||
local configure=setmetatable(OrderedDict({checkprog=function(L,env,config)return dropuntil(config.progs,function(prog)checking(L,'for',prog)if found_prog(L,check_executable_in_path(L,env,config,prog))then
|
||||
return prog
|
||||
end
|
||||
end)or fatal('cannot find '..config.checkprog)end},{checkheader=function(L,env,config)checking(L,'for',config.checkheader)local extra_hdrs=concat(format_includes(config.includes),'\n')return found_result(L,check_header_compile(L,env,config,config.checkheader,extra_hdrs))end},{checkdecl=function(L,env,config)checking(L,'whether',config.checkdecl,'is declared')local extra_hdrs=concat(format_includes(config.includes),'\n')return found_result(L,check_func_decl(L,env,config,config.checkdecl,extra_hdrs))end},{checksymbol=function(L,env,config)checking(L,'for library containing',config.checksymbol)if config.ifdef~=nil then
|
||||
local headers=concat(format_includes(config.includes),'\n')if try_compile(L,env,config,headers)~=0 then
|
||||
return found_library(L,{})end
|
||||
end
|
||||
local libraries,symbol=config.libraries,config.checksymbol
|
||||
local trylibs=reduce(libraries,{''},function(r,lib)append(r,'-l'..lib)end)return dropuntil(trylibs,function(lib)if try_link(L,env,config,lib,symbol)==0 then
|
||||
if lib~=''then
|
||||
if CONFIGENV.libs~=''then
|
||||
CONFIGENV.libs=' '..CONFIGENV.libs
|
||||
end
|
||||
CONFIGENV.libs=lib..CONFIGENV.libs
|
||||
end
|
||||
return found_library(L,lib)end
|
||||
end)or call(function()L.verbose'\n'fatal("required symbol '%s' not found in any of libc, lib%s",symbol,concat(libraries,', lib'))end)end},{checkfunc=function(L,env,config)checking(L,'for',config.checkfunc)return found_result(L,check_func_link(L,env,config,config.checkfunc))end},{checkmember=function(L,env,config)checking(L,'for',config.checkmember)local extra_hdrs=concat(format_includes(config.includes),'\n')local i=find(config.checkmember,'%.')local structname=sub(config.checkmember,1,i-1)local member=sub(config.checkmember,i+1)return found_result(L,check_struct_member_compile(L,env,config,structname,member,extra_hdrs))end}),{__call=function(self,L,env,config,prefix)return case(type(config),{['number']=function()return str(config)end,['string']=function()return config
|
||||
end,['table']=function()return dropuntil(self,function(fname)if config[fname]~=nil then
|
||||
add_external_deps(env,config,prefix)return apply(self[fname],list(L,env,config))end
|
||||
end)or fatal("unable to configure with keys '%s'",concat(keys(config),"', '"))end,function(type)fatal("unsupported configure type '%s'",type)end,})end,})return{config_compiler=function(L,env)local CC=env.CC
|
||||
if CC==nil then
|
||||
CC=configure(L,env,{checkprog='C compiler',progs=CCPROGS})env=makeenv(env,{CC=CC})end
|
||||
checking(L,interpolate(env,'whether $CC works'))local cm=CTest()local works,err=with(cm,function(conftest)conftest:write('typedef int x;\n')return spawn(env,'$compile',conftest.filename)end)if works~=0 then
|
||||
L.verbose'no\n'L.log(interpolate(env,'$compile '..cm.filename))if err and err~=''then
|
||||
L.log(err)end
|
||||
fatal('could not find a working C compiler')end
|
||||
found_prog(L,CC)return env
|
||||
end,config_ldoc=function(L,env)local LDOC=env.LDOC
|
||||
if LDOC==nil then
|
||||
LDOC=configure(L,env,{checkprog='LDocs generator',progs={'ldoc','true'}})env=makeenv(env,{LDOC=LDOC})end
|
||||
return env
|
||||
end,configure=configure,}
|
||||
end
|
||||
package.preload['luke.environment']=function()
|
||||
local _ENV=require'std.normalize'{'luke.platforms','std.functional',LUAVERSION=string.gsub(_VERSION,'[^0-9%.]+',''),}local env_mt={__index=function(self,varname)return dropuntil(self,function(env)local value=env[varname]if value~=nil then
|
||||
self[varname]=value
|
||||
return value
|
||||
end
|
||||
end)end,}local function interpolate_with(pattern,env,s)local r=''while r~=s do
|
||||
r=s
|
||||
s=gsub(r,pattern,function(varname)return env[varname]or''end)end
|
||||
return r
|
||||
end
|
||||
local function isenv(t)return getmetatable(t)==env_mt
|
||||
end
|
||||
return{CONFIGENV={compile='$CC -c $CFLAGS $CPPFLAGS',libs='',link='$CC $CFLAGS $CPPFLAGS $LDFLAGS',},DEFAULTENV=filter_platforms{LUAVERSION=LUAVERSION,PREFIX='/usr/local',INST_LIBDIR='$PREFIX/lib/lua/$LUAVERSION',INST_LUADIR='$PREFIX/share/lua/$LUAVERSION',LIB_EXTENSION='so',OBJ_EXTENSION='o',INSTALL='cp',MAKEDIRS='mkdir -p',CFLAGS='-O2',platforms={macosx={LIBFLAG='-fPIC -bundle -undefined dynamic_lookup -all_load',},LIBFLAG='-shared -fPIC',},},SHELLENV=setmetatable({},{__index=function(_,v)return getenv(v)end,}),expand=bind(interpolate_with,{'@([^@]+)@'}),interpolate=bind(interpolate_with,{'%$([%w_]+)'}),makeenv=function(...)local env=reduce(except(list(...),nil),function(r,t)if isenv(t)then
|
||||
map(t,bind(append,{r}))else
|
||||
append(r,t)end
|
||||
end)return setmetatable(env,env_mt)end,}
|
||||
end
|
||||
package.preload['luke']=function()
|
||||
local _ENV=require'std.normalize'{'luke.cli','luke.compile','luke.configure','luke.environment','luke.lukefile','std.functional',}local function run_ldocs(L,env,ldocs)return run_command(L,env,flatten{'$LDOC -c',ldocs.sources,'.'})end
|
||||
local function build_modules(L,env)local conf=makeenv(CONFIGENV,env)if not isempty(L.luke.ldocs or{})then
|
||||
conf=config_ldoc(L,conf)env=makeenv(env,{LDOC=conf.LDOC})end
|
||||
local c=c_modules(L.luke.modules)if not isempty(c)then
|
||||
conf=config_compiler(L,conf)env=makeenv(env,{CC=conf.CC})end
|
||||
L.luke=run_configs(L,conf,L.luke)local substitute=makeenv(L.clidefs,L.luke.substitute,SHELLENV)L.luke=run_templates(L,substitute,L.luke)local status=dropuntil(c,isnonzero,function(name)return build_c_module(L,env,L.luke,name)end)or 0
|
||||
if status==0 and not isempty(L.luke.ldocs or{})then
|
||||
status=run_ldocs(L,env,L.luke.ldocs)end
|
||||
return status
|
||||
end
|
||||
return{main=function(args)local L=validate_arguments(parse_arguments(args))local env=makeenv(L.clidefs,L.luke.variables,DEFAULTENV,SHELLENV)local status=0
|
||||
if not isempty(L.valreqs)then
|
||||
map(L.valreqs,function(name)print(interpolate(env,concat{name,"='$",name,"'"}))end)exit(0)end
|
||||
if status==0 and not isempty(L.luke.modules or{})then
|
||||
status=build_modules(L,env)end
|
||||
if status==0 then
|
||||
status=install_modules(L,env,L.luke,L.install)end
|
||||
return status
|
||||
end,}
|
||||
end
|
||||
package.preload['luke.lukefile']=function()
|
||||
local _ENV=require'std.normalize'{'luke._base','luke.configure','luke.environment','luke.platforms','std.functional','type.context-manager',}local function has_anykey(t,keylist)return any(map(keylist,function(k)return t[k]~=nil
|
||||
end))end
|
||||
local function isconfig(x)return istable(x)and has_anykey(x,configure)end
|
||||
local function collect_configs(luke,modulename,configs)configs=configs or{}for k,v in next,luke do
|
||||
if isconfig(v)then
|
||||
append(configs,{t=luke,k=k,module=modulename})elseif istable(v)then
|
||||
if k=='modules'or k=='external_dependencies'then
|
||||
for name,rules in next,v do
|
||||
collect_configs(rules,name,configs)end
|
||||
else
|
||||
collect_configs(v,modulename,configs)end
|
||||
end
|
||||
end
|
||||
return configs
|
||||
end
|
||||
local function deepcopy(t)return mapvalues(t,function(v)return case(type(v),{['table']=function()return deepcopy(v)end,v,})end)end
|
||||
local weighting=setmetatable(copy(configure),{__call=function(self,config)local t=config.t[config.k]for i=1,len(self)do
|
||||
if t[self[i]]~=nil then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end})local function config_cmp(a,b)return weighting(a)<weighting(b)end
|
||||
local function fill_templates(env,src,dest)with(File(dest,'w'),function(cm)for line in lines(src)do
|
||||
cm:write(expand(env,line)..'\n')end
|
||||
end)return dest
|
||||
end
|
||||
local function rewrite_template_files(L,env,source)return case(source,{['(.+)%.in']=function(r)L.write('creating '..r..'\n')return fill_templates(env,r..'.in',r)end,source,})end
|
||||
local function collect_variables(luke,variables)for k,v in next,luke do
|
||||
if k=='external_dependencies'then
|
||||
map(keys(v),function(name)local rootdir=concat{'$',name,'_DIR'}variables[name..'_DIR']='/usr'variables[name..'_BINDIR']=rootdir..'/bin'variables[name..'_INCDIR']=rootdir..'/include'variables[name..'_LIBDIR']=rootdir..'/lib'end)elseif istable(v)then
|
||||
collect_variables(v,variables)end
|
||||
end
|
||||
return variables
|
||||
end
|
||||
local function normalize_configs(config)return cond({[not istable(config)]=config,},{[not isconfig(config)]=function()return mapvalues(config,normalize_configs)end,},{[true]=function()local keymap={include='includes',prog='progs',library='libraries',}return foldkeys(keymap,config,function(a,b)local r=istable(a)and copy(a)or{a}b=istable(b)and b or{b}return reduce(b,r,function(v)append(r,v)end)end)end,})end
|
||||
local function normalize_rules(rules)return case(type(rules),{['nil']=nop,['string']=function()return{sources={rules}}end,['table']=function()if len(rules)>0 then
|
||||
return{sources=rules}elseif isstring(rules.sources)then
|
||||
return merge({sources={rules.sources}},normalize_configs(rules))end
|
||||
return normalize_configs(rules)end,function(v)fatal("unsupported rule type '%s'",v)end,})end
|
||||
local function unwrap_external_dependencies(luke)if istable(luke.external_dependencies)then
|
||||
for prefix,config in next,luke.external_dependencies do
|
||||
if istable(config)and next(config)and config.library~=''then
|
||||
luke.incdirs=append(luke.incdirs or{},format('$%s_INCDIR',prefix))luke.libdirs=append(luke.libdirs or{},format('$%s_LIBDIR',prefix))luke.libraries=append(luke.libraries or{},config.library)end
|
||||
end
|
||||
luke.external_dependencies=nil
|
||||
end
|
||||
return luke
|
||||
end
|
||||
return{loadluke=function(filename)local content,err=slurp(File(filename))if content==nil then
|
||||
return nil,err
|
||||
end
|
||||
local r={}local chunk,err=loadstring(content,filename,r)if chunk==nil then
|
||||
return nil,"Error loading file: "..err
|
||||
end
|
||||
local ok,err=pcall(chunk)if not ok then
|
||||
return nil,"Error running file: "..err
|
||||
end
|
||||
r=filter_platforms(r)r.external_dependencies=normalize_configs(r.external_dependencies)r.ldocs=normalize_rules(r.ldocs)r.modules=mapvalues(r.modules,normalize_rules)return r
|
||||
end,collect_variables=function(luke)return collect_variables(luke,{})end,run_configs=function(L,env,luke)local r=deepcopy(luke)local all_configs=collect_configs(r)sort(all_configs,config_cmp)map(all_configs,function(config)config.t[config.k]=configure(L,env,config.t[config.k],config.module)end)return unwrap_external_dependencies(r)end,run_templates=function(L,env,luke)local r=copy(luke)local rewrite=bind(rewrite_template_files,{L,env})r.modules=mapvalues(r.modules,function(rules)rules.sources=map(rules.sources,rewrite)end)if r.ldocs then
|
||||
r.ldocs.sources=map(r.ldocs.sources,rewrite)end
|
||||
return r
|
||||
end,}
|
||||
end
|
||||
package.preload['luke.platforms']=function()
|
||||
local _ENV=require'std.normalize'{'std.functional',}local CANON={['AIX']=list('aix','unix'),['FreeBSD']=list('freebsd','bsd','unix'),['OpenBSD']=list('openbsd','bsd','unix'),['NetBSD']=list('netbsd','bsd','unix'),['Darwin']=list('macosx','bsd','unix'),['Linux']=list('linux','unix'),['SunOS']=list('solaris','unix'),['^CYGWIN']=list('cygwin','unix'),['^MSYS']=list('msys','cygwin','unix'),['^Windows']=list('win32','windows'),['^MINGW']=list('mingw32','win32','windows'),['^procnto']=list('qnx'),['QNX']=list('qnx'),['Haiku']=list('haiku','unix'),}local ALLPLATFORMS=reduce(values(CANON),function(acc,platforms)map(platforms,function(v)acc[v]=true
|
||||
end)end)local function match_uname(canon,uname,x)return match(uname,x)and canon[x]end
|
||||
local function toplatforms(canon,uname)local literalkeys,patternkeys=partition(keys(canon),function(k)return sub(k,1,1)~='^'end)return(pluck(literalkeys,canon)or{})[uname]or dropuntil(map(patternkeys,bind(match_uname,{canon,uname})))or list('unix')end
|
||||
local supported=toplatforms(CANON,popen('uname -s'):read'*l')local function isplatform(x)return ALLPLATFORMS[x]~=nil
|
||||
end
|
||||
local function filter_platforms(t,using,predicate)local r,supported,isplatform={},using or supported,predicate or isplatform
|
||||
for k,v in next,t do
|
||||
if k=='platforms'then
|
||||
local matches=filter(supported,bind(get,{v}))local default=except(keys(v),isplatform)merge(r,hoist(matches,v)or pluck(default,v))elseif istable(v)then
|
||||
r[k]=filter_platforms(v,supported)else
|
||||
r[k]=r[k]or v
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
return{filter_platforms=filter_platforms,platforms=supported,toplatforms=toplatforms,}
|
||||
end
|
||||
package.preload['std.functional']=function()
|
||||
local _ENV=require'std.normalize'{destructure=next,isfile=function(x)return io.type(x)=='file'end,wrap=coroutine.wrap,yield=coroutine.yield,}local function apply(fn,argu)assert(fn~=nil,'cannot apply nil-valued function')if iscallable(fn)then
|
||||
return fn(unpack(argu))end
|
||||
return fn
|
||||
end
|
||||
local function call(fn,...)assert(fn~=nil,'cannot call nil-valued function')if iscallable(fn)then
|
||||
return fn(...)end
|
||||
return fn
|
||||
end
|
||||
local function wrapnonnil(iterator)return function(...)local r=list(iterator(...))if r[1]~=nil then
|
||||
return r
|
||||
end
|
||||
end
|
||||
end
|
||||
local function each(seq)if type(seq)=='function'then
|
||||
return wrapnonnil(seq)end
|
||||
local i,n=0,int(seq.n)or len(seq)return function()if i<n then
|
||||
i=i+1
|
||||
return list(seq[i])end
|
||||
end
|
||||
end
|
||||
local function eq(x)return function(y)return x==y
|
||||
end
|
||||
end
|
||||
local function isnonnil(x)return x~=nil
|
||||
end
|
||||
local function mkpredicate(x)return type(x)=='function'and x or eq(x)end
|
||||
local function except(seq,predicate)predicate=mkpredicate(predicate)local r={}for valu in each(seq)do
|
||||
if not predicate(unpack(valu))then
|
||||
r[#r+1]=unpack(valu)end
|
||||
end
|
||||
return r
|
||||
end
|
||||
local function visit(x)if type(x)=='table'then
|
||||
for valu in each(x)do
|
||||
visit(unpack(valu))end
|
||||
else
|
||||
yield(x)end
|
||||
end
|
||||
local function flatten(...)local r={}for v in wrap(visit),except(list(...),nil)do
|
||||
r[#r+1]=v
|
||||
end
|
||||
return r
|
||||
end
|
||||
return{any=function(seq)for valu in each(seq)do
|
||||
if unpack(valu)then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,apply=apply,bind=function(fn,bound)local n=bound.n or maxn(bound)return function(...)local argu,unbound=copy(bound),list(...)local i=1
|
||||
for j=1,unbound.n do
|
||||
while argu[i]~=nil do
|
||||
i=i+1
|
||||
end
|
||||
argu[i],i=unbound[j],i+1
|
||||
end
|
||||
bound.n=n>=i and n or i-1
|
||||
return apply(fn,argu)end
|
||||
end,call=call,case=function(s,branches)if branches[s]~=nil then
|
||||
return call(branches[s],s)end
|
||||
local DEFAULT=1
|
||||
for pattern,fn in next,branches do
|
||||
if pattern~=DEFAULT then
|
||||
local argu=list(match(s,'^'..pattern..'$'))if argu[1]~=nil then
|
||||
return apply(fn,argu)end
|
||||
end
|
||||
end
|
||||
local default=branches[DEFAULT]if iscallable(default)then
|
||||
return call(default,s)end
|
||||
return default
|
||||
end,cond=function(...)for clauseu in each(list(...))do
|
||||
local expr,consequence=destructure(unpack(clauseu))if expr then
|
||||
return call(consequence,expr)end
|
||||
end
|
||||
end,contains=function(seq,predicate)if type(predicate)~='function'then
|
||||
predicate=eq(predicate)end
|
||||
for valu in each(seq)do
|
||||
if predicate(unpack(valu))then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,destructure=destructure,dropuntil=function(seq,predicate,block)if block==nil then
|
||||
predicate,block=isnonnil,predicate
|
||||
end
|
||||
if block~=nil then
|
||||
for valu in each(seq)do
|
||||
local r=list(block(unpack(valu)))if predicate(unpack(r))then
|
||||
return unpack(r)end
|
||||
end
|
||||
else
|
||||
for r in each(seq)do
|
||||
if predicate(unpack(r))then
|
||||
return unpack(r)end
|
||||
end
|
||||
end
|
||||
end,except=except,filter=function(seq,predicate)predicate=mkpredicate(predicate)local r={}for valu in each(seq)do
|
||||
if predicate(unpack(valu))then
|
||||
r[#r+1]=unpack(valu)end
|
||||
end
|
||||
return r
|
||||
end,flatten=flatten,foldkeys=function(keymap,dict,combinator)local r={}for k,v in next,dict or{}do
|
||||
local key=keymap[k]if key then
|
||||
r[key]=combinator(v,dict[key])else
|
||||
r[k]=r[k]or v
|
||||
end
|
||||
end
|
||||
return r
|
||||
end,get=function(dict,key)return(dict or{})[key]end,hoist=function(keylist,dict)local r={}for keyu in each(keylist)do
|
||||
merge(r,dict[unpack(keyu)])end
|
||||
return next(r)and r or nil
|
||||
end,id=function(...)return...end,isempty=function(x)return type(x)=='table'and not next(x)end,isfile=isfile,isfunction=function(x)return type(x)=='function'end,isnil=function(x)return x==nil
|
||||
end,isstring=function(x)return type(x)=='string'end,istable=function(x)return type(x)=='table'end,isnonzero=function(x)return x~=0
|
||||
end,keys=function(iterable)local r=list()for k in next,iterable or{}do
|
||||
append(r,k)end
|
||||
return r
|
||||
end,map=function(seq,block)local r=list()for valu in each(seq)do
|
||||
append(r,block(unpack(valu)))end
|
||||
return r
|
||||
end,mapvalues=function(iterable,block)local r={}for k,v in next,iterable or{}do
|
||||
r[k]=block(v)or v
|
||||
end
|
||||
return r
|
||||
end,nop=function()end,partition=function(seq,block)local r,s=list(),list()for valu in each(seq)do
|
||||
append(block(unpack(valu))and r or s,unpack(valu))end
|
||||
return r,s
|
||||
end,pluck=function(keylist,dict)local r={}for keyu in each(keylist)do
|
||||
local key=unpack(keyu)r[key]=dict[key]end
|
||||
return next(r)and r or nil
|
||||
end,reduce=function(seq,acc,block)if block==nil then
|
||||
acc,block={},acc
|
||||
end
|
||||
for valu in each(seq)do
|
||||
acc=block(acc,unpack(valu))or acc
|
||||
end
|
||||
return acc
|
||||
end,values=function(iterable)local r=list()for _,v in next,iterable or{}do
|
||||
append(r,v)end
|
||||
return r
|
||||
end,zip_with=function(iterable,block)local r=list()for k,v in next,iterable or{}do
|
||||
append(r,block(k,v))end
|
||||
return r
|
||||
end,}
|
||||
end
|
||||
package.preload['std.normalize']=function()
|
||||
local ceil=math.ceil
|
||||
local concat=table.concat
|
||||
local config=package.config
|
||||
local getmetatable=getmetatable
|
||||
local loadstring=loadstring
|
||||
local match=string.match
|
||||
local next=next
|
||||
local pack=table.pack or function(...)return{n=select('#',...),...}end
|
||||
local setfenv=setfenv
|
||||
local sort=table.sort
|
||||
local tointeger=math.tointeger
|
||||
local tonumber=tonumber
|
||||
local tostring=tostring
|
||||
local type=type
|
||||
local unpack=table.unpack or unpack
|
||||
local dirsep,pathsep,pathmark,execdir,igmark=match(config,'^([^\n]+)\n([^\n]+)\n([^\n]+)\n([^\n]+)\n([^\n]+)')local function copy(iterable)local r={}for k,v in next,iterable or{}do
|
||||
r[k]=v
|
||||
end
|
||||
return r
|
||||
end
|
||||
local int=(function(f)if f==nil then
|
||||
return function(x)if type(x)=='number'and ceil(x)-x==0.0 then
|
||||
return x
|
||||
end
|
||||
end
|
||||
elseif f'1'~=nil then
|
||||
return function(x)if type(x)=='number'then
|
||||
return tointeger(x)end
|
||||
end
|
||||
end
|
||||
return f
|
||||
end)(tointeger)local function iscallable(x)return type(x)=='function'and x or(getmetatable(x)or{}).__call
|
||||
end
|
||||
local function getmetamethod(x,n)return iscallable((getmetatable(x)or{})[tostring(n)])end
|
||||
local function rawlen(x)if type(x)~='table'then
|
||||
return#x
|
||||
end
|
||||
local n=#x
|
||||
for i=1,n do
|
||||
if x[i]==nil then
|
||||
return i-1
|
||||
end
|
||||
end
|
||||
return n
|
||||
end
|
||||
local function len(x)local m=getmetamethod(x,'__len')return m and m(x)or rawlen(x)end
|
||||
if setfenv then
|
||||
local _loadstring=loadstring
|
||||
loadstring=function(s,filename,env)chunk,err=_loadstring(s,filename)if chunk~=nil and env~=nil then
|
||||
setfenv(chunk,env)end
|
||||
return chunk,err
|
||||
end
|
||||
else
|
||||
loadstring=function(s,filename,env)return load(s,filename,"t",env)end
|
||||
setfenv=function()end
|
||||
end
|
||||
local function keysort(a,b)if int(a)then
|
||||
return int(b)==nil or a<b
|
||||
else
|
||||
return int(b)==nil and tostring(a)<tostring(b)end
|
||||
end
|
||||
local function str(x,roots)roots=roots or{}local function stop_roots(x)return roots[x]or str(x,copy(roots))end
|
||||
if type(x)~='table'or getmetamethod(x,'__tostring')then
|
||||
return tostring(x)else
|
||||
local buf={'{'}roots[x]=tostring(x)local n,keys=1,{}for k in next,x do
|
||||
keys[n],n=k,n+1
|
||||
end
|
||||
sort(keys,keysort)local kp
|
||||
for _,k in next,keys do
|
||||
if kp~=nil and k~=nil then
|
||||
buf[#buf+1]=type(kp)=='number'and k~=kp+1 and'; 'or', 'end
|
||||
if k==1 or type(k)=='number'and k-1==kp then
|
||||
buf[#buf+1]=stop_roots(x[k])else
|
||||
buf[#buf+1]=stop_roots(k)..'='..stop_roots(x[k])end
|
||||
kp=k
|
||||
end
|
||||
buf[#buf+1]='}'return concat(buf)end
|
||||
end
|
||||
return setmetatable({append=function(seq,v)local n=(int(seq.n)or len(seq))+1
|
||||
seq.n,seq[n]=n,v
|
||||
return seq
|
||||
end,arg=arg,assert=assert,char=string.char,close=io.close,concat=concat,copy=copy,dirsep=dirsep,exit=os.exit,find=string.find,format=string.format,getenv=os.getenv,getmetatable=getmetatable,getmetamethod=getmetamethod,gmatch=string.gmatch,gsub=string.gsub,int=int,iscallable=iscallable,len=len,lines=io.lines,list=pack,loadstring=loadstring,match=string.match,maxn=function(iterable)local n=0
|
||||
for k,v in next,iterable or{}do
|
||||
local i=int(k)if i and i>n then
|
||||
n=i
|
||||
end
|
||||
end
|
||||
return n
|
||||
end,merge=function(r,...)local argu=pack(...)for i=1,argu.n do
|
||||
for k,v in next,argu[i]or{}do
|
||||
r[k]=r[k]or v
|
||||
end
|
||||
end
|
||||
return r
|
||||
end,next=next,open=io.open,pack=pack,pcall=pcall,pop=function(seq)local n,r=seq.n or len(seq)r,seq[n]=seq[n]if int(seq.n)and seq.n>0 then
|
||||
seq.n=seq.n-1
|
||||
end
|
||||
return r
|
||||
end,popen=io.popen,print=print,rawget=rawget,rawset=rawset,rep=string.rep,rm=os.remove,select=select,setmetatable=setmetatable,sort=sort,stderr=io.stderr,stdout=io.stdout,str=str,sub=string.sub,tmpname=os.tmpname,tonumber=tonumber,type=type,unpack=function(seq,i,j)return unpack(seq,int(i)or 1,int(j)or int(seq.n)or len(seq))end,write=io.write,},{__call=function(self,env,level)local userenv,level=copy(self),level or 1
|
||||
for name,value in next,env do
|
||||
if int(name)and type(value)=='string'then
|
||||
for k,v in next,(require(value))do
|
||||
userenv[k]=userenv[k]or v
|
||||
end
|
||||
else
|
||||
userenv[name]=value
|
||||
end
|
||||
end
|
||||
setfenv(level+1,userenv)return userenv
|
||||
end,})
|
||||
end
|
||||
package.preload['type.context-manager']=function()
|
||||
local _ENV=require'std.normalize'{'std.functional',}local contextmanager_mt={__index=function(self,key)if iscallable(self.context[key])then
|
||||
return function(_,...)return self.context[key](self.context,...)end
|
||||
end
|
||||
if key=='filename'then
|
||||
return self[1]end
|
||||
end,}local function ContextManager(release,acquire,...)local fh,err=acquire(...)if not fh then
|
||||
return nil,err
|
||||
end
|
||||
local cm={context=fh,release=release,n=select("#",...),...}if cm.context~=nil then
|
||||
setmetatable(cm,contextmanager_mt)end
|
||||
return cm
|
||||
end
|
||||
local function context_close(cm)return isfile(cm.context)and close(cm.context)end
|
||||
local function with(...)local argu=list(...)local block=pop(argu)local r=list(apply(block,argu))map(argu,function(cm)if cm~=nil then
|
||||
cm:release()end
|
||||
end)return unpack(r)end
|
||||
return{ContextManager=ContextManager,CTest=function()local conftest=tmpname()return ContextManager(function(cm)rm(conftest)rm(gsub(conftest,'^.*/','')..'.o')if context_close(cm)then
|
||||
return rm(cm.filename)end
|
||||
return false
|
||||
end,open,conftest..'.c','w')end,File=function(fname,mode)return ContextManager(context_close,open,fname,mode)end,Pipe=function(cmd,mode)return ContextManager(context_close,popen,cmd,mode)end,TmpFile=function(fname,mode)return ContextManager(function(cm)if context_close(cm)then
|
||||
return rm(cm.filename)end
|
||||
return false
|
||||
end,open,fname or tmpname(),mode or'w')end,slurp=function(cm,...)if not cm then
|
||||
return cm,...end
|
||||
return with(cm,function(h)return h:read'*a'end)end,with=with,}
|
||||
end
|
||||
package.preload['type.dict']=function()
|
||||
local _ENV=require'std.normalize'{destructure=next,}return{OrderedDict=function(...)local r,argu={},list(...)for i=1,argu.n do
|
||||
local k,v=destructure(argu[i])append(r,k)r[k]=v
|
||||
end
|
||||
return r
|
||||
end,}
|
||||
end
|
||||
package.preload['type.path']=function()
|
||||
local _ENV=require'std.normalize'{}local BASENAMEPAT='.*'..dirsep
|
||||
local DIRNAMEPAT=dirsep..'[^'..dirsep..']*$'return{basename=function(path)return(gsub(path,BASENAMEPAT,''))end,dirname=function(path)return(gsub(path,DIRNAMEPAT,'',1))end,exists=function(path)local fh=open(path)if fh==nil then
|
||||
return false
|
||||
end
|
||||
close(fh)return true
|
||||
end,}
|
||||
end
|
||||
os.exit(require'luke'.main(arg))
|
||||
97
doc/index.html
Normal file
97
doc/index.html
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>lyaml 6.2.8 Reference</title>
|
||||
<link rel="stylesheet" href="ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>lyaml 6.2.8</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="modules/lyaml.html">lyaml</a></li>
|
||||
<li><a href="modules/lyaml.explicit.html">lyaml.explicit</a></li>
|
||||
<li><a href="modules/lyaml.functional.html">lyaml.functional</a></li>
|
||||
<li><a href="modules/lyaml.implicit.html">lyaml.implicit</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
|
||||
<h2>
|
||||
<h1>LYAML binding for Lua</h1>
|
||||
|
||||
<p>This is a Lua binding for the fast libYAML C library for converting
|
||||
between <code>%YAML 1.1</code> and Lua tables, with a flexible Lua language
|
||||
API to load and save YAML documents.</p>
|
||||
|
||||
<p>It works with Lua 5.1 (including LuaJIT), 5.2, 5.3 and 5.4.</p>
|
||||
|
||||
<h2>LICENSE</h2>
|
||||
|
||||
<p>The code is copyright by its respective authors, and released under the
|
||||
MIT license (the same license as Lua itself). There is no warranty.</p>
|
||||
|
||||
</h2>
|
||||
|
||||
<h2>Modules</h2>
|
||||
<table class="module_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="modules/lyaml.html">lyaml</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="modules/lyaml.explicit.html">lyaml.explicit</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="modules/lyaml.functional.html">lyaml.functional</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="modules/lyaml.implicit.html">lyaml.implicit</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-10-22 17:12:03 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
||||
303
doc/ldoc.css
Normal file
303
doc/ldoc.css
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/* BEGIN RESET
|
||||
|
||||
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
|
||||
Code licensed under the BSD License:
|
||||
http://developer.yahoo.com/yui/license.html
|
||||
version: 2.8.2r1
|
||||
*/
|
||||
html {
|
||||
color: #000;
|
||||
background: #FFF;
|
||||
}
|
||||
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
fieldset,img {
|
||||
border: 0;
|
||||
}
|
||||
address,caption,cite,code,dfn,em,strong,th,var,optgroup {
|
||||
font-style: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
del,ins {
|
||||
text-decoration: none;
|
||||
}
|
||||
li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
caption,th {
|
||||
text-align: left;
|
||||
}
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
}
|
||||
q:before,q:after {
|
||||
content: '';
|
||||
}
|
||||
abbr,acronym {
|
||||
border: 0;
|
||||
font-variant: normal;
|
||||
}
|
||||
sup {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
sub {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
legend {
|
||||
color: #000;
|
||||
}
|
||||
input,button,textarea,select,optgroup,option {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-style: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
input,button,textarea,select {*font-size:100%;
|
||||
}
|
||||
/* END RESET */
|
||||
|
||||
body {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
font-family: arial, helvetica, geneva, sans-serif;
|
||||
background-color: #ffffff; margin: 0px;
|
||||
}
|
||||
|
||||
code, tt { font-family: monospace; font-size: 1.1em; }
|
||||
span.parameter { font-family:monospace; }
|
||||
span.parameter:after { content:":"; }
|
||||
span.types:before { content:"("; }
|
||||
span.types:after { content:")"; }
|
||||
.type { font-weight: bold; font-style:italic }
|
||||
|
||||
body, p, td, th { font-size: .95em; line-height: 1.2em;}
|
||||
|
||||
p, ul { margin: 10px 0 0 0px;}
|
||||
|
||||
strong { font-weight: bold;}
|
||||
|
||||
em { font-style: italic;}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
margin: 20px 0 20px 0;
|
||||
}
|
||||
h2, h3, h4 { margin: 15px 0 10px 0; }
|
||||
h2 { font-size: 1.25em; }
|
||||
h3 { font-size: 1.15em; }
|
||||
h4 { font-size: 1.06em; }
|
||||
|
||||
a:link { font-weight: bold; color: #004080; text-decoration: none; }
|
||||
a:visited { font-weight: bold; color: #006699; text-decoration: none; }
|
||||
a:link:hover { text-decoration: underline; }
|
||||
|
||||
hr {
|
||||
color:#cccccc;
|
||||
background: #00007f;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
blockquote { margin-left: 3em; }
|
||||
|
||||
ul { list-style-type: disc; }
|
||||
|
||||
p.name {
|
||||
font-family: "Andale Mono", monospace;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: rgb(245, 245, 245);
|
||||
border: 1px solid #C0C0C0; /* silver */
|
||||
padding: 10px;
|
||||
margin: 10px 0 10px 0;
|
||||
overflow: auto;
|
||||
font-family: "Andale Mono", monospace;
|
||||
}
|
||||
|
||||
pre.example {
|
||||
font-size: .85em;
|
||||
}
|
||||
|
||||
table.index { border: 1px #00007f; }
|
||||
table.index td { text-align: left; vertical-align: top; }
|
||||
|
||||
#container {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
#product {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#product big {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#main {
|
||||
background-color: #f0f0f0;
|
||||
border-left: 2px solid #cccccc;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
float: left;
|
||||
width: 14em;
|
||||
vertical-align: top;
|
||||
background-color: #f0f0f0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#navigation h2 {
|
||||
background-color:#e7e7e7;
|
||||
font-size:1.1em;
|
||||
color:#000000;
|
||||
text-align: left;
|
||||
padding:0.2em;
|
||||
border-top:1px solid #dddddd;
|
||||
border-bottom:1px solid #dddddd;
|
||||
}
|
||||
|
||||
#navigation ul
|
||||
{
|
||||
font-size:1em;
|
||||
list-style-type: none;
|
||||
margin: 1px 1px 10px 1px;
|
||||
}
|
||||
|
||||
#navigation li {
|
||||
text-indent: -1em;
|
||||
display: block;
|
||||
margin: 3px 0px 0px 22px;
|
||||
}
|
||||
|
||||
#navigation li li a {
|
||||
margin: 0px 3px 0px -1em;
|
||||
}
|
||||
|
||||
#content {
|
||||
margin-left: 14em;
|
||||
padding: 1em;
|
||||
width: 700px;
|
||||
border-left: 2px solid #cccccc;
|
||||
border-right: 2px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#about {
|
||||
clear: both;
|
||||
padding: 5px;
|
||||
border-top: 2px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
font: 12pt "Times New Roman", "TimeNR", Times, serif;
|
||||
}
|
||||
a { font-weight: bold; color: #004080; text-decoration: underline; }
|
||||
|
||||
#main {
|
||||
background-color: #ffffff;
|
||||
border-left: 0px;
|
||||
}
|
||||
|
||||
#container {
|
||||
margin-left: 2%;
|
||||
margin-right: 2%;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 1em;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
display: none;
|
||||
}
|
||||
pre.example {
|
||||
font-family: "Andale Mono", monospace;
|
||||
font-size: 10pt;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
}
|
||||
|
||||
table.module_list {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.module_list td {
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
table.module_list td.name { background-color: #f0f0f0; min-width: 200px; }
|
||||
table.module_list td.summary { width: 100%; }
|
||||
|
||||
|
||||
table.function_list {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.function_list td {
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
table.function_list td.name { background-color: #f0f0f0; min-width: 200px; }
|
||||
table.function_list td.summary { width: 100%; }
|
||||
|
||||
ul.nowrap {
|
||||
overflow:auto;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
|
||||
dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;}
|
||||
dl.table h3, dl.function h3 {font-size: .95em;}
|
||||
|
||||
/* stop sublists from having initial vertical space */
|
||||
ul ul { margin-top: 0px; }
|
||||
ol ul { margin-top: 0px; }
|
||||
ol ol { margin-top: 0px; }
|
||||
ul ol { margin-top: 0px; }
|
||||
|
||||
/* make the target distinct; helps when we're navigating to a function */
|
||||
a:target + * {
|
||||
background-color: #FF9;
|
||||
}
|
||||
|
||||
|
||||
/* styles for prettification of source */
|
||||
pre .comment { color: #558817; }
|
||||
pre .constant { color: #a8660d; }
|
||||
pre .escape { color: #844631; }
|
||||
pre .keyword { color: #aa5050; font-weight: bold; }
|
||||
pre .library { color: #0e7c6b; }
|
||||
pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
|
||||
pre .string { color: #8080ff; }
|
||||
pre .number { color: #f8660d; }
|
||||
pre .operator { color: #2239a8; font-weight: bold; }
|
||||
pre .preprocessor, pre .prepro { color: #a33243; }
|
||||
pre .global { color: #800080; }
|
||||
pre .user-keyword { color: #800080; }
|
||||
pre .prompt { color: #558817; }
|
||||
pre .url { color: #272fc2; text-decoration: underline; }
|
||||
|
||||
267
doc/modules/lyaml.explicit.html
Normal file
267
doc/modules/lyaml.explicit.html
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>lyaml 6.2.8 Reference</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>lyaml 6.2.8</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="../modules/lyaml.html">lyaml</a></li>
|
||||
<li><strong>lyaml.explicit</strong></li>
|
||||
<li><a href="../modules/lyaml.functional.html">lyaml.functional</a></li>
|
||||
<li><a href="../modules/lyaml.implicit.html">lyaml.implicit</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>lyaml.explicit</code></h1>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#bool">bool (value)</a></td>
|
||||
<td class="summary">Parse the value following an explicit <code>!!bool</code> tag.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#float">float (value)</a></td>
|
||||
<td class="summary">Parse the value following an explicit <code>!!float</code> tag.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#int">int (value)</a></td>
|
||||
<td class="summary">Parse the value following an explicit <code>!!int</code> tag.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#null">null ()</a></td>
|
||||
<td class="summary">Parse an explicit <code>!!null</code> tag.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#str">str (value)</a></td>
|
||||
<td class="summary">Parse the value following an explicit <code>!!str</code> tag.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "bool"></a>
|
||||
<strong>bool (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse the value following an explicit <code>!!bool</code> tag.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../modules/lyaml.explicit.html#bool">bool</a></span>
|
||||
boolean equivalent, if a valid value was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_bool = explicit.bool(tagarg)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "float"></a>
|
||||
<strong>float (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse the value following an explicit <code>!!float</code> tag.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">number</span></span>
|
||||
float equivalent, if a valid value was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_float = explicit.float(tagarg)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "int"></a>
|
||||
<strong>int (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse the value following an explicit <code>!!int</code> tag.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../modules/lyaml.explicit.html#int">int</a></span>
|
||||
integer equivalent, if a valid value was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_int = explicit.int(tagarg)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "null"></a>
|
||||
<strong>null ()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse an explicit <code>!!null</code> tag.
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">lyaml.null</span></span>
|
||||
|
||||
|
||||
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">null = explicit.null(tagarg)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "str"></a>
|
||||
<strong>str (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse the value following an explicit <code>!!str</code> tag.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
<em>value</em> which was a string already
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">tagarg = explicit.str(tagarg)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-10-22 17:12:03 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
||||
236
doc/modules/lyaml.functional.html
Normal file
236
doc/modules/lyaml.functional.html
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>lyaml 6.2.8 Reference</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>lyaml 6.2.8</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
<li><a href="#Tables">Tables</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="../modules/lyaml.html">lyaml</a></li>
|
||||
<li><a href="../modules/lyaml.explicit.html">lyaml.explicit</a></li>
|
||||
<li><strong>lyaml.functional</strong></li>
|
||||
<li><a href="../modules/lyaml.implicit.html">lyaml.implicit</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>lyaml.functional</code></h1>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#isnull">isnull (x)</a></td>
|
||||
<td class="summary"><code>lyaml.null</code> predicate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#iscallable">iscallable (x)</a></td>
|
||||
<td class="summary">Callable predicate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#anyof">anyof (fns)</a></td>
|
||||
<td class="summary">Compose a function to try each callable with supplied args.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#id">id (...)</a></td>
|
||||
<td class="summary">Return arguments unchanged.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a href="#Tables">Tables</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#NULL">NULL</a></td>
|
||||
<td class="summary"><code>lyaml.null</code> value.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "isnull"></a>
|
||||
<strong>isnull (x)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
<code>lyaml.null</code> predicate.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">x</span>
|
||||
operand
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
<code>true</code> if <em>x</em> is <code>lyaml.null</code>.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "iscallable"></a>
|
||||
<strong>iscallable (x)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Callable predicate.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">x</span>
|
||||
operand
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
<code>true</code> if <em>x</em> is a function has a __call metamethod
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">r = iscallable(x) <span class="keyword">and</span> x(...)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "anyof"></a>
|
||||
<strong>anyof (fns)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Compose a function to try each callable with supplied args.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">fns</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
|
||||
list of functions to try
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
|
||||
<p>a new function to call <em>...</em> functions, stopping</p>
|
||||
<pre><code>and returning the first non-nil result, if any
|
||||
</code></pre>
|
||||
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "id"></a>
|
||||
<strong>id (...)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Return arguments unchanged.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">...</span>
|
||||
arguments
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<em>...</em>
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "NULL"></a>
|
||||
<strong>NULL</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
<code>lyaml.null</code> value.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-10-22 17:12:03 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
||||
224
doc/modules/lyaml.html
Normal file
224
doc/modules/lyaml.html
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>lyaml 6.2.8 Reference</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>lyaml 6.2.8</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
<li><a href="#Tables">Tables</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<ul class="nowrap">
|
||||
<li><strong>lyaml</strong></li>
|
||||
<li><a href="../modules/lyaml.explicit.html">lyaml.explicit</a></li>
|
||||
<li><a href="../modules/lyaml.functional.html">lyaml.functional</a></li>
|
||||
<li><a href="../modules/lyaml.implicit.html">lyaml.implicit</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>lyaml</code></h1>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#dump">dump (documents[, opts])</a></td>
|
||||
<td class="summary">Dump a list of Lua tables to an equivalent YAML stream.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#load">load (s[, opts])</a></td>
|
||||
<td class="summary">Load a YAML stream into a Lua table.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a href="#Tables">Tables</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#dumper_opts">dumper_opts</a></td>
|
||||
<td class="summary">Dump options table.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#loader_opts">loader_opts</a></td>
|
||||
<td class="summary">Load options table.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "dump"></a>
|
||||
<strong>dump (documents[, opts])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Dump a list of Lua tables to an equivalent YAML stream.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">documents</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
|
||||
a sequence of Lua tables.
|
||||
</li>
|
||||
<li><span class="parameter">opts</span>
|
||||
<span class="types"><span class="type">dumper_opts</span></span>
|
||||
initialisation options
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
equivalest YAML stream
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "load"></a>
|
||||
<strong>load (s[, opts])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Load a YAML stream into a Lua table.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">s</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
YAML stream
|
||||
</li>
|
||||
<li><span class="parameter">opts</span>
|
||||
<span class="types"><span class="type">loader_opts</span></span>
|
||||
initialisation options
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
|
||||
Lua table equivalent of stream <em>s</em>
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "dumper_opts"></a>
|
||||
<strong>dumper_opts</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Dump options table.
|
||||
|
||||
|
||||
<h3>Fields:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">anchors</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
|
||||
map initial anchor names to values
|
||||
</li>
|
||||
<li><span class="parameter">implicit_scalar</span>
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
parse implicit scalar values
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "loader_opts"></a>
|
||||
<strong>loader_opts</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Load options table.
|
||||
|
||||
|
||||
<h3>Fields:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">all</span>
|
||||
<span class="types"><span class="type">boolean</span></span>
|
||||
load all documents from the stream
|
||||
</li>
|
||||
<li><span class="parameter">explicit_scalar</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
|
||||
map full tag-names to parser functions
|
||||
</li>
|
||||
<li><span class="parameter">implicit_scalar</span>
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
parse implicit scalar values
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-10-22 17:12:03 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
||||
533
doc/modules/lyaml.implicit.html
Normal file
533
doc/modules/lyaml.implicit.html
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>lyaml 6.2.8 Reference</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>lyaml 6.2.8</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<ul class="nowrap">
|
||||
<li><a href="../modules/lyaml.html">lyaml</a></li>
|
||||
<li><a href="../modules/lyaml.explicit.html">lyaml.explicit</a></li>
|
||||
<li><a href="../modules/lyaml.functional.html">lyaml.functional</a></li>
|
||||
<li><strong>lyaml.implicit</strong></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>lyaml.implicit</code></h1>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#null">null (value)</a></td>
|
||||
<td class="summary">Parse a null token to a null value.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#bool">bool (value)</a></td>
|
||||
<td class="summary">Parse a boolean token to the equivalent value.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#binary">binary (value)</a></td>
|
||||
<td class="summary">Parse a binary token, such as '0b1010_0111_0100_1010_1110'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#octal">octal (value)</a></td>
|
||||
<td class="summary">Parse an octal token, such as '012345'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#decimal">decimal (value)</a></td>
|
||||
<td class="summary">Parse a decimal token, such as '0' or '12345'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#hexadecimal">hexadecimal (value)</a></td>
|
||||
<td class="summary">Parse a hexadecimal token, such as '0xdeadbeef'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#sexagesimal">sexagesimal (value)</a></td>
|
||||
<td class="summary">Parse a sexagesimal token, such as '190:20:30'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#nan">nan (value)</a></td>
|
||||
<td class="summary">Parse a <code>nan</code> token.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#inf">inf (value)</a></td>
|
||||
<td class="summary">Parse a signed <code>inf</code> token.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#float">float (value)</a></td>
|
||||
<td class="summary">Parse a floating point number token, such as '1e-3' or '-0.12'.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#sexfloat">sexfloat (value)</a></td>
|
||||
<td class="summary">Parse a sexagesimal float, such as '190:20:30.15'.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "null"></a>
|
||||
<strong>null (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a null token to a null value.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
lyaml.null, for an empty string or literal ~
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
nil otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_null = implicit.null(token)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "bool"></a>
|
||||
<strong>bool (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a boolean token to the equivalent value.
|
||||
Treats capilalized, lower and upper-cased variants of true/false,
|
||||
yes/no or on/off tokens as boolean <code>true</code> and <code>false</code> values.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../modules/lyaml.implicit.html#bool">bool</a></span>
|
||||
if a valid boolean token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_bool = implicit.bool(token)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "binary"></a>
|
||||
<strong>binary (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a binary token, such as '0b1010_0111_0100_1010_1110'.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
integer equivalent, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_int = implicit.binary(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "octal"></a>
|
||||
<strong>octal (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse an octal token, such as '012345'.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
integer equivalent, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_int = implicit.octal(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "decimal"></a>
|
||||
<strong>decimal (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a decimal token, such as '0' or '12345'.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
integer equivalent, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_int = implicit.decimal(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "hexadecimal"></a>
|
||||
<strong>hexadecimal (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a hexadecimal token, such as '0xdeadbeef'.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
integer equivalent, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_int = implicit.hexadecimal(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "sexagesimal"></a>
|
||||
<strong>sexagesimal (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a sexagesimal token, such as '190:20:30'.
|
||||
Useful for times and angles.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
integer equivalent, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_int = implicit.sexagesimal(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "nan"></a>
|
||||
<strong>nan (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a <code>nan</code> token.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../modules/lyaml.implicit.html#nan">nan</a></span>
|
||||
not-a-number, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_nan = implicit.nan(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "inf"></a>
|
||||
<strong>inf (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a signed <code>inf</code> token.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">number</span></span>
|
||||
plus/minus-infinity, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_inf = implicit.inf(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "float"></a>
|
||||
<strong>float (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a floating point number token, such as '1e-3' or '-0.12'.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">number</span></span>
|
||||
float equivalent, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_float = implicit.float(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "sexfloat"></a>
|
||||
<strong>sexfloat (value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Parse a sexagesimal float, such as '190:20:30.15'.
|
||||
Useful for times and angles.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
token
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">number</span></span>
|
||||
float equivalent, if a valid token was recognized
|
||||
</ol>
|
||||
<h3>Or</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">nil</span></span>
|
||||
otherwise, nil
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">maybe_float = implicit.sexfloat(value)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-10-22 17:12:03 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
||||
459
ext/yaml/emitter.c
Normal file
459
ext/yaml/emitter.c
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* emitter.c, LibYAML emitter binding for Lua
|
||||
* Written by Gary V. Vaughan, 2013
|
||||
*
|
||||
* Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "lyaml.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
yaml_emitter_t emitter;
|
||||
|
||||
/* output accumulator */
|
||||
lua_State *outputL;
|
||||
luaL_Buffer yamlbuff;
|
||||
|
||||
/* error handling */
|
||||
lua_State *errL;
|
||||
luaL_Buffer errbuff;
|
||||
int error;
|
||||
} lyaml_emitter;
|
||||
|
||||
|
||||
/* Emit a STREAM_START event. */
|
||||
static int
|
||||
emit_STREAM_START (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_encoding_t yaml_encoding;
|
||||
const char *encoding = NULL;
|
||||
|
||||
RAWGET_STRDUP (encoding); lua_pop (L, 1);
|
||||
|
||||
#define MENTRY(_s) (STREQ (encoding, #_s)) { yaml_encoding = YAML_##_s##_ENCODING; }
|
||||
if (encoding == NULL) { yaml_encoding = YAML_ANY_ENCODING; } else
|
||||
if MENTRY( UTF8 ) else
|
||||
if MENTRY( UTF16LE ) else
|
||||
if MENTRY( UTF16BE ) else
|
||||
{
|
||||
emitter->error++;
|
||||
luaL_addsize (&emitter->errbuff,
|
||||
sprintf (luaL_prepbuffer (&emitter->errbuff),
|
||||
"invalid stream encoding '%s'", encoding));
|
||||
}
|
||||
#undef MENTRY
|
||||
|
||||
if (encoding) free ((void *) encoding);
|
||||
|
||||
if (emitter->error != 0)
|
||||
return 0;
|
||||
|
||||
yaml_stream_start_event_initialize (&event, yaml_encoding);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a STREAM_END event. */
|
||||
static int
|
||||
emit_STREAM_END (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_stream_end_event_initialize (&event);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a DOCUMENT_START event. */
|
||||
static int
|
||||
emit_DOCUMENT_START (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_version_directive_t version_directive, *Pversion_directive = NULL;
|
||||
yaml_tag_directive_t *tag_directives_start = NULL, *tag_directives_end = NULL;
|
||||
int implicit = 0;
|
||||
|
||||
RAWGET_PUSHTABLE ("version_directive");
|
||||
if (lua_type (L, -1) == LUA_TTABLE)
|
||||
{
|
||||
RAWGETS_INTEGER (version_directive.major, "major");
|
||||
ERROR_IFNIL ("version_directive missing key 'major'");
|
||||
if (emitter->error == 0)
|
||||
{
|
||||
RAWGETS_INTEGER (version_directive.minor, "minor");
|
||||
ERROR_IFNIL ("version_directive missing key 'minor'");
|
||||
}
|
||||
Pversion_directive = &version_directive;
|
||||
}
|
||||
lua_pop (L, 1); /* pop version_directive rawget */
|
||||
|
||||
RAWGET_PUSHTABLE ("tag_directives");
|
||||
if (lua_type (L, -1) == LUA_TTABLE)
|
||||
{
|
||||
size_t bytes = lua_objlen (L, -1) * sizeof (yaml_tag_directive_t);
|
||||
|
||||
tag_directives_start = (yaml_tag_directive_t *) malloc (bytes);
|
||||
tag_directives_end = tag_directives_start;
|
||||
|
||||
lua_pushnil (L); /* first key */
|
||||
while (lua_next (L, -2) != 0)
|
||||
{
|
||||
RAWGETS_STRDUP (tag_directives_end->handle, "handle");
|
||||
ERROR_IFNIL ("tag_directives item missing key 'handle'");
|
||||
lua_pop (L, 1); /* pop handle */
|
||||
|
||||
RAWGETS_STRDUP (tag_directives_end->prefix, "prefix");
|
||||
ERROR_IFNIL ("tag_directives item missing key 'prefix'");
|
||||
lua_pop (L, 1); /* pop prefix */
|
||||
|
||||
tag_directives_end += 1;
|
||||
|
||||
/* pop tag_directives list elewent, leave key for next iteration */
|
||||
lua_pop (L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop (L, 1); /* pop lua_rawget "tag_directives" result */
|
||||
|
||||
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
|
||||
|
||||
if (emitter->error != 0)
|
||||
return 0;
|
||||
|
||||
yaml_document_start_event_initialize (&event, Pversion_directive,
|
||||
tag_directives_start, tag_directives_end, implicit);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a DOCUMENT_END event. */
|
||||
static int
|
||||
emit_DOCUMENT_END (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
int implicit = 0;
|
||||
|
||||
RAWGET_BOOLEAN (implicit);
|
||||
|
||||
yaml_document_end_event_initialize (&event, implicit);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a MAPPING_START event. */
|
||||
static int
|
||||
emit_MAPPING_START (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mapping_style_t yaml_style;
|
||||
yaml_char_t *anchor = NULL, *tag = NULL;
|
||||
int implicit = 1;
|
||||
const char *style = NULL;
|
||||
|
||||
RAWGET_STRDUP (style); lua_pop (L, 1);
|
||||
|
||||
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_MAPPING_STYLE; }
|
||||
if (style == NULL) { yaml_style = YAML_ANY_MAPPING_STYLE; } else
|
||||
if MENTRY( BLOCK ) else
|
||||
if MENTRY( FLOW ) else
|
||||
{
|
||||
emitter->error++;
|
||||
luaL_addsize (&emitter->errbuff,
|
||||
sprintf (luaL_prepbuffer (&emitter->errbuff),
|
||||
"invalid mapping style '%s'", style));
|
||||
}
|
||||
#undef MENTRY
|
||||
|
||||
if (style) free ((void *) style);
|
||||
|
||||
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
|
||||
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
|
||||
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
|
||||
|
||||
yaml_mapping_start_event_initialize (&event, anchor, tag, implicit, yaml_style);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a MAPPING_END event. */
|
||||
static int
|
||||
emit_MAPPING_END (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_mapping_end_event_initialize (&event);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a SEQUENCE_START event. */
|
||||
static int
|
||||
emit_SEQUENCE_START (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_sequence_style_t yaml_style;
|
||||
yaml_char_t *anchor = NULL, *tag = NULL;
|
||||
int implicit = 1;
|
||||
const char *style = NULL;
|
||||
|
||||
RAWGET_STRDUP (style); lua_pop (L, 1);
|
||||
|
||||
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_SEQUENCE_STYLE; }
|
||||
if (style == NULL) { yaml_style = YAML_ANY_SEQUENCE_STYLE; } else
|
||||
if MENTRY( BLOCK ) else
|
||||
if MENTRY( FLOW ) else
|
||||
{
|
||||
emitter->error++;
|
||||
luaL_addsize (&emitter->errbuff,
|
||||
sprintf (luaL_prepbuffer (&emitter->errbuff),
|
||||
"invalid sequence style '%s'", style));
|
||||
}
|
||||
#undef MENTRY
|
||||
|
||||
if (style) free ((void *) style);
|
||||
|
||||
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
|
||||
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
|
||||
RAWGET_BOOLEAN (implicit); lua_pop (L, 1);
|
||||
|
||||
yaml_sequence_start_event_initialize (&event, anchor, tag, implicit, yaml_style);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a SEQUENCE_END event. */
|
||||
static int
|
||||
emit_SEQUENCE_END (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_sequence_end_event_initialize (&event);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit a SCALAR event. */
|
||||
static int
|
||||
emit_SCALAR (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_scalar_style_t yaml_style;
|
||||
yaml_char_t *anchor = NULL, *tag = NULL, *value;
|
||||
int length = 0, plain_implicit = 1, quoted_implicit = 1;
|
||||
const char *style = NULL;
|
||||
|
||||
RAWGET_STRDUP (style); lua_pop (L, 1);
|
||||
|
||||
#define MENTRY(_s) (STREQ (style, #_s)) { yaml_style = YAML_##_s##_SCALAR_STYLE; }
|
||||
if (style == NULL) { yaml_style = YAML_ANY_SCALAR_STYLE; } else
|
||||
if MENTRY( PLAIN ) else
|
||||
if MENTRY( SINGLE_QUOTED ) else
|
||||
if MENTRY( DOUBLE_QUOTED ) else
|
||||
if MENTRY( LITERAL ) else
|
||||
if MENTRY( FOLDED ) else
|
||||
{
|
||||
emitter->error++;
|
||||
luaL_addsize (&emitter->errbuff,
|
||||
sprintf (luaL_prepbuffer (&emitter->errbuff),
|
||||
"invalid scalar style '%s'", style));
|
||||
}
|
||||
#undef MENTRY
|
||||
|
||||
if (style) free ((void *) style);
|
||||
|
||||
RAWGET_YAML_CHARP (anchor); lua_pop (L, 1);
|
||||
RAWGET_YAML_CHARP (tag); lua_pop (L, 1);
|
||||
RAWGET_YAML_CHARP (value); length = lua_objlen (L, -1); lua_pop (L, 1);
|
||||
RAWGET_BOOLEAN (plain_implicit);
|
||||
RAWGET_BOOLEAN (quoted_implicit);
|
||||
|
||||
yaml_scalar_event_initialize (&event, anchor, tag, value, length,
|
||||
plain_implicit, quoted_implicit, yaml_style);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
/* Emit an ALIAS event. */
|
||||
static int
|
||||
emit_ALIAS (lua_State *L, lyaml_emitter *emitter)
|
||||
{
|
||||
yaml_event_t event;
|
||||
yaml_char_t *anchor;
|
||||
|
||||
RAWGET_YAML_CHARP (anchor);
|
||||
|
||||
yaml_alias_event_initialize (&event, anchor);
|
||||
return yaml_emitter_emit (&emitter->emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
emit (lua_State *L)
|
||||
{
|
||||
lyaml_emitter *emitter;
|
||||
int yaml_ok = 0;
|
||||
int finalize = 0;
|
||||
|
||||
luaL_argcheck (L, lua_istable (L, 1), 1, "expected table");
|
||||
|
||||
emitter = (lyaml_emitter *) lua_touserdata (L, lua_upvalueindex (1));
|
||||
|
||||
{
|
||||
const char *type;
|
||||
|
||||
RAWGET_STRDUP (type); lua_pop (L, 1);
|
||||
|
||||
if (type == NULL)
|
||||
{
|
||||
emitter->error++;
|
||||
luaL_addstring (&emitter->errbuff, "no type field in event table");
|
||||
}
|
||||
#define MENTRY(_s) (STREQ (type, #_s)) { yaml_ok = emit_##_s (L, emitter); }
|
||||
/* Minimize comparisons by putting more common types earlier. */
|
||||
else if MENTRY( SCALAR )
|
||||
else if MENTRY( MAPPING_START )
|
||||
else if MENTRY( MAPPING_END )
|
||||
else if MENTRY( SEQUENCE_START )
|
||||
else if MENTRY( SEQUENCE_END )
|
||||
else if MENTRY( DOCUMENT_START )
|
||||
else if MENTRY( DOCUMENT_END )
|
||||
else if MENTRY( STREAM_START )
|
||||
else if MENTRY( STREAM_END )
|
||||
else if MENTRY( ALIAS )
|
||||
#undef MENTRY
|
||||
else
|
||||
{
|
||||
emitter->error++;
|
||||
luaL_addsize (&emitter->errbuff,
|
||||
sprintf (luaL_prepbuffer (&emitter->errbuff),
|
||||
"invalid event type '%s'", type));
|
||||
}
|
||||
|
||||
/* If the stream has finished, finalize the YAML output. */
|
||||
if (type && STREQ (type, "STREAM_END"))
|
||||
finalize = 1;
|
||||
|
||||
if (type) free ((void *) type);
|
||||
}
|
||||
|
||||
/* Copy any yaml_emitter_t errors into the error buffer. */
|
||||
if (!emitter->error && !yaml_ok)
|
||||
{
|
||||
if (emitter->emitter.problem)
|
||||
luaL_addstring (&emitter->errbuff, emitter->emitter.problem);
|
||||
else
|
||||
luaL_addstring (&emitter->errbuff, "LibYAML call failed");
|
||||
emitter->error++;
|
||||
}
|
||||
|
||||
/* Report errors back to the caller as `false, "error message"`. */
|
||||
if (emitter->error != 0)
|
||||
{
|
||||
assert (emitter->error == 1); /* bail on uncaught additional errors */
|
||||
lua_pushboolean (L, 0);
|
||||
luaL_pushresult (&emitter->errbuff);
|
||||
lua_xmove (emitter->errL, L, 1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Return `true, "YAML string"` after accepting a STREAM_END event. */
|
||||
if (finalize)
|
||||
{
|
||||
lua_pushboolean (L, 1);
|
||||
luaL_pushresult (&emitter->yamlbuff);
|
||||
lua_xmove (emitter->outputL, L, 1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Otherwise, just report success to the caller as `true`. */
|
||||
lua_pushboolean (L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
append_output (void *arg, unsigned char *buff, size_t len)
|
||||
{
|
||||
lyaml_emitter *emitter = (lyaml_emitter *) arg;
|
||||
luaL_addlstring (&emitter->yamlbuff, (char *) buff, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
emitter_gc (lua_State *L)
|
||||
{
|
||||
lyaml_emitter *emitter = (lyaml_emitter *) lua_touserdata (L, 1);
|
||||
|
||||
if (emitter)
|
||||
yaml_emitter_delete (&emitter->emitter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Pemitter (lua_State *L)
|
||||
{
|
||||
lyaml_emitter *emitter;
|
||||
|
||||
lua_newtable (L); /* object table */
|
||||
|
||||
/* Create a user datum to store the emitter. */
|
||||
emitter = (lyaml_emitter *) lua_newuserdata (L, sizeof (*emitter));
|
||||
emitter->error = 0;
|
||||
|
||||
/* Initialize the emitter. */
|
||||
if (!yaml_emitter_initialize (&emitter->emitter))
|
||||
{
|
||||
if (!emitter->emitter.problem)
|
||||
emitter->emitter.problem = "cannot initialize emitter";
|
||||
return luaL_error (L, "%s", emitter->emitter.problem);
|
||||
}
|
||||
yaml_emitter_set_unicode (&emitter->emitter, 1);
|
||||
yaml_emitter_set_width (&emitter->emitter, 2);
|
||||
yaml_emitter_set_output (&emitter->emitter, &append_output, emitter);
|
||||
|
||||
/* Set it's metatable, and ensure it is garbage collected properly. */
|
||||
luaL_newmetatable (L, "lyaml.emitter");
|
||||
lua_pushcfunction (L, emitter_gc);
|
||||
lua_setfield (L, -2, "__gc");
|
||||
lua_setmetatable (L, -2);
|
||||
|
||||
/* Set the emit method of object as a closure over the user datum, and
|
||||
return the whole object. */
|
||||
lua_pushcclosure (L, emit, 1);
|
||||
lua_setfield (L, -2, "emit");
|
||||
|
||||
/* Set up a separate thread to collect error messages; save the thread
|
||||
in the returned table so that it's not garbage collected when the
|
||||
function call stack for Pemitter is cleaned up. */
|
||||
emitter->errL = lua_newthread (L);
|
||||
luaL_buffinit (emitter->errL, &emitter->errbuff);
|
||||
lua_setfield (L, -2, "errthread");
|
||||
|
||||
/* Create a thread for the YAML buffer. */
|
||||
emitter->outputL = lua_newthread (L);
|
||||
luaL_buffinit (emitter->outputL, &emitter->yamlbuff);
|
||||
lua_setfield (L, -2, "outputthread");
|
||||
|
||||
return 1;
|
||||
}
|
||||
161
ext/yaml/lyaml.h
Normal file
161
ext/yaml/lyaml.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* lyaml.h, libyaml parser binding for Lua
|
||||
* Written by Gary V. Vaughan, 2013
|
||||
*
|
||||
* Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef LYAML_H
|
||||
#define LYAML_H 1
|
||||
|
||||
#include <yaml.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "lyaml.h"
|
||||
|
||||
#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 504
|
||||
# define lua_objlen lua_rawlen
|
||||
# define lua_strlen lua_rawlen
|
||||
# define luaL_openlib(L,n,l,nup) luaL_setfuncs((L),(l),(nup))
|
||||
# define luaL_register(L,n,l) (luaL_newlib(L,l))
|
||||
#endif
|
||||
|
||||
#ifndef STREQ
|
||||
#define STREQ !strcmp
|
||||
#endif
|
||||
#ifndef STRNEQ
|
||||
#define STRNEQ strcmp
|
||||
#endif
|
||||
|
||||
/* NOTE: Make sure L is in scope before using these macros.
|
||||
lua_pushyamlstr casts away the impedance mismatch between Lua's
|
||||
signed char APIs and libYAML's unsigned char APIs. */
|
||||
|
||||
#define lua_pushyamlstr(_s) lua_pushstring (L, (char *)(_s))
|
||||
|
||||
#define RAWSET_BOOLEAN(_k, _v) \
|
||||
lua_pushyamlstr (_k); \
|
||||
lua_pushboolean (L, (_v) != 0); \
|
||||
lua_rawset (L, -3)
|
||||
|
||||
#define RAWSET_INTEGER(_k, _v) \
|
||||
lua_pushyamlstr (_k); \
|
||||
lua_pushinteger (L, (_v)); \
|
||||
lua_rawset (L, -3)
|
||||
|
||||
#define RAWSET_STRING(_k, _v) \
|
||||
lua_pushyamlstr (_k); \
|
||||
lua_pushyamlstr (_v); \
|
||||
lua_rawset (L, -3)
|
||||
|
||||
#define RAWSET_EVENTF(_k) \
|
||||
lua_pushstring (L, #_k); \
|
||||
lua_pushyamlstr (EVENTF(_k)); \
|
||||
lua_rawset (L, -3)
|
||||
|
||||
|
||||
/* NOTE: Make sure L is in scope before using these macros.
|
||||
The table value at _k is not popped from the stack for strings
|
||||
or tables, so that we can check for an empty table entry with
|
||||
lua_isnil (L, -1), or get the length of a string with
|
||||
lua_objlen (L, -1) before popping. */
|
||||
|
||||
#define RAWGET_BOOLEAN(_k) \
|
||||
lua_pushstring (L, #_k); \
|
||||
lua_rawget (L, -2); \
|
||||
if (!lua_isnil (L, -1)) { \
|
||||
_k = lua_toboolean (L, -1); \
|
||||
} \
|
||||
lua_pop (L, 1)
|
||||
|
||||
#define RAWGET_INTEGER(_k) \
|
||||
lua_pushstring (L, #_k); \
|
||||
lua_rawget (L, -2); \
|
||||
if (!lua_isnil (L, -1)) { \
|
||||
_k = lua_tointeger (L, -1); \
|
||||
} \
|
||||
lua_pop (L, 1)
|
||||
|
||||
#define RAWGET_STRING(_k) \
|
||||
lua_pushstring (L, #_k); \
|
||||
lua_rawget (L, -2); \
|
||||
if (!lua_isnil (L, -1)) { \
|
||||
_k = lua_tostring (L, -1); \
|
||||
} else { _k = NULL; }
|
||||
|
||||
#define RAWGET_STRDUP(_k) \
|
||||
lua_pushstring (L, #_k); \
|
||||
lua_rawget (L, -2); \
|
||||
if (!lua_isnil (L, -1)) { \
|
||||
_k = strdup (lua_tostring (L, -1)); \
|
||||
} else { _k = NULL; }
|
||||
|
||||
#define RAWGET_YAML_CHARP(_k) \
|
||||
lua_pushstring (L, #_k); \
|
||||
lua_rawget (L, -2); \
|
||||
if (!lua_isnil (L, -1)) { \
|
||||
_k = (yaml_char_t *) lua_tostring (L, -1); \
|
||||
} else { _k = NULL; }
|
||||
|
||||
#define RAWGETS_INTEGER(_v, _s) \
|
||||
lua_pushstring (L, _s); \
|
||||
lua_rawget (L, -2); \
|
||||
if (!lua_isnil (L, -1)) { \
|
||||
_v = lua_tointeger (L, -1); \
|
||||
} \
|
||||
lua_pop (L, 1)
|
||||
|
||||
#define RAWGETS_STRDUP( _v, _s) \
|
||||
lua_pushstring (L, _s); \
|
||||
lua_rawget (L, -2); \
|
||||
if (!lua_isnil (L, -1)) { \
|
||||
_v = (yaml_char_t *) strdup (lua_tostring (L, -1)); \
|
||||
} else { _v = NULL; }
|
||||
|
||||
#define RAWGET_PUSHTABLE(_k) \
|
||||
lua_pushstring (L, _k); \
|
||||
lua_rawget (L, -2); \
|
||||
if ((lua_type (L, -1) != LUA_TTABLE) && !lua_isnil (L, -1)) { \
|
||||
lua_pop (L, 1); \
|
||||
return luaL_error (L, "%s must be a table", _k); \
|
||||
}
|
||||
|
||||
#define ERROR_IFNIL(_err) \
|
||||
if (lua_isnil (L, -1)) { \
|
||||
emitter->error++; \
|
||||
luaL_addstring (&emitter->errbuff, _err); \
|
||||
}
|
||||
|
||||
|
||||
/* from emitter.c */
|
||||
extern int Pemitter (lua_State *L);
|
||||
|
||||
/* from parser.c */
|
||||
extern void parser_init (lua_State *L);
|
||||
extern int Pparser (lua_State *L);
|
||||
|
||||
/* from scanner.c */
|
||||
extern void scanner_init (lua_State *L);
|
||||
extern int Pscanner (lua_State *L);
|
||||
|
||||
#endif
|
||||
410
ext/yaml/parser.c
Normal file
410
ext/yaml/parser.c
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
* parser.c, libyaml parser binding for Lua
|
||||
* Written by Gary V. Vaughan, 2013
|
||||
*
|
||||
* Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "lyaml.h"
|
||||
|
||||
typedef struct {
|
||||
lua_State *L;
|
||||
yaml_parser_t parser;
|
||||
yaml_event_t event;
|
||||
char validevent;
|
||||
int document_count;
|
||||
} lyaml_parser;
|
||||
|
||||
|
||||
static void
|
||||
parser_delete_event (lyaml_parser *parser)
|
||||
{
|
||||
if (parser->validevent)
|
||||
{
|
||||
yaml_event_delete (&parser->event);
|
||||
parser->validevent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* With the event result table on the top of the stack, insert
|
||||
a mark entry. */
|
||||
static void
|
||||
parser_set_mark (lua_State *L, const char *k, yaml_mark_t mark)
|
||||
{
|
||||
lua_pushstring (L, k);
|
||||
lua_createtable (L, 0, 3);
|
||||
#define MENTRY(_s) RAWSET_INTEGER(#_s, mark._s)
|
||||
MENTRY( index );
|
||||
MENTRY( line );
|
||||
MENTRY( column );
|
||||
#undef MENTRY
|
||||
lua_rawset (L, -3);
|
||||
}
|
||||
|
||||
/* Push a new event table, pre-populated with shared elements. */
|
||||
static void
|
||||
parser_push_eventtable (lyaml_parser *parser, const char *v, int n)
|
||||
{
|
||||
lua_State *L = parser->L;
|
||||
|
||||
lua_createtable (L, 0, n + 3);
|
||||
RAWSET_STRING ("type", v);
|
||||
#define MENTRY(_s) parser_set_mark (L, #_s, parser->event._s)
|
||||
MENTRY( start_mark );
|
||||
MENTRY( end_mark );
|
||||
#undef MENTRY
|
||||
}
|
||||
|
||||
static void
|
||||
parse_STREAM_START (lyaml_parser *parser)
|
||||
{
|
||||
#define EVENTF(_f) (parser->event.data.stream_start._f)
|
||||
lua_State *L = parser->L;
|
||||
const char *encoding;
|
||||
|
||||
switch (EVENTF (encoding))
|
||||
{
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_ENCODING: encoding = #_s; break
|
||||
|
||||
MENTRY( ANY );
|
||||
MENTRY( UTF8 );
|
||||
MENTRY( UTF16LE );
|
||||
MENTRY( UTF16BE );
|
||||
#undef MENTRY
|
||||
|
||||
default:
|
||||
lua_pushfstring (L, "invalid encoding %d", EVENTF (encoding));
|
||||
lua_error (L);
|
||||
}
|
||||
|
||||
parser_push_eventtable (parser, "STREAM_START", 1);
|
||||
RAWSET_STRING ("encoding", encoding);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
/* With the tag list on the top of the stack, append TAG. */
|
||||
static void
|
||||
parser_append_tag (lua_State *L, yaml_tag_directive_t tag)
|
||||
{
|
||||
lua_createtable (L, 0, 2);
|
||||
#define MENTRY(_s) RAWSET_STRING(#_s, tag._s)
|
||||
MENTRY( handle );
|
||||
MENTRY( prefix );
|
||||
#undef MENTRY
|
||||
lua_rawseti (L, -2, lua_objlen (L, -2) + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_DOCUMENT_START (lyaml_parser *parser)
|
||||
{
|
||||
#define EVENTF(_f) (parser->event.data.document_start._f)
|
||||
lua_State *L = parser->L;
|
||||
|
||||
/* increment document count */
|
||||
parser->document_count++;
|
||||
|
||||
parser_push_eventtable (parser, "DOCUMENT_START", 1);
|
||||
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
|
||||
|
||||
/* version_directive = { major = M, minor = N } */
|
||||
if (EVENTF (version_directive))
|
||||
{
|
||||
lua_pushliteral (L, "version_directive");
|
||||
lua_createtable (L, 0, 2);
|
||||
#define MENTRY(_s) RAWSET_INTEGER(#_s, EVENTF (version_directive->_s))
|
||||
MENTRY( major );
|
||||
MENTRY( minor );
|
||||
#undef MENTRY
|
||||
lua_rawset (L, -3);
|
||||
}
|
||||
|
||||
/* tag_directives = { {handle = H1, prefix = P1}, ... } */
|
||||
if (EVENTF (tag_directives.start) &&
|
||||
EVENTF (tag_directives.end)) {
|
||||
yaml_tag_directive_t *cur;
|
||||
|
||||
lua_pushliteral (L, "tag_directives");
|
||||
lua_newtable (L);
|
||||
for (cur = EVENTF (tag_directives.start);
|
||||
cur != EVENTF (tag_directives.end);
|
||||
cur = cur + 1)
|
||||
{
|
||||
parser_append_tag (L, *cur);
|
||||
}
|
||||
lua_rawset (L, -3);
|
||||
}
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
parse_DOCUMENT_END (lyaml_parser *parser)
|
||||
{
|
||||
#define EVENTF(_f) (parser->event.data.document_end._f)
|
||||
lua_State *L = parser->L;
|
||||
|
||||
parser_push_eventtable (parser, "DOCUMENT_END", 1);
|
||||
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
parse_ALIAS (lyaml_parser *parser)
|
||||
{
|
||||
#define EVENTF(_f) (parser->event.data.alias._f)
|
||||
lua_State *L = parser->L;
|
||||
|
||||
parser_push_eventtable (parser, "ALIAS", 1);
|
||||
RAWSET_EVENTF (anchor);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
parse_SCALAR (lyaml_parser *parser)
|
||||
{
|
||||
#define EVENTF(_f) (parser->event.data.scalar._f)
|
||||
lua_State *L = parser->L;
|
||||
const char *style;
|
||||
|
||||
switch (EVENTF (style))
|
||||
{
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_SCALAR_STYLE: style = #_s; break
|
||||
|
||||
MENTRY( ANY );
|
||||
MENTRY( PLAIN );
|
||||
MENTRY( SINGLE_QUOTED );
|
||||
MENTRY( DOUBLE_QUOTED );
|
||||
MENTRY( LITERAL );
|
||||
MENTRY( FOLDED );
|
||||
#undef MENTRY
|
||||
|
||||
default:
|
||||
lua_pushfstring (L, "invalid sequence style %d", EVENTF (style));
|
||||
lua_error (L);
|
||||
}
|
||||
|
||||
|
||||
parser_push_eventtable (parser, "SCALAR", 6);
|
||||
RAWSET_EVENTF (anchor);
|
||||
RAWSET_EVENTF (tag);
|
||||
RAWSET_EVENTF (value);
|
||||
|
||||
RAWSET_BOOLEAN ("plain_implicit", EVENTF (plain_implicit));
|
||||
RAWSET_BOOLEAN ("quoted_implicit", EVENTF (quoted_implicit));
|
||||
RAWSET_STRING ("style", style);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
parse_SEQUENCE_START (lyaml_parser *parser)
|
||||
{
|
||||
#define EVENTF(_f) (parser->event.data.sequence_start._f)
|
||||
lua_State *L = parser->L;
|
||||
const char *style;
|
||||
|
||||
switch (EVENTF (style))
|
||||
{
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_SEQUENCE_STYLE: style = #_s; break
|
||||
|
||||
MENTRY( ANY );
|
||||
MENTRY( BLOCK );
|
||||
MENTRY( FLOW );
|
||||
#undef MENTRY
|
||||
|
||||
default:
|
||||
lua_pushfstring (L, "invalid sequence style %d", EVENTF (style));
|
||||
lua_error (L);
|
||||
}
|
||||
|
||||
parser_push_eventtable (parser, "SEQUENCE_START", 4);
|
||||
RAWSET_EVENTF (anchor);
|
||||
RAWSET_EVENTF (tag);
|
||||
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
|
||||
RAWSET_STRING ("style", style);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
parse_MAPPING_START (lyaml_parser *parser)
|
||||
{
|
||||
#define EVENTF(_f) (parser->event.data.mapping_start._f)
|
||||
lua_State *L = parser->L;
|
||||
const char *style;
|
||||
|
||||
switch (EVENTF (style))
|
||||
{
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_MAPPING_STYLE: style = #_s; break
|
||||
|
||||
MENTRY( ANY );
|
||||
MENTRY( BLOCK );
|
||||
MENTRY( FLOW );
|
||||
#undef MENTRY
|
||||
|
||||
default:
|
||||
lua_pushfstring (L, "invalid mapping style %d", EVENTF (style));
|
||||
lua_error (L);
|
||||
}
|
||||
|
||||
parser_push_eventtable (parser, "MAPPING_START", 4);
|
||||
RAWSET_EVENTF (anchor);
|
||||
RAWSET_EVENTF (tag);
|
||||
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
|
||||
RAWSET_STRING ("style", style);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
parser_generate_error_message (lyaml_parser *parser)
|
||||
{
|
||||
yaml_parser_t *P = &parser->parser;
|
||||
char buf[256];
|
||||
luaL_Buffer b;
|
||||
|
||||
luaL_buffinit (parser->L, &b);
|
||||
luaL_addstring (&b, P->problem ? P->problem : "A problem");
|
||||
snprintf (buf, sizeof (buf), " at document: %d", parser->document_count);
|
||||
luaL_addstring (&b, buf);
|
||||
|
||||
if (P->problem_mark.line || P->problem_mark.column)
|
||||
{
|
||||
snprintf (buf, sizeof (buf), ", line: %lu, column: %lu",
|
||||
(unsigned long) P->problem_mark.line + 1,
|
||||
(unsigned long) P->problem_mark.column + 1);
|
||||
luaL_addstring (&b, buf);
|
||||
}
|
||||
luaL_addstring (&b, "\n");
|
||||
|
||||
if (P->context)
|
||||
{
|
||||
snprintf (buf, sizeof (buf), "%s at line: %lu, column: %lu\n",
|
||||
P->context,
|
||||
(unsigned long) P->context_mark.line + 1,
|
||||
(unsigned long) P->context_mark.column + 1);
|
||||
luaL_addstring (&b, buf);
|
||||
}
|
||||
|
||||
luaL_pushresult (&b);
|
||||
}
|
||||
|
||||
static int
|
||||
event_iter (lua_State *L)
|
||||
{
|
||||
lyaml_parser *parser = (lyaml_parser *)lua_touserdata(L, lua_upvalueindex(1));
|
||||
char *str;
|
||||
|
||||
parser_delete_event (parser);
|
||||
if (yaml_parser_parse (&parser->parser, &parser->event) != 1)
|
||||
{
|
||||
parser_generate_error_message (parser);
|
||||
return lua_error (L);
|
||||
}
|
||||
|
||||
parser->validevent = 1;
|
||||
|
||||
lua_newtable (L);
|
||||
lua_pushliteral (L, "type");
|
||||
|
||||
switch (parser->event.type)
|
||||
{
|
||||
/* First the simple events, generated right here... */
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_EVENT: parser_push_eventtable (parser, #_s, 0); break
|
||||
MENTRY( STREAM_END );
|
||||
MENTRY( SEQUENCE_END );
|
||||
MENTRY( MAPPING_END );
|
||||
#undef MENTRY
|
||||
|
||||
/* ...then the complex events, generated by a function call. */
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_EVENT: parse_##_s (parser); break
|
||||
MENTRY( STREAM_START );
|
||||
MENTRY( DOCUMENT_START );
|
||||
MENTRY( DOCUMENT_END );
|
||||
MENTRY( ALIAS );
|
||||
MENTRY( SCALAR );
|
||||
MENTRY( SEQUENCE_START );
|
||||
MENTRY( MAPPING_START );
|
||||
#undef MENTRY
|
||||
|
||||
case YAML_NO_EVENT:
|
||||
lua_pushnil (L);
|
||||
break;
|
||||
default:
|
||||
lua_pushfstring (L, "invalid event %d", parser->event.type);
|
||||
return lua_error (L);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
parser_gc (lua_State *L)
|
||||
{
|
||||
lyaml_parser *parser = (lyaml_parser *) lua_touserdata (L, 1);
|
||||
|
||||
if (parser)
|
||||
{
|
||||
parser_delete_event (parser);
|
||||
yaml_parser_delete (&parser->parser);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
parser_init (lua_State *L)
|
||||
{
|
||||
luaL_newmetatable(L, "lyaml.parser");
|
||||
lua_pushcfunction(L, parser_gc);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
}
|
||||
|
||||
int
|
||||
Pparser (lua_State *L)
|
||||
{
|
||||
lyaml_parser *parser;
|
||||
const unsigned char *str;
|
||||
|
||||
/* requires a single string type argument */
|
||||
luaL_argcheck (L, lua_isstring (L, 1), 1, "must provide a string argument");
|
||||
str = (const unsigned char *) lua_tostring (L, 1);
|
||||
|
||||
/* create a user datum to store the parser */
|
||||
parser = (lyaml_parser *) lua_newuserdata (L, sizeof (*parser));
|
||||
memset ((void *) parser, 0, sizeof (*parser));
|
||||
parser->L = L;
|
||||
|
||||
/* set its metatable */
|
||||
luaL_getmetatable (L, "lyaml.parser");
|
||||
lua_setmetatable (L, -2);
|
||||
|
||||
/* try to initialize the parser */
|
||||
if (yaml_parser_initialize (&parser->parser) == 0)
|
||||
luaL_error (L, "cannot initialize parser for %s", str);
|
||||
yaml_parser_set_input_string (&parser->parser, str, lua_strlen (L, 1));
|
||||
|
||||
/* create and return the iterator function, with the loader userdatum as
|
||||
its sole upvalue */
|
||||
lua_pushcclosure (L, event_iter, 1);
|
||||
return 1;
|
||||
}
|
||||
340
ext/yaml/scanner.c
Normal file
340
ext/yaml/scanner.c
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* scanner.c, libyaml scanner binding for Lua
|
||||
* Written by Gary V. Vaughan, 2013
|
||||
*
|
||||
* Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "lyaml.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
lua_State *L;
|
||||
yaml_parser_t parser;
|
||||
yaml_token_t token;
|
||||
char validtoken;
|
||||
int document_count;
|
||||
} lyaml_scanner;
|
||||
|
||||
|
||||
static void
|
||||
scanner_delete_token (lyaml_scanner *scanner)
|
||||
{
|
||||
if (scanner->validtoken)
|
||||
{
|
||||
yaml_token_delete (&scanner->token);
|
||||
scanner->validtoken = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* With the token result table on the top of the stack, insert
|
||||
a mark entry. */
|
||||
static void
|
||||
scanner_set_mark (lua_State *L, const char *k, yaml_mark_t mark)
|
||||
{
|
||||
lua_pushstring (L, k);
|
||||
lua_createtable (L, 0, 3);
|
||||
#define MENTRY(_s) RAWSET_INTEGER (#_s, mark._s)
|
||||
MENTRY( index );
|
||||
MENTRY( line );
|
||||
MENTRY( column );
|
||||
#undef MENTRY
|
||||
lua_rawset (L, -3);
|
||||
}
|
||||
|
||||
/* Push a new token table, pre-populated with shared elements. */
|
||||
static void
|
||||
scanner_push_tokentable (lyaml_scanner *scanner, const char *v, int n)
|
||||
{
|
||||
lua_State *L = scanner->L;
|
||||
|
||||
lua_createtable (L, 0, n + 3);
|
||||
RAWSET_STRING ("type", v);
|
||||
|
||||
#define MENTRY(_s) scanner_set_mark (L, #_s, scanner->token._s)
|
||||
MENTRY( start_mark );
|
||||
MENTRY( end_mark );
|
||||
#undef MENTRY
|
||||
}
|
||||
|
||||
static void
|
||||
scan_STREAM_START (lyaml_scanner *scanner)
|
||||
{
|
||||
#define EVENTF(_f) (scanner->token.data.stream_start._f)
|
||||
lua_State *L = scanner->L;
|
||||
const char *encoding;
|
||||
|
||||
switch (EVENTF (encoding))
|
||||
{
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_ENCODING: encoding = #_s; break
|
||||
MENTRY( UTF8 );
|
||||
MENTRY( UTF16LE );
|
||||
MENTRY( UTF16BE );
|
||||
#undef MENTRY
|
||||
|
||||
default:
|
||||
lua_pushfstring (L, "invalid encoding %d", EVENTF (encoding));
|
||||
lua_error (L);
|
||||
}
|
||||
|
||||
scanner_push_tokentable (scanner, "STREAM_START", 1);
|
||||
RAWSET_STRING ("encoding", encoding);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
scan_VERSION_DIRECTIVE (lyaml_scanner *scanner)
|
||||
{
|
||||
#define EVENTF(_f) (scanner->token.data.version_directive._f)
|
||||
lua_State *L = scanner->L;
|
||||
|
||||
scanner_push_tokentable (scanner, "VERSION_DIRECTIVE", 2);
|
||||
|
||||
#define MENTRY(_s) RAWSET_INTEGER (#_s, EVENTF (_s))
|
||||
MENTRY( major );
|
||||
MENTRY( minor );
|
||||
#undef MENTRY
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
scan_TAG_DIRECTIVE (lyaml_scanner *scanner)
|
||||
{
|
||||
#define EVENTF(_f) (scanner->token.data.tag_directive._f)
|
||||
lua_State *L = scanner->L;
|
||||
|
||||
scanner_push_tokentable (scanner, "TAG_DIRECTIVE", 2);
|
||||
RAWSET_EVENTF( handle );
|
||||
RAWSET_EVENTF( prefix );
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
scan_ALIAS (lyaml_scanner *scanner)
|
||||
{
|
||||
#define EVENTF(_f) (scanner->token.data.alias._f)
|
||||
lua_State *L = scanner->L;
|
||||
|
||||
scanner_push_tokentable (scanner, "ALIAS", 1);
|
||||
RAWSET_EVENTF (value);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
scan_ANCHOR (lyaml_scanner *scanner)
|
||||
{
|
||||
#define EVENTF(_f) (scanner->token.data.anchor._f)
|
||||
lua_State *L = scanner->L;
|
||||
|
||||
scanner_push_tokentable (scanner, "ANCHOR", 1);
|
||||
RAWSET_EVENTF (value);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
scan_TAG(lyaml_scanner *scanner)
|
||||
{
|
||||
#define EVENTF(_f) (scanner->token.data.tag._f)
|
||||
lua_State *L = scanner->L;
|
||||
|
||||
scanner_push_tokentable (scanner, "TAG", 2);
|
||||
RAWSET_EVENTF( handle );
|
||||
RAWSET_EVENTF( suffix );
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
scan_SCALAR (lyaml_scanner *scanner)
|
||||
{
|
||||
#define EVENTF(_f) (scanner->token.data.scalar._f)
|
||||
lua_State *L = scanner->L;
|
||||
const char *style;
|
||||
|
||||
switch (EVENTF (style))
|
||||
{
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_SCALAR_STYLE: style = #_s; break
|
||||
|
||||
MENTRY( PLAIN );
|
||||
MENTRY( SINGLE_QUOTED );
|
||||
MENTRY( DOUBLE_QUOTED );
|
||||
MENTRY( LITERAL );
|
||||
MENTRY( FOLDED );
|
||||
#undef MENTRY
|
||||
|
||||
default:
|
||||
lua_pushfstring (L, "invalid scalar style %d", EVENTF (style));
|
||||
lua_error (L);
|
||||
}
|
||||
|
||||
scanner_push_tokentable (scanner, "SCALAR", 3);
|
||||
RAWSET_EVENTF (value);
|
||||
RAWSET_INTEGER ("length", EVENTF (length));
|
||||
RAWSET_STRING ("style", style);
|
||||
#undef EVENTF
|
||||
}
|
||||
|
||||
static void
|
||||
scanner_generate_error_message (lyaml_scanner *scanner)
|
||||
{
|
||||
yaml_parser_t *P = &scanner->parser;
|
||||
char buf[256];
|
||||
luaL_Buffer b;
|
||||
|
||||
luaL_buffinit (scanner->L, &b);
|
||||
luaL_addstring (&b, P->problem ? P->problem : "A problem");
|
||||
snprintf (buf, sizeof (buf), " at document: %d", scanner->document_count);
|
||||
luaL_addstring (&b, buf);
|
||||
|
||||
if (P->problem_mark.line || P->problem_mark.column)
|
||||
{
|
||||
snprintf (buf, sizeof (buf), ", line: %lu, column: %lu",
|
||||
(unsigned long) P->problem_mark.line + 1,
|
||||
(unsigned long) P->problem_mark.column + 1);
|
||||
luaL_addstring (&b, buf);
|
||||
}
|
||||
luaL_addstring (&b, "\n");
|
||||
|
||||
if (P->context)
|
||||
{
|
||||
snprintf (buf, sizeof (buf), "%s at line: %lu, column: %lu\n",
|
||||
P->context,
|
||||
(unsigned long) P->context_mark.line + 1,
|
||||
(unsigned long) P->context_mark.column + 1);
|
||||
luaL_addstring (&b, buf);
|
||||
}
|
||||
|
||||
luaL_pushresult (&b);
|
||||
}
|
||||
|
||||
static int
|
||||
token_iter (lua_State *L)
|
||||
{
|
||||
lyaml_scanner *scanner = (lyaml_scanner *)lua_touserdata(L, lua_upvalueindex(1));
|
||||
char *str;
|
||||
|
||||
scanner_delete_token (scanner);
|
||||
if (yaml_parser_scan (&scanner->parser, &scanner->token) != 1)
|
||||
{
|
||||
scanner_generate_error_message (scanner);
|
||||
return lua_error (L);
|
||||
}
|
||||
|
||||
scanner->validtoken = 1;
|
||||
|
||||
lua_newtable (L);
|
||||
lua_pushliteral (L, "type");
|
||||
|
||||
switch (scanner->token.type)
|
||||
{
|
||||
/* First the simple tokens, generated right here... */
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_TOKEN: scanner_push_tokentable (scanner, #_s, 0); break
|
||||
MENTRY( STREAM_END );
|
||||
MENTRY( DOCUMENT_START );
|
||||
MENTRY( DOCUMENT_END );
|
||||
MENTRY( BLOCK_SEQUENCE_START );
|
||||
MENTRY( BLOCK_MAPPING_START );
|
||||
MENTRY( BLOCK_END );
|
||||
MENTRY( FLOW_SEQUENCE_START );
|
||||
MENTRY( FLOW_SEQUENCE_END );
|
||||
MENTRY( FLOW_MAPPING_START );
|
||||
MENTRY( FLOW_MAPPING_END );
|
||||
MENTRY( BLOCK_ENTRY );
|
||||
MENTRY( FLOW_ENTRY );
|
||||
MENTRY( KEY );
|
||||
MENTRY( VALUE );
|
||||
#undef MENTRY
|
||||
|
||||
/* ...then the complex tokens, generated by a function call. */
|
||||
#define MENTRY(_s) \
|
||||
case YAML_##_s##_TOKEN: scan_##_s (scanner); break
|
||||
MENTRY( STREAM_START );
|
||||
MENTRY( VERSION_DIRECTIVE );
|
||||
MENTRY( TAG_DIRECTIVE );
|
||||
MENTRY( ALIAS );
|
||||
MENTRY( ANCHOR );
|
||||
MENTRY( TAG );
|
||||
MENTRY( SCALAR );
|
||||
#undef MENTRY
|
||||
|
||||
case YAML_NO_TOKEN:
|
||||
lua_pushnil (L);
|
||||
break;
|
||||
default:
|
||||
lua_pushfstring (L, "invalid token %d", scanner->token.type);
|
||||
return lua_error (L);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
scanner_gc (lua_State *L)
|
||||
{
|
||||
lyaml_scanner *scanner = (lyaml_scanner *) lua_touserdata (L, 1);
|
||||
|
||||
if (scanner)
|
||||
{
|
||||
scanner_delete_token (scanner);
|
||||
yaml_parser_delete (&scanner->parser);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
scanner_init (lua_State *L)
|
||||
{
|
||||
luaL_newmetatable (L, "lyaml.scanner");
|
||||
lua_pushcfunction (L, scanner_gc);
|
||||
lua_setfield (L, -2, "__gc");
|
||||
}
|
||||
|
||||
int
|
||||
Pscanner (lua_State *L)
|
||||
{
|
||||
lyaml_scanner *scanner;
|
||||
const unsigned char *str;
|
||||
|
||||
/* requires a single string type argument */
|
||||
luaL_argcheck (L, lua_isstring (L, 1), 1, "must provide a string argument");
|
||||
str = (const unsigned char *) lua_tostring (L, 1);
|
||||
|
||||
/* create a user datum to store the scanner */
|
||||
scanner = (lyaml_scanner *) lua_newuserdata (L, sizeof (*scanner));
|
||||
memset ((void *) scanner, 0, sizeof (*scanner));
|
||||
scanner->L = L;
|
||||
|
||||
/* set its metatable */
|
||||
luaL_getmetatable (L, "lyaml.scanner");
|
||||
lua_setmetatable (L, -2);
|
||||
|
||||
/* try to initialize the scanner */
|
||||
if (yaml_parser_initialize (&scanner->parser) == 0)
|
||||
luaL_error (L, "cannot initialize parser for %s", str);
|
||||
yaml_parser_set_input_string (&scanner->parser, str, lua_strlen (L, 1));
|
||||
|
||||
/* create and return the iterator function, with the loader userdatum as
|
||||
its sole upvalue */
|
||||
lua_pushcclosure (L, token_iter, 1);
|
||||
return 1;
|
||||
}
|
||||
66
ext/yaml/yaml.c
Normal file
66
ext/yaml/yaml.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* yaml.c, LibYAML binding for Lua
|
||||
* Written by Andrew Danforth, 2009
|
||||
*
|
||||
* Copyright (C) 2014-2022 Gary V. Vaughan
|
||||
* Copyright (C) 2009 Andrew Danforth
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Portions of this software were inspired by Perl's YAML::LibYAML module by
|
||||
* Ingy döt Net <ingy@cpan.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <lualib.h>
|
||||
|
||||
#include "lyaml.h"
|
||||
|
||||
#define MYNAME "yaml"
|
||||
#define MYVERSION MYNAME " library for " LUA_VERSION " / " VERSION
|
||||
|
||||
#define LYAML__STR_1(_s) (#_s + 1)
|
||||
#define LYAML_STR_1(_s) LYAML__STR_1(_s)
|
||||
|
||||
static const luaL_Reg R[] =
|
||||
{
|
||||
#define MENTRY(_s) {LYAML_STR_1(_s), (_s)}
|
||||
MENTRY( Pemitter ),
|
||||
MENTRY( Pparser ),
|
||||
MENTRY( Pscanner ),
|
||||
#undef MENTRY
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
LUALIB_API int
|
||||
luaopen_yaml (lua_State *L)
|
||||
{
|
||||
parser_init (L);
|
||||
scanner_init (L);
|
||||
|
||||
luaL_register(L, "yaml", R);
|
||||
|
||||
lua_pushliteral(L, MYVERSION);
|
||||
lua_setfield(L, -2, "version");
|
||||
|
||||
return 1;
|
||||
}
|
||||
120
lib/lyaml/explicit.lua
Normal file
120
lib/lyaml/explicit.lua
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
-- LYAML parse explicit token values.
|
||||
-- Written by Gary V. Vaughan, 2015
|
||||
--
|
||||
-- Copyright(C) 2015-2022 Gary V. Vaughan
|
||||
--
|
||||
-- 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.
|
||||
|
||||
--- @module lyaml.explicit
|
||||
|
||||
local functional = require 'lyaml.functional'
|
||||
local implicit = require 'lyaml.implicit'
|
||||
|
||||
local NULL = functional.NULL
|
||||
local anyof = functional.anyof
|
||||
local id = functional.id
|
||||
|
||||
|
||||
local yn = {y=true, Y=true, n=false, N=false}
|
||||
|
||||
|
||||
--- Parse the value following an explicit `!!bool` tag.
|
||||
-- @function bool
|
||||
-- @param value token
|
||||
-- @treturn[1] bool boolean equivalent, if a valid value was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_bool = explicit.bool(tagarg)
|
||||
local bool = anyof {
|
||||
implicit.bool,
|
||||
function(x) return yn[x] end,
|
||||
}
|
||||
|
||||
|
||||
--- Return a function that converts integer results to equivalent float.
|
||||
-- @tparam function fn token parsing function
|
||||
-- @treturn function new function that converts int results to float
|
||||
-- @usage maybe_float = maybefloat(implicit.decimal)(tagarg)
|
||||
local function maybefloat(fn)
|
||||
return function(...)
|
||||
local r = fn(...)
|
||||
if type(r) == 'number' then
|
||||
return r + 0.0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Parse the value following an explicit `!!float` tag.
|
||||
-- @function float
|
||||
-- @param value token
|
||||
-- @treturn[1] number float equivalent, if a valid value was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_float = explicit.float(tagarg)
|
||||
local float = anyof {
|
||||
implicit.float,
|
||||
implicit.nan,
|
||||
implicit.inf,
|
||||
maybefloat(implicit.octal),
|
||||
maybefloat(implicit.decimal),
|
||||
maybefloat(implicit.hexadecimal),
|
||||
maybefloat(implicit.binary),
|
||||
implicit.sexfloat,
|
||||
}
|
||||
|
||||
|
||||
--- Parse the value following an explicit `!!int` tag.
|
||||
-- @function int
|
||||
-- @param value token
|
||||
-- @treturn[1] int integer equivalent, if a valid value was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_int = explicit.int(tagarg)
|
||||
local int = anyof {
|
||||
implicit.octal,
|
||||
implicit.decimal,
|
||||
implicit.hexadecimal,
|
||||
implicit.binary,
|
||||
implicit.sexagesimal,
|
||||
}
|
||||
|
||||
|
||||
--- Parse an explicit `!!null` tag.
|
||||
-- @treturn lyaml.null
|
||||
-- @usage null = explicit.null(tagarg)
|
||||
local function null()
|
||||
return NULL
|
||||
end
|
||||
|
||||
|
||||
--- Parse the value following an explicit `!!str` tag.
|
||||
-- @function str
|
||||
-- @tparam string value token
|
||||
-- @treturn string *value* which was a string already
|
||||
-- @usage tagarg = explicit.str(tagarg)
|
||||
local str = id
|
||||
|
||||
|
||||
--- @export
|
||||
return {
|
||||
bool = bool,
|
||||
float = float,
|
||||
int = int,
|
||||
null = null,
|
||||
str = str,
|
||||
}
|
||||
87
lib/lyaml/functional.lua
Normal file
87
lib/lyaml/functional.lua
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
-- Minimal functional programming utilities.
|
||||
-- Written by Gary V. Vaughan, 2015
|
||||
--
|
||||
-- Copyright(C) 2015-2022 Gary V. Vaughan
|
||||
--
|
||||
-- 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.
|
||||
|
||||
--- @module lyaml.functional
|
||||
|
||||
|
||||
--- `lyaml.null` value.
|
||||
-- @table NULL
|
||||
local NULL = setmetatable({}, {_type='LYAML null'})
|
||||
|
||||
|
||||
--- `lyaml.null` predicate.
|
||||
-- @param x operand
|
||||
-- @treturn bool `true` if *x* is `lyaml.null`.
|
||||
local function isnull(x)
|
||||
return(getmetatable(x) or {})._type == 'LYAML null'
|
||||
end
|
||||
|
||||
|
||||
--- Callable predicate.
|
||||
-- @param x operand
|
||||
-- @treturn bool `true` if *x* is a function has a __call metamethod
|
||||
-- @usage r = iscallable(x) and x(...)
|
||||
local function iscallable(x)
|
||||
if type(x) ~= 'function' then
|
||||
x =(getmetatable(x) or {}).__call
|
||||
end
|
||||
if type(x) == 'function' then
|
||||
return x
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Compose a function to try each callable with supplied args.
|
||||
-- @tparam table fns list of functions to try
|
||||
-- @treturn function a new function to call *...* functions, stopping
|
||||
-- and returning the first non-nil result, if any
|
||||
local function anyof(fns)
|
||||
return function(...)
|
||||
for _, fn in ipairs(fns) do
|
||||
if iscallable(fn) then
|
||||
local r = fn(...)
|
||||
if r ~= nil then
|
||||
return r
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Return arguments unchanged.
|
||||
-- @param ... arguments
|
||||
-- @return *...*
|
||||
local function id(...)
|
||||
return ...
|
||||
end
|
||||
|
||||
--- @export
|
||||
return {
|
||||
NULL = NULL,
|
||||
anyof = anyof,
|
||||
id = id,
|
||||
iscallable = iscallable,
|
||||
isnull = isnull,
|
||||
}
|
||||
283
lib/lyaml/implicit.lua
Normal file
283
lib/lyaml/implicit.lua
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
-- LYAML parse implicit type tokens.
|
||||
-- Written by Gary V. Vaughan, 2015
|
||||
--
|
||||
-- Copyright(C) 2015-2022 Gary V. Vaughan
|
||||
--
|
||||
-- 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.
|
||||
|
||||
--- @module lyaml.implicit
|
||||
|
||||
|
||||
local NULL = require 'lyaml.functional'.NULL
|
||||
local find = string.find
|
||||
local floor = math.floor
|
||||
local gsub = string.gsub
|
||||
local sub = string.sub
|
||||
|
||||
local tointeger = (function(f)
|
||||
if not tointeger then
|
||||
-- No host tointeger implementation, use our own.
|
||||
return function(x)
|
||||
if type(x) == 'number' and x - floor(x) == 0.0 then
|
||||
return x
|
||||
end
|
||||
end
|
||||
|
||||
elseif f '1' ~= nil then
|
||||
-- Don't perform implicit string-to-number conversion!
|
||||
return function(x)
|
||||
if type(x) == 'number' then
|
||||
return tointeger(x)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Host tointeger is good!
|
||||
return f
|
||||
end)(math.tointeger)
|
||||
|
||||
|
||||
local function int(x)
|
||||
local r = tonumber(x)
|
||||
if r ~= nil then
|
||||
return tointeger(r)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local is_null = {['']=true, ['~']=true, null=true, Null=true, NULL=true}
|
||||
|
||||
|
||||
--- Parse a null token to a null value.
|
||||
-- @param value token
|
||||
-- @return[1] lyaml.null, for an empty string or literal ~
|
||||
-- @return[2] nil otherwise, nil
|
||||
-- @usage maybe_null = implicit.null(token)
|
||||
local function null(value)
|
||||
if is_null[value] then
|
||||
return NULL
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local to_bool = {
|
||||
['true'] = true, True = true, TRUE = true,
|
||||
['false'] = false, False = false, FALSE = false,
|
||||
yes = true, Yes = true, YES = true,
|
||||
no = false, No = false, NO = false,
|
||||
on = true, On = true, ON = true,
|
||||
off = false, Off = false, OFF = false,
|
||||
}
|
||||
|
||||
|
||||
--- Parse a boolean token to the equivalent value.
|
||||
-- Treats capilalized, lower and upper-cased variants of true/false,
|
||||
-- yes/no or on/off tokens as boolean `true` and `false` values.
|
||||
-- @param value token
|
||||
-- @treturn[1] bool if a valid boolean token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_bool = implicit.bool(token)
|
||||
local function bool(value)
|
||||
return to_bool[value]
|
||||
end
|
||||
|
||||
|
||||
--- Parse a binary token, such as '0b1010\_0111\_0100\_1010\_1110'.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] int integer equivalent, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_int = implicit.binary(value)
|
||||
local function binary(value)
|
||||
local r
|
||||
gsub(value, '^([+-]?)0b_*([01][01_]+)$', function(sign, rest)
|
||||
r = 0
|
||||
gsub(rest, '_*(.)', function(digit)
|
||||
r = r * 2 + int(digit)
|
||||
end)
|
||||
if sign == '-' then
|
||||
r = r * -1
|
||||
end
|
||||
end)
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--- Parse an octal token, such as '012345'.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] int integer equivalent, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_int = implicit.octal(value)
|
||||
local function octal(value)
|
||||
local r
|
||||
gsub(value, '^([+-]?)0_*([0-7][0-7_]*)$', function(sign, rest)
|
||||
r = 0
|
||||
gsub(rest, '_*(.)', function(digit)
|
||||
r = r * 8 + int(digit)
|
||||
end)
|
||||
if sign == '-' then
|
||||
r = r * -1
|
||||
end
|
||||
end)
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--- Parse a decimal token, such as '0' or '12345'.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] int integer equivalent, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_int = implicit.decimal(value)
|
||||
local function decimal(value)
|
||||
local r
|
||||
gsub(value, '^([+-]?)_*([0-9][0-9_]*)$', function(sign, rest)
|
||||
rest = gsub(rest, '_', '')
|
||||
if rest == '0' or #rest > 1 or sub(rest, 1, 1) ~= '0' then
|
||||
r = int(rest)
|
||||
if sign == '-' then
|
||||
r = r * -1
|
||||
end
|
||||
end
|
||||
end)
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--- Parse a hexadecimal token, such as '0xdeadbeef'.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] int integer equivalent, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_int = implicit.hexadecimal(value)
|
||||
local function hexadecimal(value)
|
||||
local r
|
||||
gsub(value, '^([+-]?)(0x_*[0-9a-fA-F][0-9a-fA-F_]*)$', function(sign, rest)
|
||||
rest = gsub(rest, '_', '')
|
||||
r = int(rest)
|
||||
if sign == '-' then
|
||||
r = r * -1
|
||||
end
|
||||
end)
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--- Parse a sexagesimal token, such as '190:20:30'.
|
||||
-- Useful for times and angles.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] int integer equivalent, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_int = implicit.sexagesimal(value)
|
||||
local function sexagesimal(value)
|
||||
local r
|
||||
gsub(value, '^([+-]?)([0-9]+:[0-5]?[0-9][:0-9]*)$', function(sign, rest)
|
||||
r = 0
|
||||
gsub(rest, '([0-9]+):?', function(digit)
|
||||
r = r * 60 + int(digit)
|
||||
end)
|
||||
if sign == '-' then
|
||||
r = r * -1
|
||||
end
|
||||
end)
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
local isnan = {['.nan']=true, ['.NaN']=true, ['.NAN']=true}
|
||||
|
||||
|
||||
--- Parse a `nan` token.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] nan not-a-number, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_nan = implicit.nan(value)
|
||||
local function nan(value)
|
||||
if isnan[value] then
|
||||
return 0/0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local isinf = {
|
||||
['.inf'] = math.huge, ['.Inf'] = math.huge, ['.INF'] = math.huge,
|
||||
['+.inf'] = math.huge, ['+.Inf'] = math.huge, ['+.INF'] = math.huge,
|
||||
['-.inf'] = -math.huge, ['-.Inf'] = -math.huge, ['-.INF'] = -math.huge,
|
||||
}
|
||||
|
||||
|
||||
--- Parse a signed `inf` token.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] number plus/minus-infinity, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_inf = implicit.inf(value)
|
||||
local function inf(value)
|
||||
return isinf[value]
|
||||
end
|
||||
|
||||
|
||||
--- Parse a floating point number token, such as '1e-3' or '-0.12'.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] number float equivalent, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_float = implicit.float(value)
|
||||
local function float(value)
|
||||
local r = tonumber((gsub(value, '_', '')))
|
||||
if r and find(value, '[%.eE]') then
|
||||
return r
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Parse a sexagesimal float, such as '190:20:30.15'.
|
||||
-- Useful for times and angles.
|
||||
-- @tparam string value token
|
||||
-- @treturn[1] number float equivalent, if a valid token was recognized
|
||||
-- @treturn[2] nil otherwise, nil
|
||||
-- @usage maybe_float = implicit.sexfloat(value)
|
||||
local function sexfloat(value)
|
||||
local r
|
||||
gsub(value, '^([+-]?)([0-9]+:[0-5]?[0-9][:0-9]*)(%.[0-9]+)$',
|
||||
function(sign, rest, float)
|
||||
r = 0
|
||||
gsub(rest, '([0-9]+):?', function(digit)
|
||||
r = r * 60 + int(digit)
|
||||
end)
|
||||
r = r + tonumber(float)
|
||||
if sign == '-' then
|
||||
r = r * -1
|
||||
end
|
||||
end
|
||||
)
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--- @export
|
||||
return {
|
||||
binary = binary,
|
||||
decimal = decimal,
|
||||
float = float,
|
||||
hexadecimal = hexadecimal,
|
||||
inf = inf,
|
||||
nan = nan,
|
||||
null = null,
|
||||
octal = octal,
|
||||
sexagesimal = sexagesimal,
|
||||
sexfloat = sexfloat,
|
||||
bool = bool,
|
||||
}
|
||||
534
lib/lyaml/init.lua
Normal file
534
lib/lyaml/init.lua
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
-- Transform between YAML 1.1 streams and Lua table representations.
|
||||
-- Written by Gary V. Vaughan, 2013
|
||||
--
|
||||
-- Copyright(C) 2013-2022 Gary V. Vaughan
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- Portions of this software were inspired by an earlier LibYAML binding
|
||||
-- by Andrew Danforth <acd@weirdness.net>
|
||||
|
||||
--- @module lyaml
|
||||
|
||||
|
||||
local explicit = require 'lyaml.explicit'
|
||||
local functional = require 'lyaml.functional'
|
||||
local implicit = require 'lyaml.implicit'
|
||||
local yaml = require 'yaml'
|
||||
|
||||
local NULL = functional.NULL
|
||||
local anyof = functional.anyof
|
||||
local find = string.find
|
||||
local format = string.format
|
||||
local gsub = string.gsub
|
||||
local id = functional.id
|
||||
local isnull = functional.isnull
|
||||
local match = string.match
|
||||
|
||||
|
||||
local TAG_PREFIX = 'tag:yaml.org,2002:'
|
||||
|
||||
|
||||
local function tag(name)
|
||||
return TAG_PREFIX .. name
|
||||
end
|
||||
|
||||
|
||||
local default = {
|
||||
-- Tag table to lookup explicit scalar conversions.
|
||||
explicit_scalar = {
|
||||
[tag 'bool'] = explicit.bool,
|
||||
[tag 'float'] = explicit.float,
|
||||
[tag 'int'] = explicit.int,
|
||||
[tag 'null'] = explicit.null,
|
||||
[tag 'str'] = explicit.str,
|
||||
},
|
||||
-- Order is important, so we put most likely and fastest nearer
|
||||
-- the top to reduce average number of comparisons and funcalls.
|
||||
implicit_scalar = anyof {
|
||||
implicit.null,
|
||||
implicit.octal, -- subset of decimal, must come earlier
|
||||
implicit.decimal,
|
||||
implicit.float,
|
||||
implicit.bool,
|
||||
implicit.inf,
|
||||
implicit.nan,
|
||||
implicit.hexadecimal,
|
||||
implicit.binary,
|
||||
implicit.sexagesimal,
|
||||
implicit.sexfloat,
|
||||
id,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
-- Metatable for Dumper objects.
|
||||
local dumper_mt = {
|
||||
__index = {
|
||||
-- Emit EVENT to the LibYAML emitter.
|
||||
emit = function(self, event)
|
||||
return self.emitter.emit(event)
|
||||
end,
|
||||
|
||||
-- Look up an anchor for a repeated document element.
|
||||
get_anchor = function(self, value)
|
||||
local r = self.anchors[value]
|
||||
if r then
|
||||
self.aliased[value], self.anchors[value] = self.anchors[value], nil
|
||||
end
|
||||
return r
|
||||
end,
|
||||
|
||||
-- Look up an already anchored repeated document element.
|
||||
get_alias = function(self, value)
|
||||
return self.aliased[value]
|
||||
end,
|
||||
|
||||
-- Dump ALIAS into the event stream.
|
||||
dump_alias = function(self, alias)
|
||||
return self:emit {
|
||||
type = 'ALIAS',
|
||||
anchor = alias,
|
||||
}
|
||||
end,
|
||||
|
||||
-- Dump MAP into the event stream.
|
||||
dump_mapping = function(self, map)
|
||||
local alias = self:get_alias(map)
|
||||
if alias then
|
||||
return self:dump_alias(alias)
|
||||
end
|
||||
|
||||
self:emit {
|
||||
type = 'MAPPING_START',
|
||||
anchor = self:get_anchor(map),
|
||||
style = 'BLOCK',
|
||||
}
|
||||
for k, v in pairs(map) do
|
||||
self:dump_node(k)
|
||||
self:dump_node(v)
|
||||
end
|
||||
return self:emit {type='MAPPING_END'}
|
||||
end,
|
||||
|
||||
-- Dump SEQUENCE into the event stream.
|
||||
dump_sequence = function(self, sequence)
|
||||
local alias = self:get_alias(sequence)
|
||||
if alias then
|
||||
return self:dump_alias(alias)
|
||||
end
|
||||
|
||||
self:emit {
|
||||
type = 'SEQUENCE_START',
|
||||
anchor = self:get_anchor(sequence),
|
||||
style = 'BLOCK',
|
||||
}
|
||||
for _, v in ipairs(sequence) do
|
||||
self:dump_node(v)
|
||||
end
|
||||
return self:emit {type='SEQUENCE_END'}
|
||||
end,
|
||||
|
||||
-- Dump a null into the event stream.
|
||||
dump_null = function(self)
|
||||
return self:emit {
|
||||
type = 'SCALAR',
|
||||
value = '~',
|
||||
plain_implicit = true,
|
||||
quoted_implicit = true,
|
||||
style = 'PLAIN',
|
||||
}
|
||||
end,
|
||||
|
||||
-- Dump VALUE into the event stream.
|
||||
dump_scalar = function(self, value)
|
||||
local alias = self:get_alias(value)
|
||||
if alias then
|
||||
return self:dump_alias(alias)
|
||||
end
|
||||
|
||||
local anchor = self:get_anchor(value)
|
||||
local itsa = type(value)
|
||||
local style = 'PLAIN'
|
||||
if itsa == 'string' and self.implicit_scalar(value) ~= value then
|
||||
-- take care to round-trip strings that look like scalars
|
||||
style = 'SINGLE_QUOTED'
|
||||
elseif value == math.huge then
|
||||
value = '.inf'
|
||||
elseif value == -math.huge then
|
||||
value = '-.inf'
|
||||
elseif value ~= value then
|
||||
value = '.nan'
|
||||
elseif itsa == 'number' or itsa == 'boolean' then
|
||||
value = tostring(value)
|
||||
elseif itsa == 'string' and find(value, '\n') then
|
||||
style = 'LITERAL'
|
||||
end
|
||||
return self:emit {
|
||||
type = 'SCALAR',
|
||||
anchor = anchor,
|
||||
value = value,
|
||||
plain_implicit = true,
|
||||
quoted_implicit = true,
|
||||
style = style,
|
||||
}
|
||||
end,
|
||||
|
||||
-- Decompose NODE into a stream of events.
|
||||
dump_node = function(self, node)
|
||||
local itsa = type(node)
|
||||
if isnull(node) then
|
||||
return self:dump_null()
|
||||
elseif itsa == 'string' or itsa == 'boolean' or itsa == 'number' then
|
||||
return self:dump_scalar(node)
|
||||
elseif itsa == 'table' then
|
||||
-- Something is only a sequence if its keys start at 1
|
||||
-- and are consecutive integers without any jumps.
|
||||
local prior_key = 0
|
||||
local is_pure_sequence = true
|
||||
local i, v = next(node, nil)
|
||||
while i and is_pure_sequence do
|
||||
if type(i) ~= "number" or (prior_key + 1 ~= i) then
|
||||
is_pure_sequence = false -- breaks the loop
|
||||
else
|
||||
prior_key = i
|
||||
i, v = next(node, prior_key)
|
||||
end
|
||||
end
|
||||
if is_pure_sequence then
|
||||
-- Only sequentially numbered integer keys starting from 1.
|
||||
return self:dump_sequence(node)
|
||||
else
|
||||
-- Table contains non sequential integer keys or mixed keys.
|
||||
return self:dump_mapping(node)
|
||||
end
|
||||
else -- unsupported Lua type
|
||||
error("cannot dump object of type '" .. itsa .. "'", 2)
|
||||
end
|
||||
end,
|
||||
|
||||
-- Dump DOCUMENT into the event stream.
|
||||
dump_document = function(self, document)
|
||||
self:emit {type='DOCUMENT_START'}
|
||||
self:dump_node(document)
|
||||
return self:emit {type='DOCUMENT_END'}
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
-- Emitter object constructor.
|
||||
local function Dumper(opts)
|
||||
local anchors = {}
|
||||
for k, v in pairs(opts.anchors) do
|
||||
anchors[v] = k
|
||||
end
|
||||
local object = {
|
||||
aliased = {},
|
||||
anchors = anchors,
|
||||
emitter = yaml.emitter(),
|
||||
implicit_scalar = opts.implicit_scalar,
|
||||
}
|
||||
return setmetatable(object, dumper_mt)
|
||||
end
|
||||
|
||||
|
||||
--- Dump options table.
|
||||
-- @table dumper_opts
|
||||
-- @tfield table anchors map initial anchor names to values
|
||||
-- @tfield function implicit_scalar parse implicit scalar values
|
||||
|
||||
|
||||
--- Dump a list of Lua tables to an equivalent YAML stream.
|
||||
-- @tparam table documents a sequence of Lua tables.
|
||||
-- @tparam[opt] dumper_opts opts initialisation options
|
||||
-- @treturn string equivalest YAML stream
|
||||
local function dump(documents, opts)
|
||||
opts = opts or {}
|
||||
|
||||
-- backwards compatibility
|
||||
if opts.anchors == nil and opts.implicit_scalar == nil then
|
||||
opts = {anchors=opts}
|
||||
end
|
||||
|
||||
local dumper = Dumper {
|
||||
anchors = opts.anchors or {},
|
||||
implicit_scalar = opts.implicit_scalar or default.implicit_scalar,
|
||||
}
|
||||
|
||||
dumper:emit {type='STREAM_START', encoding='UTF8'}
|
||||
for _, document in ipairs(documents) do
|
||||
dumper:dump_document(document)
|
||||
end
|
||||
local ok, stream = dumper:emit {type='STREAM_END'}
|
||||
return stream
|
||||
end
|
||||
|
||||
|
||||
-- We save anchor types that will match the node type from expanding
|
||||
-- an alias for that anchor.
|
||||
local alias_type = {
|
||||
MAPPING_END = 'MAPPING_END',
|
||||
MAPPING_START = 'MAPPING_END',
|
||||
SCALAR = 'SCALAR',
|
||||
SEQUENCE_END = 'SEQUENCE_END',
|
||||
SEQUENCE_START = 'SEQUENCE_END',
|
||||
}
|
||||
|
||||
|
||||
-- Metatable for Parser objects.
|
||||
local parser_mt = {
|
||||
__index = {
|
||||
-- Return the type of the current event.
|
||||
type = function(self)
|
||||
return tostring(self.event.type)
|
||||
end,
|
||||
|
||||
-- Raise a parse error.
|
||||
error = function(self, errmsg, ...)
|
||||
error(format('%d:%d: ' .. errmsg, self.mark.line,
|
||||
self.mark.column, ...), 0)
|
||||
end,
|
||||
|
||||
-- Save node in the anchor table for reference in future ALIASes.
|
||||
add_anchor = function(self, node)
|
||||
if self.event.anchor ~= nil then
|
||||
self.anchors[self.event.anchor] = {
|
||||
type = alias_type[self.event.type],
|
||||
value = node,
|
||||
}
|
||||
end
|
||||
end,
|
||||
|
||||
-- Fetch the next event.
|
||||
parse = function(self)
|
||||
local ok, event = pcall(self.next)
|
||||
if not ok then
|
||||
-- if ok is nil, then event is a parser error from libYAML
|
||||
self:error(gsub(event, ' at document: .*$', ''))
|
||||
end
|
||||
self.event = event
|
||||
self.mark = {
|
||||
line = self.event.start_mark.line + 1,
|
||||
column = self.event.start_mark.column + 1,
|
||||
}
|
||||
return self:type()
|
||||
end,
|
||||
|
||||
-- Construct a Lua hash table from following events.
|
||||
load_map = function(self)
|
||||
local map = {}
|
||||
self:add_anchor(map)
|
||||
while true do
|
||||
local key = self:load_node()
|
||||
local tag = self.event.tag
|
||||
if tag then
|
||||
tag = match(tag, '^' .. TAG_PREFIX .. '(.*)$')
|
||||
end
|
||||
if key == nil then
|
||||
break
|
||||
end
|
||||
if key == '<<' or tag == 'merge' then
|
||||
tag = self.event.tag or key
|
||||
local node, event = self:load_node()
|
||||
if event == 'MAPPING_END' then
|
||||
for k, v in pairs(node) do
|
||||
if map[k] == nil then
|
||||
map[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == 'SEQUENCE_END' then
|
||||
for i, merge in ipairs(node) do
|
||||
if type(merge) ~= 'table' then
|
||||
self:error("invalid '%s' sequence element %d: %s",
|
||||
tag, i, tostring(merge))
|
||||
end
|
||||
for k, v in pairs(merge) do
|
||||
if map[k] == nil then
|
||||
map[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
if event == 'SCALAR' then
|
||||
event = tostring(node)
|
||||
end
|
||||
self:error("invalid '%s' merge event: %s", tag, event)
|
||||
end
|
||||
else
|
||||
local value, event = self:load_node()
|
||||
if value == nil then
|
||||
self:error('unexpected %s event', self:type())
|
||||
end
|
||||
map[key] = value
|
||||
end
|
||||
end
|
||||
return map, self:type()
|
||||
end,
|
||||
|
||||
-- Construct a Lua array table from following events.
|
||||
load_sequence = function(self)
|
||||
local sequence = {}
|
||||
self:add_anchor(sequence)
|
||||
while true do
|
||||
local node = self:load_node()
|
||||
if node == nil then
|
||||
break
|
||||
end
|
||||
sequence[#sequence + 1] = node
|
||||
end
|
||||
return sequence, self:type()
|
||||
end,
|
||||
|
||||
-- Construct a primitive type from the current event.
|
||||
load_scalar = function(self)
|
||||
local value = self.event.value
|
||||
local tag = self.event.tag
|
||||
local explicit = self.explicit_scalar[tag]
|
||||
|
||||
-- Explicitly tagged values.
|
||||
if explicit then
|
||||
value = explicit(value)
|
||||
if value == nil then
|
||||
self:error("invalid '%s' value: '%s'", tag, self.event.value)
|
||||
end
|
||||
|
||||
-- Otherwise, implicit conversion according to value content.
|
||||
elseif self.event.style == 'PLAIN' then
|
||||
value = self.implicit_scalar(self.event.value)
|
||||
end
|
||||
self:add_anchor(value)
|
||||
return value, self:type()
|
||||
end,
|
||||
|
||||
load_alias = function(self)
|
||||
local anchor = self.event.anchor
|
||||
local event = self.anchors[anchor]
|
||||
if event == nil then
|
||||
self:error('invalid reference: %s', tostring(anchor))
|
||||
end
|
||||
return event.value, event.type
|
||||
end,
|
||||
|
||||
load_node = function(self)
|
||||
local dispatch = {
|
||||
SCALAR = self.load_scalar,
|
||||
ALIAS = self.load_alias,
|
||||
MAPPING_START = self.load_map,
|
||||
SEQUENCE_START = self.load_sequence,
|
||||
MAPPING_END = function() end,
|
||||
SEQUENCE_END = function() end,
|
||||
DOCUMENT_END = function() end,
|
||||
}
|
||||
|
||||
local event = self:parse()
|
||||
if dispatch[event] == nil then
|
||||
self:error('invalid event: %s', self:type())
|
||||
end
|
||||
return dispatch[event](self)
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
-- Parser object constructor.
|
||||
local function Parser(s, opts)
|
||||
local object = {
|
||||
anchors = {},
|
||||
explicit_scalar = opts.explicit_scalar,
|
||||
implicit_scalar = opts.implicit_scalar,
|
||||
mark = {line=0, column=0},
|
||||
next = yaml.parser(s),
|
||||
}
|
||||
return setmetatable(object, parser_mt)
|
||||
end
|
||||
|
||||
|
||||
--- Load options table.
|
||||
-- @table loader_opts
|
||||
-- @tfield boolean all load all documents from the stream
|
||||
-- @tfield table explicit_scalar map full tag-names to parser functions
|
||||
-- @tfield function implicit_scalar parse implicit scalar values
|
||||
|
||||
|
||||
--- Load a YAML stream into a Lua table.
|
||||
-- @tparam string s YAML stream
|
||||
-- @tparam[opt] loader_opts opts initialisation options
|
||||
-- @treturn table Lua table equivalent of stream *s*
|
||||
local function load(s, opts)
|
||||
opts = opts or {}
|
||||
local documents = {}
|
||||
local all = false
|
||||
|
||||
-- backwards compatibility
|
||||
if opts == true then
|
||||
opts = {all=true}
|
||||
end
|
||||
|
||||
local parser = Parser(s, {
|
||||
explicit_scalar = opts.explicit_scalar or default.explicit_scalar,
|
||||
implicit_scalar = opts.implicit_scalar or default.implicit_scalar,
|
||||
})
|
||||
|
||||
if parser:parse() ~= 'STREAM_START' then
|
||||
error('expecting STREAM_START event, but got ' .. parser:type(), 2)
|
||||
end
|
||||
|
||||
while parser:parse() ~= 'STREAM_END' do
|
||||
local document = parser:load_node()
|
||||
if document == nil then
|
||||
error('unexpected ' .. parser:type() .. ' event')
|
||||
end
|
||||
|
||||
if parser:parse() ~= 'DOCUMENT_END' then
|
||||
error('expecting DOCUMENT_END event, but got ' .. parser:type(), 2)
|
||||
end
|
||||
|
||||
-- save document
|
||||
documents[#documents + 1] = document
|
||||
|
||||
-- reset anchor table
|
||||
parser.anchors = {}
|
||||
end
|
||||
|
||||
return opts.all and documents or documents[1]
|
||||
end
|
||||
|
||||
|
||||
--[[ ----------------- ]]--
|
||||
--[[ Public Interface. ]]--
|
||||
--[[ ----------------- ]]--
|
||||
|
||||
|
||||
--- @export
|
||||
return {
|
||||
dump = dump,
|
||||
load = load,
|
||||
|
||||
--- `lyaml.null` value.
|
||||
-- @table null
|
||||
null = NULL,
|
||||
|
||||
--- Version number from yaml C binding.
|
||||
-- @table _VERSION
|
||||
_VERSION = yaml.version,
|
||||
}
|
||||
47
lukefile
Normal file
47
lukefile
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
--[[
|
||||
LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
]]
|
||||
|
||||
package = 'lyaml'
|
||||
version = '$USER'
|
||||
|
||||
defines = {
|
||||
PACKAGE = '"$package"',
|
||||
VERSION = '"$version"',
|
||||
NDEBUG = 1,
|
||||
_FORTIFY_SOURCE = 2,
|
||||
platforms = {
|
||||
aix = {_ALL_SOURCE = 1},
|
||||
bsd = {_BSD_SOURCE = 1},
|
||||
freebsd = {__BSD_VISIBLE = 1},
|
||||
macosx = {_DARWIN_C_SOURCE = 1},
|
||||
},
|
||||
}
|
||||
|
||||
external_dependencies = {
|
||||
YAML = {
|
||||
library = {checksymbol='yaml_document_initialize', library='yaml'},
|
||||
},
|
||||
}
|
||||
|
||||
incdirs = {
|
||||
'ext/include',
|
||||
'$LUA_INCDIR',
|
||||
}
|
||||
|
||||
ldocs = 'build-aux/config.ld.in'
|
||||
|
||||
modules = {
|
||||
['yaml'] = {
|
||||
'ext/yaml/yaml.c',
|
||||
'ext/yaml/emitter.c',
|
||||
'ext/yaml/parser.c',
|
||||
'ext/yaml/scanner.c',
|
||||
},
|
||||
|
||||
['lyaml'] = 'lib/lyaml/init.lua',
|
||||
['lyaml.explicit'] = 'lib/lyaml/explicit.lua',
|
||||
['lyaml.functional'] = 'lib/lyaml/functional.lua',
|
||||
['lyaml.implicit'] = 'lib/lyaml/implicit.lua',
|
||||
}
|
||||
59
lyaml-6.2.8-1.rockspec
Normal file
59
lyaml-6.2.8-1.rockspec
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
local _MODREV, _SPECREV = '6.2.8', '-1'
|
||||
|
||||
package = 'lyaml'
|
||||
version = _MODREV .. _SPECREV
|
||||
|
||||
description = {
|
||||
summary = 'libYAML binding for Lua',
|
||||
detailed = 'Read and write YAML format files with Lua.',
|
||||
homepage = 'http://github.com/gvvaughan/lyaml',
|
||||
license = 'MIT/X11',
|
||||
}
|
||||
|
||||
source = {
|
||||
url = 'http://github.com/gvvaughan/lyaml/archive/v' .. _MODREV .. '.zip',
|
||||
dir = 'lyaml-' .. _MODREV,
|
||||
}
|
||||
|
||||
dependencies = {
|
||||
'lua >= 5.1, < 5.5',
|
||||
}
|
||||
|
||||
external_dependencies = {
|
||||
YAML = {
|
||||
library = 'yaml',
|
||||
},
|
||||
}
|
||||
|
||||
build = {
|
||||
type = 'command',
|
||||
build_command = '$(LUA) build-aux/luke'
|
||||
.. ' package="' .. package .. '"'
|
||||
.. ' version="' .. _MODREV .. '"'
|
||||
.. ' PREFIX="$(PREFIX)"'
|
||||
.. ' CFLAGS="$(CFLAGS)"'
|
||||
.. ' LIBFLAG="$(LIBFLAG)"'
|
||||
.. ' LIB_EXTENSION="$(LIB_EXTENSION)"'
|
||||
.. ' OBJ_EXTENSION="$(OBJ_EXTENSION)"'
|
||||
.. ' LUA="$(LUA)"'
|
||||
.. ' LUA_DIR="$(LUADIR)"'
|
||||
.. ' LUA_INCDIR="$(LUA_INCDIR)"'
|
||||
.. ' YAML_DIR="$(YAML_DIR)"'
|
||||
.. ' YAML_INCDIR="$(YAML_INCDIR)"'
|
||||
.. ' YAML_LIBDIR="$(YAML_LIBDIR)"'
|
||||
,
|
||||
install_command = '$(LUA) build-aux/luke install --quiet'
|
||||
.. ' INST_LIBDIR="$(LIBDIR)"'
|
||||
.. ' INST_LUADIR="$(LUADIR)"'
|
||||
,
|
||||
copy_directories = {'doc'},
|
||||
}
|
||||
|
||||
if _MODREV == 'git' then
|
||||
build.copy_directories = nil
|
||||
|
||||
source = {
|
||||
url = 'git://github.com/gvvaughan/lyaml.git',
|
||||
}
|
||||
end
|
||||
|
||||
239
spec/ext_yaml_emitter_spec.yaml
Normal file
239
spec/ext_yaml_emitter_spec.yaml
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
# LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
# Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
|
||||
specify emitting:
|
||||
- it diagnoses an invalid event:
|
||||
emitter = yaml.emitter ()
|
||||
expect (emitter.emit "not an event").to_raise "expected table"
|
||||
- it can generate an empty stream:
|
||||
pending (github_issue "2")
|
||||
expect (emit {
|
||||
{type = "DOCUMENT_START", implicit = true},
|
||||
{type = "SCALAR", value = ""},
|
||||
{type = "DOCUMENT_END", implicit = true},
|
||||
}).
|
||||
to_equal ""
|
||||
|
||||
- describe STREAM_START:
|
||||
- it diagnoses unrecognised encodings:
|
||||
expect (emitevents (yaml.emitter (), {
|
||||
{type = "STREAM_START", encoding = "notexists"},
|
||||
"STREAM_END"})).
|
||||
to_raise "invalid stream encoding 'notexists'"
|
||||
- it accepts an encoding parameter:
|
||||
expect (emitevents (yaml.emitter (), {
|
||||
{type = "STREAM_START", encoding = "UTF16BE"},
|
||||
"STREAM_END"})).
|
||||
to_equal (BOM)
|
||||
|
||||
- describe STREAM_END:
|
||||
- it returns the yaml document from the preceding events:
|
||||
expect (emit {"DOCUMENT_START", {type = "SCALAR", value = "woo!"},
|
||||
"DOCUMENT_END"}).
|
||||
to_equal "--- woo!\n...\n"
|
||||
|
||||
- describe DOCUMENT_START:
|
||||
- it accepts a version directive parameter:
|
||||
expect (emit {{type = "DOCUMENT_START",
|
||||
version_directive = { major = 1, minor = 1 }},
|
||||
{type = "SCALAR", value = ""},
|
||||
"DOCUMENT_END"}).
|
||||
to_match "^%%YAML 1.1\n---"
|
||||
- it accepts a list of tag directives:
|
||||
expect (emit {{type = "DOCUMENT_START",
|
||||
tag_directives = {{handle = "!",
|
||||
prefix = "tag:ben-kiki.org,2000:app/"}}},
|
||||
{type = "SCALAR", value = ""},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "%TAG ! tag:ben-kiki.org,2000:app/\n---"
|
||||
expect (emit {
|
||||
{type = "DOCUMENT_START",
|
||||
tag_directives = {{handle = "!",
|
||||
prefix = "tag:ben-kiki.org,2000:app/"},
|
||||
{handle = "!!",
|
||||
prefix = "tag:yaml.org,2002:"}}},
|
||||
{type = "SCALAR", value = ""},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain ("%TAG ! tag:ben-kiki.org,2000:app/\n" ..
|
||||
"%TAG !! tag:yaml.org,2002:\n---")
|
||||
- it accepts an implicit parameter:
|
||||
expect (emit {{type = "DOCUMENT_START", implicit = true},
|
||||
{type = "SCALAR", value = ""}, "DOCUMENT_END"}).
|
||||
not_to_contain "--- \n"
|
||||
pending (github_issue "2")
|
||||
expect (emit {{type = "DOCUMENT_START", implicit = false},
|
||||
{type = "SCALAR", value = ""}, "DOCUMENT_END"}).
|
||||
not_to_contain "---"
|
||||
|
||||
- describe DOCUMENT_END:
|
||||
- it accepts an implicit parameter:
|
||||
expect (emit {"DOCUMENT_START", {type = "SCALAR", value = ""},
|
||||
{type = "DOCUMENT_END", implicit = false}}).
|
||||
to_contain "\n..."
|
||||
pending (github_issue "2")
|
||||
expect (emit {"DOCUMENT_START", {type = "SCALAR", value = ""},
|
||||
{type = "DOCUMENT_END", implicit = true}}).
|
||||
not_to_contain "\n..."
|
||||
|
||||
- describe MAPPING_START:
|
||||
- it accepts an anchor parameter:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "MAPPING_START", anchor = "foo"},
|
||||
"MAPPING_END", "DOCUMENT_END"}).
|
||||
to_contain "&foo"
|
||||
- it diagnoses unrecognised styles:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "MAPPING_START", style = "notexists"},
|
||||
"MAPPING_END", "DOCUMENT_END"}).
|
||||
to_raise "invalid mapping style 'notexists'"
|
||||
- it understands block style: '
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "MAPPING_START", style = "BLOCK"},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"MAPPING_END", "DOCUMENT_END"}).
|
||||
to_contain "foo: bar\n"'
|
||||
- it understands flow style: '
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "MAPPING_START", style = "FLOW"},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
{type = "SCALAR", value = "baz"}, {type = "SCALAR", value = "qux"},
|
||||
"MAPPING_END", "DOCUMENT_END"}).
|
||||
to_contain "{foo: bar, baz: qux}\n"'
|
||||
- it accepts an explicit tag parameter: '
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "MAPPING_START", style = "FLOW",
|
||||
tag = "tag:yaml.org,2002:map", implicit = false},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"MAPPING_END", "DOCUMENT_END"}).
|
||||
to_contain "!!map {foo: bar}"'
|
||||
- it accepts an implicit tag parameter: '
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "MAPPING_START", tag = "tag:yaml.org,2002:map", implicit = true},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"MAPPING_END", "DOCUMENT_END"}).
|
||||
not_to_contain "map"'
|
||||
|
||||
- describe MAPPING_END:
|
||||
- it requires no parameters: '
|
||||
expect (emit {"DOCUMENT_START", "MAPPING_START",
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"MAPPING_END", "DOCUMENT_END"}).
|
||||
to_contain "foo: bar\n"'
|
||||
|
||||
- describe SEQUENCE_START:
|
||||
- it accepts an anchor parameter:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SEQUENCE_START", anchor = "foo"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
to_contain "&foo"
|
||||
- it diagnoses unrecognised styles:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SEQUENCE_START", style = "notexists"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
to_raise "invalid sequence style 'notexists'"
|
||||
- it understands block style:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SEQUENCE_START", style = "BLOCK"},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
to_contain "- foo\n- bar\n"
|
||||
- it understands flow style:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SEQUENCE_START", style = "FLOW"},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
to_contain "[foo, bar]"
|
||||
- it accepts an explicit tag parameter:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SEQUENCE_START", style = "FLOW",
|
||||
tag = "tag:yaml.org,2002:sequence", implicit = false},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
to_contain "!!sequence [foo, bar]\n"
|
||||
- it accepts an implicit tag parameter:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SEQUENCE_START", style = "FLOW",
|
||||
tag = "tag:yaml.org,2002:sequence", implicit = true},
|
||||
{type = "SCALAR", value = "foo"}, {type = "SCALAR", value = "bar"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
not_to_contain "sequence"
|
||||
|
||||
- describe SEQUENCE_END:
|
||||
- it requires no parameters: '
|
||||
expect (emit {"DOCUMENT_START", "SEQUENCE_START",
|
||||
{type = "SCALAR", value = "moo"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
to_contain "- moo\n"'
|
||||
|
||||
- describe SCALAR:
|
||||
- it diagnoses a missing value parameter:
|
||||
- it accepts a value parameter:
|
||||
expect (emit {"DOCUMENT_START", {type = "SCALAR", value = "boo"},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "boo"
|
||||
- it diagnoses unrecognised styles:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "notexists", value = "foo"},
|
||||
"DOCUMENT_END"}).
|
||||
to_raise "invalid scalar style 'notexists'"
|
||||
- it understands plain style:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "PLAIN", value = "boo"},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "boo\n"
|
||||
- it understands single quoted style:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "SINGLE_QUOTED", value = "bar"},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "'bar'\n"
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "SINGLE_QUOTED", value = "bar'"},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "'bar'''\n"
|
||||
- it understands double quoted style:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "DOUBLE_QUOTED", value = "baz"},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain '"baz"\n'
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "DOUBLE_QUOTED", value = '"baz"'},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain ([["\"baz\""]] .. "\n")
|
||||
- it understands literal style:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "LITERAL", value = "quux"},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "|-\n quux\n"
|
||||
- it understands folded style:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "FOLDED", value = "thud"},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain ">-\n thud\n"
|
||||
- it understands plain_implicit:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "PLAIN", value = "hello", plain_implicit=false},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "'hello'\n"
|
||||
- it understands quoted_implicit:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "PLAIN", value = "- world", quoted_implicit=false},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "! '- world'\n"
|
||||
- it understands tag:
|
||||
expect (emit {"DOCUMENT_START",
|
||||
{type = "SCALAR", style = "PLAIN", value = "bug_squash", tag="tagger", plain_implicit=false, quoted_implicit=false},
|
||||
"DOCUMENT_END"}).
|
||||
to_contain "!<tagger> bug_squash\n"
|
||||
|
||||
- describe ALIAS:
|
||||
- it diagnoses missing anchor parameter:
|
||||
- it diagnoses non-alphanumeric anchor characters:
|
||||
expect (emit {"DOCUMENT_START", {type = "ALIAS", anchor = "woo!"},
|
||||
"DOCUMENT_END"}).
|
||||
to_raise "must contain alphanumerical characters only"
|
||||
- it accepts an anchor parameter:
|
||||
expect (emit {"DOCUMENT_START", "SEQUENCE_START",
|
||||
{type = "SCALAR", anchor = "woo", value = "hoo"},
|
||||
{type = "ALIAS", anchor = "woo"},
|
||||
"SEQUENCE_END", "DOCUMENT_END"}).
|
||||
to_contain.all_of {"&woo", "*woo"}
|
||||
391
spec/ext_yaml_parser_spec.yaml
Normal file
391
spec/ext_yaml_parser_spec.yaml
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
# LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
# Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
|
||||
specify parsing:
|
||||
- it parses empty streams:
|
||||
e = yaml.parser ""
|
||||
expect (e ().type).to_be "STREAM_START"
|
||||
expect (e ().type).to_be "STREAM_END"
|
||||
expect (e ()).to_be (nil)
|
||||
expect (e ()).to_be (nil)
|
||||
- it ignores comments: '
|
||||
e = yaml.parser "# A comment\nnon-comment # trailing comment\n"
|
||||
expect (e ().type).to_be "STREAM_START"
|
||||
expect (e ().type).to_be "DOCUMENT_START"
|
||||
expect (e ().value).to_be "non-comment"
|
||||
expect (e ().type).to_be "DOCUMENT_END"'
|
||||
|
||||
- describe STREAM_START:
|
||||
- before:
|
||||
e = yaml.parser "# no BOM"
|
||||
- it is the first event:
|
||||
expect (e ().type).to_be "STREAM_START"
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it uses UTF-8 by default:
|
||||
expect (e ().encoding).to_be "UTF8"
|
||||
- it recognizes UTF-16 BOM:
|
||||
e = yaml.parser (BOM .. " BOM")
|
||||
expect (e ().encoding).to_match "UTF16[BL]E"
|
||||
|
||||
- describe STREAM_END:
|
||||
- before:
|
||||
for t in yaml.parser "nothing to see" do ev = t end
|
||||
- it is the last event:
|
||||
expect (ev.type).to_be "STREAM_END"
|
||||
- it reports event start marker:
|
||||
expect (ev.start_mark).to_equal {line = 1, column = 0, index = 14}
|
||||
- it reports event end marker:
|
||||
expect (ev.end_mark).to_equal {line = 1, column = 0, index = 14}
|
||||
|
||||
- describe DOCUMENT_START:
|
||||
- before:
|
||||
e = consume (1, "---")
|
||||
- it recognizes document start marker:
|
||||
expect (filter (e (), "type", "implicit")).
|
||||
to_equal {type = "DOCUMENT_START", implicit = false}
|
||||
- it reports implicit document start:
|
||||
e = consume (1, "foo")
|
||||
expect (e ().implicit).to_be (true)
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 0, column = 3, index = 3}
|
||||
|
||||
- context parser directives:
|
||||
- it can recognize document versions:
|
||||
e = consume (1, "%YAML 1.1\n---")
|
||||
expect (e ().version_directive).to_equal {major = 1, minor = 1}
|
||||
- it can diagnose missing document start:
|
||||
e = consume (1, "%YAML 1.1\n")
|
||||
expect (e ()).to_error "expected <document start>"
|
||||
- it can diagnose multiple versions:
|
||||
e = consume (1, "%YAML 1.1\n%YAML 1.1\n---")
|
||||
expect (e ()).to_error "duplicate %YAML directive"
|
||||
- it can diagnose too-new versions:
|
||||
e = consume (1, "%YAML 2.0\n---")
|
||||
expect (e ()).to_error "incompatible YAML document"
|
||||
- it warns of newer minor versions:
|
||||
pending (github_issue "1")
|
||||
e = consume (1, "%YAML 1.9\n---")
|
||||
expect (e ()).
|
||||
to_error "attempting parsing of newer minor document version"
|
||||
|
||||
- it can recognize primary tag handles:
|
||||
e = consume (1, "%TAG ! tag:ben-kiki.org,2000:app/\n---")
|
||||
expect (e ().tag_directives).
|
||||
to_equal {{handle = "!", prefix = "tag:ben-kiki.org,2000:app/"}}
|
||||
- it can recognize secondary tag handles:
|
||||
e = consume (1, "%TAG !! tag:yaml.org,2002:\n---")
|
||||
expect (e ().tag_directives).
|
||||
to_equal {{handle = "!!", prefix = "tag:yaml.org,2002:"}}
|
||||
- it can recognize named tag handles:
|
||||
e = consume (1, "%TAG !o! tag:ben-kiki.org,2000:\n---")
|
||||
expect (e ().tag_directives).
|
||||
to_equal {{handle = "!o!", prefix = "tag:ben-kiki.org,2000:"}}
|
||||
- it can concatenate multiple tag handles:
|
||||
e = consume (1, "%TAG ! !\n" ..
|
||||
"%TAG !! tag:yaml.org,2002:\n" ..
|
||||
"%TAG !o! tag:ben-kiki.org,2000:\n" ..
|
||||
"---")
|
||||
expect (e ().tag_directives).to_contain.
|
||||
all_of {{handle = "!", prefix = "!"},
|
||||
{handle = "!!", prefix = "tag:yaml.org,2002:"},
|
||||
{handle = "!o!", prefix = "tag:ben-kiki.org,2000:"}}
|
||||
- it can diagnose missing document start:
|
||||
e = consume (1, "%TAG ! !\n")
|
||||
expect (e ()).to_error "expected <document start>"
|
||||
|
||||
- describe DOCUMENT_END:
|
||||
- before:
|
||||
e = consume (3, "foo\n...")
|
||||
- it recognizes the document end marker:
|
||||
expect (filter (e (), "type", "implicit")).
|
||||
to_equal {type = "DOCUMENT_END", implicit = false}
|
||||
- it reports an implicit document end marker:
|
||||
e = consume (3, "foo\n")
|
||||
expect (filter (e (), "type", "implicit")).
|
||||
to_equal {type = "DOCUMENT_END", implicit = true}
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 1, column = 0, index = 4}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 1, column = 3, index = 7}
|
||||
|
||||
- describe ALIAS:
|
||||
- before:
|
||||
e = consume (10, "---\n" ..
|
||||
"hr:\n" ..
|
||||
"- Mark McGwire\n" ..
|
||||
"- &SS Sammy Sosa\n" ..
|
||||
"rbi:\n" ..
|
||||
"- *SS\n" ..
|
||||
"- Ken Griffey")
|
||||
- it recognizes an alias event:
|
||||
expect (filter (e (), "type", "anchor")).
|
||||
to_equal {type = "ALIAS", anchor = "SS"}
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 5, column = 2, index = 47}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 5, column = 5, index = 50}
|
||||
|
||||
- describe SCALAR:
|
||||
- before:
|
||||
e = consume (6, "---\n" ..
|
||||
"hr:\n" ..
|
||||
"- Mark McGwire\n" ..
|
||||
"- &SS Sammy Sosa\n" ..
|
||||
"rbi:\n" ..
|
||||
"- *SS\n" ..
|
||||
"- Ken Griffey")
|
||||
- it recognizes a scalar event:
|
||||
expect (filter (e (), "type", "value")).
|
||||
to_equal {type = "SCALAR", value = "Sammy Sosa"}
|
||||
- it records anchors:
|
||||
expect (e ().anchor).to_be "SS"
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 3, column = 2, index = 25}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 3, column = 16, index = 39}
|
||||
|
||||
- context with quoting style:
|
||||
- context plain style:
|
||||
- before:
|
||||
e = consume (2, "---\n" ..
|
||||
" Mark McGwire's\n" ..
|
||||
" year was crippled\n" ..
|
||||
" by a knee injury.\n")
|
||||
- it ignores line-breaks and indentation:
|
||||
expect (e ().value).
|
||||
to_be "Mark McGwire's year was crippled by a knee injury."
|
||||
- it recognizes implicit plain style:
|
||||
e = consume (2, "---\n" ..
|
||||
" Mark McGwire's\n" ..
|
||||
" year was crippled\n" ..
|
||||
" by a knee injury.\n")
|
||||
expect (e ().plain_implicit).to_be (true)
|
||||
- it recognizes explicit plain style:
|
||||
e = consume (2, "|\n" ..
|
||||
" Mark McGwire's\n" ..
|
||||
" year was crippled\n" ..
|
||||
" by a knee injury.\n")
|
||||
expect (e ().plain_implicit).to_be (false)
|
||||
- it recognizes implicit quoted style:
|
||||
e = consume (2, "|\n" ..
|
||||
" Mark McGwire's\n" ..
|
||||
" year was crippled\n" ..
|
||||
" by a knee injury.\n")
|
||||
expect (e ().quoted_implicit).to_be (true)
|
||||
- it recognizes explicit quoted style:
|
||||
e = consume (2, "'\n" ..
|
||||
" Mark McGwire's\n" ..
|
||||
" year was crippled\n" ..
|
||||
" by a knee injury.'\n")
|
||||
expect (e ().plain_implicit).to_be (false)
|
||||
- context folded style:
|
||||
- it preserves blank lines and deeper indentation:
|
||||
e = consume (2, ">\n" ..
|
||||
" Sammy Sosa completed another\n" ..
|
||||
" fine season with great stats.\n" ..
|
||||
"\n" ..
|
||||
" 63 Home Runs\n" ..
|
||||
" 0.288 Batting Average\n" ..
|
||||
"\n" ..
|
||||
" What a year!\n")
|
||||
expect (e ().value).
|
||||
to_be ("Sammy Sosa completed another fine season with great stats.\n" ..
|
||||
"\n" ..
|
||||
" 63 Home Runs\n" ..
|
||||
" 0.288 Batting Average\n" ..
|
||||
"\n" ..
|
||||
"What a year!\n")
|
||||
- context literal style:
|
||||
- it removes indentation but preserves all line-breaks:
|
||||
e = consume (2, [[# ASCII Art]] .. "\n" ..
|
||||
[[--- |]] .. "\n" ..
|
||||
[[ \//||\/||]] .. "\n" ..
|
||||
[[ // || ||__]] .. "\n")
|
||||
expect (e ().value).
|
||||
to_be ([[\//||\/||]] .. "\n" ..
|
||||
[[// || ||__]] .. "\n")
|
||||
|
||||
- context single quoted style:
|
||||
- it folds line breaks:
|
||||
e = consume (2, [['This quoted scalar]] .. "\n" ..
|
||||
[[ spans two lines.']])
|
||||
expect (e ().value).
|
||||
to_be "This quoted scalar spans two lines."
|
||||
- it does not process escape sequences:
|
||||
# Lua [[ quoting makes sure libyaml sees all the quotes.
|
||||
e = consume (2, [['"Howdy!"\t\u263A']])
|
||||
expect (e ().value).to_be [["Howdy!"\t\u263A]]
|
||||
|
||||
# Note that we have to single quote the Lua snippets to prevent
|
||||
# libyaml from interpreting the bytes as the spec file is read, so
|
||||
# that the raw strings get correctly passed to the Lua compiler.
|
||||
- context double quoted style:
|
||||
- it folds line breaks: '
|
||||
e = consume (4, [[quoted: "This quoted scalar]] .. "\n" ..
|
||||
[[ spans two lines\n"]])
|
||||
expect (e ().value).
|
||||
to_be "This quoted scalar spans two lines\n"'
|
||||
- it recognizes unicode escape sequences: '
|
||||
e = consume (4, [[unicode: "Sosa did fine.\u263A"]])
|
||||
expect (e ().value).to_be "Sosa did fine.\226\152\186"'
|
||||
- it recognizes control escape sequences: '
|
||||
e = consume (4, [[control: "\b1998\t1999\t2000\n"]])
|
||||
expect (e ().value).to_be "\b1998\t1999\t2000\n"'
|
||||
- it recognizes hexadecimal escape sequences: '
|
||||
e = consume (4, [[hexesc: "\x41\x42\x43 is ABC"]])
|
||||
expect (e ().value).to_be "ABC is ABC"'
|
||||
|
||||
- context indentation determines scope: '
|
||||
e = consume (4, "name: Mark McGwire\n" ..
|
||||
"accomplishment: >\n" ..
|
||||
" Mark set a major league\n" ..
|
||||
" home run record in 1998.\n" ..
|
||||
"stats: |\n" ..
|
||||
" 65 Home Runs\n" ..
|
||||
" 0.278 Batting Average\n")
|
||||
expect (e ().value).to_be "Mark McGwire"
|
||||
expect (e ().value).to_be "accomplishment"
|
||||
expect (e ().value).
|
||||
to_be "Mark set a major league home run record in 1998.\n"
|
||||
expect (e ().value).to_be "stats"
|
||||
expect (e ().value).to_be "65 Home Runs\n0.278 Batting Average\n"'
|
||||
|
||||
- context with tag:
|
||||
- it recognizes local tags: '
|
||||
e = consume (4, "application specific tag: !something |\n" ..
|
||||
" The semantics of the tag\n" ..
|
||||
" above may be different for\n" ..
|
||||
" different documents.")
|
||||
expect (e ().tag).to_be "!something"'
|
||||
- it recognizes global tags: '
|
||||
e = consume (4, "picture: !!binary |\n" ..
|
||||
" R0lGODlhDAAMAIQAAP//9/X\n" ..
|
||||
" 17unp5WZmZgAAAOfn515eXv\n" ..
|
||||
" Pz7Y6OjuDg4J+fn5OTk6enp\n" ..
|
||||
" 56enmleECcgggoBADs=")
|
||||
expect (e ().tag).to_be "tag:yaml.org,2002:binary"'
|
||||
- it resolves %TAG declarations: '
|
||||
e = consume (5, "%TAG ! tag:clarkevans.com,2002:\n" ..
|
||||
"---\n" ..
|
||||
"shape:\n" ..
|
||||
"- !circle\n" ..
|
||||
" center: &ORIGIN {x: 73, y: 129}\n" ..
|
||||
" radius: 7")
|
||||
expect (e ().tag).to_be "tag:clarkevans.com,2002:circle"'
|
||||
|
||||
- describe SEQUENCE_START:
|
||||
- before: '
|
||||
e = consume (4, "fubar: &FOO\n" ..
|
||||
" - foo\n" ..
|
||||
" - bar\n")'
|
||||
- it recognizes a sequence start event:
|
||||
expect (e ().type).to_be "SEQUENCE_START"
|
||||
- it records anchors:
|
||||
expect (e ().anchor).to_be "FOO"
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 0, column = 7, index = 7}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 1, column = 2, index = 14}
|
||||
|
||||
- context with tag:
|
||||
- it recognizes local tags: '
|
||||
e = consume (2, "--- !something\n" ..
|
||||
"- foo\n")
|
||||
expect (filter (e (), "type", "tag")).
|
||||
to_equal {type = "SEQUENCE_START", tag = "!something"}'
|
||||
- it recognizes global tags: '
|
||||
e = consume (2, "--- !!omap\n" ..
|
||||
"- Mark McGwire: 65\n" ..
|
||||
"- Sammy Sosa: 63\n" ..
|
||||
"- Ken Griffy: 58\n")
|
||||
expect (filter (e (), "type", "tag")).
|
||||
to_equal {type = "SEQUENCE_START",
|
||||
tag = "tag:yaml.org,2002:omap"}'
|
||||
- it resolves %TAG declarations: '
|
||||
e = consume (2, "%TAG ! tag:clarkevans.com,2002:\n" ..
|
||||
"--- !shape\n" ..
|
||||
"- !circle\n" ..
|
||||
" center: &ORIGIN {x: 73, y: 129}\n" ..
|
||||
" radius: 7\n")
|
||||
expect (filter (e (), "type", "tag")).
|
||||
to_equal {type = "SEQUENCE_START",
|
||||
tag = "tag:clarkevans.com,2002:shape"}'
|
||||
|
||||
- context with style:
|
||||
- it recognizes block style:
|
||||
e = consume (2, "- first\n- second")
|
||||
expect (filter (e (), "type", "style")).
|
||||
to_equal {type = "SEQUENCE_START", style = "BLOCK"}
|
||||
- it recognizes flow style:
|
||||
e = consume (2, "[first, second]")
|
||||
expect (filter (e (), "type", "style")).
|
||||
to_equal {type = "SEQUENCE_START", style = "FLOW"}
|
||||
|
||||
- describe SEQUENCE_END:
|
||||
- before:
|
||||
e = consume (5, "- foo\n- bar\n")
|
||||
- it recognizes a sequence end event:
|
||||
expect (e ().type).to_equal "SEQUENCE_END"
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 2, column = 0, index = 12}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 2, column = 0, index = 12}
|
||||
|
||||
- describe MAPPING_START:
|
||||
- before: 'e = consume (3, "- &FUBAR\n foo: bar\n")'
|
||||
- it recognizes a mapping start event:
|
||||
expect (e ().type).to_be "MAPPING_START"
|
||||
- it records anchors:
|
||||
expect (e ().anchor).to_be "FUBAR"
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 0, column = 2, index = 2}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 1, column = 2, index = 11}
|
||||
|
||||
- context with tag:
|
||||
- it recognizes local tags: '
|
||||
e = consume (2, "--- !something\nfoo: bar\n")
|
||||
expect (filter (e (), "type", "tag")).
|
||||
to_equal {type = "MAPPING_START", tag = "!something"}'
|
||||
- it recognizes global tags: '
|
||||
e = consume (2, "--- !!set\n" ..
|
||||
"? Mark McGwire\n" ..
|
||||
"? Sammy Sosa\n" ..
|
||||
"? Ken Griffy\n")
|
||||
expect (filter (e (), "type", "tag")).
|
||||
to_equal {type = "MAPPING_START",
|
||||
tag = "tag:yaml.org,2002:set"}'
|
||||
- it resolves %TAG declarations: '
|
||||
e = consume (3, "%TAG ! tag:clarkevans.com,2002:\n" ..
|
||||
"--- !shape\n" ..
|
||||
"- !circle\n" ..
|
||||
" center: &ORIGIN {x: 73, y: 129}\n" ..
|
||||
" radius: 7\n")
|
||||
expect (filter (e (), "type", "tag")).
|
||||
to_equal {type = "MAPPING_START",
|
||||
tag = "tag:clarkevans.com,2002:circle"}'
|
||||
|
||||
- context with style:
|
||||
- it recognizes block style: '
|
||||
e = consume (2, "foo: bar\nbaz:\n quux")
|
||||
expect (filter (e (), "type", "style")).
|
||||
to_equal {type = "MAPPING_START", style = "BLOCK"}'
|
||||
- it recognizes flow style: '
|
||||
e = consume (2, "{foo: bar, baz: quux}")
|
||||
expect (filter (e (), "type", "style")).
|
||||
to_equal {type = "MAPPING_START", style = "FLOW"}'
|
||||
|
||||
|
||||
- describe MAPPING_END:
|
||||
- before: 'e = consume (5, "foo: bar\n")'
|
||||
- it recognizes the mapping end event:
|
||||
expect (e ().type).to_equal "MAPPING_END"
|
||||
- it reports event start marker:
|
||||
expect (e ().start_mark).to_equal {line = 1, column = 0, index = 9}
|
||||
- it reports event end marker:
|
||||
expect (e ().end_mark).to_equal {line = 1, column = 0, index = 9}
|
||||
380
spec/ext_yaml_scanner_spec.yaml
Normal file
380
spec/ext_yaml_scanner_spec.yaml
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
# LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
# Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
|
||||
before:
|
||||
function consume (n, str)
|
||||
local k = yaml.scanner (str)
|
||||
for n = 1, n do k () end
|
||||
return k
|
||||
end
|
||||
|
||||
specify scanning:
|
||||
- it scans empty streams:
|
||||
k = yaml.scanner ""
|
||||
expect (k ().type).to_be "STREAM_START"
|
||||
expect (k ().type).to_be "STREAM_END"
|
||||
expect (k ()).to_be (nil)
|
||||
expect (k ()).to_be (nil)
|
||||
- it ignores comments: '
|
||||
k = yaml.scanner "# A comment\nnon-comment # trailing comment\n"
|
||||
expect (k ().type).to_be "STREAM_START"
|
||||
expect (k ().value).to_be "non-comment"
|
||||
expect (k ().type).to_be "STREAM_END"'
|
||||
|
||||
- describe STREAM_START:
|
||||
- before:
|
||||
k = yaml.scanner "# no BOM"
|
||||
- it is the first token:
|
||||
expect (k ().type).to_be "STREAM_START"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it uses UTF-8 by default:
|
||||
expect (k ().encoding).to_be "UTF8"
|
||||
- it recognizes UTF-16 BOM:
|
||||
k = yaml.scanner (BOM .. " BOM")
|
||||
expect (k ().encoding).to_match "UTF16[BL]E"
|
||||
|
||||
- describe STREAM_END:
|
||||
- before:
|
||||
for t in yaml.scanner "nothing to see" do k = t end
|
||||
- it is the last token:
|
||||
expect (k.type).to_be "STREAM_END"
|
||||
- it reports token start marker:
|
||||
expect (k.start_mark).to_equal {line = 1, column = 0, index = 14}
|
||||
- it reports token end marker:
|
||||
expect (k.end_mark).to_equal {line = 1, column = 0, index = 14}
|
||||
|
||||
- describe VERSION_DIRECTIVE:
|
||||
- before:
|
||||
k = consume (1, "%YAML 1.0")
|
||||
- it can recognize document versions:
|
||||
expect (filter (k (), "type", "major", "minor")).
|
||||
to_equal {type = "VERSION_DIRECTIVE", major = 1, minor = 0}
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 9, index = 9}
|
||||
|
||||
- describe TAG_DIRECTIVE:
|
||||
- it can recognize primary tag handles:
|
||||
k = consume (1, "%TAG ! tag:ben-kiki.org,2000:app/")
|
||||
expect (filter (k (), "handle", "prefix")).
|
||||
to_equal {handle = "!", prefix = "tag:ben-kiki.org,2000:app/"}
|
||||
- it can recognize secondary tag handles:
|
||||
k = consume (1, "%TAG !! tag:yaml.org,2002:")
|
||||
expect (filter (k (), "handle", "prefix")).
|
||||
to_equal {handle = "!!", prefix = "tag:yaml.org,2002:"}
|
||||
- it can recognize named tag handles:
|
||||
k = consume (1, "%TAG !o! tag:ben-kiki.org,2000:\n---")
|
||||
expect (filter (k (), "handle", "prefix")).
|
||||
to_equal {handle = "!o!", prefix = "tag:ben-kiki.org,2000:"}
|
||||
|
||||
- describe DOCUMENT_START:
|
||||
- before:
|
||||
k = consume (1, "---")
|
||||
- it recognizes document start marker:
|
||||
expect (k ().type).to_be "DOCUMENT_START"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 3, index = 3}
|
||||
|
||||
- describe DOCUMENT_END:
|
||||
- before:
|
||||
k = consume (2, "foo\n...")
|
||||
- it recognizes the document end marker:
|
||||
expect (k ().type).to_be "DOCUMENT_END"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 1, column = 0, index = 4}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 1, column = 3, index = 7}
|
||||
|
||||
- describe ALIAS:
|
||||
- before:
|
||||
k = consume (15, "---\n" ..
|
||||
"hr:\n" ..
|
||||
"- Mark McGwire\n" ..
|
||||
"- &SS Sammy Sosa\n" ..
|
||||
"rbi:\n" ..
|
||||
"- *SS\n" ..
|
||||
"- Ken Griffey")
|
||||
- it recognizes an alias token:
|
||||
expect (filter (k (), "type", "value")).
|
||||
to_equal {type = "ALIAS", value = "SS"}
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 5, column = 2, index = 47}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 5, column = 5, index = 50}
|
||||
|
||||
- describe ANCHOR:
|
||||
- before:
|
||||
k = consume (9, "---\n" ..
|
||||
"hr:\n" ..
|
||||
"- Mark McGwire\n" ..
|
||||
"- &SS Sammy Sosa\n" ..
|
||||
"rbi:\n" ..
|
||||
"- *SS\n" ..
|
||||
"- Ken Griffey")
|
||||
- it recognizes an anchor token:
|
||||
expect (filter (k (), "type", "value")).
|
||||
to_equal {type = "ANCHOR", value = "SS"}
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 3, column = 2, index = 25}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 3, column = 5, index = 28}
|
||||
|
||||
- describe SCALAR:
|
||||
- before:
|
||||
k = consume (10, "---\n" ..
|
||||
"hr:\n" ..
|
||||
"- Mark McGwire\n" ..
|
||||
"- &SS Sammy Sosa\n" ..
|
||||
"rbi:\n" ..
|
||||
"- *SS\n" ..
|
||||
"- Ken Griffey")
|
||||
- it recognizes a scalar token:
|
||||
expect (filter (k (), "type", "value")).
|
||||
to_equal {type = "SCALAR", value = "Sammy Sosa"}
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 3, column = 6, index = 29}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 3, column = 16, index = 39}
|
||||
|
||||
- context with quoting style:
|
||||
- context plain style:
|
||||
- before:
|
||||
k = consume (2, "---\n" ..
|
||||
" Mark McGwire's\n" ..
|
||||
" year was crippled\n" ..
|
||||
" by a knee injury.\n")
|
||||
- it ignores line-breaks and indentation:
|
||||
expect (k ().value).
|
||||
to_be "Mark McGwire's year was crippled by a knee injury."
|
||||
- it recognizes PLAIN style:
|
||||
expect (k ().style).to_be "PLAIN"
|
||||
- context folded style:
|
||||
- before:
|
||||
k = consume (1, ">\n" ..
|
||||
" Sammy Sosa completed another\n" ..
|
||||
" fine season with great stats.\n" ..
|
||||
"\n" ..
|
||||
" 63 Home Runs\n" ..
|
||||
" 0.288 Batting Average\n" ..
|
||||
"\n" ..
|
||||
" What a year!\n")
|
||||
- it preserves blank lines and deeper indentation:
|
||||
expect (k ().value).
|
||||
to_be ("Sammy Sosa completed another fine season with great stats.\n" ..
|
||||
"\n" ..
|
||||
" 63 Home Runs\n" ..
|
||||
" 0.288 Batting Average\n" ..
|
||||
"\n" ..
|
||||
"What a year!\n")
|
||||
- it recognizes FOLDED style:
|
||||
expect (k ().style).to_be "FOLDED"
|
||||
- context literal style:
|
||||
- before:
|
||||
k = consume (2, [[# ASCII Art]] .. "\n" ..
|
||||
[[--- |]] .. "\n" ..
|
||||
[[ \//||\/||]] .. "\n" ..
|
||||
[[ // || ||__]] .. "\n")
|
||||
- it removes indentation but preserves all line-breaks:
|
||||
expect (k ().value).
|
||||
to_be ([[\//||\/||]] .. "\n" ..
|
||||
[[// || ||__]] .. "\n")
|
||||
- it recognizes LITERAL style:
|
||||
expect (k ().style).to_be "LITERAL"
|
||||
|
||||
- context single quoted style:
|
||||
- before:
|
||||
k = consume (1, [['This quoted scalar]] .. "\n" ..
|
||||
[[ spans two lines.']])
|
||||
- it folds line breaks:
|
||||
expect (k ().value).
|
||||
to_be "This quoted scalar spans two lines."
|
||||
- it does not process escape sequences:
|
||||
# Lua [[ quoting makes sure libyaml sees all the quotes.
|
||||
k = consume (1, [['"Howdy!"\t\u263A']])
|
||||
expect (k ().value).to_be [["Howdy!"\t\u263A]]
|
||||
- it recognizes LITERAL style:
|
||||
expect (k ().style).to_be "SINGLE_QUOTED"
|
||||
|
||||
# Note that we have to single quote the Lua snippets to prevent
|
||||
# libyaml from interpreting the bytes as the spec file is read, so
|
||||
# that the raw strings get correctly passed to the Lua compiler.
|
||||
- context double quoted style:
|
||||
- it folds line breaks: '
|
||||
k = consume (5, [[quoted: "This quoted scalar]] .. "\n" ..
|
||||
[[ spans two lines\n"]])
|
||||
expect (k ().value).
|
||||
to_be "This quoted scalar spans two lines\n"'
|
||||
- it recognizes unicode escape sequences: '
|
||||
k = consume (5, [[unicode: "Sosa did fine.\u263A"]])
|
||||
expect (k ().value).to_be "Sosa did fine.\226\152\186"'
|
||||
- it recognizes control escape sequences: '
|
||||
k = consume (5, [[control: "\b1998\t1999\t2000\n"]])
|
||||
expect (k ().value).to_be "\b1998\t1999\t2000\n"'
|
||||
- it recognizes hexadecimal escape sequences: '
|
||||
k = consume (5, [[hexesc: "\x41\x42\x43 is ABC"]])
|
||||
expect (k ().value).to_be "ABC is ABC"'
|
||||
|
||||
- context indentation determines scope: '
|
||||
k = consume (5, "name: Mark McGwire\n" ..
|
||||
"accomplishment: >\n" ..
|
||||
" Mark set a major league\n" ..
|
||||
" home run record in 1998.\n" ..
|
||||
"stats: |\n" ..
|
||||
" 65 Home Runs\n" ..
|
||||
" 0.278 Batting Average\n")
|
||||
expect (k ().value).to_be "Mark McGwire"
|
||||
expect (k ().type).to_be "KEY"
|
||||
expect (k ().value).to_be "accomplishment"
|
||||
expect (k ().type).to_be "VALUE"
|
||||
expect (k ().value).
|
||||
to_be "Mark set a major league home run record in 1998.\n"
|
||||
expect (k ().type).to_be "KEY"
|
||||
expect (k ().value).to_be "stats"
|
||||
expect (k ().type).to_be "VALUE"
|
||||
expect (k ().value).to_be "65 Home Runs\n0.278 Batting Average\n"'
|
||||
|
||||
- describe TAG:
|
||||
- it recognizes local tags: '
|
||||
k = consume (5, "application specific tag: !something |\n" ..
|
||||
" The semantics of the tag\n" ..
|
||||
" above may be different for\n" ..
|
||||
" different documents.")
|
||||
expect (filter (k (), "type", "handle", "suffix")).
|
||||
to_equal {type = "TAG", handle = "!", suffix = "something"}'
|
||||
- it recognizes global tags: '
|
||||
k = consume (5, "picture: !!binary |\n" ..
|
||||
" R0lGODlhDAAMAIQAAP//9/X\n" ..
|
||||
" 17unp5WZmZgAAAOfn515eXv\n" ..
|
||||
" Pz7Y6OjuDg4J+fn5OTk6enp\n" ..
|
||||
" 56enmleECcgggoBADs=")
|
||||
expect (filter (k (), "type", "handle", "suffix")).
|
||||
to_equal {type = "TAG", handle = "!!", suffix = "binary"}'
|
||||
|
||||
- describe BLOCK_SEQUENCE_START:
|
||||
- before: '
|
||||
k = consume (5, "fubar:\n" ..
|
||||
" - foo\n" ..
|
||||
" - bar\n")'
|
||||
- it recognizes a sequence start token:
|
||||
expect (k ().type).to_be "BLOCK_SEQUENCE_START"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 1, column = 2, index = 9}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 1, column = 2, index = 9}
|
||||
|
||||
- describe BLOCK_MAPPING_START:
|
||||
- before: 'k = consume (3, "-\n foo: bar\n-")'
|
||||
- it recognizes a mapping start token:
|
||||
expect (k ().type).to_be "BLOCK_MAPPING_START"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 1, column = 2, index = 4}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 1, column = 2, index = 4}
|
||||
|
||||
- describe BLOCK_ENTRY:
|
||||
- before: 'k = consume (2, "-\n foo: bar\n-")'
|
||||
- it recognizes a sequence block entry token: '
|
||||
k = consume (8, "fubar:\n" ..
|
||||
" - foo\n" ..
|
||||
" - bar\n")
|
||||
expect (k ().type).to_be "BLOCK_ENTRY"'
|
||||
- it recognizes a mapping block entry token:
|
||||
expect (k ().type).to_be "BLOCK_ENTRY"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 1, index = 1}
|
||||
|
||||
- describe BLOCK_END:
|
||||
- before: 'k = consume (8, "-\n foo: bar\n-")'
|
||||
- it recognizes a sequence block end token: '
|
||||
k = consume (10, "fubar:\n" ..
|
||||
" - foo\n" ..
|
||||
" - bar\n")
|
||||
expect (k ().type).to_be "BLOCK_END"'
|
||||
- it recognizes a mapping block end token:
|
||||
expect (k ().type).to_be "BLOCK_END"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 2, column = 0, index = 13}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 2, column = 0, index = 13}
|
||||
|
||||
- describe FLOW_SEQUENCE_START:
|
||||
- before: '
|
||||
k = consume (5, "fubar: [foo, bar]\n")'
|
||||
- it recognizes a sequence start token:
|
||||
expect (k ().type).to_be "FLOW_SEQUENCE_START"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 7, index = 7}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 8, index = 8}
|
||||
|
||||
- describe FLOW_SEQUENCE_END:
|
||||
- before: '
|
||||
k = consume (9, "fubar: [foo, bar]\n")'
|
||||
- it recognizes a sequence end token:
|
||||
expect (k ().type).to_equal "FLOW_SEQUENCE_END"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 16, index = 16}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 17, index = 17}
|
||||
|
||||
- describe FLOW_ENTRY:
|
||||
- before: 'k = consume (6, "{foo: bar, baz: quux}")'
|
||||
- it recognizes a sequence flow entry: '
|
||||
k = consume (6, "[foo: bar, baz: quux]")
|
||||
expect (k ().type).to_be "FLOW_ENTRY"'
|
||||
- it recognizes a mapping flow entry:
|
||||
expect (k ().type).to_be "FLOW_ENTRY"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 9, index = 9}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 10, index = 10}
|
||||
|
||||
- describe FLOW_MAPPING_START:
|
||||
- before: 'k = consume (1, "{foo: bar, baz: quux}")'
|
||||
- it recognizes flow style:
|
||||
expect (k ().type).to_be "FLOW_MAPPING_START"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 0, index = 0}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 1, index = 1}
|
||||
|
||||
- describe FLOW_MAPPING_END:
|
||||
- before: 'k = consume (6, "{foo: bar}\n")'
|
||||
- it recognizes the mapping end token:
|
||||
expect (k ().type).to_equal "FLOW_MAPPING_END"
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 9, index = 9}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 10, index = 10}
|
||||
|
||||
- describe KEY:
|
||||
- before: 'k = consume (2, "{the key: the value, another key: meh}")'
|
||||
- it recognizes a flow mapping key token:
|
||||
expect (k ().type).to_be "KEY"
|
||||
- it recognizes a block mapping key token: '
|
||||
k = consume (2, "the key: the value\nanother key: meh\n")
|
||||
expect (k ().type).to_be "KEY"'
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 1, index = 1}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 1, index = 1}
|
||||
|
||||
- describe VALUE:
|
||||
- before: 'k = consume (4, "{the key: the value, another key: meh}")'
|
||||
- it recognizes a flow mapping value token:
|
||||
expect (k ().type).to_be "VALUE"
|
||||
- it recognizes a block mapping key value: '
|
||||
k = consume (4, "the key: the value\nanother key: meh\n")
|
||||
expect (k ().type).to_be "VALUE"'
|
||||
- it reports token start marker:
|
||||
expect (k ().start_mark).to_equal {line = 0, column = 8, index = 8}
|
||||
- it reports token end marker:
|
||||
expect (k ().end_mark).to_equal {line = 0, column = 9, index = 9}
|
||||
121
spec/lib_lyaml_functional_spec.yaml
Normal file
121
spec/lib_lyaml_functional_spec.yaml
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
# LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
# Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
|
||||
before:
|
||||
this_module = 'lyaml.functional'
|
||||
global_table = '_G'
|
||||
|
||||
exported_apis = {'NULL', 'anyof', 'id', 'iscallable', 'isnull'}
|
||||
|
||||
M = require(this_module)
|
||||
|
||||
nop = function() end
|
||||
|
||||
fail = function() return nil end
|
||||
pass = function() return false end
|
||||
throw = function() error 'oh noes!' end
|
||||
|
||||
parmlist = pack(
|
||||
nil,
|
||||
false,
|
||||
42,
|
||||
'str',
|
||||
io.stderr,
|
||||
{},
|
||||
nop,
|
||||
setmetatable({}, {__call=nop})
|
||||
)
|
||||
|
||||
|
||||
specify functional:
|
||||
- context when required:
|
||||
- context by name:
|
||||
- it does not touch the global table:
|
||||
expect(show_apis{added_to=global_table, by=this_module}).to_equal{}
|
||||
- it exports the decumented apis:
|
||||
t = {}
|
||||
for k in pairs(M) do t[#t + 1] = k end
|
||||
expect(t).to_contain.a_permutation_of(exported_apis)
|
||||
|
||||
|
||||
- describe anyof:
|
||||
- before:
|
||||
f = M.anyof
|
||||
|
||||
- it returns a callable:
|
||||
expect(f{nop}).to_be_callable()
|
||||
expect(f{nop, nop}).to_be_callable()
|
||||
- it returns a lazy function that calls arguments if necessary:
|
||||
expect(f{pass, throw}()).not_to_raise 'any error'
|
||||
expect(f{pass, throw}()).not_to_be(nil)
|
||||
- it silently skips non-callable arguments:
|
||||
expect(f(list({nil, false, true}))()).to_be(nil)
|
||||
expect(f{1, 2, pass, 'pass'}()).not_to_be(nil)
|
||||
- it returns non-nil if any callable returns non-nil:
|
||||
expect(f{pass, pass, fail}()).not_to_be(nil)
|
||||
expect(f{pass, fail}()).not_to_be(nil)
|
||||
expect(f{fail, pass}()).not_to_be(nil)
|
||||
- it returns nil if all callables are nil:
|
||||
expect(f{fail}()).to_be(nil)
|
||||
expect(f{fail, fail}()).to_be(nil)
|
||||
expect(f{fail, fail, fail}()).to_be(nil)
|
||||
- it propagates data to all callables:
|
||||
expect(f{fail, function(...) return select('#', ...) end}(nil)).to_be(1)
|
||||
expect(f{function(...) return select('#', ...) end, fail}(nil, false)).to_be(2)
|
||||
expect(f{function(...) return select('#', ...) end, pass}(nil, false)).to_be(2)
|
||||
- it returns the first non-nil callables result:
|
||||
expect(f{fail, function(...) return ... end}(42)).to_be(42)
|
||||
expect(f{function(...) return ... end, fail}(42)).to_be(42)
|
||||
expect(f{pass, fail}(42)).to_be(false)
|
||||
expect(f{fail, pass}(42)).to_be(false)
|
||||
- it propagates only the first return value:
|
||||
expect(f{fail, function(...) return ... end}(1, 2, 5)).to_be(1)
|
||||
expect(f{function(...) return ... end, fail}(1, 2, 5)).to_be(1)
|
||||
expect(f{function(...) return ... end, pass}(1, 2, 5)).to_be(1)
|
||||
|
||||
|
||||
- describe id:
|
||||
- before:
|
||||
f = M.id
|
||||
|
||||
- it returns its own argument:
|
||||
expect(f(false)).to_be(false)
|
||||
expect(f(42)).to_be(42)
|
||||
- it handles nil argumen:
|
||||
expect(f(nil)).to_be(nil)
|
||||
- it handles missing argument:
|
||||
expect(f()).to_be()
|
||||
- it returns multiple arguments:
|
||||
expect(f(nil, 1, fn, false, nil)).to_be(nil, 1, fn, false, nil)
|
||||
|
||||
|
||||
- describe iscallable:
|
||||
- before:
|
||||
f = M.iscallable
|
||||
|
||||
- it returns callable for a callable:
|
||||
expect(f(f)).to_be(f)
|
||||
expect(f(setmetatable({}, {__call=f}))).to_be(f)
|
||||
- it returns nil for a non-callable:
|
||||
expect(f()).to_be(nil)
|
||||
expect(f(nil)).to_be(nil)
|
||||
expect(f(false)).to_be(nil)
|
||||
expect(f(true)).to_be(nil)
|
||||
expect(f'str').to_be(nil)
|
||||
expect(f(42)).to_be(nil)
|
||||
expect(f(setmetatable({}, {__index={}}))).to_be(nil)
|
||||
expect(f(setmetatable({}, {__call=42}))).to_be(nil)
|
||||
|
||||
|
||||
- describe isnull:
|
||||
- before:
|
||||
NULL = M.NULL
|
||||
f = M.isnull
|
||||
|
||||
- it returns 'true' for a NULL argument:
|
||||
expect(f(NULL)).to_be(true)
|
||||
- it returns 'false' for any argument other than NULL:
|
||||
for i=1,parmlist.n do
|
||||
expect(f(parmlist[i])).to_be(false)
|
||||
end
|
||||
|
||||
343
spec/lib_lyaml_spec.yaml
Normal file
343
spec/lib_lyaml_spec.yaml
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
# LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
# Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
|
||||
before: |
|
||||
lyaml = require "lyaml"
|
||||
|
||||
-- Always use the new multi-doc capable API.
|
||||
lyaml.legacy = lyaml.load
|
||||
lyaml.load = function (stream) return lyaml.legacy (stream, true) end
|
||||
|
||||
specify lyaml:
|
||||
- describe dumping:
|
||||
- context streams:
|
||||
- it writes an empty stream:
|
||||
expect (lyaml.dump {}).to_equal ""
|
||||
|
||||
- context documents:
|
||||
- it writes an empty document:
|
||||
expect (lyaml.dump {""}).to_match "^%-%-%-%s*''\n%.%.%.%s*$"
|
||||
- it writes consecutive documents:
|
||||
expect (lyaml.dump {"one", "two"}).
|
||||
to_match "^%-%-%-%s+one%s*\n%.%.%.%s*\n%-%-%-%s+two%s*\n%.%.%.%s*$"
|
||||
|
||||
- context scalars:
|
||||
- it writes null:
|
||||
expect (lyaml.dump {lyaml.null}).to_be "--- ~\n...\n"
|
||||
expect (lyaml.dump {"~"}).to_be "--- '~'\n...\n"
|
||||
- it writes booleans:
|
||||
expect (lyaml.dump {"true"}).to_be "--- 'true'\n...\n"
|
||||
expect (lyaml.dump {"yes"}).to_be "--- 'yes'\n...\n"
|
||||
expect (lyaml.dump {"false"}).to_be "--- 'false'\n...\n"
|
||||
expect (lyaml.dump {"no"}).to_be "--- 'no'\n...\n"
|
||||
expect (lyaml.dump {true}).to_be "--- true\n...\n"
|
||||
expect (lyaml.dump {false}).to_be "--- false\n...\n"
|
||||
- it writes numbers:
|
||||
expect (lyaml.dump {"123"}).to_be "--- '123'\n...\n"
|
||||
expect (lyaml.dump {"12.3"}).to_be "--- '12.3'\n...\n"
|
||||
expect (lyaml.dump {"0/0"}).to_be "--- 0/0\n...\n"
|
||||
expect (lyaml.dump {123}).to_be "--- 123\n...\n"
|
||||
expect (lyaml.dump {12.3}).to_be "--- 12.3\n...\n"
|
||||
expect (lyaml.dump {0/0}).to_be "--- .nan\n...\n"
|
||||
expect (lyaml.dump {math.huge}).to_be "--- .inf\n...\n"
|
||||
expect (lyaml.dump {-math.huge}).to_be "--- -.inf\n...\n"
|
||||
- it writes strings:
|
||||
expect (lyaml.dump {"a string"}).to_be "--- a string\n...\n"
|
||||
expect (lyaml.dump {"'a string'"}).to_be "--- '''a string'''\n...\n"
|
||||
expect (lyaml.dump {"a\nmultiline\nstring"}).to_be "--- |-\n a\n multiline\n string\n...\n"
|
||||
expect (lyaml.dump {""}).to_be "--- ''\n...\n"
|
||||
|
||||
- context sequences:
|
||||
- it writes a sequence:
|
||||
expect (lyaml.dump {{1, 2, 3}}).to_contain "- 1\n- 2\n- 3"
|
||||
|
||||
- context mappings:
|
||||
- it writes a mapping: |
|
||||
expect (lyaml.dump {{a=1, b=2, c=3, d=""}}).
|
||||
to_contain.all_of {"a: 1", "b: 2", "c: 3", "d: ''"}
|
||||
- it writes a mapping of mixed keys: |
|
||||
expect (lyaml.dump {{[1]=1, [2]=2, three="three", four="4", [5]="five"}}).
|
||||
to_contain.all_of {"1: 1", "2: 2", "three: three", "four: '4'", "5: five"}
|
||||
- it writes a mapping of integer keys starting at two: |
|
||||
expect (lyaml.dump {{[2]=2, [3]=3, [4]=4}}).
|
||||
to_contain.all_of {"2: 2", "3: 3", "4: 4"}
|
||||
- it writes a mapping of mixed keys starting at one: |
|
||||
expect (lyaml.dump {{[1]=1, [2]=2, [3]=3, foo="bar"}}).
|
||||
to_contain.all_of {"1: 1", "2: 2", "3: 3", "foo: bar"}
|
||||
- it writes a mapping of mixed keys starting at two: |
|
||||
expect (lyaml.dump {{[2]=2, [3]=3, [4]=4, foo="bar"}}).
|
||||
to_contain.all_of {"2: 2", "3: 3", "4: 4", "foo: bar"}
|
||||
- it writes a table containing nils (jumps in index) as mapping: |
|
||||
expect (lyaml.dump {{1, 2, nil, 3, 4}}).
|
||||
to_contain.all_of {"1: 1", "2: 2", "4: 3", "5: 4"}
|
||||
|
||||
- context anchors and aliases:
|
||||
- before:
|
||||
anchors = {
|
||||
MAP = {["Mark McGwire"] = 65, ["Sammy Sosa"] = 63},
|
||||
SEQ = {"Mark McGwire", "Sammy Sosa"},
|
||||
}
|
||||
- it writes scalar anchors: '
|
||||
anchors = { SS = "Sammy Sosa" }
|
||||
expect (lyaml.dump ({{{anchor = anchors.SS}, {alias = anchors.SS}}}, anchors)).
|
||||
to_contain "- anchor: &SS Sammy Sosa\n- alias: *SS\n"'
|
||||
- it writes sequence anchors: '
|
||||
expect (lyaml.dump ({{{anchor = anchors.SEQ}, {alias = anchors.SEQ}}}, anchors)).
|
||||
to_contain "\n- anchor: &SEQ\n - Mark McGwire\n - Sammy Sosa\n- alias: *SEQ\n"'
|
||||
- it writes mapping anchors: '
|
||||
expect (lyaml.dump ({{{anchor = anchors.MAP}, {alias = anchors.MAP}}}, anchors)).
|
||||
to_match "\n%- anchor: &MAP\n %w+ %w+: %d+\n %w+ %w+: %d+\n%- alias: %*MAP\n"'
|
||||
|
||||
|
||||
- describe loading:
|
||||
- before:
|
||||
fn = lyaml.load
|
||||
|
||||
- it loads an empty stream:
|
||||
expect (fn "").to_equal {}
|
||||
- it ignores comments: '
|
||||
expect (fn "# A comment\nnon-comment # trailing comment\n").
|
||||
to_equal { "non-comment" }'
|
||||
- it diagnoses unexpected events: '
|
||||
expect (fn "...").to_error "1:1: did not find expected node content"
|
||||
expect (fn "---\n...\ngarbage\n").
|
||||
to_error "2:1: did not find expected <document start>"
|
||||
expect (fn " *ALIAS").
|
||||
to_error "1:2: invalid reference: ALIAS"'
|
||||
|
||||
- context documents:
|
||||
- it lyaml.loads an empty document:
|
||||
expect (fn "---").to_equal {lyaml.null}
|
||||
expect (fn "---\n").to_equal {lyaml.null}
|
||||
expect (fn "---\n...").to_equal {lyaml.null}
|
||||
expect (fn "---\n...\n").to_equal {lyaml.null}
|
||||
- it lyaml.loads multiple documents:
|
||||
expect (fn "one\n---\ntwo").to_equal {"one", "two"}
|
||||
expect (fn "---\none\n---\ntwo").to_equal {"one", "two"}
|
||||
expect (fn "one\n...\n---\ntwo\n...").to_equal {"one", "two"}
|
||||
expect (fn "---\none\n...\n---\ntwo\n...").to_equal {"one", "two"}
|
||||
- it reports an empty document:
|
||||
expect (fn "---\n---\ntwo\n---").
|
||||
to_equal {lyaml.null, "two", lyaml.null}
|
||||
expect (fn "---\n...\n---\ntwo\n---").
|
||||
to_equal {lyaml.null, "two", lyaml.null}
|
||||
expect (fn "---\n...\n---\ntwo\n...\n---").
|
||||
to_equal {lyaml.null, "two", lyaml.null}
|
||||
expect (fn "---\n...\n---\ntwo\n...\n---\n...").
|
||||
to_equal {lyaml.null, "two", lyaml.null}
|
||||
|
||||
- context version directive:
|
||||
- it recognizes version number:
|
||||
expect (fn "%YAML 1.1\n---").to_equal {lyaml.null}
|
||||
- it diagneses missing document start:
|
||||
expect (fn "%YAML 1.1").
|
||||
to_error "expected <document start>"
|
||||
- it diagnoses unsupported version:
|
||||
expect (fn "%YAML 2.0\n---").
|
||||
to_error "incompatible YAML document"
|
||||
|
||||
- context tag directive:
|
||||
- it recognizes primary tag directive: '
|
||||
expect (fn ("%TAG ! tag:yaml.org,2002:\n" ..
|
||||
"---\n" ..
|
||||
"!bool N")).to_equal {false}'
|
||||
- it recognizes secondary tag directive: '
|
||||
expect (fn ("%TAG !! tag:ben-kiki.org,2000:\n" ..
|
||||
"---\n" ..
|
||||
"!!bool untrue")).to_equal {"untrue"}'
|
||||
- it recognizes named tag directive: '
|
||||
expect (fn ("%TAG !bkk! tag:ben-kiki.org,2000:\n" ..
|
||||
"---\n" ..
|
||||
"!bkk!bool untrue")).to_equal {"untrue"}'
|
||||
- it diagnoses undefined tag handles: '
|
||||
expect (fn ("!bkk!bool untrue")).
|
||||
to_error "undefined tag handle"'
|
||||
|
||||
- context scalars:
|
||||
- it recognizes null: '
|
||||
expect (fn "~").to_equal {lyaml.null}
|
||||
expect (fn "foo: ").to_equal {{foo = lyaml.null}}
|
||||
expect (fn "foo: ~").to_equal {{foo = lyaml.null}}
|
||||
expect (fn "foo: !!null").to_equal {{foo = lyaml.null}}
|
||||
expect (fn "foo: null").to_equal {{foo = lyaml.null}}
|
||||
expect (fn "foo: Null").to_equal {{foo = lyaml.null}}
|
||||
expect (fn "foo: NULL").to_equal {{foo = lyaml.null}}'
|
||||
- it recognizes booleans: '
|
||||
expect (fn "true").to_equal {true}
|
||||
expect (fn "false").to_equal {false}
|
||||
expect (fn "yes").to_equal {true}
|
||||
expect (fn "no").to_equal {false}'
|
||||
- it loads bare y and n as strings:
|
||||
expect (fn "y").to_equal {"y"}
|
||||
expect (fn "n").to_equal {"n"}
|
||||
- it recognizes integers:
|
||||
expect (fn "0b001010011010").to_equal {666}
|
||||
expect (fn "0b0010_1001_1010").to_equal {666}
|
||||
expect (fn "+0b001_010_011_010").to_equal {666}
|
||||
expect (fn "-0b0010_1001_1010").to_equal {-666}
|
||||
expect (fn "0_1232").to_equal {666}
|
||||
expect (fn "-01232").to_equal {-666}
|
||||
expect (fn "666").to_equal {666}
|
||||
expect (fn "0x29a").to_equal {666}
|
||||
expect (fn "-0x29a").to_equal {-666}
|
||||
expect (fn "12_345_678").to_equal {12345678}
|
||||
expect (fn "11:6").to_equal {666}
|
||||
- it recognizes floats:
|
||||
expect (fn "12.3").to_equal {12.3}
|
||||
expect (fn "685.230_15e+03").to_equal {685230.15}
|
||||
expect (fn "685_230.15e+03").to_equal {685230150.0}
|
||||
expect (fn "12_345_678.9").to_equal {12345678.9}
|
||||
expect (fn "11:6.777").to_equal {666.777}
|
||||
expect (fn ".Inf").to_equal {math.huge}
|
||||
expect (fn "-.inf").to_equal {-math.huge}
|
||||
nant = fn ".NaN"
|
||||
expect (nant[1]).not_to_equal (nant[1])
|
||||
- it recognizes strings:
|
||||
expect (fn "a string").to_equal {"a string"}
|
||||
expect (fn "'''a string'''").to_equal {"'a string'"}
|
||||
expect (fn "|-\n a\n multiline\n string").to_equal {"a\nmultiline\nstring"}
|
||||
expect (fn "'yes'").to_equal {"yes"}
|
||||
expect (fn "''").to_equal {""}
|
||||
expect (fn '""').to_equal {""}
|
||||
|
||||
- context global tags:
|
||||
- it recognizes !!null:
|
||||
expect (fn "!!null").to_equal {lyaml.null}
|
||||
- it recognizes !!bool: |
|
||||
expect (fn '!!bool "true"').to_equal {true}
|
||||
expect (fn '!!bool true').to_equal {true}
|
||||
expect (fn '!!bool True').to_equal {true}
|
||||
expect (fn '!!bool TRUE').to_equal {true}
|
||||
expect (fn "!!bool 'false'").to_equal {false}
|
||||
expect (fn '!!bool false').to_equal {false}
|
||||
expect (fn '!!bool False').to_equal {false}
|
||||
expect (fn '!!bool FALSE').to_equal {false}
|
||||
expect (fn '!!bool "yes"').to_equal {true}
|
||||
expect (fn "!!bool 'Yes'").to_equal {true}
|
||||
expect (fn '!!bool YES').to_equal {true}
|
||||
expect (fn '!!bool no').to_equal {false}
|
||||
expect (fn "!!bool 'No'").to_equal {false}
|
||||
expect (fn '!!bool "NO"').to_equal {false}
|
||||
expect (fn '!!bool garbage').
|
||||
to_raise "invalid 'tag:yaml.org,2002:bool' value: 'garbage'"
|
||||
- it loads explicit y and n as booleans:
|
||||
expect (fn '!!bool Y').to_equal {true}
|
||||
expect (fn '!!bool y').to_equal {true}
|
||||
expect (fn '!!bool N').to_equal {false}
|
||||
expect (fn '!!bool n').to_equal {false}
|
||||
- it recognizes !!float: |
|
||||
expect (fn '!!float 42').to_equal {42.0}
|
||||
expect (fn '!!float "42"').to_equal {42.0}
|
||||
expect (fn '!!float +42').to_equal {42.0}
|
||||
expect (fn '!!float 12.3').to_equal {12.3}
|
||||
expect (fn '!!float -3.141592').to_equal {-3.141592}
|
||||
expect (fn '!!float 685_230.15e+03').to_equal {685230150.0}
|
||||
expect (fn '!!float +685.230_15e+03').to_equal {685230.15}
|
||||
expect (fn '!!float 12_345_678.9').to_equal {12345678.9}
|
||||
expect (fn '!!float -0:3:11:6.777').to_equal {-11466.777}
|
||||
expect (fn '!!float .Inf').to_equal {math.huge}
|
||||
expect (fn '!!float -.inf').to_equal {-math.huge}
|
||||
nant = fn '!!float .NaN'
|
||||
expect (nant[1]).not_to_equal (nant[1])
|
||||
expect (fn '!!float garbage').
|
||||
to_raise "invalid 'tag:yaml.org,2002:float' value: 'garbage'"
|
||||
- it recognizes !!int: |
|
||||
expect (fn '!!int 0b0010_1001_1010').to_equal {666}
|
||||
expect (fn '!!int "+0b001_010_011_010"').to_equal {666}
|
||||
expect (fn '!!int -0b0010_1001_1010').to_equal {-666}
|
||||
expect (fn '!!int 0_1232').to_equal {666}
|
||||
expect (fn '!!int "-01232"').to_equal {-666}
|
||||
expect (fn '!!int 666').to_equal {666}
|
||||
expect (fn '!!int 0668').to_equal {668}
|
||||
expect (fn '!!int "0x29a"').to_equal {666}
|
||||
expect (fn '!!int -0x29a').to_equal {-666}
|
||||
expect (fn '!!int 12_345_678').to_equal {12345678}
|
||||
expect (fn '!!int 11:6').to_equal {666}
|
||||
expect (fn '!!int 12.3').
|
||||
to_raise "invalid 'tag:yaml.org,2002:int' value: '12.3'"
|
||||
expect (fn '!!int garbage').
|
||||
to_raise "invalid 'tag:yaml.org,2002:int' value: 'garbage'"
|
||||
|
||||
- context sequences:
|
||||
- it recognizes block sequences:
|
||||
expect (fn "- ~\n- \n- true\n- 42").
|
||||
to_equal {{lyaml.null, lyaml.null, true, 42}}
|
||||
- it recognizes flow sequences:
|
||||
expect (fn "[~, true, 42]").
|
||||
to_equal {{lyaml.null, true, 42}}
|
||||
|
||||
- context anchors and aliases:
|
||||
- it resolves scalar anchors: '
|
||||
expect (fn "anchor: &SS Sammy Sosa\nalias: *SS").
|
||||
to_equal {{anchor = "Sammy Sosa", alias = "Sammy Sosa"}}'
|
||||
- it resolves sequence anchors: '
|
||||
expect (fn "anchor: &SEQ [Mark McGwire, Sammy Sosa]\nalias: *SEQ").
|
||||
to_equal {{anchor = {"Mark McGwire", "Sammy Sosa"},
|
||||
alias = {"Mark McGwire", "Sammy Sosa"}}}'
|
||||
- it resolves mapping anchors: '
|
||||
expect (fn "anchor: &MAP {Mark McGwire: 65, Sammy Sosa: 63}\nalias: *MAP").
|
||||
to_equal {{anchor = {["Mark McGwire"] = 65, ["Sammy Sosa"] = 63},
|
||||
alias = {["Mark McGwire"] = 65, ["Sammy Sosa"] = 63}}}'
|
||||
|
||||
- context a map:
|
||||
- it recognizes block mapping: |
|
||||
expect (fn "'null': ~\nboolean: yes\nnumber: 3.14").
|
||||
to_equal {{null = lyaml.null, boolean = true, number = 3.14}}
|
||||
- it recognizes flow mapping: |
|
||||
expect (fn "{null: null, boolean: yes, number: 3.14}").
|
||||
to_equal {{[lyaml.null] = lyaml.null, boolean = true, number = 3.14}}
|
||||
- context with merge keys:
|
||||
- before: |
|
||||
merge = {x=1, y=2}
|
||||
override = {x=0, z=2}
|
||||
bogus = true
|
||||
YAML = "- &MERGE {x: 1, y: 2}\n" ..
|
||||
"- &OVERRIDE {x: 0, z: 2}\n" ..
|
||||
"- &BOGUS true\n"
|
||||
- it diagnoses invalid merge events: |
|
||||
expect (fn "-\n !!merge : x\n z: 3").
|
||||
to_raise "invalid 'tag:yaml.org,2002:merge' merge event: x"
|
||||
expect (fn "-\n << : x\n z: 3").
|
||||
to_raise "invalid '<<' merge event: x"
|
||||
- it diagnoses invalid merge alias types: |
|
||||
expect (fn (YAML .. "-\n !!merge : *BOGUS")).
|
||||
to_raise "invalid 'tag:yaml.org,2002:merge' merge event: true"
|
||||
expect (fn (YAML .. "-\n << : *BOGUS")).
|
||||
to_raise "invalid '<<' merge event: true"
|
||||
- it diagnoses invalid merge sequence elements: |
|
||||
expect (fn (YAML .. '-\n !!merge : [*MERGE, OVERRIDE]')).
|
||||
to_raise "invalid 'tag:yaml.org,2002:merge' sequence element 2: OVERRIDE"
|
||||
expect (fn (YAML .. '-\n <<: [*MERGE, OVERRIDE]')).
|
||||
to_raise "invalid '<<' sequence element 2: OVERRIDE"
|
||||
- it diagnoses invalid merge sequence alias tyes: |
|
||||
expect (fn (YAML .. '-\n !!merge : [*MERGE, *BOGUS]')).
|
||||
to_raise "invalid 'tag:yaml.org,2002:merge' sequence element 2: true"
|
||||
expect (fn (YAML .. '-\n <<: [*MERGE, *BOGUS]')).
|
||||
to_raise "invalid '<<' sequence element 2: true"
|
||||
- it supports merging bare maps: |
|
||||
expect (fn ("-\n !!merge : {x: 1, y: 2}\n z: 3")).
|
||||
to_equal {{{x=1, y=2, z=3}}}
|
||||
expect (fn "-\n <<: {x: 1, y: 2}\n z: 3").
|
||||
to_equal {{{x=1, y=2, z=3}}}
|
||||
- it supports merging map aliases: |
|
||||
expect (fn (YAML .. "-\n !!merge : *MERGE\n z: 3")).
|
||||
to_equal {{merge, override, bogus, {x=1, y=2, z=3}}}
|
||||
expect (fn (YAML .. "-\n <<: *MERGE\n z: 3")).
|
||||
to_equal {{merge, override, bogus, {x=1, y=2, z=3}}}
|
||||
- it merges sequence of bare maps with decreasing precedence: |
|
||||
expect (fn "-\n !!merge : [{x: 1, y: 2}, {x: 0, z: 2}]\n z: 3").
|
||||
to_equal {{{x=1, y=2, z=3}}}
|
||||
expect (fn "-\n <<: [{x: 1, y: 2}, {x: 0, z: 2}]\n z: 3").
|
||||
to_equal {{{x=1, y=2, z=3}}}
|
||||
- it merges sequence of aliases with decreasing precedence: |
|
||||
expect (fn (YAML .. "-\n !!merge : [*MERGE, *OVERRIDE]\n z: 3")).
|
||||
to_equal {{merge, override, bogus, {x=1, y=2, z=3}}}
|
||||
expect (fn (YAML .. "-\n <<: [*MERGE, *OVERRIDE]\n z: 3")).
|
||||
to_equal {{merge, override, bogus, {x=1, y=2, z=3}}}
|
||||
- it merges a sequence alias with decreasing precedence: |
|
||||
seq = {merge, override}
|
||||
r = {{merge, override, bogus, seq, {x=1, y=2, z=3}}}
|
||||
expect (fn (YAML .. "- &SEQ [*MERGE, *OVERRIDE]\n" ..
|
||||
"-\n !!merge : *SEQ\n z: 3")).to_equal (r)
|
||||
expect (fn (YAML .. "- &SEQ [*MERGE, *OVERRIDE]\n" ..
|
||||
"-\n <<: *SEQ\n z: 3")).to_equal (r)
|
||||
277
spec/spec_helper.lua
Normal file
277
spec/spec_helper.lua
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
--[[
|
||||
LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
|
||||
Copyright (C) 2013-2022 Gary V. Vaughan
|
||||
]]
|
||||
|
||||
do
|
||||
local std = require 'specl.std'
|
||||
local spawn = require 'specl.shell'.spawn
|
||||
local objdir = spawn('./build-aux/luke --value=objdir').output
|
||||
|
||||
|
||||
package.path = std.package.normalize(
|
||||
'./lib/?.lua',
|
||||
'./lib/?/init.lua',
|
||||
package.path
|
||||
)
|
||||
package.cpath = std.package.normalize(
|
||||
'./' .. objdir:match("^objdir='(.*)'") .. '/?.so',
|
||||
'./' .. objdir:match("^objdir='(.*)'") .. '/?.dll',
|
||||
package.cpath
|
||||
)
|
||||
end
|
||||
|
||||
local hell = require 'specl.shell'
|
||||
|
||||
|
||||
yaml = require 'yaml'
|
||||
|
||||
BOM = string.char(254, 255) -- UTF-16 Byte Order Mark
|
||||
|
||||
-- Allow use of bare 'pack' and 'unpack' even in Lua > 5.2.
|
||||
pack = table.pack or function(...) return {n = select('#', ...), ...} end
|
||||
unpack = table.unpack or unpack
|
||||
list = pack
|
||||
|
||||
|
||||
function dump(e)
|
||||
print(std.string.prettytostring(e))
|
||||
end
|
||||
|
||||
|
||||
function github_issue(n)
|
||||
return 'see http://github.com/gvvaughan/lyaml/issues/' .. tostring(n)
|
||||
end
|
||||
|
||||
|
||||
-- Output a list of event tables to the given emitter.
|
||||
function emitevents(emitter, list)
|
||||
for _, v in ipairs(list) do
|
||||
if type(v) == 'string' then
|
||||
ok, msg = emitter.emit {type=v}
|
||||
elseif type(v) == 'table' then
|
||||
ok, msg = emitter.emit(v)
|
||||
else
|
||||
error 'expected table or string argument'
|
||||
end
|
||||
|
||||
if not ok then
|
||||
error(msg)
|
||||
elseif ok and msg then
|
||||
return msg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Create a new emitter and send STREAM_START, listed events and STREAM_END.
|
||||
function emit(list)
|
||||
local emitter = yaml.emitter()
|
||||
emitter.emit {type='STREAM_START'}
|
||||
emitevents(emitter, list)
|
||||
local _, msg = emitter.emit {type='STREAM_END'}
|
||||
return msg
|
||||
end
|
||||
|
||||
|
||||
-- Create a new parser for STR, and consume the first N events.
|
||||
function consume(n, str)
|
||||
local e = yaml.parser(str)
|
||||
for n = 1, n do
|
||||
e()
|
||||
end
|
||||
return e
|
||||
end
|
||||
|
||||
|
||||
-- Return a new table with only elements of T that have keys listed
|
||||
-- in the following arguments.
|
||||
function filter(t, ...)
|
||||
local u = {}
|
||||
for _, k in ipairs {...} do
|
||||
u[k] = t[k]
|
||||
end
|
||||
return u
|
||||
end
|
||||
|
||||
|
||||
function iscallable(x)
|
||||
return type(x) == 'function' or type((getmetatable(x) or {}).__call) == 'function'
|
||||
end
|
||||
|
||||
|
||||
local function mkscript(code)
|
||||
local f = os.tmpname()
|
||||
local h = io.open(f, 'w')
|
||||
-- TODO: Move this into specl, or expose arguments so that we can
|
||||
-- turn this on and off based on specl `--coverage` arg.
|
||||
h:write "pcall(require, 'luacov')"
|
||||
h:write(code)
|
||||
h:close()
|
||||
return f
|
||||
end
|
||||
|
||||
|
||||
-- Allow user override of LUA binary used by hell.spawn, falling
|
||||
-- back to environment PATH search for 'lua' if nothing else works.
|
||||
local LUA = os.getenv 'LUA' or 'lua'
|
||||
|
||||
|
||||
--- Run some Lua code with the given arguments and input.
|
||||
-- @string code valid Lua code
|
||||
-- @tparam[opt={}] string|table arg single argument, or table of
|
||||
-- arguments for the script invocation.
|
||||
-- @string[opt] stdin standard input contents for the script process
|
||||
-- @treturn specl.shell.Process|nil status of resulting process if
|
||||
-- execution was successful, otherwise nil
|
||||
function luaproc(code, arg, stdin)
|
||||
local f = mkscript(code)
|
||||
if type(arg) ~= 'table' then arg = {arg} end
|
||||
local cmd = {LUA, f, unpack(arg)}
|
||||
-- inject env and stdin keys separately to avoid truncating `...` in
|
||||
-- cmd constructor
|
||||
cmd.env = { LUA_PATH=package.path, LUA_INIT='', LUA_INIT_5_2='' }
|
||||
cmd.stdin = stdin
|
||||
local proc = hell.spawn(cmd)
|
||||
os.remove(f)
|
||||
return proc
|
||||
end
|
||||
|
||||
|
||||
local function tabulate_output(code)
|
||||
local proc = luaproc(code)
|
||||
if proc.status ~= 0 then return error(proc.errout) end
|
||||
local r = {}
|
||||
proc.output:gsub('(%S*)[%s]*',
|
||||
function(x)
|
||||
if x ~= '' then r[x] = true end
|
||||
end)
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--- Show changes to tables wrought by a require statement.
|
||||
-- There are a few modes to this function, controlled by what named
|
||||
-- arguments are given. Lists new keys in T1 after `require "import"`:
|
||||
--
|
||||
-- show_apis {added_to=T1, by=import}
|
||||
--
|
||||
-- @tparam table argt one of the combinations above
|
||||
-- @treturn table a list of keys according to criteria above
|
||||
function show_apis(argt)
|
||||
return tabulate_output([[
|
||||
local before, after = {}, {}
|
||||
for k in pairs(]] .. argt.added_to .. [[) do
|
||||
before[k] = true
|
||||
end
|
||||
|
||||
local M = require ']] .. argt.by .. [['
|
||||
for k in pairs(]] .. argt.added_to .. [[) do
|
||||
after[k] = true
|
||||
end
|
||||
|
||||
for k in pairs(after) do
|
||||
if not before[k] then print(k) end
|
||||
end
|
||||
]])
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ ========= ]]--
|
||||
--[[ Call Spy. ]]--
|
||||
--[[ ========= ]]--
|
||||
|
||||
|
||||
spy = function(fn)
|
||||
return setmetatable({}, {
|
||||
__call = function(self, ...)
|
||||
self[#self + 1] = list(...)
|
||||
return fn(...)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
--[[ ================ ]]--
|
||||
--[[ Custom matchers. ]]--
|
||||
--[[ ================ ]]--
|
||||
|
||||
local matchers = require 'specl.matchers'
|
||||
local eqv = require 'specl.std'.operator.eqv
|
||||
local str = require 'specl.std'.string.tostring
|
||||
|
||||
local Matcher, matchers = matchers.Matcher, matchers.matchers
|
||||
local concat = table.concat
|
||||
|
||||
|
||||
matchers.be_called_with = Matcher {
|
||||
function(self, actual, expected)
|
||||
for i,v in ipairs(expected or {}) do
|
||||
if not eqv(actual[i], v) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
actual = 'argmuents',
|
||||
|
||||
format_expect = function(self, expect)
|
||||
return ' arguments (' .. str(expect) .. '), '
|
||||
end,
|
||||
}
|
||||
|
||||
matchers.be_callable = Matcher {
|
||||
function(self, actual, _)
|
||||
return iscallable(actual)
|
||||
end,
|
||||
|
||||
actual = 'callable',
|
||||
|
||||
format_expect = function(self, expect)
|
||||
return ' callable, '
|
||||
end,
|
||||
}
|
||||
|
||||
matchers.be_falsey = Matcher {
|
||||
function(self, actual, _)
|
||||
return not actual and true or false
|
||||
end,
|
||||
|
||||
actual = 'falsey',
|
||||
|
||||
format_expect = function(self, expect)
|
||||
return ' falsey, '
|
||||
end,
|
||||
}
|
||||
|
||||
matchers.be_truthy = Matcher {
|
||||
function(self, actual, _)
|
||||
return actual and true or false
|
||||
end,
|
||||
|
||||
actual = 'truthy',
|
||||
|
||||
format_expect = function(self, expect)
|
||||
return ' truthy, '
|
||||
end,
|
||||
}
|
||||
|
||||
matchers.have_type = Matcher {
|
||||
function(self, actual, expected)
|
||||
return type(actual) == expected or (getmetatable(actual) or {})._type == expected
|
||||
end,
|
||||
|
||||
actual = 'type',
|
||||
|
||||
format_expect = function(self, expect)
|
||||
local article = 'a'
|
||||
if match(expect, '^[aehiou]') then
|
||||
article = 'an'
|
||||
end
|
||||
return concat{' ', article, ' ', expect, ', '}
|
||||
end
|
||||
}
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue