Skip to content

Commit 7df4ddd

Browse files
committed
Initial commit.
- Lexer and Parser fully functional - Complex weighting not supported (eg referencing weights of nested lists) - Arithmetic weighting not supported - Leaderboards not implemented
0 parents  commit 7df4ddd

22 files changed

+2711
-0
lines changed

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
*.opensdf
2+
*.opendb
3+
*.sdf
4+
*.suo
5+
*.log
6+
*.tlog
7+
*.lastbuildstate
8+
*.cache
9+
*.pdb
10+
*.obj
11+
*.aps
12+
/.vs
13+
/.vscode
14+
15+
main.lua

NameList.lua

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
require "NameList.Lexer"
2+
require "NameList.Parser"
3+
require "NameList.Entry"
4+
require "NameList.InnerList"
5+
6+
7+
NameList = NameList or {}
8+
MasterList = NameList.MasterList or {}
9+
10+
local Parser = NameList.Parser
11+
local InnerList = NameList.InnerList
12+
local SimpleList = NameList.SimpleList
13+
local ComplexList = NameList.ComplexList
14+
local MasterList = NameList.MasterList
15+
16+
17+
18+
19+
20+
21+
--Checks for cycles in th
22+
function CycleCheck(list, checked)
23+
checked = checked or {}
24+
end
25+
26+
function NameList:AssertNoLoops()
27+
for list, dependencies in pairs(self.complex_dependencies) do
28+
end
29+
end
30+
31+
--[[
32+
The NameList, a random name generator
33+
--]]
34+
function NameList.new(o)
35+
--List must have a name
36+
if (o == nil or o.name == nil) then
37+
error("NameList constructor called without a valid name parameter.")
38+
end
39+
40+
--Name must be unique
41+
--if (NameList.lists[o.name] ~= nil) then
42+
-- error("A NameList must have a unique name.")
43+
--end
44+
45+
setmetatable(o, {__index = NameList})
46+
47+
o.simple_list = SimpleList.new()
48+
o.complex_list = ComplexList.new()
49+
--o.dependents = {}
50+
51+
--NameList.lists[o.name] = o
52+
return o
53+
end
54+
55+
function NameList.repairMetatable(o)
56+
if getmetatable(o) ~= nil then
57+
return
58+
end
59+
setmetatable(o, {__index = NameList})
60+
SimpleList.repairMetatable(o.simple_list)
61+
ComplexList.repairMetatable(o.complex_list)
62+
end
63+
64+
local function is_weight_complex(token_chain)
65+
if token_chain == nil or type(token_chain) ~= "table" then
66+
return false
67+
end
68+
69+
for i, token in ipairs(token_chain) do
70+
if token.type == Token.types.list_placeholder then
71+
return true
72+
end
73+
end
74+
75+
return false
76+
end
77+
78+
function NameList:recalculateWeight(o)
79+
error("Not implemented yet.")
80+
end
81+
82+
--Adds an entry to a name list with the given weight
83+
--(TODO) Weight should be a NameList expression
84+
function NameList:add(entry, weight)
85+
weight = weight or 1
86+
assert(weight > 0, "Weight must be greater than zero.")
87+
88+
if (is_weight_complex(weight)) then
89+
self.complex_list:add(entry, weight)
90+
else
91+
self.simple_list:add(entry,weight)
92+
end
93+
end
94+
95+
--Returns a random name generated this name list based on the weights given to it
96+
--If this name list references any other lists in its entries, master_list is required or it will error
97+
function NameList:randomName(master_list)
98+
local list
99+
100+
if self.complex_list:size() == 0 then
101+
list = self.simple_list
102+
else
103+
local weight = math.random() * self.total_weight
104+
if weight < self.simple_list.total_weight then
105+
list = self.simple_list
106+
else
107+
list = self.complex_list
108+
end
109+
end
110+
111+
local entry = list:randomEntry()
112+
local name = entry:toString(master_list)
113+
return name
114+
end
115+
116+
-- Parses a NameList text
117+
-- returns a MasterList
118+
function NameList.parse(text)
119+
return Parser.parse(text)
120+
end

