pax_global_header00006660000000000000000000000064143251035430014512gustar00rootroot0000000000000052 comment=1afb1f870ae486097f79586502f4254d6074afcb lyaml-6.2.8/000077500000000000000000000000001432510354300126455ustar00rootroot00000000000000lyaml-6.2.8/.github/000077500000000000000000000000001432510354300142055ustar00rootroot00000000000000lyaml-6.2.8/.github/workflows/000077500000000000000000000000001432510354300162425ustar00rootroot00000000000000lyaml-6.2.8/.github/workflows/spec.yml000066400000000000000000000015731432510354300177250ustar00rootroot00000000000000name: spec on: push: branches: [ '*' ] pull_request: branches: [ 'master' ] jobs: test: strategy: fail-fast: false matrix: lua-version: ["5.4", "5.3", "5.2", "5.1", "luajit"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: leafo/gh-actions-lua@v8.0.0 with: luaVersion: ${{ matrix.lua-version }} - uses: leafo/gh-actions-luarocks@v4.0.0 - name: install run: | sudo apt-get install -y libyaml-dev luarocks install ansicolors luarocks install ldoc luarocks install luacov luarocks install specl - name: build run: | luarocks make --force - name: test run: | specl -vfreport --coverage spec/*_spec.yaml bash <(curl -s https://codecov.io/bash) -f luacov.report.out lyaml-6.2.8/.gitignore000066400000000000000000000001331432510354300146320ustar00rootroot00000000000000*~ *.o *.so *.src.rock /ChangeLog /build-aux/config.ld /luacov.*.out /lyaml-*.tar.gz /TAGS lyaml-6.2.8/.luacov000066400000000000000000000001521432510354300141350ustar00rootroot00000000000000modules = { ['lyaml'] = 'lib/lyaml/init.lua', ['lyaml.*'] = 'lib', } runreport = true tick = true lyaml-6.2.8/AUTHORS000066400000000000000000000002411432510354300137120ustar00rootroot00000000000000lyaml is the work of several authors (see git history for contributors). There is an earlier C LibYAML binding Copyright Andrew Danforth lyaml-6.2.8/LICENSE000066400000000000000000000026521432510354300136570ustar00rootroot00000000000000This 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. ==================================================================== lyaml-6.2.8/NEWS.md000066400000000000000000000216611432510354300137510ustar00rootroot00000000000000# 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! lyaml-6.2.8/README.md000066400000000000000000000162441432510354300141330ustar00rootroot00000000000000LYAML ===== Copyright (C) 2013-2022 Gary V. Vaughan [![License](https://img.shields.io/:license-mit-blue.svg)](https://mit-license.org) [![workflow status](https://github.com/gvvaughan/lyaml/actions/workflows/spec.yml/badge.svg?branch=release-v6.2.8)](https://github.com/gvvaughan/lyaml/actions) [![codecov.io](https://codecov.io/github/gvvaughan/lyaml/coverage.svg?branch=release-v6.2.8)](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/ lyaml-6.2.8/build-aux/000077500000000000000000000000001432510354300145375ustar00rootroot00000000000000lyaml-6.2.8/build-aux/config.ld.in000066400000000000000000000014471432510354300167400ustar00rootroot00000000000000--[[ 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 lyaml-6.2.8/build-aux/luke000077500000000000000000001041561432510354300154340ustar00rootroot00000000000000#!/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 , 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 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 declares it. For example, HP-UX 11i declares gettimeofday. */ #define %s innocuous_%s /* System header to define __stub macros and hopefully few prototypes, which can conflict with declaration below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #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)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=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 an 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)) lyaml-6.2.8/doc/000077500000000000000000000000001432510354300134125ustar00rootroot00000000000000lyaml-6.2.8/doc/index.html000066400000000000000000000043121432510354300154070ustar00rootroot00000000000000 lyaml 6.2.8 Reference

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.

Modules

lyaml
lyaml.explicit
lyaml.functional
lyaml.implicit
generated by LDoc 1.4.6 Last updated 2022-10-22 17:12:03
lyaml-6.2.8/doc/ldoc.css000066400000000000000000000143001432510354300150430ustar00rootroot00000000000000/* 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; } lyaml-6.2.8/doc/modules/000077500000000000000000000000001432510354300150625ustar00rootroot00000000000000lyaml-6.2.8/doc/modules/lyaml.explicit.html000066400000000000000000000130171432510354300207100ustar00rootroot00000000000000 lyaml 6.2.8 Reference

Module lyaml.explicit

Functions

bool (value) Parse the value following an explicit !!bool tag.
float (value) Parse the value following an explicit !!float tag.
int (value) Parse the value following an explicit !!int tag.
null () Parse an explicit !!null tag.
str (value) Parse the value following an explicit !!str tag.


Functions

bool (value)
Parse the value following an explicit !!bool tag.

Parameters:

  • value token

Returns:

    bool boolean equivalent, if a valid value was recognized

Or

    nil otherwise, nil

Usage:

    maybe_bool = explicit.bool(tagarg)
float (value)
Parse the value following an explicit !!float tag.

Parameters:

  • value token

Returns:

    number float equivalent, if a valid value was recognized

Or

    nil otherwise, nil

Usage:

    maybe_float = explicit.float(tagarg)
int (value)
Parse the value following an explicit !!int tag.

Parameters:

  • value token

Returns:

    int integer equivalent, if a valid value was recognized

Or

    nil otherwise, nil

Usage:

    maybe_int = explicit.int(tagarg)
null ()
Parse an explicit !!null tag.

Returns:

    lyaml.null

Usage:

    null = explicit.null(tagarg)
str (value)
Parse the value following an explicit !!str tag.

Parameters:

Returns:

    string value which was a string already

Usage:

    tagarg = explicit.str(tagarg)
generated by LDoc 1.4.6 Last updated 2022-10-22 17:12:03
lyaml-6.2.8/doc/modules/lyaml.functional.html000066400000000000000000000110111432510354300212210ustar00rootroot00000000000000 lyaml 6.2.8 Reference

Module lyaml.functional

Functions

isnull (x) lyaml.null predicate.
iscallable (x) Callable predicate.
anyof (fns) Compose a function to try each callable with supplied args.
id (...) Return arguments unchanged.

Tables

NULL lyaml.null value.


Functions

isnull (x)
lyaml.null predicate.

Parameters:

  • x operand

Returns:

    bool true if x is lyaml.null.
iscallable (x)
Callable predicate.

Parameters:

  • x operand

Returns:

    bool true if x is a function has a __call metamethod

Usage:

    r = iscallable(x) and x(...)
anyof (fns)
Compose a function to try each callable with supplied args.

Parameters:

  • fns table list of functions to try

Returns:

    function

    a new function to call ... functions, stopping

    and returning the first non-nil result, if any
    
id (...)
Return arguments unchanged.

Parameters:

  • ... arguments

Returns:

    ...

Tables

NULL
lyaml.null value.
generated by LDoc 1.4.6 Last updated 2022-10-22 17:12:03
lyaml-6.2.8/doc/modules/lyaml.html000066400000000000000000000123661432510354300170760ustar00rootroot00000000000000 lyaml 6.2.8 Reference

Module lyaml

Functions

dump (documents[, opts]) Dump a list of Lua tables to an equivalent YAML stream.
load (s[, opts]) Load a YAML stream into a Lua table.

Tables

dumper_opts Dump options table.
loader_opts Load options table.


Functions

dump (documents[, opts])
Dump a list of Lua tables to an equivalent YAML stream.

Parameters:

  • documents table a sequence of Lua tables.
  • opts dumper_opts initialisation options (optional)

Returns:

    string equivalest YAML stream
load (s[, opts])
Load a YAML stream into a Lua table.

Parameters:

  • s string YAML stream
  • opts loader_opts initialisation options (optional)

Returns:

    table Lua table equivalent of stream s

Tables

dumper_opts
Dump options table.

Fields:

  • anchors table map initial anchor names to values
  • implicit_scalar function parse implicit scalar values
loader_opts
Load options table.

Fields:

  • all boolean load all documents from the stream
  • explicit_scalar table map full tag-names to parser functions
  • implicit_scalar function parse implicit scalar values
generated by LDoc 1.4.6 Last updated 2022-10-22 17:12:03
lyaml-6.2.8/doc/modules/lyaml.implicit.html000066400000000000000000000274001432510354300207020ustar00rootroot00000000000000 lyaml 6.2.8 Reference

Module lyaml.implicit

Functions

null (value) Parse a null token to a null value.
bool (value) Parse a boolean token to the equivalent value.
binary (value) Parse a binary token, such as '0b1010_0111_0100_1010_1110'.
octal (value) Parse an octal token, such as '012345'.
decimal (value) Parse a decimal token, such as '0' or '12345'.
hexadecimal (value) Parse a hexadecimal token, such as '0xdeadbeef'.
sexagesimal (value) Parse a sexagesimal token, such as '190:20:30'.
nan (value) Parse a nan token.
inf (value) Parse a signed inf token.
float (value) Parse a floating point number token, such as '1e-3' or '-0.12'.
sexfloat (value) Parse a sexagesimal float, such as '190:20:30.15'.


Functions

null (value)
Parse a null token to a null value.

Parameters:

  • value token

Returns:

    lyaml.null, for an empty string or literal ~

Or

    nil otherwise, nil

Usage:

    maybe_null = implicit.null(token)
bool (value)
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.

Parameters:

  • value token

Returns:

    bool if a valid boolean token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_bool = implicit.bool(token)
binary (value)
Parse a binary token, such as '0b1010_0111_0100_1010_1110'.

Parameters:

Returns:

    int integer equivalent, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_int = implicit.binary(value)
octal (value)
Parse an octal token, such as '012345'.

Parameters:

Returns:

    int integer equivalent, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_int = implicit.octal(value)
decimal (value)
Parse a decimal token, such as '0' or '12345'.

Parameters:

Returns:

    int integer equivalent, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_int = implicit.decimal(value)
hexadecimal (value)
Parse a hexadecimal token, such as '0xdeadbeef'.

Parameters:

Returns:

    int integer equivalent, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_int = implicit.hexadecimal(value)
sexagesimal (value)
Parse a sexagesimal token, such as '190:20:30'. Useful for times and angles.

Parameters:

Returns:

    int integer equivalent, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_int = implicit.sexagesimal(value)
nan (value)
Parse a nan token.

Parameters:

Returns:

    nan not-a-number, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_nan = implicit.nan(value)
inf (value)
Parse a signed inf token.

Parameters:

Returns:

    number plus/minus-infinity, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_inf = implicit.inf(value)
float (value)
Parse a floating point number token, such as '1e-3' or '-0.12'.

Parameters:

Returns:

    number float equivalent, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_float = implicit.float(value)
sexfloat (value)
Parse a sexagesimal float, such as '190:20:30.15'. Useful for times and angles.

Parameters:

Returns:

    number float equivalent, if a valid token was recognized

Or

    nil otherwise, nil

Usage:

    maybe_float = implicit.sexfloat(value)
generated by LDoc 1.4.6 Last updated 2022-10-22 17:12:03
lyaml-6.2.8/ext/000077500000000000000000000000001432510354300134455ustar00rootroot00000000000000lyaml-6.2.8/ext/yaml/000077500000000000000000000000001432510354300144075ustar00rootroot00000000000000lyaml-6.2.8/ext/yaml/emitter.c000066400000000000000000000322531432510354300162310ustar00rootroot00000000000000/* * 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 #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; } lyaml-6.2.8/ext/yaml/lyaml.h000066400000000000000000000112551432510354300157020ustar00rootroot00000000000000/* * 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 #include #include #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 lyaml-6.2.8/ext/yaml/parser.c000066400000000000000000000247121432510354300160550ustar00rootroot00000000000000/* * 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; } lyaml-6.2.8/ext/yaml/scanner.c000066400000000000000000000213251432510354300162070ustar00rootroot00000000000000/* * 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; } lyaml-6.2.8/ext/yaml/yaml.c000066400000000000000000000036711432510354300155240ustar00rootroot00000000000000/* * 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 * */ #include #include #include #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; } lyaml-6.2.8/lib/000077500000000000000000000000001432510354300134135ustar00rootroot00000000000000lyaml-6.2.8/lib/lyaml/000077500000000000000000000000001432510354300145315ustar00rootroot00000000000000lyaml-6.2.8/lib/lyaml/explicit.lua000066400000000000000000000066501432510354300170640ustar00rootroot00000000000000-- 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, } lyaml-6.2.8/lib/lyaml/functional.lua000066400000000000000000000047641432510354300174110ustar00rootroot00000000000000-- 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, } lyaml-6.2.8/lib/lyaml/implicit.lua000066400000000000000000000172671432510354300170630ustar00rootroot00000000000000-- 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, } lyaml-6.2.8/lib/lyaml/init.lua000066400000000000000000000372071432510354300162100ustar00rootroot00000000000000-- 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 --- @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, } lyaml-6.2.8/lukefile000066400000000000000000000020331432510354300143660ustar00rootroot00000000000000--[[ 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', } lyaml-6.2.8/lyaml-6.2.8-1.rockspec000066400000000000000000000025561432510354300163350ustar00rootroot00000000000000local _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 lyaml-6.2.8/spec/000077500000000000000000000000001432510354300135775ustar00rootroot00000000000000lyaml-6.2.8/spec/ext_yaml_emitter_spec.yaml000066400000000000000000000254561432510354300210640ustar00rootroot00000000000000# 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 "! 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"} lyaml-6.2.8/spec/ext_yaml_parser_spec.yaml000066400000000000000000000407351432510354300207040ustar00rootroot00000000000000# 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 " - 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 " - 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} lyaml-6.2.8/spec/ext_yaml_scanner_spec.yaml000066400000000000000000000366331432510354300210430ustar00rootroot00000000000000# 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} lyaml-6.2.8/spec/lib_lyaml_functional_spec.yaml000066400000000000000000000072211432510354300216650ustar00rootroot00000000000000# 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 lyaml-6.2.8/spec/lib_lyaml_spec.yaml000066400000000000000000000405341432510354300174470ustar00rootroot00000000000000# 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 " 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 " - 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) lyaml-6.2.8/spec/spec_helper.lua000066400000000000000000000147521432510354300166040ustar00rootroot00000000000000--[[ 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