mirror of
https://github.com/Oreolek/ink-instead.git
synced 2024-05-12 22:18:26 +03:00
Merge pull request #4 from premek/flatparse
Flat parser refactor - parsed table is now flat, not nested - e.g. knot content is not inside the knot node but following the knot node. the same for options. Simpler parser, runtime not much more complicated
This commit is contained in:
commit
faedb6a3be
|
@ -4,11 +4,6 @@ local S,C,Ct,Cc,Cg,Cb,Cf,Cmt,P,V =
|
||||||
lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cb, lpeg.Cf, lpeg.Cmt,
|
lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cb, lpeg.Cf, lpeg.Cmt,
|
||||||
lpeg.P, lpeg.V
|
lpeg.P, lpeg.V
|
||||||
|
|
||||||
local concat = function (p)
|
|
||||||
return Cf(p, function (a,b) return a..b end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local parserLogger = print
|
|
||||||
local eof = -1
|
local eof = -1
|
||||||
local sp = S" \t" ^0 + eof
|
local sp = S" \t" ^0 + eof
|
||||||
local wh = S" \t\r\n" ^0 + eof
|
local wh = S" \t\r\n" ^0 + eof
|
||||||
|
@ -16,68 +11,52 @@ local nl = S"\r\n" ^1 + eof
|
||||||
local id = (lpeg.alpha + '_') * (lpeg.alnum + '_')^0
|
local id = (lpeg.alpha + '_') * (lpeg.alnum + '_')^0
|
||||||
local addr = C(id) * ('.' * C(id))^-1
|
local addr = C(id) * ('.' * C(id))^-1
|
||||||
|
|
||||||
local todo = sp * 'TODO:' * sp * (1-nl)^0 / parserLogger * wh -- TODO log location
|
local todo = Ct(sp * 'TODO:'/"todo" * sp * C((1-nl)^0)) * wh
|
||||||
local commOL = sp * '//' * sp * (1-nl)^0 * wh
|
local commOL = Ct(sp * '//'/"comment" * sp * C((1-nl)^0)) * wh
|
||||||
local commML = sp * '/*' * wh * (P(1)-'*/')^0 * '*/' * wh
|
local commML = Ct(sp * '/*'/"comment" * wh * C((P(1)-'*/')^0)) * '*/' * wh
|
||||||
local comm = commOL + commML + todo
|
local comm = commOL + commML + todo
|
||||||
|
|
||||||
local glue = P'<>'/'glue' *wh -- FIXME do not consume spaces after glue
|
local glue = Ct(P'<>'/'glue') *wh -- FIXME do not consume spaces after glue
|
||||||
|
|
||||||
local divertSym = '->' *wh
|
local divertSym = '->' *wh
|
||||||
local divertEndSym = C('END') *wh
|
local divertEnd = Ct(divertSym/'end' * 'END' * wh)
|
||||||
local divertEnd = divertSym * divertEndSym
|
|
||||||
local divertJump = Ct(divertSym/'divert' * addr * wh)
|
local divertJump = Ct(divertSym/'divert' * addr * wh)
|
||||||
local divert = divertEnd + divertJump
|
local divert = divertEnd + divertJump
|
||||||
|
|
||||||
local knotHead = P('=')^2/'knot' * wh * C(id) * wh * P('=')^0 * wh
|
local knot = Ct(P('=')^2/'knot' * wh * C(id) * wh * P('=')^0) * wh
|
||||||
local stitchHead = P('=')^1/'stitch' * wh * C(id) * wh * P('=')^0 * wh
|
local stitch = Ct(P('=')^1/'stitch' * wh * C(id) * wh * P('=')^0) * wh
|
||||||
|
|
||||||
local optDiv = '[' * C((P(1) - ']')^0) * ']'
|
local optDiv = '[' * C((P(1) - ']')^0) * ']'
|
||||||
|
|
||||||
local optStars = concat(wh * C(P'*') * (sp * C'*')^0)
|
local optStars = wh * Ct(C'*' * (sp * C'*')^0)/table.getn
|
||||||
local optStarsSameIndent = Cmt(Cb("indent") * optStars,
|
|
||||||
function (s, i, a, b) return a == b end)
|
|
||||||
local optStarsLEIndent = Cmt(Cb("indent") * optStars,
|
|
||||||
function (s, i, backtrack, this)
|
|
||||||
return string.len(this) <= string.len(backtrack)
|
|
||||||
end)
|
|
||||||
|
|
||||||
|
|
||||||
local tag = Ct(wh * P('#')/'tag' * wh * V'text' * wh)
|
|
||||||
|
|
||||||
|
|
||||||
|
local hash = P('#')
|
||||||
|
local tag = hash * wh * V'text'
|
||||||
|
local tagGlobal = Ct(Cc'tag' * Cc'global' * tag * wh)
|
||||||
|
local tagAbove = Ct(Cc'tag' * Cc'above' * tag * wh)
|
||||||
|
local tagEnd = Ct(Cc'tag' * Cc'end' * tag * sp)
|
||||||
|
|
||||||
local ink = P({
|
local ink = P({
|
||||||
"lines",
|
"lines",
|
||||||
|
|
||||||
knotKnot = Ct(knotHead * (V'line'-knotHead)^0 * wh),
|
stmt = glue + divert + knot + stitch + V'option' + optDiv + comm + V'include',
|
||||||
knotStitch = Ct(stitchHead * (V'line'-stitchHead)^0 * wh),
|
text = C((1-nl-V'stmt'-hash)^1),
|
||||||
knot = V'knotKnot' + V'knotStitch',
|
textEmptyCapt = C((1-nl-V'stmt'-hash)^0),
|
||||||
|
|
||||||
stmt = glue + divert + V'knot' + optDiv + comm + V'include' + tag,
|
optAnsWithDiv = V'textEmptyCapt' * sp * optDiv * V'text'^0 * wh,
|
||||||
text = C((1-nl-V'stmt')^1) *wh,
|
optAnsWithoutDiv = V'textEmptyCapt' * sp * Cc '' * Cc '' * wh, -- huh?
|
||||||
textE = C((1-nl-V'stmt')^0) *wh,
|
|
||||||
|
|
||||||
optAnsWithDiv = V'textE' * optDiv * V'textE' * wh,
|
|
||||||
optAnsWithoutDiv = V'textE' * Cc ''* Cc ''* wh, -- huh?
|
|
||||||
optAns = V'optAnsWithDiv' + V'optAnsWithoutDiv',
|
optAns = V'optAnsWithDiv' + V'optAnsWithoutDiv',
|
||||||
|
|
||||||
-- TODO clean this
|
option = Ct(Cc'option' * optStars * sp * V'optAns'),
|
||||||
opt = Cg(optStars,'indent') *
|
|
||||||
Ct(Cc'option' * sp * V'optAns' * (V'line'-V'optLEIndent'-V'knot')^0 * wh), --TODO which can by toplevel only?
|
|
||||||
optSameIndent = Ct(Cc'option' * optStarsSameIndent * sp * V'optAns' * (V'line'-V'optLEIndent'-V'knot')^0 * wh),
|
|
||||||
optLEIndent = Ct(Cc'option' * optStarsLEIndent * sp * V'optAns' * (V'line'-V'optLEIndent'-V'knot')^0 * wh),
|
|
||||||
|
|
||||||
opts = (V'opt'*V'optSameIndent'^0),
|
|
||||||
|
|
||||||
choice = Ct(Cc'choice' * V'opts')/function(t) t.indent=nil; return t end,
|
|
||||||
|
|
||||||
|
|
||||||
include = Ct(P('INCLUDE')/'include' * wh * V'text' * wh),
|
include = Ct(P('INCLUDE')/'include' * wh * V'text' * wh),
|
||||||
|
|
||||||
para = Ct(Cc'para' * V'text'),
|
para = tagAbove^0 * Ct(Cc'para' * V'text') * tagEnd^0 * wh + tagGlobal,
|
||||||
|
|
||||||
line = V'stmt' + V'choice' + V'para',
|
line = V'stmt' + V'para',
|
||||||
lines = Ct(V'line'^0)
|
lines = Ct(V'line'^0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
177
pink/runtime.lua
177
pink/runtime.lua
|
@ -1,104 +1,158 @@
|
||||||
|
local debug = function(x) print( require('test/luaunit').prettystr(x) ) end
|
||||||
|
|
||||||
local is = function (what, node)
|
local is = function (what, node)
|
||||||
return node ~= nil
|
return node ~= nil
|
||||||
and (type(node) == "table" and node[1] == what)
|
and (type(node) == "table" and node[1] == what)
|
||||||
or (type(node) == "string" and node == what)
|
|
||||||
end
|
|
||||||
|
|
||||||
local getPara = function (node)
|
|
||||||
if is('para', node) then return node[2] end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return function (tree)
|
return function (tree)
|
||||||
local s = {}
|
local s = {
|
||||||
|
globalTags = {},
|
||||||
local pointer = nil
|
state = {
|
||||||
local tab = {}
|
visitCount = {},
|
||||||
|
}
|
||||||
local knots = {}
|
|
||||||
|
|
||||||
-- TODO state should contain tab/pointer to be able to save / load
|
|
||||||
s.state = {
|
|
||||||
visitCount = {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local process = function ()
|
local pointer = 1
|
||||||
for _, v in ipairs(tree) do
|
local knots = {}
|
||||||
if is('knot', v) then
|
local tags = {} -- maps (pointer to para) -> (list of tags)
|
||||||
knots[v[2]] = v
|
local tagsForContentAtPath = {}
|
||||||
|
local currentChoicesPointers = {}
|
||||||
|
|
||||||
|
-- TODO state should contain tree/pointer to be able to save / load
|
||||||
|
|
||||||
|
local preProcess = function ()
|
||||||
|
|
||||||
|
local aboveTags = {}
|
||||||
|
local lastPara = {}
|
||||||
|
local lastKnotName
|
||||||
|
|
||||||
|
for p, n in ipairs(tree) do
|
||||||
|
if is('knot', n) then -- FIXME stitches
|
||||||
|
knots[n[2]] = p
|
||||||
|
--print(v[2],k)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if is('tag', n) then
|
||||||
|
if n[2] == 'global' then
|
||||||
|
table.insert(s.globalTags, n[3])
|
||||||
|
end
|
||||||
|
if n[2] == 'above' then
|
||||||
|
if lastKnotName then table.insert(tagsForContentAtPath[lastKnotName], n[3]) end
|
||||||
|
table.insert(aboveTags, n[3])
|
||||||
|
end
|
||||||
|
if n[2] == 'end' then
|
||||||
|
table.insert(tags[lastPara], n[3])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if is('knot', n) or is('stitch', n) then
|
||||||
|
lastKnotName = n[2]
|
||||||
|
tagsForContentAtPath[lastKnotName] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
if is('para', n) then
|
||||||
|
tags[p] = aboveTags
|
||||||
|
aboveTags = {}
|
||||||
|
lastPara = p
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local goToKnot = function(knotName)
|
local goToKnot = function(knotName)
|
||||||
if knots[knotName] then
|
if knots[knotName] then
|
||||||
s.state.visitCount[knotName] = (s.state.visitCount[knotName] or 0) + 1
|
s.state.visitCount[knotName] = s.state.visitCountAtPathString(knotName) + 1
|
||||||
tab = knots[knotName]
|
pointer = knots[knotName] + 1 -- go to the line after the knot
|
||||||
pointer = 3
|
else
|
||||||
return tab[pointer]
|
|
||||||
else
|
|
||||||
print('unknown knot', knotName)
|
print('unknown knot', knotName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local update = function ()
|
local isNext = function (what)
|
||||||
local next = tab[pointer]
|
return is(what, tree[pointer])
|
||||||
|
end
|
||||||
|
|
||||||
if is('knot', next) then
|
local getPara = function ()
|
||||||
|
if isNext('para') then return tree[pointer][2] end
|
||||||
|
end
|
||||||
|
|
||||||
|
local update
|
||||||
|
update = function ()
|
||||||
|
|
||||||
|
if isNext('knot') then
|
||||||
-- FIXME: we shouldn't continue to next knot automatically probably - how about stitches?
|
-- FIXME: we shouldn't continue to next knot automatically probably - how about stitches?
|
||||||
--next = goToKnot(next[2])
|
--next = goToKnot(next[2])
|
||||||
end
|
end
|
||||||
|
|
||||||
if is('divert', next) then next = goToKnot(next[2]) end
|
if isNext('divert') then
|
||||||
|
goToKnot(tree[pointer][2])
|
||||||
|
update()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
s.canContinue = is('para', next)
|
if isNext('tag') then
|
||||||
|
|
||||||
|
pointer = pointer + 1
|
||||||
|
update()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
s.canContinue = isNext('para')
|
||||||
|
|
||||||
s.currentChoices = {}
|
s.currentChoices = {}
|
||||||
if is('choice', next) then
|
currentChoicesPointers = {}
|
||||||
for i=2, #next do
|
|
||||||
--print(to_string(next[i]))
|
if isNext('option') then
|
||||||
table.insert(s.currentChoices, {
|
local choiceDepth = tree[pointer][2]
|
||||||
text = (next[i][2] or '') .. (next[i][3] or ''),
|
-- find all choices on the same level in the same knot and in the same super-choice
|
||||||
choiceText = next[i][2] .. (next[i][4] or ''),
|
for p=pointer, #tree do
|
||||||
})
|
local n = tree[p]
|
||||||
|
--print('looking for options', choiceDepth, n[1], n[2])
|
||||||
|
if is('knot', n) or is('stitch', n) or (is('option', n) and n[2] < choiceDepth) then
|
||||||
|
--print('stop looking for options');
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
if is('option', n) and n[2] == choiceDepth then
|
||||||
|
-- print('adding', p, n[3])
|
||||||
|
table.insert(currentChoicesPointers, p)
|
||||||
|
table.insert(s.currentChoices, {
|
||||||
|
text = (n[3] or '') .. (n[4] or ''),
|
||||||
|
choiceText = n[3] .. (n[5] or ''),
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local step = function ()
|
local step = function ()
|
||||||
pointer = pointer + 1
|
|
||||||
update()
|
|
||||||
return tab[pointer]
|
|
||||||
end
|
|
||||||
|
|
||||||
local stepTo = function (table, pos)
|
|
||||||
tab = table
|
|
||||||
pointer = pos
|
|
||||||
update()
|
|
||||||
return tab[pointer]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.canContinue = nil
|
s.canContinue = nil
|
||||||
|
|
||||||
s.continue = function()
|
s.continue = function()
|
||||||
local res = getPara(tab[pointer])
|
|
||||||
local next = step()
|
|
||||||
|
|
||||||
if is('glue', next) then
|
local res = getPara()
|
||||||
step()
|
s.currentTags = tags[pointer] or {}
|
||||||
|
|
||||||
|
pointer = pointer + 1
|
||||||
|
update()
|
||||||
|
|
||||||
|
if isNext('glue') then
|
||||||
|
pointer = pointer + 1
|
||||||
|
update()
|
||||||
res = res .. s.continue()
|
res = res .. s.continue()
|
||||||
end
|
end
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
end
|
end
|
||||||
|
|
||||||
s.currentChoices = nil
|
s.currentChoices = {}
|
||||||
|
|
||||||
s.chooseChoiceIndex = function(index)
|
s.chooseChoiceIndex = function(index)
|
||||||
s.currentChoices = {}
|
pointer = currentChoicesPointers[index]+1
|
||||||
local choice = tab[pointer]
|
update()
|
||||||
local option = choice[1 + index]
|
|
||||||
stepTo(option, 5)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.choosePathString = function(knotName)
|
s.choosePathString = function(knotName)
|
||||||
|
@ -110,14 +164,21 @@ return function (tree)
|
||||||
return s.state.visitCount[knotName] or 0
|
return s.state.visitCount[knotName] or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
s.tagsForContentAtPath = function(knotName)
|
||||||
|
return tagsForContentAtPath[knotName] or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
s.currentTags = {}
|
||||||
|
|
||||||
s.variablesState = {}
|
s.variablesState = {}
|
||||||
-- s.state.ToJson();s.state.LoadJson(savedJson);
|
-- s.state.ToJson();s.state.LoadJson(savedJson);
|
||||||
|
|
||||||
stepTo(tree, 1)
|
preProcess()
|
||||||
process()
|
--debug(tree)
|
||||||
|
--debug(tags)
|
||||||
|
|
||||||
-- debug
|
-- debug
|
||||||
s._tree = tree
|
s._tree = tree
|
||||||
|
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,21 +2,10 @@ return {
|
||||||
ink=[[
|
ink=[[
|
||||||
Hello, world!
|
Hello, world!
|
||||||
Hello?
|
Hello?
|
||||||
//TODO: this is a test todo-item
|
|
||||||
|
|
||||||
"What do you make of this?" she asked.
|
"What do you make of this?" she asked.
|
||||||
|
|
||||||
// Something unprintable...
|
|
||||||
|
|
||||||
"I couldn't possibly comment," I replied.
|
"I couldn't possibly comment," I replied.
|
||||||
|
we <>
|
||||||
/*
|
hurr ied-> to_savile_row
|
||||||
... or an unlimited block of text
|
|
||||||
*/
|
|
||||||
we <> /* he
|
|
||||||
asdf
|
|
||||||
*/ hurr ied-> to_savile_row // comm
|
|
||||||
|
|
||||||
|
|
||||||
=== to_savile_row ===
|
=== to_savile_row ===
|
||||||
|
|
||||||
|
@ -33,14 +22,14 @@ expected= {
|
||||||
{"para", '"What do you make of this?" she asked.'},
|
{"para", '"What do you make of this?" she asked.'},
|
||||||
{"para", "\"I couldn't possibly comment,\" I replied."},
|
{"para", "\"I couldn't possibly comment,\" I replied."},
|
||||||
{"para", "we "},
|
{"para", "we "},
|
||||||
"glue",
|
{"glue"},
|
||||||
{"para", "hurr ied"},
|
{"para", "hurr ied"},
|
||||||
{"divert", "to_savile_row"},
|
{"divert", "to_savile_row"},
|
||||||
{
|
{"knot", "to_savile_row"},
|
||||||
"knot",
|
{"para", "to Savile Row"},
|
||||||
"to_savile_row",
|
{"stitch", "st"},
|
||||||
{"para", "to Savile Row"},
|
{"para", "stiiii"},
|
||||||
{"stitch", "st", {"para", "stiiii"}},
|
{"stitch", "st2"},
|
||||||
{"stitch", "st2", {"para", "222stiiii "}, "END"}
|
{"para", "222stiiii "},
|
||||||
}
|
{"end"}
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -27,46 +27,27 @@ He insisted that we hurried home to Savile Row
|
||||||
<> as fast as we could.
|
<> as fast as we could.
|
||||||
]],
|
]],
|
||||||
expected= {
|
expected= {
|
||||||
|
{"knot", "back_in_london"},
|
||||||
|
{"para", "We arrived into London at 9.45pm exactly."},
|
||||||
|
{"option", 1, '"There is not a moment to lose!"', "", " I declared."},
|
||||||
|
{"divert", "hurry_outside"},
|
||||||
|
{"option", 1, '"Monsieur, let us savour this moment!"', "", " I declared."},
|
||||||
{
|
{
|
||||||
"knot",
|
"para",
|
||||||
"back_in_london",
|
"My master clouted me firmly around the head and dragged me out of the door."
|
||||||
{"para", "We arrived into London at 9.45pm exactly."},
|
|
||||||
{
|
|
||||||
"choice",
|
|
||||||
{
|
|
||||||
"option",
|
|
||||||
'"There is not a moment to lose!"',
|
|
||||||
"",
|
|
||||||
" I declared.",
|
|
||||||
{"divert", "hurry_outside"}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"option",
|
|
||||||
'"Monsieur, let us savour this moment!"',
|
|
||||||
"",
|
|
||||||
" I declared.",
|
|
||||||
{
|
|
||||||
"para",
|
|
||||||
"My master clouted me firmly around the head and dragged me out of the door."
|
|
||||||
},
|
|
||||||
'glue',
|
|
||||||
{"divert", "dragged_outside"}
|
|
||||||
},
|
|
||||||
{"option", "", "We hurried home", " ", {"divert", "hurry_outside"}}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{"glue"},
|
||||||
"knot",
|
{"divert", "dragged_outside"},
|
||||||
"hurry_outside",
|
{"option", 1, "", "We hurried home", " "},
|
||||||
{"para", "We hurried home to Savile Row "},
|
{"divert", "hurry_outside"},
|
||||||
{"divert", "as_fast_as_we_could"}
|
{"knot", "hurry_outside"},
|
||||||
},
|
{"para", "We hurried home to Savile Row "},
|
||||||
{
|
{"divert", "as_fast_as_we_could"},
|
||||||
"knot",
|
{"knot", "dragged_outside"},
|
||||||
"dragged_outside",
|
{"para", "He insisted that we hurried home to Savile Row"},
|
||||||
{"para", "He insisted that we hurried home to Savile Row"},
|
{"divert", "as_fast_as_we_could"},
|
||||||
{"divert", "as_fast_as_we_could"}
|
{"knot", "as_fast_as_we_could"},
|
||||||
},
|
{"glue"},
|
||||||
{"knot", "as_fast_as_we_could", "glue", {"para", "as fast as we could."}}
|
{"para", "as fast as we could."}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,30 +12,16 @@ ink=[[
|
||||||
== finale ==
|
== finale ==
|
||||||
]],
|
]],
|
||||||
expected= {
|
expected= {
|
||||||
{
|
{"knot", "start"},
|
||||||
"knot",
|
{"option", 1, "I dont know", "", ""},
|
||||||
"start",
|
{"option", 1, '"I am somewhat tired', '."', '," I repeated.'},
|
||||||
{
|
{"para", '"Really," he responded.'},
|
||||||
"choice",
|
{"para", '"How deleterious."'},
|
||||||
{"option", "I dont know", "", ""},
|
{"option", 1, '"Nothing, Monsieur!"', "", " I replied."},
|
||||||
{
|
{"para", '"Very good,'},
|
||||||
"option",
|
{"option", 1, 'then."', "", ""},
|
||||||
'"I am somewhat tired',
|
{"option", 1, "I said no more", "", ""},
|
||||||
'."',
|
{"para", '"Ah,". "I see you"'},
|
||||||
'," I repeated.',
|
|
||||||
{"para", '"Really," he responded.'},
|
|
||||||
{"para", '"How deleterious."'}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"option",
|
|
||||||
'"Nothing, Monsieur!"',
|
|
||||||
"",
|
|
||||||
" I replied.",
|
|
||||||
{"para", '"Very good, *then."'}
|
|
||||||
},
|
|
||||||
{"option", "I said no more", "", "", {"para", '"Ah,". "I see you"'}}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"knot", "finale"}
|
{"knot", "finale"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
test/parser/comments.lua
Normal file
34
test/parser/comments.lua
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
return {
|
||||||
|
ink=[[
|
||||||
|
Hello?
|
||||||
|
TODO: this is a test todo-item
|
||||||
|
|
||||||
|
"What do you make of this?" she asked.
|
||||||
|
|
||||||
|
// Something unprintable...
|
||||||
|
|
||||||
|
"I couldn't possibly comment," I replied.
|
||||||
|
|
||||||
|
/*
|
||||||
|
... or an unlimited block of text
|
||||||
|
*/
|
||||||
|
we <> /* he
|
||||||
|
asdf
|
||||||
|
*/ hurr ied-> to_savile_row // comm
|
||||||
|
|
||||||
|
|
||||||
|
]],
|
||||||
|
expected= {
|
||||||
|
{"para", "Hello?"},
|
||||||
|
{"todo", "this is a test todo-item"},
|
||||||
|
{"para", '"What do you make of this?" she asked.'},
|
||||||
|
{"comment", "Something unprintable..."},
|
||||||
|
{"para", "\"I couldn't possibly comment,\" I replied."},
|
||||||
|
{"comment", "... or an unlimited block of text\n"},
|
||||||
|
{"para", "we "},
|
||||||
|
{"glue"},
|
||||||
|
{"comment", "he\nasdf\n"},
|
||||||
|
{"para", "hurr ied"},
|
||||||
|
{"divert", "to_savile_row"},
|
||||||
|
{"comment", "comm"},
|
||||||
|
}}
|
|
@ -9,22 +9,14 @@ ink=[[
|
||||||
|
|
||||||
]],
|
]],
|
||||||
expected={
|
expected={
|
||||||
{
|
{"option", 1, '"Monsieur, let us savour this moment!"', "", " I declared."},
|
||||||
"choice",
|
{"para", "My master clouted me firmly around the head and dragged me out of the door. " },
|
||||||
{
|
{"glue"},
|
||||||
"option",
|
{"divert", "dragged_outside"},
|
||||||
'"Monsieur, let us savour this moment!"',
|
{"option", 1, "", "We hurried home", " "},
|
||||||
"",
|
{"divert", "hurry_outside"},
|
||||||
" I declared.",
|
{"knot", "as_fast_as_we_could"},
|
||||||
{
|
{"glue"},
|
||||||
"para",
|
{"para", "as fast as we could."} -- TODO should be space before 'as'
|
||||||
"My master clouted me firmly around the head and dragged me out of the door. "
|
|
||||||
},
|
|
||||||
"glue",
|
|
||||||
{"divert", "dragged_outside"}
|
|
||||||
},
|
|
||||||
{"option", "", "We hurried home", " ", {"divert", "hurry_outside"}}
|
|
||||||
},
|
|
||||||
{"knot", "as_fast_as_we_could", "glue", {"para", "as fast as we could."}} -- TODO should be space before 'as'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,18 @@ ink=[[
|
||||||
|
|
||||||
]],
|
]],
|
||||||
expected={
|
expected={
|
||||||
{
|
{ "knot", "the_orient_express"},
|
||||||
"knot",
|
{"stitch", "in_first_class"},
|
||||||
"the_orient_express",
|
{"para", "..."},
|
||||||
{"stitch", "in_first_class", {"para", "..."}},
|
{"stitch", "in_third_class"},
|
||||||
{"stitch", "in_third_class", {"para", "..."}},
|
{"para", "..."},
|
||||||
{"stitch", "in_the_guards_van", {"para", "..."}, {"para", "..."}},
|
{"stitch", "in_the_guards_van"},
|
||||||
{"stitch", "missed_the_train", {"para", "..."}}
|
{"para", "..."},
|
||||||
},
|
{"para", "..."},
|
||||||
{"knot", "the_orient_express"},
|
{"stitch", "missed_the_train"},
|
||||||
{"knot", "the_orient_express", {"stitch", "stitch"}}
|
{"para", "..."},
|
||||||
|
{"knot", "the_orient_express"},
|
||||||
|
{"knot", "the_orient_express"},
|
||||||
|
{"stitch", "stitch"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,14 @@ return {
|
||||||
ink=[[
|
ink=[[
|
||||||
* "Murder!"
|
* "Murder!"
|
||||||
** A
|
** A
|
||||||
|
* * A
|
||||||
* "Suicide!"
|
* "Suicide!"
|
||||||
]], expected= {
|
]], expected= {
|
||||||
{
|
|
||||||
"choice",
|
{"option", 1, '"Murder!"', "", ""},
|
||||||
{
|
{"option", 2, "A", "", ""},
|
||||||
"option",
|
{"option", 2, "A", "", ""},
|
||||||
'"Murder!"',
|
{"option", 1, '"Suicide!"', "", ""}
|
||||||
"",
|
|
||||||
"",
|
|
||||||
{"choice", {"option", "A", "", ""}}
|
|
||||||
},
|
|
||||||
{"option", '"Suicide!"', "", ""}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,22 +10,11 @@ ink=[[
|
||||||
]],
|
]],
|
||||||
expected = {
|
expected = {
|
||||||
{"para", '"Well, Poirot? Murder or suicide?"'},
|
{"para", '"Well, Poirot? Murder or suicide?"'},
|
||||||
{
|
{"option", 1, '"Murder"', "", ""},
|
||||||
"choice",
|
{"para", '"And who did it?"'},
|
||||||
{
|
{"option", 2, '"Detective-Inspector Japp!"', "", ""},
|
||||||
"option",
|
{"option", 2, '"Captain Hastings!"', "", ""},
|
||||||
'"Murder"',
|
{"option", 2, '"Myself!"', "", ""},
|
||||||
"",
|
{"option", 1, '"Suicide"', "", ""}
|
||||||
"",
|
|
||||||
{"para", '"And who did it?"'},
|
|
||||||
{
|
|
||||||
"choice",
|
|
||||||
{"option", '"Detective-Inspector Japp!"', "", ""},
|
|
||||||
{"option", '"Captain Hastings!"', "", ""},
|
|
||||||
{"option", '"Myself!"', "", ""}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"option", '"Suicide"', "", ""}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,21 @@ ink=[[
|
||||||
# require: Train ticket
|
# require: Train ticket
|
||||||
|
|
||||||
This is the line of content. # the third tag # really_monsieur.ogg
|
This is the line of content. # the third tag # really_monsieur.ogg
|
||||||
|
#tag
|
||||||
aaa
|
aaa
|
||||||
]],
|
]],
|
||||||
expected={
|
expected={
|
||||||
|
{"tag", "global", "author: Joseph Humfrey"},
|
||||||
|
{"tag", "global", "title: My Wonderful Ink Story"},
|
||||||
|
{"knot", "content"},
|
||||||
|
{"tag", "above", "location: Germany"},
|
||||||
|
{"tag", "above", "overview: munich.ogg"},
|
||||||
|
{"tag", "above", "require: Train ticket"},
|
||||||
|
{"para", "This is the line of content. "},
|
||||||
|
{"tag", "end", "the third tag "},
|
||||||
|
{"tag", "end", "really_monsieur.ogg"},
|
||||||
|
{"tag", "above", "tag"},
|
||||||
|
{"para", "aaa"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
=== back_in_london ===
|
=== back_in_london ===
|
||||||
|
|
||||||
We arrived into London at 9.45pm exactly.
|
We arrived into London at 9.45pm
|
||||||
|
exactly
|
||||||
|
|
||||||
* "There is not a moment to lose!"[] I declared.
|
* "There is not a moment to lose!"[] I declared.
|
||||||
-> hurry_outside
|
-> hurry_outside
|
||||||
|
|
||||||
* "Monsieur, let us savour this moment!"[] I declared.
|
* "Monsieur, let us savour this moment!"[] I declared.
|
||||||
My master clouted me firmly around the head and dragged me out of the door.<>
|
My master clouted me firmly around the head
|
||||||
-> dragged_outside
|
** ugh?
|
||||||
|
no thanks
|
||||||
|
** hug
|
||||||
|
huhu
|
||||||
* [We hurried home] -> hurry_outside
|
* [We hurried home] -> hurry_outside
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,11 @@
|
||||||
|
|
||||||
->content
|
->content
|
||||||
=== content
|
=== content
|
||||||
A line of normal game-text. # colour it blue
|
|
||||||
|
|
||||||
Passepartout: Really, Monsieur. # surly
|
|
||||||
|
|
||||||
Passepartout: Really, Monsieur. # surly # really_monsieur.ogg
|
|
||||||
|
|
||||||
# the first tag
|
# the first tag
|
||||||
# the second tag
|
# the second tag
|
||||||
This is the line of content. # the third tag
|
This is the line of content. # the third tag
|
||||||
|
#not this one
|
||||||
|
that to this
|
||||||
|
|
||||||
=== Munich ==
|
=== Munich ==
|
||||||
# location: Germany
|
# location: Germany
|
||||||
|
|
|
@ -15,13 +15,10 @@ function testText() doTestS(
|
||||||
{{"para", "Hello world"}}
|
{{"para", "Hello world"}}
|
||||||
) end
|
) end
|
||||||
|
|
||||||
function testOpt1() doTestS(
|
|
||||||
'* "I am somewhat tired[."]," I repeated.',
|
|
||||||
{{'choice', {"option", '"I am somewhat tired', '."', '," I repeated.'}}}
|
|
||||||
) end
|
|
||||||
|
|
||||||
|
|
||||||
function testBasic() doTest('basic') end
|
function testBasic() doTest('basic') end
|
||||||
|
function testComments() doTest('comments') end
|
||||||
function testChoices() doTest('choices') end
|
function testChoices() doTest('choices') end
|
||||||
function testNest() doTest('nested') end
|
function testNest() doTest('nested') end
|
||||||
function testNest2() doTest('nested2') end
|
function testNest2() doTest('nested2') end
|
||||||
|
@ -29,12 +26,34 @@ function testKnot() doTest('knot') end
|
||||||
function testBranching() doTest('branching') end
|
function testBranching() doTest('branching') end
|
||||||
function testGlue() doTest('glue') end
|
function testGlue() doTest('glue') end
|
||||||
function testInclude() doTest('include') end
|
function testInclude() doTest('include') end
|
||||||
function testInclude() doTest('tags') end
|
function testTags() doTest('tags') end
|
||||||
|
|
||||||
|
|
||||||
--- runtime ---
|
--- runtime ---
|
||||||
|
|
||||||
function testVisitCount()
|
function testRBasic()
|
||||||
|
local story = pink.getStory('test/runtime/hello.ink')
|
||||||
|
luaunit.assertEquals(story.continue(), 'hello world')
|
||||||
|
luaunit.assertFalse(story.canContinue)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function testRChoices()
|
||||||
|
local story = pink.getStory('test/runtime/branching.ink')
|
||||||
|
story.choosePathString('back_in_london');
|
||||||
|
story.continue()
|
||||||
|
luaunit.assertEquals(story.continue(), 'exactly')
|
||||||
|
luaunit.assertFalse(story.canContinue)
|
||||||
|
luaunit.assertEquals(#story.currentChoices, 3)
|
||||||
|
story.chooseChoiceIndex(2)
|
||||||
|
luaunit.assertEquals(story.continue(), 'My master clouted me firmly around the head')
|
||||||
|
luaunit.assertEquals(#story.currentChoices, 2)
|
||||||
|
story.chooseChoiceIndex(2)
|
||||||
|
luaunit.assertEquals(story.continue(), 'huhu')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function testRVisitCount()
|
||||||
local story = pink.getStory('test/runtime/branching.ink')
|
local story = pink.getStory('test/runtime/branching.ink')
|
||||||
story.choosePathString('hurry_outside');
|
story.choosePathString('hurry_outside');
|
||||||
luaunit.assertEquals(story.state.visitCountAtPathString('as_fast_as_we_could'), 0)
|
luaunit.assertEquals(story.state.visitCountAtPathString('as_fast_as_we_could'), 0)
|
||||||
|
@ -46,22 +65,26 @@ function testVisitCount()
|
||||||
luaunit.assertEquals(story.state.visitCountAtPathString('as_fast_as_we_could'), 2)
|
luaunit.assertEquals(story.state.visitCountAtPathString('as_fast_as_we_could'), 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
function testIncludeR()
|
function testRInclude()
|
||||||
local story = pink.getStory('test/runtime/include.ink')
|
local story = pink.getStory('test/runtime/include.ink')
|
||||||
luaunit.assertEquals(story.continue(), 'hello world')
|
luaunit.assertEquals(story.continue(), 'hello world')
|
||||||
luaunit.assertEquals(story.continue(), 'hello again')
|
luaunit.assertEquals(story.continue(), 'hello again')
|
||||||
luaunit.assertFalse(story.canContinue)
|
luaunit.assertFalse(story.canContinue)
|
||||||
end
|
end
|
||||||
|
|
||||||
function testTags()
|
function testRTags()
|
||||||
local story = pink.getStory('test/runtime/tags.ink')
|
local story = pink.getStory('test/runtime/tags.ink')
|
||||||
luaunit.assertEquals(story.continue(), '')
|
luaunit.assertEquals(story.globalTags, {"author: Joseph Humfrey", "title: My Wonderful Ink Story"})
|
||||||
luaunit.assertEquals(story.continue(), '')
|
story.choosePathString('content');
|
||||||
luaunit.assertEquals(story.globalTags, {""})
|
luaunit.assertEquals(story.continue(), 'This is the line of content. ')
|
||||||
|
luaunit.assertEquals(story.currentTags, {"the first tag", "the second tag", "the third tag"})
|
||||||
|
story.continue()
|
||||||
|
luaunit.assertEquals(story.currentTags, {"not this one"})
|
||||||
luaunit.assertFalse(story.canContinue)
|
luaunit.assertFalse(story.canContinue)
|
||||||
|
luaunit.assertEquals(story.tagsForContentAtPath('Munich'), {"location: Germany", "overview: munich.ogg", "require: Train ticket"})
|
||||||
end
|
end
|
||||||
|
|
||||||
function testInvisibleDiverts()
|
function testRInvisibleDiverts()
|
||||||
local story = pink.getStory('test/runtime/branching.ink')
|
local story = pink.getStory('test/runtime/branching.ink')
|
||||||
story.choosePathString('hurry_outside')
|
story.choosePathString('hurry_outside')
|
||||||
luaunit.assertEquals(story.continue(), "We hurried home to Savile Row as fast as we could.")
|
luaunit.assertEquals(story.continue(), "We hurried home to Savile Row as fast as we could.")
|
||||||
|
|
Loading…
Reference in a new issue