1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
----
-- A string with substitutions, partially implements the `AST` interface.
--
-- Is automatically "splatted" into multiple expressions when the containing
-- `Cell` is evaluated: the original string (str=), but with with substitution
-- markers like `#{1}`, `#{2}` and so on and one expression for each substitution.
--
-- `#` symbols in the original string are escaped to `##`.
--
-- @classmod TemplateString
import Constant from require 'alv.result'
-- @type TemplateString
class TemplateString
--- AST interface
--
-- `TemplateString` partially implements the `AST` interface.
-- @section ast
--- create a clone with its own identity.
--
-- creates a clone of this TemplateString by cloning all child expressions
-- recursively.
--
-- @tparam Tag parent
-- @treturn TemplateString
clone: (parent) =>
children = [child\clone parent for child in *@children]
@@ @string, children
--- stringify this TemplateString.
--
-- if `depth` is passed, does not faithfully recreate the original string but
-- rather create useful debug output.
--
-- @tparam[opt] int depth the maximum depth, defaults to infinite
-- @treturn string the exact string this TemplateString was parsed from
stringify: (depth=-1) =>
children = ['#' .. child\stringify depth for child in *@children]
str = @@.subst @.string!, (i) -> '#' .. @children[i]\stringify depth
'#"' .. str .. '"'
--- static functions
-- @section static
new: (@string, @children) =>
--- apply substitutions to a template string.
--
-- This also reverses the escaping that the parser applied.
--
-- @classmethod
-- @tparam string str the evaluated `TemplateString.string`
-- @tparam function fn function called with index i to obtain string to substitute
-- @treturn string
@subst: (str, fn) ->
str = str\gsub '##', '#'
str\gsub '#{(%d+)}', (i) -> fn tonumber i
--- parse a TemplateString (for parsing with Lpeg).
--
-- @classmethod
-- @tparam {string|AST,...} pieces
-- @treturn TemplateString
@parse: (...) =>
string = ''
children = {}
i = 1
for elem in *{...}
if 'string' == type elem
string ..= elem\gsub '#', '##'
else
table.insert children, elem
string ..= '#{' .. #children .. '}'
string = Constant.str string
@@ string, children
{
:TemplateString
}
|