Moved str to global.
@@ -15,7 +15,6 @@ ../lib/[min_global,
min_stack, min_seq, min_dict, - min_str, min_time, min_sys, min_io,@@ -42,7 +41,6 @@ i.global_module
i.stack_module i.seq_module i.dict_module - i.str_module i.time_module i.sys_module i.fs_module
@@ -9,6 +9,8 @@ math,
streams, random, bitops, + macros, + uri, nre, os, logging]@@ -1711,6 +1713,330 @@ i.pushSym("expect-all")
def.symbol("||") do (i: In): i.pushSym("expect-any") + + # String operations + + when not defined(nopcre): + + when defined(windows) and defined(amd64): + {.passL: "-static -L"&getProjectPath()&"/minpkg/vendor/pcre/windows -lpcre".} + elif defined(linux) and defined(amd64): + {.passL: "-static -L"&getProjectPath()&"/minpkg/vendor/pcre/linux -lpcre".} + elif defined(macosx) and defined(amd64): + {.passL: "-Bstatic -L"&getProjectPath()&"/minpkg/vendor/pcre/macosx -lpcre -Bdynamic".} + + def.symbol("search") do (i: In): + let vals = i.expect("str", "str") + let reg = re(vals[0].strVal) + let str = vals[1] + let m = str.strVal.find(reg) + var res = newSeq[MinValue](0) + if m.isNone: + res.add "".newVal + for i in 0..reg.captureCount-1: + res.add "".newVal + i.push res.newVal + return + let matches = m.get.captures + res.add m.get.match.newVal + for i in 0..reg.captureCount-1: + res.add matches[i].newVal + i.push res.newVal + + def.symbol("match?") do (i: In): + let vals = i.expect("str", "str") + let reg = re(vals[0].strVal) + let str = vals[1].strVal + i.push str.find(reg).isSome.newVal + + def.symbol("search-all") do (i: In): + let vals = i.expect("str", "str") + var res = newSeq[MinValue](0) + let reg = re(vals[0].strVal) + let str = vals[1].strVal + for m in str.findIter(reg): + let matches = m.captures + var mres = newSeq[MinValue](0) + mres.add m.match.newVal + for i in 0..reg.captureCount-1: + mres.add matches[i].newVal + res.add mres.newval + i.push res.newVal + + def.symbol("replace-apply") do (i: In): + let vals = i.expect("quot", "str", "str") + let q = vals[0] + let reg = re(vals[1].strVal) + let s_find = vals[2].strVal + var i2 = i.copy(i.filename) + let repFn = proc(match: RegexMatch): string {.closure.} = + var ss = newSeq[MinValue](0) + ss.add match.match.newVal + for s in match.captures: + if s.isNone: + ss.add "".newVal + else: + ss.add s.get.newVal + i2.push ss.newVal + i2.push q + i2.pushSym "dequote" + return i2.pop.getString + i.push s_find.replace(reg, repFn).newVal + + def.symbol("replace") do (i: In): + let vals = i.expect("str", "str", "str") + let s_replace = vals[0].strVal + let reg = re(vals[1].strVal) + let s_find = vals[2].strVal + i.push s_find.replace(reg, s_replace).newVal + + def.symbol("interpolate") do (i: In): + let vals = i.expect("quot", "str") + var q = vals[0] + let s = vals[1] + var strings = newSeq[string](0) + for el in q.qVal: + strings.add $$el + let res = s.strVal % strings + i.push res.newVal + + def.symbol("apply-interpolate") do (i: In): + i.pushSym "apply" + i.pushSym "interpolate" + + def.symbol("strip") do (i: In): + let vals = i.expect("'sym") + let s = vals[0] + i.push s.getString.strip.newVal + + def.symbol("substr") do (i: In): + let vals = i.expect("int", "int", "'sym") + let length = vals[0].intVal + let start = vals[1].intVal + let s = vals[2].getString + let index = min(start+length-1, s.len-1) + i.push s[start..index].newVal + + def.symbol("split") do (i: In): + let vals = i.expect("'sym", "'sym") + let sep = re(vals[0].getString) + let s = vals[1].getString + var q = newSeq[MinValue](0) + for e in s.split(sep): + q.add e.newVal + i.push q.newVal + + def.symbol("join") do (i: In): + let vals = i.expect("'sym", "quot") + let s = vals[0] + let q = vals[1] + i.push q.qVal.mapIt($$it).join(s.getString).newVal + + def.symbol("length") do (i: In): + let vals = i.expect("'sym") + let s = vals[0] + i.push s.getString.len.newVal + + def.symbol("lowercase") do (i: In): + let vals = i.expect("'sym") + let s = vals[0] + i.push s.getString.toLowerAscii.newVal + + def.symbol("uppercase") do (i: In): + let vals = i.expect("'sym") + let s = vals[0] + i.push s.getString.toUpperAscii.newVal + + def.symbol("capitalize") do (i: In): + let vals = i.expect("'sym") + let s = vals[0] + i.push s.getString.capitalizeAscii.newVal + + def.symbol("ord") do (i: In): + let vals = i.expect("'sym") + let s = vals[0] + if s.getString.len != 1: + raiseInvalid("Symbol ord requires a string containing a single character.") + i.push s.getString[0].ord.newVal + + def.symbol("chr") do (i: In): + let vals = i.expect("int") + let n = vals[0] + let c = n.intVal.chr + i.push ($c).newVal + + def.symbol("titleize") do (i: In): + let vals = i.expect("'sym") + let s = vals[0] + i.push s.getString.split(" ").mapIt(it.capitalizeAscii).join(" ").newVal + + def.symbol("repeat") do (i: In): + let vals = i.expect("int", "str") + let n = vals[0] + let s = vals[1] + i.push s.getString.repeat(n.intVal).newVal + + def.symbol("indent") do (i: In): + let vals = i.expect("int", "str") + let n = vals[0] + let s = vals[1] + i.push s.getString.indent(n.intVal).newVal + + def.symbol("indexof") do (i: In): + let vals = i.expect("str", "str") + let reg = vals[0] + let str = vals[1] + let index = str.strVal.find(reg.strVal) + i.push index.newVal + + def.symbol("encode-url") do (i: In): + let vals = i.expect("str") + let s = vals[0].strVal + i.push s.encodeUrl.newVal + + def.symbol("decode-url") do (i: In): + let vals = i.expect("str") + let s = vals[0].strVal + i.push s.decodeUrl.newVal + + def.symbol("parse-url") do (i: In): + let vals = i.expect("str") + let s = vals[0].strVal + let u = s.parseUri + var d = newDict(i.scope) + d.objType = "url" + i.dset(d, "scheme", u.scheme.newVal) + i.dset(d, "username", u.username.newVal) + i.dset(d, "password", u.password.newVal) + i.dset(d, "hostname", u.hostname.newVal) + i.dset(d, "port", u.port.newVal) + i.dset(d, "path", u.path.newVal) + i.dset(d, "query", u.query.newVal) + i.dset(d, "anchor", u.anchor.newVal) + i.push d + + def.symbol("semver?") do (i: In): + let vals = i.expect("str") + let v = vals[0].strVal + let m = v.match(re"^\d+\.\d+\.\d+$") + i.push m.isSome.newVal + + def.symbol("from-semver") do (i: In): + let vals = i.expect("str") + let v = vals[0].strVal + let reg = re"^(\d+)\.(\d+)\.(\d+)$" + let rawMatch = v.match(reg) + if rawMatch.isNone: + raiseInvalid("String '$1' is not a basic semver" % v) + let parts = rawMatch.get.captures + var d = newDict(i.scope) + i.dset(d, "major", parts[0].parseInt.newVal) + i.dset(d, "minor", parts[1].parseInt.newVal) + i.dset(d, "patch", parts[2].parseInt.newVal) + i.push d + + def.symbol("to-semver") do (i: In): + let vals = i.expect("dict") + let v = vals[0] + if not v.dhas("major") or not v.dhas("minor") or not v.dhas("patch"): + raiseInvalid("Dictionary does not contain major, minor and patch keys") + let major = i.dget(v, "major") + let minor = i.dget(v, "minor") + let patch = i.dget(v, "patch") + if major.kind != minInt or minor.kind != minInt or patch.kind != minInt: + raiseInvalid("major, minor, and patch values are not integers") + i.push(newVal("$#.$#.$#" % [$major, $minor, $patch])) + + def.symbol("semver-inc-major") do (i: In): + i.pushSym("from-semver") + var d = i.pop + let cv = i.dget(d, "major") + let v = cv.intVal + 1 + i.dset(d, "major", v.newVal) + i.dset(d, "minor", 0.newVal) + i.dset(d, "patch", 0.newVal) + i.push(d) + i.pushSym("to-semver") + + def.symbol("semver-inc-minor") do (i: In): + i.pushSym("from-semver") + var d = i.pop + let cv = i.dget(d, "minor") + let v = cv.intVal + 1 + i.dset(d, "minor", v.newVal) + i.dset(d, "patch", 0.newVal) + i.push(d) + i.pushSym("to-semver") + + def.symbol("semver-inc-patch") do (i: In): + i.pushSym("from-semver") + var d = i.pop + let cv = i.dget(d, "patch") + let v = cv.intVal + 1 + i.dset(d, "patch", v.newVal) + i.push(d) + i.pushSym("to-semver") + + def.symbol("escape") do (i: In): + let vals = i.expect("'sym") + let a = vals[0].getString + i.push a.escapeEx(true).newVal + + def.symbol("prefix") do (i: In): + let vals = i.expect("'sym", "'sym") + let a = vals[1].getString + let b = vals[0].getString + var s = b & a + i.push s.newVal + + def.symbol("suffix") do (i: In): + let vals = i.expect("'sym", "'sym") + let a = vals[1].getString + let b = vals[0].getString + var s = a & b + i.push s.newVal + + def.symbol("to-hex") do (i: In): + let vals = i.expect("int") + let v = vals[0].intVal + i.push (("0x"&v.toHex(sizeof(v))).newVal) + + def.symbol("to-oct") do (i: In): + let vals = i.expect("int") + let v = vals[0].intVal + i.push (("0o"&v.toOct(sizeof(v))).newVal) + + def.symbol("to-dec") do (i: In): + let vals = i.expect("int") + let v = vals[0].intVal + i.push ($v).newVal + + def.symbol("to-bin") do (i: In): + let vals = i.expect("int") + let v = vals[0].intVal + i.push (("0b"&v.toBin(sizeof(v))).newVal) + + def.symbol("from-hex") do (i: In): + let vals = i.expect("'sym") + i.push fromHex[BiggestInt](vals[0].getString).newVal + + def.symbol("from-oct") do (i: In): + let vals = i.expect("'sym") + i.push fromOct[BiggestInt](vals[0].getString).newVal + + def.symbol("from-bin") do (i: In): + let vals = i.expect("'sym") + i.push fromBin[BiggestInt](vals[0].getString).newVal + + def.symbol("from-dec") do (i: In): + let vals = i.expect("'sym") + i.push parseInt(vals[0].getString).newVal + + def.symbol("%") do (i: In): + i.pushSym("interpolate") + + def.symbol("=%") do (i: In): + i.pushSym("apply-interpolate") # Sigils
@@ -1,339 +0,0 @@
-import - std/[strutils, - sequtils, - nre, - macros, - uri] -import - ../core/parser, - ../core/value, - ../core/interpreter, - ../core/baseutils, - ../core/utils - -proc str_module*(i: In) = - let def = i.define() - - when not defined(nopcre): - - when defined(windows) and defined(amd64): - {.passL: "-static -L"&getProjectPath()&"/minpkg/vendor/pcre/windows -lpcre".} - elif defined(linux) and defined(amd64): - {.passL: "-static -L"&getProjectPath()&"/minpkg/vendor/pcre/linux -lpcre".} - elif defined(macosx) and defined(amd64): - {.passL: "-Bstatic -L"&getProjectPath()&"/minpkg/vendor/pcre/macosx -lpcre -Bdynamic".} - - def.symbol("search") do (i: In): - let vals = i.expect("str", "str") - let reg = re(vals[0].strVal) - let str = vals[1] - let m = str.strVal.find(reg) - var res = newSeq[MinValue](0) - if m.isNone: - res.add "".newVal - for i in 0..reg.captureCount-1: - res.add "".newVal - i.push res.newVal - return - let matches = m.get.captures - res.add m.get.match.newVal - for i in 0..reg.captureCount-1: - res.add matches[i].newVal - i.push res.newVal - - def.symbol("match?") do (i: In): - let vals = i.expect("str", "str") - let reg = re(vals[0].strVal) - let str = vals[1].strVal - i.push str.find(reg).isSome.newVal - - def.symbol("search-all") do (i: In): - let vals = i.expect("str", "str") - var res = newSeq[MinValue](0) - let reg = re(vals[0].strVal) - let str = vals[1].strVal - for m in str.findIter(reg): - let matches = m.captures - var mres = newSeq[MinValue](0) - mres.add m.match.newVal - for i in 0..reg.captureCount-1: - mres.add matches[i].newVal - res.add mres.newval - i.push res.newVal - - def.symbol("replace-apply") do (i: In): - let vals = i.expect("quot", "str", "str") - let q = vals[0] - let reg = re(vals[1].strVal) - let s_find = vals[2].strVal - var i2 = i.copy(i.filename) - let repFn = proc(match: RegexMatch): string {.closure.} = - var ss = newSeq[MinValue](0) - ss.add match.match.newVal - for s in match.captures: - if s.isNone: - ss.add "".newVal - else: - ss.add s.get.newVal - i2.push ss.newVal - i2.push q - i2.pushSym "dequote" - return i2.pop.getString - i.push s_find.replace(reg, repFn).newVal - - def.symbol("replace") do (i: In): - let vals = i.expect("str", "str", "str") - let s_replace = vals[0].strVal - let reg = re(vals[1].strVal) - let s_find = vals[2].strVal - i.push s_find.replace(reg, s_replace).newVal - - def.symbol("interpolate") do (i: In): - let vals = i.expect("quot", "str") - var q = vals[0] - let s = vals[1] - var strings = newSeq[string](0) - for el in q.qVal: - strings.add $$el - let res = s.strVal % strings - i.push res.newVal - - def.symbol("apply-interpolate") do (i: In): - i.pushSym "apply" - i.pushSym "interpolate" - - def.symbol("strip") do (i: In): - let vals = i.expect("'sym") - let s = vals[0] - i.push s.getString.strip.newVal - - def.symbol("substr") do (i: In): - let vals = i.expect("int", "int", "'sym") - let length = vals[0].intVal - let start = vals[1].intVal - let s = vals[2].getString - let index = min(start+length-1, s.len-1) - i.push s[start..index].newVal - - def.symbol("split") do (i: In): - let vals = i.expect("'sym", "'sym") - let sep = re(vals[0].getString) - let s = vals[1].getString - var q = newSeq[MinValue](0) - for e in s.split(sep): - q.add e.newVal - i.push q.newVal - - def.symbol("join") do (i: In): - let vals = i.expect("'sym", "quot") - let s = vals[0] - let q = vals[1] - i.push q.qVal.mapIt($$it).join(s.getString).newVal - - def.symbol("length") do (i: In): - let vals = i.expect("'sym") - let s = vals[0] - i.push s.getString.len.newVal - - def.symbol("lowercase") do (i: In): - let vals = i.expect("'sym") - let s = vals[0] - i.push s.getString.toLowerAscii.newVal - - def.symbol("uppercase") do (i: In): - let vals = i.expect("'sym") - let s = vals[0] - i.push s.getString.toUpperAscii.newVal - - def.symbol("capitalize") do (i: In): - let vals = i.expect("'sym") - let s = vals[0] - i.push s.getString.capitalizeAscii.newVal - - def.symbol("ord") do (i: In): - let vals = i.expect("'sym") - let s = vals[0] - if s.getString.len != 1: - raiseInvalid("Symbol ord requires a string containing a single character.") - i.push s.getString[0].ord.newVal - - def.symbol("chr") do (i: In): - let vals = i.expect("int") - let n = vals[0] - let c = n.intVal.chr - i.push ($c).newVal - - def.symbol("titleize") do (i: In): - let vals = i.expect("'sym") - let s = vals[0] - i.push s.getString.split(" ").mapIt(it.capitalizeAscii).join(" ").newVal - - def.symbol("repeat") do (i: In): - let vals = i.expect("int", "str") - let n = vals[0] - let s = vals[1] - i.push s.getString.repeat(n.intVal).newVal - - def.symbol("indent") do (i: In): - let vals = i.expect("int", "str") - let n = vals[0] - let s = vals[1] - i.push s.getString.indent(n.intVal).newVal - - def.symbol("indexof") do (i: In): - let vals = i.expect("str", "str") - let reg = vals[0] - let str = vals[1] - let index = str.strVal.find(reg.strVal) - i.push index.newVal - - def.symbol("encode-url") do (i: In): - let vals = i.expect("str") - let s = vals[0].strVal - i.push s.encodeUrl.newVal - - def.symbol("decode-url") do (i: In): - let vals = i.expect("str") - let s = vals[0].strVal - i.push s.decodeUrl.newVal - - def.symbol("parse-url") do (i: In): - let vals = i.expect("str") - let s = vals[0].strVal - let u = s.parseUri - var d = newDict(i.scope) - d.objType = "url" - i.dset(d, "scheme", u.scheme.newVal) - i.dset(d, "username", u.username.newVal) - i.dset(d, "password", u.password.newVal) - i.dset(d, "hostname", u.hostname.newVal) - i.dset(d, "port", u.port.newVal) - i.dset(d, "path", u.path.newVal) - i.dset(d, "query", u.query.newVal) - i.dset(d, "anchor", u.anchor.newVal) - i.push d - - def.symbol("semver?") do (i: In): - let vals = i.expect("str") - let v = vals[0].strVal - let m = v.match(re"^\d+\.\d+\.\d+$") - i.push m.isSome.newVal - - def.symbol("from-semver") do (i: In): - let vals = i.expect("str") - let v = vals[0].strVal - let reg = re"^(\d+)\.(\d+)\.(\d+)$" - let rawMatch = v.match(reg) - if rawMatch.isNone: - raiseInvalid("String '$1' is not a basic semver" % v) - let parts = rawMatch.get.captures - var d = newDict(i.scope) - i.dset(d, "major", parts[0].parseInt.newVal) - i.dset(d, "minor", parts[1].parseInt.newVal) - i.dset(d, "patch", parts[2].parseInt.newVal) - i.push d - - def.symbol("to-semver") do (i: In): - let vals = i.expect("dict") - let v = vals[0] - if not v.dhas("major") or not v.dhas("minor") or not v.dhas("patch"): - raiseInvalid("Dictionary does not contain major, minor and patch keys") - let major = i.dget(v, "major") - let minor = i.dget(v, "minor") - let patch = i.dget(v, "patch") - if major.kind != minInt or minor.kind != minInt or patch.kind != minInt: - raiseInvalid("major, minor, and patch values are not integers") - i.push(newVal("$#.$#.$#" % [$major, $minor, $patch])) - - def.symbol("semver-inc-major") do (i: In): - i.pushSym("from-semver") - var d = i.pop - let cv = i.dget(d, "major") - let v = cv.intVal + 1 - i.dset(d, "major", v.newVal) - i.dset(d, "minor", 0.newVal) - i.dset(d, "patch", 0.newVal) - i.push(d) - i.pushSym("to-semver") - - def.symbol("semver-inc-minor") do (i: In): - i.pushSym("from-semver") - var d = i.pop - let cv = i.dget(d, "minor") - let v = cv.intVal + 1 - i.dset(d, "minor", v.newVal) - i.dset(d, "patch", 0.newVal) - i.push(d) - i.pushSym("to-semver") - - def.symbol("semver-inc-patch") do (i: In): - i.pushSym("from-semver") - var d = i.pop - let cv = i.dget(d, "patch") - let v = cv.intVal + 1 - i.dset(d, "patch", v.newVal) - i.push(d) - i.pushSym("to-semver") - - def.symbol("escape") do (i: In): - let vals = i.expect("'sym") - let a = vals[0].getString - i.push a.escapeEx(true).newVal - - def.symbol("prefix") do (i: In): - let vals = i.expect("'sym", "'sym") - let a = vals[1].getString - let b = vals[0].getString - var s = b & a - i.push s.newVal - - def.symbol("suffix") do (i: In): - let vals = i.expect("'sym", "'sym") - let a = vals[1].getString - let b = vals[0].getString - var s = a & b - i.push s.newVal - - def.symbol("to-hex") do (i: In): - let vals = i.expect("int") - let v = vals[0].intVal - i.push (("0x"&v.toHex(sizeof(v))).newVal) - - def.symbol("to-oct") do (i: In): - let vals = i.expect("int") - let v = vals[0].intVal - i.push (("0o"&v.toOct(sizeof(v))).newVal) - - def.symbol("to-dec") do (i: In): - let vals = i.expect("int") - let v = vals[0].intVal - i.push ($v).newVal - - def.symbol("to-bin") do (i: In): - let vals = i.expect("int") - let v = vals[0].intVal - i.push (("0b"&v.toBin(sizeof(v))).newVal) - - def.symbol("from-hex") do (i: In): - let vals = i.expect("'sym") - i.push fromHex[BiggestInt](vals[0].getString).newVal - - def.symbol("from-oct") do (i: In): - let vals = i.expect("'sym") - i.push fromOct[BiggestInt](vals[0].getString).newVal - - def.symbol("from-bin") do (i: In): - let vals = i.expect("'sym") - i.push fromBin[BiggestInt](vals[0].getString).newVal - - def.symbol("from-dec") do (i: In): - let vals = i.expect("'sym") - i.push parseInt(vals[0].getString).newVal - - def.symbol("%") do (i: In): - i.pushSym("interpolate") - - def.symbol("=%") do (i: In): - i.pushSym("apply-interpolate") - - def.finalize("str")
@@ -2,6 +2,7 @@ ### BREAKING CHANGES
- All symbols defined in the **num** module have been moved to the **global** module. - All symbols defined in the **logic** module have been moved to the **global** module. +- All symbols defined in the **str** module have been moved to the **global** module. ### New Features
@@ -1,5 +1,4 @@
; Imports -'str import 'stack import 'seq import 'dict import
@@ -70,13 +70,13 @@ * {#link-operator||crypto||aes#}
#### -d:nopcre -If the **-d:nopcre** is specified when compiling, min will be built _without_ PCRE support, so it will not be possible to use regular expressions and the following symbols will _not_ be exposed by the {#link-module||str#}: +If the **-d:nopcre** is specified when compiling, min will be built _without_ PCRE support, so it will not be possible to use regular expressions and the following symbols will _not_ be exposed by the {#link-module||global#}: -* {#link-operator||str||search#} -* {#link-operator||str||match?#} -* {#link-operator||str||search-all#} -* {#link-operator||str||replace#} -* {#link-operator||str||replace-apply#} +* {#link-operator||global||search#} +* {#link-operator||global||match?#} +* {#link-operator||global||search-all#} +* {#link-operator||global||replace#} +* {#link-operator||global||replace-apply#} ## Building a docker image
@@ -39,7 +39,6 @@ By default, when min is started it loads the following *prelude.min* program:
``` ; Imports -'str import 'io import 'sys import 'stack import
@@ -43,6 +43,10 @@ Symbol used to separate input and output values in operator signatures.#}
{#alias||=-=||expect-empty-stack#} +{#alias||%||interpolate#} + +{#alias||=%||apply-interpolate#} + {#sig||^||lambda#} {#alias||^||lambda#}@@ -106,6 +110,9 @@
{#op||apply||{{q}}||({{a0p}})|| Returns a new quotation obtained by evaluating each element of {{q}} in a separate stack. #} +{#op||apply-interpolate||{{s}} {{q}}||{{s}}|| +The same as pushing `apply` and then `interpolate` on the stack.#} + {#op||args||{{none}}||{{q}}|| Returns a list of all arguments passed to the current program.#}@@ -156,6 +163,12 @@ > * If {{any}} is a string, the empty string, and `"false"` are converted to {{f}}, otherwise it is converted to {{t}}.#}
{#op||boolean?||{{any}}||{{b}}|| Returns {{t}} if {{any}} is a boolean, {{f}} otherwise. #} + +{#op||capitalize||{{sl}}||{{s}}|| +Returns a copy of {{sl}} with the first character capitalized.#} + +{#op||chr||{{i}}||{{s}}|| +Returns the single character {{s}} obtained by interpreting {{i}} as an ASCII code.#} {#op||case||(({{q1}} {{q2}}){{0p}})||{{a0p}}|| > This operator takes a quotation containing _n_ different conditional branches.@@ -214,6 +227,9 @@
{#op||div||{{i1}} {{i2}}||{{i3}}|| Divides {{i1}} by {{i2}} (integer division). #} +{#op||escape||{{sl}}||{{s}}|| +Returns a copy of {{sl}} with quotes and backslashes escaped with a backslash.#} + {#op||eval||{{s}}||{{a0p}}|| Parses and interprets {{s}}. #}@@ -285,10 +301,26 @@ > > (format-error)
> > ) try > > > > produces: `"This is a test error"`#} + +{#op||from-bin||{{sl}}||{{i}}|| +Parses {{sl}} as a binary number. #} + +{#op||from-dec||{{sl}}||{{i}}|| +Parses {{sl}} as a decimal number. #} + +{#op||from-hex||{{sl}}||{{i}}|| +Parses {{sl}} as a hexadecimal number. #} {#op||from-json||{{s}}||{{any}}|| Converts a JSON string into {{m}} data.#} +{#op||from-oct||{{sl}}||{{i}}|| +Parses {{sl}} as a octal number. #} + +{#op||from-semver||{{s}}||{{d}}|| +Given a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}}, +it pushes a dictionary {{d}} on the stack containing a **major**, **minor**, and **patch** key/value pairs.#} + {#op||from-yaml||{{s}}||{{any}}|| > Converts a YAML string into {{m}} data. > > %note%@@ -311,6 +343,12 @@
{#op||import||{{sl}}||{{none}}|| Imports the a previously-loaded module {{sl}}, defining all its symbols in the current scope. #} +{#op||indent||{{sl}} {{i}}||{{s}}|| +Returns {{s}} containing {{sl}} indented with {{i}} spaces.#} + +{#op||indexof||{{s1}} {{s2}}||{{i}}|| +If {{s2}} is contained in {{s1}}, returns the index of the first match or -1 if no match is found. #} + {#op||inf||{{none}}||{{n}}|| Returns infinity. #}@@ -343,8 +381,31 @@ > * If {{any}} is a string, it is parsed as an integer value.#}
{#op||integer?||{{any}}||{{b}}|| Returns {{t}} if {{any}} is an integer, {{f}} otherwise. #} + +{#op||interpolate||{{s}} {{q}}||{{s}}|| +> Substitutes the placeholders included in {{s}} with the values in {{q}}. +> > %note% +> > Notes +> > +> > * If {{q}} contains symbols or quotations, they are not interpreted. To do so, call `apply` before interpolating or use `apply-interpolate` instead. +> > * You can use the `$#` placeholder to indicate the next placeholder that has not been already referenced in the string. +> > * You can use named placeholders like `$pwd`, but in this case {{q}} must contain a quotation containing both the placeholder names (odd items) and the values (even items). +> +> > %sidebar% +> > Example +> > +> > The following code (executed in a directory called '/Users/h3rald/Development/min' containing 19 files): +> > +> > `"Directory '$1' includes $2 files." (. (. ls 'file? filter size)) apply interpolate` +> > +> > produces: +> > +> > `"Directory '/Users/h3rald/Development/min' includes 19 files."`#} - {#op||lambda||{{q}} {{sl}}||{{none}}|| +{#op||join||{{q}} {{sl}}||{{s}}|| +Joins the elements of {{q}} using separator {{sl}}, producing {{s}}.#} + +{#op||lambda||{{q}} {{sl}}||{{none}}|| > Defines a new symbol {{sl}}, containing the specified quotation {{q}}. Unlike with `define`, in this case {{q}} will not be quoted, so its values will be pushed on the stack when the symbol {{sl}} is pushed on the stack. > > Essentially, this symbol allows you to define an operator without any validation of constraints and bind it to a symbol.#}@@ -354,6 +415,8 @@
{#op||lambda-bind||{{q}} {{sl}}||{{none}}|| Binds the specified quotation to an existing symbol {{sl}} which was previously-set via `lambda`. #} +{#op||length||{{sl}}||{{i}}|| +Returns the length of {{sl}}.#} {#op||line-info||{{none}}||{{d}}|| Returns a dictionary {{d}} containing a **filename**, **line**, and **column** properties identifying the filename, line and column of the current symbol.#}@@ -398,6 +461,16 @@
{#op||loglevel?||{{none}}||{{s}}|| Returns the current log level (debug, info, notice, warn, error or fatal). #} +{#op||lowercase||{{sl}}||{{s}}|| +Returns a copy of {{sl}} converted to lowercase.#} + +{#op||match?||{{s1}} {{s2}}||{{b}}|| +> Returns {{t}} if {{s2}} matches {{s1}}, {{f}} otherwise. +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}#}. + {#op||med||{{q}}||{{n}}|| Returns the median of the items of {{q}}. #}@@ -463,11 +536,20 @@
{#op||opts||{{none}}||{{d}}|| Returns a dictionary of all options passed to the current program, with their respective values.#} +{#op||ord||{{s}}||{{i}}|| +Returns the ASCII code {{i}} corresponding to the single character {{s}}.#} + {#op||parent-scope||{{d1}}||{{d2}}|| Returns a dictionary {{d2}} holding a reference to the parent scope of {{d1}} or {{null}} if {{d1}} is global.#} {#op||parse||{{s}}||{{q}}|| Parses {{s}} and returns a quoted program {{q}}. #} + +{#op||parse-url||{{s}}||{{url}}|| +Parses the url {{s}} into its components and stores them into {{url}}.#} + +{#op||prefix||{{sl1}} {{sl2}}||{{s}}|| +Prepends {{sl2}} to {{sl1}}.#} {#op||prefix-dequote||{{q}}||{{any}}|| > Dequotes {{q}} using prefix notation (essentially it reverses {{q}} and dequotes it).@@ -552,6 +634,47 @@
{#op||remove-symbol||{{sl}}||{{none}}|| Removes the symbol {{sl}} from the [.min\_symbols](class:file) file. #} +{#op||repeat||{{sl}} {{i}}||{{s}}|| +Returns {{s}} containing {{sl}} repeated {{i}} times.#} + +{#op||replace||{{s1}} {{s2}} {{s3}}||{{s4}}|| +> Returns a copy of {{s1}} containing all occurrences of {{s2}} replaced by {{s3}} +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}. +> +> > %sidebar% +> > Example +> > +> > The following: +> > +> > `"This is a stupid test. Is it really a stupid test?" " s[a-z]+" " simple" replace` +> > +> > produces: +> > +> > `"This is a simple test. Is it really a simple test?"`#} + +{#op||replace-apply||{{s1}} {{s2}} {{q}}||{{s3}}|| +> Returns a copy of {{s1}} containing all occurrences of {{s2}} replaced by applying {{q}} to each quotation corresponding to each match. +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}. +> +> > %sidebar% +> > Example +> > +> > The following: +> > +> > `":1::2::3::4:" ":(\d):" (1 get :d "-$#-" (d) =%) replace-apply` +> > +> > produces: +> > +> > `"-1--2--3--4-"` +> > +> > Note that for each match the following quotations (each containing the full match and the captured matches) are produced as input for the replace quotation: `("-1-" "1") ("-2-" "2") ("-3-" "3") ("-4-" "4")` #} + {#op||require||{{sl}}||{{d}}|| Parses and interprets (in a separated interpreter) the specified {{m}} module, and returns a module dictionary {{d}} containing all the symbols defined in {{sl}}.@@ -605,6 +728,45 @@
{#op||sealed-sigil?||{{sl}}||{{b}}|| Returns {{t}} if the sigil {{sl}} is sealed, {{f}} otherwise.#} +{#op||search||{{s1}} {{s2}}||{{q}}|| +> Returns a quotation containing the first occurrence of {{s2}} within {{s1}}. Note that: +> +> * The first element of {{q}} is the matching substring. +> * Other elements (if any) contain captured substrings. +> * If no matches are found, the quotation contains empty strings. +> +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}. +> +> > %sidebar% +> > Example +> > +> > The following: +> > +> > `"192.168.1.1, 127.0.0.1" "[0-9]+\.[0-9]+\.([0-9]+)\.([0-9]+)" search` +> > +> > produces: `("192.168.1.1", "1", "1")`#} + +{#op||search-all||{{s1}} {{s2}}||{{q}}|| +Returns a quotation of quotations (like the one returned by the search operator) containing all occurrences of {{s2}} within {{s1}}. #} + +{#op||semver-inc-major||{{s1}}||{{s2}}|| +Increments the major digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver-inc-minor||{{s1}}||{{s2}}|| +Increments the minor digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver-inc-patch||{{s1}}||{{s2}}|| +Increments the patch digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver?||{{s}}||{{b}}|| +Checks whether {{s}} is a [SemVer](https://semver.org)-compliant version or not. #} + +{#op||split||{{sl1}} {{sl2}}||{{q}}|| +Splits {{sl1}} using separator {{sl2}} (a {{pcre}}) and returns the resulting strings within the quotation {{q}}. #} + {#op||shl||{{i1}} {{i2}}||{{i3}}|| Computes the *shift left* operation of {{i1}} and {{i2}}.#}@@ -629,8 +791,18 @@
{#op||string?||{{any}}||{{b}}|| Returns {{t}} if {{any}} is a string, {{f}} otherwise. #} + +{#op||strip||{{sl}}||{{s}}|| +Returns {{s}}, which is set to {{sl}} with leading and trailing spaces removed.#} + +{#op||substr||{{s1}} {{i1}} {{i2}}||{{s2}}|| +Returns a substring {{s2}} obtained by retrieving {{i2}} characters starting from index {{i1}} within {{s1}}.#} + {#op||succ||{{i1}}||{{i2}}|| Returns the successor of {{i1}}.#} + +{#op||suffix||{{sl1}} {{sl2}}||{{s}}|| +Appends {{sl2}} to {{sl1}}.#} {#op||sum||{{q}}||{{i}}|| Returns the sum of all items of {{q}}. {{q}} is a quotation of integers. #}@@ -664,12 +836,29 @@ > > Returns `{3 :a 3 :b 3 :c}`.#}
{#op||times||{{q}} {{i}}||{{a0p}}|| Applies the quotation {{q}} {{i}} times.#} +{#op||titleize||{{sl}}||{{s}}|| +Returns a copy of {{sl}} in which the first character of each word is capitalized.#} {#op||tokenize||{{s}}||{{q}}|| Parses the min program {{s}} and returns a quotation {{q}} containing dictionaries with a `type` symbol and a `value` symbol for each token.#} +{#op||to-bin||{{i}}||{{s}}|| +Converts {{i}} to its binary representation. #} + +{#op||to-dec||{{i}}||{{s}}|| +Converts {{i}} to its decimal representation. #} + +{#op||to-hex||{{i}}||{{s}}|| +Converts {{i}} to its hexadecimal representation. #} + {#op||to-json||{{any}}||{{s}}|| Converts {{any}} into a JSON string.#} + +{#op||to-oct||{{i}}||{{s}}|| +Converts {{i}} to its octal representation. #} + +{#op||to-semver||{{d}}||{{s}}|| +Given a a dictionary {{d}} containing a **major**, **minor**, and **patch** key/value pairs , it pushes a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}} on the stack.#} {#op||to-yaml||{{any}}||{{s}}|| > Converts {{any}} into a YAML string.@@ -716,6 +905,9 @@ Unseals the user-defined symbol {{sl}}, so that it can be re-assigned. #}
{#op||unseal-sigil||{{sl}}||{{none}}|| Unseals sigil {{sl}}, so that it can be re-defined (system sigils cannot be unsealed). #} + +{#op||uppercase||{{sl1}}||{{sl2}}|| +Returns a copy of {{sl}} converted to uppercase.#} {#op||version||{{none}}||{{s}}|| Returns the current min version number. #}
@@ -1,199 +0,0 @@
------ -content-type: "page" -title: "str Module" ------ -{@ _defs_.md || 0 @} - -{#alias||%||interpolate#} - -{#alias||=%||apply-interpolate#} - -{#op||apply-interpolate||{{s}} {{q}}||{{s}}|| -The same as pushing `apply` and then `interpolate` on the stack.#} - -{#op||capitalize||{{sl}}||{{s}}|| -Returns a copy of {{sl}} with the first character capitalized.#} - -{#op||chr||{{i}}||{{s}}|| -Returns the single character {{s}} obtained by interpreting {{i}} as an ASCII code.#} - -{#op||escape||{{sl}}||{{s}}|| -Returns a copy of {{sl}} with quotes and backslashes escaped with a backslash.#} - -{#op||from-bin||{{sl}}||{{i}}|| -Parses {{sl}} as a binary number. #} - -{#op||from-dec||{{sl}}||{{i}}|| -Parses {{sl}} as a decimal number. #} - -{#op||from-hex||{{sl}}||{{i}}|| -Parses {{sl}} as a hexadecimal number. #} - -{#op||from-oct||{{sl}}||{{i}}|| -Parses {{sl}} as a octal number. #} - -{#op||from-semver||{{s}}||{{d}}|| -Given a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}}, -it pushes a dictionary {{d}} on the stack containing a **major**, **minor**, and **patch** key/value pairs.#} - -{#op||indent||{{sl}} {{i}}||{{s}}|| -Returns {{s}} containing {{sl}} indented with {{i}} spaces.#} - -{#op||indexof||{{s1}} {{s2}}||{{i}}|| -If {{s2}} is contained in {{s1}}, returns the index of the first match or -1 if no match is found. #} - -{#op||interpolate||{{s}} {{q}}||{{s}}|| -> Substitutes the placeholders included in {{s}} with the values in {{q}}. -> > %note% -> > Notes -> > -> > * If {{q}} contains symbols or quotations, they are not interpreted. To do so, call `apply` before interpolating or use `apply-interpolate` instead. -> > * You can use the `$#` placeholder to indicate the next placeholder that has not been already referenced in the string. -> > * You can use named placeholders like `$pwd`, but in this case {{q}} must contain a quotation containing both the placeholder names (odd items) and the values (even items). -> -> > %sidebar% -> > Example -> > -> > The following code (executed in a directory called '/Users/h3rald/Development/min' containing 19 files): -> > -> > `"Directory '$1' includes $2 files." (. (. ls 'file? filter size)) apply interpolate` -> > -> > produces: -> > -> > `"Directory '/Users/h3rald/Development/min' includes 19 files."`#} - -{#op||join||{{q}} {{sl}}||{{s}}|| -Joins the elements of {{q}} using separator {{sl}}, producing {{s}}.#} - -{#op||length||{{sl}}||{{i}}|| -Returns the length of {{sl}}.#} - -{#op||lowercase||{{sl}}||{{s}}|| -Returns a copy of {{sl}} converted to lowercase.#} - -{#op||match?||{{s1}} {{s2}}||{{b}}|| -> Returns {{t}} if {{s2}} matches {{s1}}, {{f}} otherwise. -> > %tip% -> > Tip -> > -> > {{s2}} is a {{pcre}}#}. - -{#op||ord||{{s}}||{{i}}|| -Returns the ASCII code {{i}} corresponding to the single character {{s}}.#} - -{#op||parse-url||{{s}}||{{url}}|| -Parses the url {{s}} into its components and stores them into {{url}}.#} - -{#op||prefix||{{sl1}} {{sl2}}||{{s}}|| -Prepends {{sl2}} to {{sl1}}.#} - -{#op||repeat||{{sl}} {{i}}||{{s}}|| -Returns {{s}} containing {{sl}} repeated {{i}} times.#} - -{#op||replace||{{s1}} {{s2}} {{s3}}||{{s4}}|| -> Returns a copy of {{s1}} containing all occurrences of {{s2}} replaced by {{s3}} -> > %tip% -> > Tip -> > -> > {{s2}} is a {{pcre}}. -> -> > %sidebar% -> > Example -> > -> > The following: -> > -> > `"This is a stupid test. Is it really a stupid test?" " s[a-z]+" " simple" replace` -> > -> > produces: -> > -> > `"This is a simple test. Is it really a simple test?"`#} - -{#op||replace-apply||{{s1}} {{s2}} {{q}}||{{s3}}|| -> Returns a copy of {{s1}} containing all occurrences of {{s2}} replaced by applying {{q}} to each quotation corresponding to each match. -> > %tip% -> > Tip -> > -> > {{s2}} is a {{pcre}}. -> -> > %sidebar% -> > Example -> > -> > The following: -> > -> > `":1::2::3::4:" ":(\d):" (1 get :d "-$#-" (d) =%) replace-apply` -> > -> > produces: -> > -> > `"-1--2--3--4-"` -> > -> > Note that for each match the following quotations (each containing the full match and the captured matches) are produced as input for the replace quotation: `("-1-" "1") ("-2-" "2") ("-3-" "3") ("-4-" "4")` #} - -{#op||search||{{s1}} {{s2}}||{{q}}|| -> Returns a quotation containing the first occurrence of {{s2}} within {{s1}}. Note that: -> -> * The first element of {{q}} is the matching substring. -> * Other elements (if any) contain captured substrings. -> * If no matches are found, the quotation contains empty strings. -> -> > %tip% -> > Tip -> > -> > {{s2}} is a {{pcre}}. -> -> > %sidebar% -> > Example -> > -> > The following: -> > -> > `"192.168.1.1, 127.0.0.1" "[0-9]+\.[0-9]+\.([0-9]+)\.([0-9]+)" search` -> > -> > produces: `("192.168.1.1", "1", "1")`#} - -{#op||search-all||{{s1}} {{s2}}||{{q}}|| -Returns a quotation of quotations (like the one returned by the search operator) containing all occurrences of {{s2}} within {{s1}}. #} - -{#op||semver-inc-major||{{s1}}||{{s2}}|| -Increments the major digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} - -{#op||semver-inc-minor||{{s1}}||{{s2}}|| -Increments the minor digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} - -{#op||semver-inc-patch||{{s1}}||{{s2}}|| -Increments the patch digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} - -{#op||semver?||{{s}}||{{b}}|| -Checks whether {{s}} is a [SemVer](https://semver.org)-compliant version or not. #} - -{#op||split||{{sl1}} {{sl2}}||{{q}}|| -Splits {{sl1}} using separator {{sl2}} (a {{pcre}}) and returns the resulting strings within the quotation {{q}}. #} - -{#op||strip||{{sl}}||{{s}}|| -Returns {{s}}, which is set to {{sl}} with leading and trailing spaces removed.#} - -{#op||substr||{{s1}} {{i1}} {{i2}}||{{s2}}|| -Returns a substring {{s2}} obtained by retrieving {{i2}} characters starting from index {{i1}} within {{s1}}.#} - -{#op||suffix||{{sl1}} {{sl2}}||{{s}}|| -Appends {{sl2}} to {{sl1}}.#} - -{#op||titleize||{{sl}}||{{s}}|| -Returns a copy of {{sl}} in which the first character of each word is capitalized.#} - -{#op||to-bin||{{i}}||{{s}}|| -Converts {{i}} to its binary representation. #} - -{#op||to-dec||{{i}}||{{s}}|| -Converts {{i}} to its decimal representation. #} - -{#op||to-hex||{{i}}||{{s}}|| -Converts {{i}} to its hexadecimal representation. #} - -{#op||to-oct||{{i}}||{{s}}|| -Converts {{i}} to its octal representation. #} - -{#op||to-semver||{{d}}||{{s}}|| -Given a a dictionary {{d}} containing a **major**, **minor**, and **patch** key/value pairs , it pushes a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}} on the stack.#} - -{#op||uppercase||{{sl1}}||{{sl2}}|| -Returns a copy of {{sl}} converted to uppercase.#} -
@@ -20,8 +20,6 @@ {#link-module||io#}
: Provides operators for reading and writing files as well as printing to STDOUT and reading from STDIN. {#link-module||fs#} : Provides operators for accessing file information and properties. -{#link-module||str#} -: Provides operators to perform operations on strings, use regular expressions, interpolation, etc. {#link-module||sys#} : Provides operators to use as basic shell commands, access environment variables, and execute external commands. {#link-module||time#}
@@ -17,7 +17,6 @@ 'global load
'math load 'seq load 'stack load -'str load 'sys load 'time load 'xml load
@@ -632,6 +632,93 @@ ("never printed" puts!)
) || ) test.assert + ;; String operations + + ("$1 - $2 - $3" (1 true "test") interpolate "1 - true - test" ==) test.assert + + ("$1 + $2 = $3" (2 2 (2 2 +)) apply interpolate "2 + 2 = 4" ==) test.assert + + (" test " strip "test" ==) test.assert + + ("test" length 4 ==) test.assert + + ("a,b,c" "," split ("a" "b" "c") ==) test.assert + + ("abc" "" split ("a" "b" "c") ==) test.assert + + ("This is a test" 5 2 substr "is" ==) test.assert + + ("this" 2 3 substr "is" ==) test.assert + + ("This is a test" "is" indexof 2 ==) test.assert + + ("test #1" "[0-9]" search ("1") ==) test.assert + + ("a" ord 97 ==) test.assert + + (97 chr "a" ==) test.assert + + ("This is test #1" "test #([0-9])" search ("test #1" "1") ==) test.assert + + ("This is a random string" "random" match?) test.assert + + ("something is not something else" "some" "any" replace "anything is not anything else" ==) test.assert + + ("MiN is a concatenative programming language" "(?i)^min" search ("MiN") ==) test.assert + + ("This is a difficult test" "difficult" "simple" replace "This is a simple test" ==) test.assert + + ("This is a DIFFICULT\n test" "(?mi)difficult" "simple" replace "This is a simple\n test" ==) test.assert + + ("This is again another test" "(again|still|yet)" (1 get :m "_$#_" (m) =%) replace-apply "This is _again_ another test" ==) test.assert + + ("/api/items/test-1" "\\/api\\/items\\/(.+)" search 1 get "test-1" ==) test.assert + + ("this is a test" uppercase "THIS IS A TEST" ==) test.assert + + ("THIS IS A TEST" lowercase "this is a test" ==) test.assert + + ("test" capitalize "Test" ==) test.assert + + ("this is a test" titleize "This Is A Test" ==) test.assert + + ("+" 3 repeat "+++" ==) test.assert + + ("test" 4 indent " test" ==) test.assert + + ((1 3 "test") ", " join "1, 3, test" ==) test.assert + + ("PWD: $pwd" ("pwd" pwd) =% ("PWD: " pwd) => "" join ==) test.assert + + ("1.2.3" from-semver {1 :major 2 :minor 3 :patch} ==) test.assert + + ({2 :major 25 :minor 300 :patch} to-semver "2.25.300" ==) test.assert + + ("2.3.6" semver-inc-major "3.0.0" ==) test.assert + + ("2.3.6" semver-inc-minor "2.4.0" ==) test.assert + + ("2.3.6" semver-inc-patch "2.3.7" ==) test.assert + + ("4.6.5" semver? true ==) test.assert + + ("4.6.5.3" semver? false ==) test.assert + + ("fix" "pre" prefix "prefix" ==) test.assert + + ("suf" "fix" suffix "suffix" ==) test.assert + + ("http://test.com?€%,,!{}" encode-url "http%3A%2F%2Ftest.com%3F%E2%82%AC%25%2C%2C%21%7B%7D" ==) test.assert + + ("http%3A%2F%2Ftest.com%3F%E2%82%AC%25%2C%2C%21%7B%7D" decode-url "http://test.com?€%,,!{}" ==) test.assert + + ("http://h3rald.com/a/b/c?test=1#123" parse-url {"123" :anchor "h3rald.com" :hostname "" :password "/a/b/c" :path "" :port "test=1" :query "http" :scheme "" :username} ==) test.assert + + ("0b00101101" dup from-bin to-bin ==) test.assert + ("0x00FF0000" dup from-hex to-hex ==) test.assert + ("0o00007473" dup from-oct to-oct ==) test.assert + ("123" dup from-dec to-dec ==) test.assert + test.report ;; Tidy up clear-stack
@@ -1,92 +0,0 @@
-'min-test require :test -;;; - -"str" test.describe - - ("$1 - $2 - $3" (1 true "test") interpolate "1 - true - test" ==) test.assert - - ("$1 + $2 = $3" (2 2 (2 2 +)) apply interpolate "2 + 2 = 4" ==) test.assert - - (" test " strip "test" ==) test.assert - - ("test" length 4 ==) test.assert - - ("a,b,c" "," split ("a" "b" "c") ==) test.assert - - ("abc" "" split ("a" "b" "c") ==) test.assert - - ("This is a test" 5 2 substr "is" ==) test.assert - - ("this" 2 3 substr "is" ==) test.assert - - ("This is a test" "is" indexof 2 ==) test.assert - - ("test #1" "[0-9]" search ("1") ==) test.assert - - ("a" ord 97 ==) test.assert - - (97 chr "a" ==) test.assert - - ("This is test #1" "test #([0-9])" search ("test #1" "1") ==) test.assert - - ("This is a random string" "random" match?) test.assert - - ("something is not something else" "some" "any" replace "anything is not anything else" ==) test.assert - - ("MiN is a concatenative programming language" "(?i)^min" search ("MiN") ==) test.assert - - ("This is a difficult test" "difficult" "simple" replace "This is a simple test" ==) test.assert - - ("This is a DIFFICULT\n test" "(?mi)difficult" "simple" replace "This is a simple\n test" ==) test.assert - - ("This is again another test" "(again|still|yet)" (1 get :m "_$#_" (m) =%) replace-apply "This is _again_ another test" ==) test.assert - - ("/api/items/test-1" "\\/api\\/items\\/(.+)" search 1 get "test-1" ==) test.assert - - ("this is a test" uppercase "THIS IS A TEST" ==) test.assert - - ("THIS IS A TEST" lowercase "this is a test" ==) test.assert - - ("test" capitalize "Test" ==) test.assert - - ("this is a test" titleize "This Is A Test" ==) test.assert - - ("+" 3 repeat "+++" ==) test.assert - - ("test" 4 indent " test" ==) test.assert - - ((1 3 "test") ", " join "1, 3, test" ==) test.assert - - ("PWD: $pwd" ("pwd" pwd) =% ("PWD: " pwd) => "" join ==) test.assert - - ("1.2.3" from-semver {1 :major 2 :minor 3 :patch} ==) test.assert - - ({2 :major 25 :minor 300 :patch} to-semver "2.25.300" ==) test.assert - - ("2.3.6" semver-inc-major "3.0.0" ==) test.assert - - ("2.3.6" semver-inc-minor "2.4.0" ==) test.assert - - ("2.3.6" semver-inc-patch "2.3.7" ==) test.assert - - ("4.6.5" semver? true ==) test.assert - - ("4.6.5.3" semver? false ==) test.assert - - ("fix" "pre" prefix "prefix" ==) test.assert - - ("suf" "fix" suffix "suffix" ==) test.assert - - ("http://test.com?€%,,!{}" encode-url "http%3A%2F%2Ftest.com%3F%E2%82%AC%25%2C%2C%21%7B%7D" ==) test.assert - - ("http%3A%2F%2Ftest.com%3F%E2%82%AC%25%2C%2C%21%7B%7D" decode-url "http://test.com?€%,,!{}" ==) test.assert - - ("http://h3rald.com/a/b/c?test=1#123" parse-url {"123" :anchor "h3rald.com" :hostname "" :password "/a/b/c" :path "" :port "test=1" :query "http" :scheme "" :username} ==) test.assert - - ("0b00101101" dup from-bin to-bin ==) test.assert - ("0x00FF0000" dup from-hex to-hex ==) test.assert - ("0o00007473" dup from-oct to-oct ==) test.assert - ("123" dup from-dec to-dec ==) test.assert - - test.report - clear-stack