|
- local doc = require "wslua.doc"
- local fndef = require "wslua.fndef"
- local ty = require "wslua.ty"
-
- local list = require "wslua.list"
-
-
-
- local string = setmetatable({}, {__index = string})
-
- doc.module{
- name = "wslua.string",
- what = "Additional string functionality",
- descr = [[
- This module also contains all functions from the default `string` library, and can be used as a drop-in replacement. Use
- the main `wslua` module to inject this module into the string metatable.
- ]],
- }
-
-
- string.split = fndef({
- name = "string.split",
- what = "Split a string into segments using a separator.",
- args = {
- {name = "subj", type = ty.stringish, what = "String to be split."},
- {name = "sep", type = ty.string & ~ ty.eq(""), what = "Separator pattern to split on."},
- {name = "plain", type = #ty.boolean, what = "Match `sep` literally, not as a pattern."},
- },
- ret = {
- {type = ty.class(list) & ty.list(ty.string, 1)},
- },
- tests = {
- function() return "{}", string.split("", "/"):__tostring() end,
- function() return "{1, 2, 3}", string.split("1/2/3", "/", true):__tostring() end,
- function() return "{1, 2, 3}", string.split("1 2 3", "%s"):__tostring() end,
- function() return "{1, 2, }", string.split("1 2 ", "%s"):__tostring() end,
- function() return "{, 2, 3}", string.split(" 2 3", "%s"):__tostring() end,
- function() return "{1, 2, , 3}", string.split("1 2 3", "%s"):__tostring() end,
- },
- },
- function(subj, sep)
- subj = tostring(subj)
-
- local ret = list()
- local i = 1
-
- while true do
- local a, b = subj:find(sep, i, plain)
- if not a then break end
- ret:insert(subj:sub(i, a-1))
- i = b + 1
- end
-
- ret:insert(subj:sub(i, -1))
-
- return ret
- end)
-
-
- string.print = fndef({
- name = "string.print",
- what = "Print a string to a stream.",
- descr = [[
- Mainly useful if injected into the string metatable using the main `wslua` module, that allows `:print()` at the end of
- a long call chain.
- ]],
- args = {
- {name = "s", type = ty.string},
- {name = "file", type = #ty.file, what = "File to print to, defaults to `stdout`."},
- {name = "nonl", type = #ty.boolean, what = "Don't add a newline after the string, defaults to `false` (= add a newline)."},
- },
- ret = {
- {type = ty.string, what = "s"},
- }
- },
- function(s, file, nonl)
- file = file or io.stdout
- file:write(s)
- if not nonl then file:write("\n") end
- return s
- end)
-
-
- string.template = fndef({
- name = "string.template",
- what = "Process a string with embedded Lua snippets.",
- descr = [=[
- There are two kinds of snippets: expression snippets and statement snippets. Expression snippets start with `%[[` and
- end with the first `]]` afterwards, statement snippets are delimited by `%{{` and `}}`. An arbitrary amount of `=`s can
- be placed between the brackets, with semantics analogous to Lua strings/comments.
-
- The function "inverts" the string:
-
- - Everything except the snippets is put inside string literals, which are fed to a concatenation function.
- - Expression snippets are wrapped in `tostring` calls, and then also fed to the concatenation function.
- - Statement snippets are left as-is between the other code.
-
- The resulting code is executed inside the specified `env`.
- ]=],
- args = {
- {name = "input", type = ty.stringish, what = "String to process."},
- {name = "loc", type = ty.stringish, what = "Location information used to generate error messages."},
- {name = "env", type = ty.table, what = "Environment to execute snippets in."},
- },
- ret = {
- {type = ty.string},
- },
- tests = {
- function() return "", string.template("", "test", {}) end,
- function() return "asdfg", string.template("as%[=[d]=]fg", "test", {d = "d"}) end,
- function() return "Hello, World!", string.template("Hello, %[[name()]]!", "test", {name = function() return "World" end}) end,
- function() return "Hello, World!", string.template("%{{ name = 'World' }}Hello, %[[ name ]]!", "test", {}) end,
- },
- ex = [=[
- require "wslua" ();
- local t = "%{{ name = 'World' }}%[[greeting]], %[[name]]!"
- s:template("test string", {name = "Lua"}):print()
- ]=]
- },
- function(input, loc, env)
- input = tostring(input )
- loc = tostring(loc )
-
- local s = table.concat({
- "local ___out___ = ...; ___out___[=========[",
- input
- :gsub("%%%[(=*)%[(.-)%]%1%]", "]=========] ___out___(%2) ___out___[=========[")
- :gsub("%%{(=*){(.-)}%1}", "]=========] %2 ___out___[=========[")
- :gsub("___out___%[=========%[\n", "___out___'\\n' %1"),
- "]=========]"
- })
-
- local ret = list{}
- assert(load(s, tostring(loc), "t", env))(function(s) ret:insert(tostring(s)) end)
- return ret:concat()
- end)
-
- return string
|