NameList/Entry.lua

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
require "NameList.Lexer"
2+
3+
NameList = NameList or {}
4+
NameList.Entry = NameList.Entry or {}
5+
6+
local Lexer = NameList.Lexer
7+
local Entry = NameList.Entry
8+
local EntryPiece = {}
9+
10+
function EntryPiece.new(o)
11+
o = o or {}
12+
setmetatable(o, {__index = EntryPiece})
13+
--is_list
14+
--text
15+
return o
16+
end
17+
18+
function EntryPiece:toList(master_list)
19+
assert(self.is_list, "Attempted to convert non-list name entry piece into a list.")
20+
return master_list:get(self.text)
21+
end
22+
23+
function Entry.new(o)
24+
o = o or {}
25+
o.entries = o.entries or {} --List of EntryPiece objects to construct a string with
26+
o.references = o.references or {} --Table of with list names as key and number of references as value
27+
setmetatable(o, {__index = Entry} )
28+
29+
if o.text ~= nil then
30+
o:parse(o.text)
31+
end
32+
33+
return o
34+
end
35+
36+
function Entry.repairMetatable(o)
37+
setmetatable(o, {__index = Entry})
38+
for k, piece in pairs(o.entries) do
39+
setmetatable(piece, {__index = EntryPiece})
40+
end
41+
end
42+
43+
local replacement_sequence_table =
44+
{
45+
["\\"] = "\\",
46+
["{"] = "{",
47+
["}"] = "}",
48+
["\""] = "\"",
49+
}
50+
51+
local function replace_escape_sequences(s)
52+
local sb = {}
53+
local next_index = 1
54+
while true do
55+
local escape_index = string.find(s, "\\", next_index)
56+
if escape_index ~= nil then
57+
local c = string.sub(s, escape_index+1, escape_index+1)
58+
assert(c ~= nil, "Unmatched escape sequence found at end of line")
59+
local replacement = replacement_sequence_table[c]
60+
assert(replacement ~= nil, "Invalid escape sequence")
61+
62+
table.insert(sb, string.sub(s, next_index, escape_index-1))
63+
table.insert(sb, replacement)
64+
next_index = escape_index + 2
65+
else
66+
table.insert(sb, string.sub(s, next_index))
67+
break
68+
end
69+
end
70+
71+
local new_string = table.concat(sb)
72+
return new_string
73+
end
74+
75+
function Entry:parse(str)
76+
77+
local next_index = 1
78+
while true do
79+
list_open_index = Lexer.findUnescaped(str, "{", next_index)
80+
list_close_index = Lexer.findUnescaped(str, "}", next_index)
81+
82+
--Ensure all lists references are well formed
83+
if list_close_index ~= nil and (list_open_index > list_close_index) then
84+
error("Unmatched \"}\" found in name list entry.")
85+
end
86+
87+
if (list_open_index~=nil) ~= (list_close_index~=nil) then
88+
if list_open_index ~= nil then
89+
error("Unmatched \"{\" found in name list entry.")
90+
else
91+
error("Unmatched \"}\" found in name list entry.")
92+
end
93+
end
94+
95+
--[[if list_open_index ~= nil and (list_close_index - list_open_index == 1) then
96+
error("A list reference can't be empty!")
97+
end--]]
98+
99+
--Extract the currently parsed chunks.
100+
local textChunk, listChunk
101+
if list_open_index ~= nil then
102+
textChunk = string.sub(str, next_index, list_open_index-1)
103+
listChunk = string.sub(str, list_open_index+1, list_close_index-1)
104+
else
105+
textChunk = string.sub(str, next_index)
106+
end
107+
108+
--Insert text chunk
109+
if textChunk:len() > 0 then
110+
textChunk = replace_escape_sequences(textChunk)
111+
local piece = EntryPiece.new{text=textChunk, is_list=false}
112+
table.insert(self.entries, piece)
113+
end
114+
115+
--Insert list chunk
116+
if listChunk ~= nil then
117+
listChunk = replace_escape_sequences(listChunk)
118+
local piece = EntryPiece.new{text=listChunk, is_list=true}
119+
table.insert(self.entries, piece)
120+
self.references[listChunk] = (self.references[listChunk] or 0) + 1
121+
end
122+
123+
if list_close_index==nil then
124+
return
125+
end
126+
next_index = list_close_index + 1
127+
end
128+
end
129+
130+
function Entry:toString(master_list)
131+
local s = ""
132+
133+
for i, entry in ipairs(self.entries) do
134+
if (entry.is_list) then
135+
s = s .. entry:toList(master_list):randomName(master_list)
136+
else
137+
s = s .. entry.text
138+
end
139+
end
140+
141+
return s
142+
end

NameList/Expression.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
--Not supported yet sorry
2+
3+
--Todo: reverse polish notation and shunting-yard algorithm
4+
5+
NameList = NameList or {}
6+
NameList.Expression = NameList.Expression or {}

0 commit comments

Comments
 (0)