1
0
Fork 0
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:
Přemek Vyhnal 2017-08-12 23:39:56 +02:00 committed by GitHub
commit faedb6a3be
14 changed files with 305 additions and 262 deletions

View file

@ -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)
}) })

View file

@ -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

View file

@ -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"}
}} }}

View file

@ -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."}
} }
} }

View file

@ -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
View 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"},
}}

View file

@ -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'
} }
} }

View file

@ -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"}
} }
} }

View file

@ -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!"', "", ""}
}
} }
} }

View file

@ -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"', "", ""}
}
} }
} }

View file

@ -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"}
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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.")