- initial commit

- note: this is not to be used yet, it is not finished, it is mostly so I can have a proper code history as well as allowing others to view what I have thus far.
- Differences from 2.0: Different syntax, uses a proper LALR parser instead of regexes. Vigorous testing, no longer unit-specific, that will be part of its own namespace.
Feel free to check out test.lua, it's pretty much a full testsuite for LibDogTag-3.0 thus far, and it will stay that way.
This commit is contained in:
ckknight
2008-03-05 02:27:40 +00:00
commit 492720efe2
11 changed files with 4265 additions and 0 deletions

19
Cleanup.lua Normal file
View File

@ -0,0 +1,19 @@
local MAJOR_VERSION = "LibDogTag-3.0"
local MINOR_VERSION = tonumber(("$Revision$"):match("%d+")) or 0
if MINOR_VERSION > _G.DogTag_MINOR_VERSION then
_G.DogTag_MINOR_VERSION = MINOR_VERSION
end
local DogTag, oldMinor = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
if not DogTag then
return
end
_G.DogTag = DogTag
for _,v in ipairs(DogTag_funcs) do
v()
end
_G.DogTag = nil

1295
Compiler.lua Normal file

File diff suppressed because it is too large Load Diff

228
LibDogTag-3.0.lua Normal file
View File

@ -0,0 +1,228 @@
--[[
Name: LibDogTag-3.0
Revision: $Rev$
Author: Cameron Kenneth Knight (ckknight@gmail.com)
Website: http://www.wowace.com/
Description: A library to provide a markup syntax
]]
local MAJOR_VERSION = "LibDogTag-3.0"
local MINOR_VERSION = tonumber(("$Revision$"):match("%d+")) or 0
if MINOR_VERSION > _G.DogTag_MINOR_VERSION then
_G.DogTag_MINOR_VERSION = MINOR_VERSION
end
DogTag_funcs[#DogTag_funcs+1] = function()
local DogTag = _G.DogTag
-- #AUTODOC_NAMESPACE DogTag
local oldLib
if next(DogTag) ~= nil then
oldLib = {}
for k,v in pairs(DogTag) do
oldLib[k] = v
DogTag[k] = nil
end
end
DogTag.oldLib = oldLib
local L = DogTag__L
DogTag.L = L
local poolNum = 0
local newList, newDict, newSet, del
do
local pool = setmetatable({}, {__mode='k'})
function newList(...)
poolNum = poolNum + 1
local t = next(pool)
if t then
pool[t] = nil
for i = 1, select('#', ...) do
t[i] = select(i, ...)
end
else
t = { ... }
end
return t
end
function newDict(...)
poolNum = poolNum + 1
local t = next(pool)
if t then
pool[t] = nil
else
t = {}
end
for i = 1, select('#', ...), 2 do
t[select(i, ...)] = select(i+1, ...)
end
return t
end
function newSet(...)
poolNum = poolNum + 1
local t = next(pool)
if t then
pool[t] = nil
else
t = {}
end
for i = 1, select('#', ...) do
t[select(i, ...)] = true
end
return t
end
function del(t)
if not t then
error("Bad argument #1 to `del'. Expected table, got nil.", 2)
end
if pool[t] then
error("Double-free syndrome.", 2)
end
pool[t] = true
poolNum = poolNum - 1
for k in pairs(t) do
t[k] = nil
end
t[''] = true
t[''] = nil
return nil
end
function deepDel(t)
if type(t) == "table" then
for k,v in pairs(t) do
deepDel(v)
deepDel(k)
end
del(t)
end
return nil
end
end
DogTag.newList, DogTag.newDict, DogTag.newSet, DogTag.del, DogTag.deepDel = newList, newDict, newSet, del, deepDel
local DEBUG = _G.DogTag_DEBUG -- set in test.lua
if DEBUG then
DogTag.getPoolNum = function()
return poolNum
end
DogTag.setPoolNum = function(value)
poolNum = value
end
end
local FakeGlobals = { ["Base"] = {} }
DogTag.FakeGlobals = FakeGlobals
local Tags = { ["Base"] = {} }
DogTag.Tags = Tags
local function sortStringList(s)
if not s then
return nil
end
local list = newList((";"):split(s))
table.sort(list)
local q = table.concat(list, ';')
list = del(list)
return q
end
function DogTag:AddTag(namespace, tag, data)
if type(namespace) ~= "string" then
error(("Bad argument #2 to `AddTag'. Expected %q, got %q"):format("string", type(namespace)), 2)
end
if type(tag) ~= "string" then
error(("Bad argument #3 to `AddTag'. Expected %q, got %q"):format("string", type(tag)), 2)
end
if type(data) ~= "table" then
error(("Bad argument #4 to `AddTag'. Expected %q, got %q"):format("table", type(data)), 2)
end
if not Tags[namespace] then
Tags[namespace] = newList()
end
if Tags["Base"][tag] or Tags[namespace][tag] then
error(("Bad argument #3 to `AddTag'. %q already registered"):format(tag), 2)
end
local tagData = newList()
Tags[namespace][tag] = tagData
if data.alias then
if type(data.alias) == "string" then
tagData.alias = data.alias
else -- function
tagData.alias = data.alias()
tagData.aliasFunc = data.alias
end
else
local arg = data.arg
if arg then
if type(arg) ~= "table" then
error("arg must be a table", 2)
end
if #arg % 3 ~= 0 then
error("arg must be a table with a length a multiple of 3", 2)
end
for i = 1, #arg, 3 do
local key, types, default = arg[i], arg[i+1], arg[i+2]
if type(key) ~= "string" then
error("arg must have its keys as strings", 2)
end
if type(types) ~= "string" then
error("arg must have its types as strings", 2)
end
if types ~= "list-number" and types ~= "list-string" then
local a,b,c = (';'):split(types)
if a ~= "nil" and a ~= "number" and a ~= "string" then
error("arg must have nil, number, string, list-number, or list-string", 2)
end
if b and b ~= "nil" and b ~= "number" and b ~= "string" then
error("arg must have nil, number, or string", 2)
end
if c and c ~= "nil" and c ~= "number" and c ~= "string" then
error("arg must have nil, number, or string", 2)
end
elseif key ~= "..." then
error("arg must have its key be ... if a list-number or list-string.", 2)
end
end
tagData.arg = arg
end
tagData.ret = sortStringList(data.ret)
if data.ret then
local a,b,c = (";"):split(data.ret)
if a ~= "nil" and a ~= "number" and a ~= "string" and a ~= "same" then
error("ret must have same, nil, number, or string", 2)
end
if b and b ~= "nil" and b ~= "number" and b ~= "string" and b ~= "same" then
error("ret must have same, nil, number, or string", 2)
end
if c and c ~= "nil" and c ~= "number" and c ~= "string" and c ~= "same" then
error("ret must have same, nil, number, or string", 2)
end
end
tagData.events = sortStringList(data.events)
tagData.globals = sortStringList(data.globals)
if tagData.globals then
local globals = newList((';'):split(tagData.globals))
for _,v in ipairs(globals) do
if not v:find("%.") and not _G[v] then
error(("Unknown global: %q"):format(v))
end
end
globals = del(globals)
end
tagData.alias = data.fakeAlias
end
tagData.doc = data.doc
tagData.example = data.example
tagData.category = data.category
if not data.alias then
tagData.code = data.code
end
del(data)
end
end

12
LibDogTag-3.0.toc Normal file
View File

@ -0,0 +1,12 @@
## Interface: 20300
## LoadOnDemand: 1
## Title: LibDogTag-3.0
## Notes: A library to provide a markup syntax
## Author: ckknight
## eMail: ckknight@gmail.com
## Version: 1.0
## X-Category: Library
## OptionalDeps:
LibStub\LibStub.lua
lib.xml

30
LibStub/LibStub.lua Normal file
View File

@ -0,0 +1,30 @@
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
function LibStub:IterateLibraries() return pairs(self.libs) end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end

172
Localization/enUS.lua Normal file
View File

@ -0,0 +1,172 @@
local MAJOR_VERSION = "LibDogTag-3.0"
local MINOR_VERSION = tonumber(("$Revision$"):match("%d+")) or 0
_G.DogTag_MINOR_VERSION = MINOR_VERSION
_G.DogTag_funcs = {}
DogTag_funcs[#DogTag_funcs+1] = function()
_G.DogTag__L = {
["DogTag Help"] = "DogTag Help",
-- races
["Blood Elf"] = "Blood Elf",
["Draenei"] = "Draenei",
["Dwarf"] = "Dwarf",
["Gnome"] = "Gnome",
["Human"] = "Human",
["Night Elf"] = "Night Elf",
["Orc"] = "Orc",
["Tauren"] = "Tauren",
["Troll"] = "Troll",
["Undead"] = "Undead",
-- short races
["Blood Elf_short"] = "BE",
["Draenei_short"] = "Dr",
["Dwarf_short"] = "Dw",
["Gnome_short"] = "Gn",
["Human_short"] = "Hu",
["Night Elf_short"] = "NE",
["Orc_short"] = "Or",
["Tauren_short"] = "Ta",
["Troll_short"] = "Tr",
["Undead_short"] = "Ud",
-- classes
["Warrior"] = "Warrior",
["Priest"] = "Priest",
["Mage"] = "Mage",
["Shaman"] = "Shaman",
["Paladin"] = "Paladin",
["Warlock"] = "Warlock",
["Druid"] = "Druid",
["Rogue"] = "Rogue",
["Hunter"] = "Hunter",
-- short classes
["Warrior_short"] = "Wr",
["Priest_short"] = "Pr",
["Mage_short"] = "Ma",
["Shaman_short"] = "Sh",
["Paladin_short"] = "Pa",
["Warlock_short"] = "Wl",
["Druid_short"] = "Dr",
["Rogue_short"] = "Ro",
["Hunter_short"] = "Hu",
["Player"] = PLAYER,
["Target"] = TARGET,
["Focus-target"] = FOCUS,
["Mouse-over"] = "Mouse-over",
["%s's pet"] = "%s's pet",
["%s's target"] = "%s's target",
["Party member #%d"] = "Party member #%d",
["Raid member #%d"] = "Raid member #%d",
-- classifications
["Rare"] = ITEM_QUALITY3_DESC,
["Rare-Elite"] = ITEM_QUALITY3_DESC and ELITE and ITEM_QUALITY3_DESC .. "-" .. ELITE,
["Elite"] = ELITE,
["Boss"] = BOSS,
-- short classifications
["Rare_short"] = "r",
["Rare-Elite_short"] = "r+",
["Elite_short"] = "+",
["Boss_short"] = "b",
["Feigned Death"] = "Feigned Death",
["Stealthed"] = "Stealthed",
["Soulstoned"] = "Soulstoned",
["Dead"] = DEAD,
["Ghost"] = "Ghost",
["Offline"] = PLAYER_OFFLINE,
["Online"] = "Online",
["Combat"] = "Combat",
["Resting"] = "Resting",
["Tapped"] = "Tapped",
["AFK"] = "AFK",
["DND"] = "DND",
["True"] = "True",
["Rage"] = RAGE,
["Focus"] = FOCUS,
["Energy"] = ENERGY,
["Mana"] = MANA,
["PvP"] = PVP,
["FFA"] = "FFA",
-- genders
["Male"] = MALE,
["Female"] = FEMALE,
-- forms
["Bear"] = "Bear",
["Cat"] = "Cat",
["Moonkin"] = "Moonkin",
["Aquatic"] = "Aquatic",
["Flight"] = "Flight",
["Travel"] = "Travel",
["Tree"] = "Tree",
["Bear_short"] = "Be",
["Cat_short"] = "Ca",
["Moonkin_short"] = "Mk",
["Aquatic_short"] = "Aq",
["Flight_short"] = "Fl",
["Travel_short"] = "Tv",
["Tree_short"] = "Tr",
-- shortgenders
["Male_short"] = "m",
["Female_short"] = "f",
["Leader"] = "Leader",
-- spell trees
["Hybrid"] = "Hybrid", -- for all 3 trees
["Druid_Tree_1"] = "Balance",
["Druid_Tree_2"] = "Feral Combat",
["Druid_Tree_3"] = "Restoration",
["Hunter_Tree_1"] = "Beast Mastery",
["Hunter_Tree_2"] = "Marksmanship",
["Hunter_Tree_3"] = "Survival",
["Mage_Tree_1"] = "Arcane",
["Mage_Tree_2"] = "Fire",
["Mage_Tree_3"] = "Frost",
["Paladin_Tree_1"] = "Holy",
["Paladin_Tree_2"] = "Protection",
["Paladin_Tree_3"] = "Retribution",
["Priest_Tree_1"] = "Discipline",
["Priest_Tree_2"] = "Holy",
["Priest_Tree_3"] = "Shadow",
["Rogue_Tree_1"] = "Assassination",
["Rogue_Tree_2"] = "Combat",
["Rogue_Tree_3"] = "Subtlety",
["Shaman_Tree_1"] = "Elemental",
["Shaman_Tree_2"] = "Enhancement",
["Shaman_Tree_3"] = "Restoration",
["Warrior_Tree_1"] = "Arms",
["Warrior_Tree_2"] = "Fury",
["Warrior_Tree_3"] = "Protection",
["Warlock_Tree_1"] = "Affliction",
["Warlock_Tree_2"] = "Demonology",
["Warlock_Tree_3"] = "Destruction",
}
for k,v in pairs(_G.DogTag__L) do
if type(v) ~= "string" then -- some evil addon messed it up
_G.DogTag__L[k] = k
end
end
setmetatable(_G.DogTag__L, {__index = function(self, key)
-- local _, ret = pcall(error, ("Error indexing L[%q]"):format(tostring(key)), 2)
-- geterrorhandler()(ret)
self[key] = key
return key
end})
end

210
Modules/Math.lua Normal file
View File

@ -0,0 +1,210 @@
local MAJOR_VERSION = "LibDogTag-2.0"
local MINOR_VERSION = tonumber(("$Revision$"):match("%d+")) or 0
if MINOR_VERSION > _G.DogTag_MINOR_VERSION then
_G.DogTag_MINOR_VERSION = MINOR_VERSION
end
DogTag_funcs[#DogTag_funcs+1] = function()
local L = DogTag.L
DogTag:AddTag("Base", "Round", {
code = [=[
return math_floor(${number} * (10^${ndigits}) + 0.5)) / (10^${ndigits})
]=],
arg = {
'number', "number", "@req",
'ndigits', "number", 0,
},
ret = "number",
globals = "math.floor",
doc = L["Round number to the one's place or the place specified by ndigits"],
example = '[1234.5:Round] => "1235"; [1234:Round(-2)] => "1200"; [Round(1234.5)] => "1235"; [Round(1234, -2)] => "1200"',
category = L["Mathematics"],
})
DogTag:AddTag("Base", "Floor", {
code = [=[
return math_floor(${number})
]=],
arg = {
'number', "number", "@req",
},
ret = "number",
globals = "math.floor",
doc = L["Take the floor of number"],
example = '[9.876:Floor] => "9"; [Floor(9.876)] => "9"',
category = L["Mathematics"],
})
DogTag:AddTag("Base", "Ceil", {
code = [=[
return math_ceil(${number})
]=],
arg = {
'number', "number", "@req",
},
ret = "number",
globals = "math.ceil",
doc = L["Take the ceiling of number"],
example = '[1.234:Ceil] => "2"; [Ceil(1.234)] => "2"',
category = L["Mathematics"],
})
DogTag:AddTag("Base", "Abs", {
code = [=[
return math_abs(${number})
]=],
arg = {
'number', "number", "@req",
},
ret = "number",
globals = "math.abs",
doc = L["Take the absolute value of number"],
example = '[5:Abs] => "5"; [-5:Abs] => "5"; [Abs(5)] => "5"; [Abs(-5)] => "5"',
category = L["Mathematics"],
})
DogTag:AddTag("Base", "Sign", {
code = [=[
if ${number} < 0 then
return -1
elseif value == 0 then
return 0
else
return 1
end
]=],
arg = {
'number', "number", "@req",
},
ret = "number",
doc = L["Take the signum of number"],
example = '[5:Sign] => "1"; [-5:Sign] => "-1"; [0:Sign] => "0"; [Sign(5)] => "1"',
category = L["Mathematics"],
})
DogTag:AddTag("Base", "Max", {
code = [=[
return math_max(${number}, unpack(${number_list}))
]=],
arg = {
'number', 'number', "@req",
'number_list', 'list-number', false
},
ret = "number",
globals = "math.max;unpack",
doc = L["Return the greatest value of the given arguments"],
example = '[1:Max(2)] => "2"; [Max(3, 2, 1)] => "3"'
})
DogTag:AddTag("Base", "Min", {
code = [=[
return math_min(${number}, unpack(${number_list}))
]=],
arg = {
'number', 'number', "@req",
'number_list', 'list-number', false
},
ret = "number",
globals = "math.min;unpack",
doc = L["Return the smallest value of the given arguments"],
example = '[1:Min(2)] => "1"; [Min(3, 2, 1)] => "1"'
})
DogTag:AddTag("Base", "Pi", {
code = ([=[return %.52f]=]):format(math.pi),
ret = "number",
doc = (L["Return the mathematical number π, or %s"]):format(math.pi),
example = ('[Pi] => "%s"'):format(math.pi),
category = L["Mathematics"]
})
DogTag:AddTag("Base", "Deg", {
code = ([=[return math_deg(${radian})]=]),
fakeAlias = "${radian} * 180 / Pi",
arg = {
'radian', 'number', "@req"
},
ret = "number",
globals = "math.deg",
doc = L["Convert radian into degrees"],
example = '[0:Deg] => "0"; [Pi:Deg] => "180"; [Deg(Pi/2)] => "90"',
category = L["Mathematics"]
})
DogTag:AddTag("Base", "Rad", {
code = ([=[return math_rad(${radian})]=]),
fakeAlias = "${degree} * Pi / 180",
arg = {
'degree', 'number', "@req"
},
ret = "number",
globals = "math.rad",
doc = L["Convert degree into radians"],
example = ('[0:Rad] => "0"; [180:Rad] => "%s"; [Rad(90)] => "%s"'):format(math.pi, math.pi/2),
category = L["Mathematics"]
})
DogTag:AddTag("Base", "Cos", {
code = [=[
return math_cos(${radian})
]=],
arg = {
'radian', 'number', "@req"
},
ret = "number",
globals = "math.cos",
doc = L["Return the cosine of radian"],
example = ('[0:Cos] => "1"; [(Pi/4):Cos] => "%s"; [Cos(Pi/2)] => "0"'):format(math.cos(math.pi/4)),
category = L["Mathematics"]
})
DogTag:AddTag("Base", "Sin", {
code = [=[
return math_sin(${radian})
]=],
arg = {
'radian', 'number', "@req"
},
ret = "number",
globals = "math.sin",
doc = L["Return the sin of radian"],
example = ('[0:Sin] => "0"; [(Pi/4):Sin] => "%s"; [Sin(Pi/2)] => "1"'):format(math.cos(math.pi/4)),
category = L["Mathematics"]
})
DogTag:AddTag("Base", "E", {
code = ([[return %.52f]]):format(math.exp(1)),
ret = "number",
doc = (L["Return the mathematical number e, or %s"]):format(math.exp(1)),
example = ('[E] => "%s"'):format(math.exp(1)),
category = L["Mathematics"]
})
DogTag:AddTag("Base", "Ln", {
code = [[return math_log(${number})]],
arg = {
'number', 'number', "@req",
},
ret = "number",
globals = "math.log",
doc = L["Return the natural log of number"],
example = '[1:Ln] => "0"; [E:Ln] => "1"; [Ln(E^2)] => "2"',
category = L["Mathematics"]
})
DogTag:AddTag("Base", "Log", {
code = [[return math_log10(value)]],
arg = {
'number', 'number', "@req",
},
ret = "number",
globals = "math.log10",
doc = L["Return the log base 10 of number"],
example = '[1:Log] => "0"; [10:Log] => "1"; [Log(100)] => "2"',
category = L["Mathematics"]
})
end

195
Modules/Operators.lua Normal file
View File

@ -0,0 +1,195 @@
local MAJOR_VERSION = "LibDogTag-2.0"
local MINOR_VERSION = tonumber(("$Revision$"):match("%d+")) or 0
if MINOR_VERSION > _G.DogTag_MINOR_VERSION then
_G.DogTag_MINOR_VERSION = MINOR_VERSION
end
DogTag_funcs[#DogTag_funcs+1] = function()
local L = DogTag.L
DogTag:AddTag("Base", "+", {
code = [=[return ${left} + ${right}]=],
arg = {
'left', 'number', "@req",
'right', 'number', "@req",
},
ret = "number",
doc = L["Add left and right together"],
example = '[1 + 2] => "3"',
category = L["Operators"]
})
DogTag:AddTag("Base", "-", {
code = [=[return ${left} - ${right}]=],
arg = {
'left', 'number', "@req",
'right', 'number', "@req",
},
ret = "number",
doc = L["Subtract right from left"],
example = '[1 - 2] => "-1"',
category = L["Operators"]
})
DogTag:AddTag("Base", "*", {
code = [=[return ${left} * ${right}]=],
arg = {
'left', 'number', "@req",
'right', 'number', "@req",
},
ret = "number",
doc = L["Multiple left and right together"],
example = '[1 * 2] => "2"',
category = L["Operators"]
})
DogTag:AddTag("Base", "/", {
code = [=[if ${left} == 0 then
return 0
else
return ${left} / ${right}
end]=],
arg = {
'left', 'number', "@req",
'right', 'number', "@req",
},
ret = "number",
doc = L["Divide left by right"],
example = '[1 / 2] => "0.5"',
category = L["Operators"]
})
DogTag:AddTag("Base", "%", {
code = [=[return ${left} % ${right}]=],
arg = {
'left', 'number', "@req",
'right', 'number', "@req",
},
ret = "number",
doc = L["Take the modulus of left and right"],
example = '[5 % 3] => "2"',
category = L["Operators"]
})
DogTag:AddTag("Base", "^", {
code = [=[return ${left} ^ ${right}]=],
arg = {
'left', 'number', "@req",
'right', 'number', "@req",
},
ret = "number",
doc = L["Raise left to the right power"],
example = '[5 ^ 3] => "125"',
category = L["Operators"]
})
DogTag:AddTag("Base", "<", {
code = [=[if type(${left}) == type(${right}) then
return ${left} < ${right} and ${left} or nil
else
return tostring(${left}) < tostring(${right}) and ${left} or nil
end]=],
arg = {
'left', 'number;string', "@req",
'right', 'number;string', "@req",
},
ret = "number;string;nil",
doc = L["Check if left is less than right, if so, return left"],
example = '[5 < 3] => ""; [3 < 5] => "3"; [3 < 3] => ""',
category = L["Operators"]
})
DogTag:AddTag("Base", ">", {
code = [=[if type(${left}) == type(${right}) then
return ${left} > ${right} and ${left} or nil
else
return tostring(${left}) > tostring(${right}) and ${left} or nil
end]=],
arg = {
'left', 'number;string', "@req",
'right', 'number;string', "@req",
},
ret = "number;string;nil",
doc = L["Check if left is greater than right, if so, return left"],
example = '[5 > 3] => "5"; [3 > 5] => ""; [3 > 3] => ""',
category = L["Operators"]
})
DogTag:AddTag("Base", "<=", {
code = [=[if type(${left}) == type(${right}) then
return ${left} <= ${right} and ${left} or nil
else
return tostring(${left}) <= tostring(${right}) and ${left} or nil
end]=],
arg = {
'left', 'number;string', "@req",
'right', 'number;string', "@req",
},
ret = "number;string;nil",
doc = L["Check if left is less than or equal to right, if so, return left"],
example = '[5 <= 3] => ""; [3 <= 5] => "3"; [3 <= 3] => "3"',
category = L["Operators"]
})
DogTag:AddTag("Base", ">=", {
code = [=[if type(${left}) == type(${right}) then
return ${left} >= ${right} and ${left} or nil
else
return tostring(${left}) >= tostring(${right}) and ${left} or nil
end]=],
arg = {
'left', 'number;string', "@req",
'right', 'number;string', "@req",
},
ret = "number;string;nil",
doc = L["Check if left is greater than or equal to right, if so, return left"],
example = '[5 >= 3] => "5"; [3 >= 5] => ""; [3 >= 3] => "3"',
category = L["Operators"]
})
DogTag:AddTag("Base", "=", {
code = [=[if type(${left}) == type(${right}) then
return ${left} == ${right} and ${left} or nil
else
return tostring(${left}) == tostring(${right}) and ${left} or nil
end]=],
arg = {
'left', 'number;string', "@req",
'right', 'number;string', "@req",
},
ret = "number;string;nil",
doc = L["Check if left is equal to right, if so, return left"],
example = '[1 = 2] => ""; [1 = 1] => "1"',
category = L["Operators"]
})
DogTag:AddTag("Base", "~=", {
code = [=[if type(${left}) ~= type(${right}) then
return ${left} ~= ${right} and ${left} or nil
else
return tostring(${left}) ~= tostring(${right}) and ${left} or nil
end]=],
arg = {
'left', 'number;string', "@req",
'right', 'number;string', "@req",
},
ret = "number;string;nil",
doc = L["Check if left is equal to right, if so, return left"],
example = '[1 ~= 2] => "1"; [1 ~= 1] => ""',
category = L["Operators"]
})
DogTag:AddTag("Base", "unm", {
code = [=[return -${number}]=],
arg = {
'number', 'number', "@req",
},
ret = "number",
doc = L["Return the negative of number"],
example = '[-1] => "-1"; [-(-1)] => "1"',
category = L["Operators"]
})
end

1211
Parser.lua Normal file

File diff suppressed because it is too large Load Diff

10
lib.xml Normal file
View File

@ -0,0 +1,10 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="Localization\enUS.lua" />
<Script file="LibDogTag-3.0.lua" />
<Script file="Parser.lua" />
<Script file="Compiler.lua" />
<Script file="Modules\Operators.lua" />
<Script file="Modules\Math.lua" />
<Script file="Cleanup.lua" />
</Ui>

883
test.lua Normal file
View File

@ -0,0 +1,883 @@
-- $Id$
local function escape_char(c)
return ("\\%03d"):format(c:byte())
end
local function table_len(t)
for i = 1, #t do
if t[i] == nil then
return i-1
end
end
return #t
end
function pprint(...)
print(ptostring(...))
end
local first_ptostring = true
function ptostring(...)
local t = {}
for i = 1, select('#', ...) do
if i > 1 then
t[#t+1] = ",\t"
end
local v = select(i, ...)
if type(v) == "string" then
t[#t+1] = (("%q"):format(v):gsub("[\001-\031\128-\255]", escape_char))
elseif type(v) == "table" then
t[#t+1] = "{ "
for a,b in pairs(v) do
if type(a) ~= "number" or a < 1 or a > table_len(v) then
t[#t+1] = "["
t[#t+1] = ptostring(a)
t[#t+1] = "] = "
end
t[#t+1] = ptostring(b)
t[#t+1] = ", "
end
t[#t+1] = "}"
else
t[#t+1] = tostring(v)
end
end
return table.concat(t)
end
local function is_equal(alpha, bravo)
if type(alpha) ~= type(bravo) then
return false
end
if type(alpha) == "number" then
return alpha == bravo or math.abs(alpha - bravo) < 1e-10
elseif type(alpha) ~= "table" then
return alpha == bravo
end
local num = 0
for k,v in pairs(alpha) do
num = num + 1
if not is_equal(v, bravo[k]) then
return false
end
end
for k,v in pairs(bravo) do
num = num - 1
end
if num ~= 0 then
return false
end
return true
end
local function assert_equal(alpha, bravo)
if not is_equal(alpha, bravo) then
error(("Assertion failed: %s == %s"):format(ptostring(alpha), ptostring(bravo)), 2)
end
end
DogTag_DEBUG = true
dofile("LibStub/LibStub.lua")
dofile("Localization/enUS.lua")
dofile("LibDogTag-3.0.lua")
dofile("Parser.lua")
dofile("Compiler.lua")
dofile("Modules/Operators.lua")
dofile("Cleanup.lua")
function geterrorhandler()
return error
end
local DogTag = LibStub("LibDogTag-3.0")
local getPoolNum, setPoolNum = DogTag.getPoolNum, DogTag.setPoolNum
local parse = DogTag.parse
local standardize = DogTag.standardize
local function assert_table_usage(func, tableChange)
local previousPoolNum = getPoolNum()
func()
local afterPoolNum = getPoolNum()
local actualChange = afterPoolNum-previousPoolNum
if tableChange ~= actualChange then
error(("Unexpected table usage: %d instead of expected %d"):format(actualChange, tableChange), 2)
end
end
local function countTables(t)
if type(t) ~= "table" then
return 0
end
local n = 1
for k, v in pairs(t) do
n = n + countTables(k) + countTables(v)
end
return n
end
local function deepCopy(t)
if type(t) ~= "table" then
return t
end
local x = {}
for k,v in pairs(t) do
x[k] = deepCopy(v)
end
return x
end
local old_parse = parse
function parse(arg)
local start = DogTag.getPoolNum()
local ret = old_parse(arg)
local finish = DogTag.getPoolNum()
local change = finish - start
local num_tables = countTables(ret)
if change ~= num_tables then
error(("Unknown table usage: %d instead of %d"):format(change, num_tables), 2)
end
local r = deepCopy(ret)
deepDel(ret)
return r
end
local old_standardize = standardize
function standardize(arg)
local realStart = DogTag.getPoolNum()
local start = realStart - countTables(arg)
local ret = old_standardize(arg)
local finish = DogTag.getPoolNum()
local change = finish - start
local num_tables = countTables(ret)
if change ~= num_tables then
error(("Unknown table usage: %d instead of %d"):format(change, num_tables), 2)
end
DogTag.setPoolNum(realStart)
return ret
end
DogTag:Evaluate("")
local old_DogTag_Evaluate = DogTag.Evaluate
function DogTag:Evaluate(...)
local start = DogTag.getPoolNum()
local ret = old_DogTag_Evaluate(self, ...)
local finish = DogTag.getPoolNum()
local change = finish - start
if change ~= 0 then
error(("Unknown table usage: %d instead of %d"):format(change, 0), 2)
end
return ret
end
local old_DogTag_CleanCode = DogTag.CleanCode
function DogTag:CleanCode(...)
local start = DogTag.getPoolNum()
local ret = old_DogTag_CleanCode(self, ...)
local finish = DogTag.getPoolNum()
local change = finish - start
if change ~= 0 then
error(("Unknown table usage: %d instead of %d"):format(change, 0), 2)
end
return ret
end
DogTag:AddTag("Base", "One", {
code = [=[return 1]=],
ret = "number",
doc = "Return the number 1",
example = '[One] => "1"',
category = "Testing"
})
DogTag:AddTag("Base", "Two", {
code = [=[return 2]=],
ret = "number",
doc = "Return the number 2",
example = '[Two] => "2"',
category = "Testing"
})
DogTag:AddTag("Base", "PlusOne", {
code = [=[return ${number} + 1]=],
arg = {
'number', 'number', "@req"
},
ret = "number",
doc = "Return the number 1",
example = '[One] => "1"',
category = "Testing"
})
DogTag:AddTag("Base", "Subtract", {
code = [=[return ${left} - ${right}]=],
arg = {
'left', 'number', "@req",
'right', 'number', "@req"
},
ret = "number",
doc = "Subtract right from left",
example = '[AddNumbers(1, 2)] => "-1"',
category = "Testing"
})
local testfunc_data = "Hello World"
_G.testfunc = function()
return testfunc_data
end
DogTag:AddTag("Base", "GlobalCheck", {
code = [=[return testfunc()]=],
ret = "string;number;nil",
doc = "Return the results of testfunc",
globals = 'testfunc',
example = '[GlobalCheck] => "Hello World"',
category = "Testing"
})
testtable = {
testfunc = function()
return testfunc_data
end
}
DogTag:AddTag("Base", "SubGlobalCheck", {
code = [=[return testtable_testfunc()]=],
ret = "string;number;nil",
doc = "Return the results of testtable.testfunc",
globals = 'testtable.testfunc',
example = '[GlobalCheck] => "Hello World"',
category = "Testing"
})
local myfunc_num = 0
function _G.myfunc()
myfunc_num = myfunc_num + 1
return myfunc_num
end
DogTag:AddTag("Base", "FunctionNumberCheck", {
code = [=[return myfunc()]=],
ret = "number;nil",
doc = "Return the results of myfunc",
globals = 'myfunc',
example = '[FunctionNumberCheck] => "1"',
category = "Testing"
})
DogTag:AddTag("Base", "CheckNumDefault", {
code = [=[return ${value}]=],
arg = {
'value', 'number', 50
},
ret = "number",
doc = "Return the given argument or 50",
example = '[CheckStrDefault(1)] => "1"; [CheckStrDefault] => "50"',
category = "Testing"
})
DogTag:AddTag("Base", "CheckStrDefault", {
code = [=[return ${value}]=],
arg = {
'value', 'string', 'Value'
},
ret = "string",
doc = "Return the given argument or value",
example = '[CheckStrDefault(1)] => "1"; [CheckStrDefault] => "Value"',
category = "Testing"
})
DogTag:AddTag("Base", "CheckNilDefault", {
code = [=[return ${value}]=],
arg = {
'value', 'nil;number', false
},
ret = "nil;number",
doc = "Return the given argument or nil",
example = '[CheckNilDefault(1)] => "1"; [CheckNilDefault] => ""',
category = "Testing"
})
DogTag:AddTag("Base", "CheckNumTuple", {
code = [=[return ("-"):join(${...})]=],
arg = {
'...', 'list-number', false
},
ret = "string",
doc = "Join ... separated by dashes",
example = '[CheckNumTuple(1)] => "1"; [CheckNumTuple] => ""',
category = "Testing"
})
DogTag:AddTag("Base", "CheckAnotherNumTuple", {
code = [=[return math_max(0, ${...})]=],
arg = {
'...', 'list-number', false
},
ret = "string",
doc = "Return the largest number of ...",
globals = 'math.max',
example = '[CheckAnotherNumTuple(1)] => "1"; [CheckAnotherNumTuple] => "0"',
category = "Testing"
})
DogTag:AddTag("Base", "CheckStrTuple", {
code = [=[
local x = ''
for i = 1, select('#', ${...}) do
x = x .. select(i, ${...}):gsub('[aeiou]', 'y')
end
return x
]=],
arg = {
'...', 'list-string', false
},
ret = "string",
doc = "Join ..., replacing vowels with 'y'",
example = '[CheckStrTuple("Hello")] => "Hylly"; [CheckStrTuple] => ""',
category = "Testing"
})
DogTag:AddTag("Base", "CheckAnotherStrTuple", {
code = [=[
local x = ''
for i = 1, ${#...} do
x = x .. select(i, ${...}):gsub('[aeiou]', 'y')
end
return x
]=],
arg = {
'...', 'list-string', false
},
ret = "string",
doc = "Join ..., replacing vowels with 'y'",
example = '[CheckAnotherStrTuple("Hello")] => "Hylly"; [CheckAnotherStrTuple] => ""',
category = "Testing"
})
DogTag:AddTag("Base", "Reverse", {
code = [=[return ${value}:reverse()]=],
arg = {
'value', 'string', '@req'
},
ret = "string",
doc = "Reverse the characters in value",
example = '[Reverse(Hello)] => "olleH"',
category = "Testing",
})
DogTag:AddTag("Base", "OtherReverse", {
code = [=[if ${value}:reverse() ~= "Stuff" then
return ${value}:reverse()
else
return "ffutS"
end]=],
arg = {
'value', 'string', '@req'
},
ret = "string",
doc = "Reverse the characters in value",
example = '[OtherReverse(Hello)] => "olleH"',
category = "Testing",
})
DogTag:AddTag("Base", "KwargAndTuple", {
code = [=[return ${value} * math_max(${...})]=],
arg = {
'value', 'number', '@req',
'...', 'list-number', false
},
ret = 'number',
globals = 'math.max';
doc = "Return the maximum of ... multiplied by value",
example = '[KwargAndTuple(5, 1, 2, 3)] => "15"',
})
DogTag:AddTag("Base", "TupleAndKwarg", {
code = [=[return ${value} * math_max(${...})]=],
arg = {
'...', 'list-number', false,
'value', 'number', '@req'
},
ret = 'number',
globals = 'math.max';
doc = "Return the maximum of ... multiplied by value",
example = '[KwargAndTuple(5, 1, 2, 3)] => "15"',
})
assert_equal(parse("[MyTag]"), { "tag", "MyTag" })
assert_equal(DogTag:CleanCode("[MyTag]"), "[MyTag]")
assert_equal(parse("Alpha [MyTag]"), {" ", "Alpha ", { "tag", "MyTag" } })
assert_equal(DogTag:CleanCode("Alpha [MyTag]"), "Alpha [MyTag]")
assert_equal(parse("[MyTag] Bravo"), {" ", { "tag", "MyTag" }, " Bravo" })
assert_equal(DogTag:CleanCode("[MyTag] Bravo"), "[MyTag] Bravo")
assert_equal(parse("Alpha [MyTag] Bravo"), {" ", "Alpha ", { "tag", "MyTag" }, " Bravo" })
assert_equal(DogTag:CleanCode("Alpha [MyTag] Bravo"), "Alpha [MyTag] Bravo")
assert_equal(parse("[Alpha][Bravo]"), { " ", { "tag", "Alpha" }, { "tag", "Bravo" } })
assert_equal(parse("[Alpha Bravo]"), { " ", { "tag", "Alpha" }, { "tag", "Bravo" } })
assert_equal(DogTag:CleanCode("[Alpha][Bravo]"), "[Alpha Bravo]")
assert_equal(parse("[Alpha][Bravo][Charlie]"), { " ", { "tag", "Alpha" }, { "tag", "Bravo" }, { "tag", "Charlie"} })
assert_equal(parse("[Alpha Bravo Charlie]"), { " ", { "tag", "Alpha" }, { "tag", "Bravo" }, { "tag", "Charlie"} })
assert_equal(DogTag:CleanCode("[Alpha][Bravo][Charlie]"), "[Alpha Bravo Charlie]")
assert_equal(DogTag:CleanCode("Alpha [Bravo][Charlie] Delta"), "Alpha [Bravo Charlie] Delta")
assert_equal(DogTag:CleanCode("[Alpha] [Bravo] [Charlie]"), "[Alpha] [Bravo] [Charlie]")
assert_equal(DogTag:CleanCode("Alpha [Bravo] [Charlie] Delta"), "Alpha [Bravo] [Charlie] Delta")
assert_equal(parse("[Alpha(Bravo)]"), { "tag", "Alpha", { "tag", "Bravo" } })
assert_equal(DogTag:CleanCode("[Alpha(Bravo)]"), "[Alpha(Bravo)]")
assert_equal(parse("[Alpha(Bravo, Charlie)]"), { "tag", "Alpha", { "tag", "Bravo" }, { "tag", "Charlie"} })
assert_equal(DogTag:CleanCode("[Alpha(Bravo, Charlie)]"), "[Alpha(Bravo, Charlie)]")
assert_equal(parse("[Alpha:Delta]"), { "mod", "Delta", { "tag", "Alpha" } })
assert_equal(DogTag:CleanCode("[Alpha:Delta]"), "[Alpha:Delta]")
assert_equal(parse("[Alpha:Bravo:Charlie]"), { "mod", "Charlie", { "mod", "Bravo", { "tag", "Alpha" } } })
assert_equal(DogTag:CleanCode("[Alpha:Bravo:Charlie]"), "[Alpha:Bravo:Charlie]")
assert_equal(standardize(parse("[Alpha:Delta]")), { "tag", "Delta", { "tag", "Alpha" } })
assert_equal(standardize(parse("[Alpha:Bravo:Charlie]")), { "tag", "Charlie", { "tag", "Bravo", { "tag", "Alpha" } } })
assert_equal(parse("[Alpha:Delta(Echo)]"), { "mod", "Delta", { "tag", "Alpha" }, { "tag", "Echo" } })
assert_equal(DogTag:CleanCode("[Alpha:Delta(Echo)]"), "[Alpha:Delta(Echo)]")
assert_equal(parse("[Alpha(Bravo):Delta]"), { "mod", "Delta", { "tag", "Alpha", { "tag", "Bravo"} } })
assert_equal(DogTag:CleanCode("[Alpha(Bravo):Delta]"), "[Alpha(Bravo):Delta]")
assert_equal(parse("[Alpha(Bravo, Charlie):Delta(Echo, Foxtrot)]"), { "mod", "Delta", { "tag", "Alpha", { "tag", "Bravo"}, {"tag", "Charlie"} }, {"tag", "Echo"}, {"tag", "Foxtrot"} })
assert_equal(DogTag:CleanCode("[Alpha(Bravo, Charlie):Delta(Echo, Foxtrot)]"), "[Alpha(Bravo, Charlie):Delta(Echo, Foxtrot)]")
assert_equal(parse("[Alpha:~Delta]"), { "~", { "mod", "Delta", { "tag", "Alpha" } } })
assert_equal(DogTag:CleanCode("[Alpha:~Delta]"), "[Alpha:~Delta]")
assert_equal(parse("[Alpha(Bravo, Charlie):~Delta(Echo, Foxtrot)]"), { "~", { "mod", "Delta", { "tag", "Alpha", { "tag", "Bravo"}, {"tag", "Charlie"} }, {"tag", "Echo"}, {"tag", "Foxtrot"} } })
assert_equal(DogTag:CleanCode("[Alpha(Bravo, Charlie):~Delta(Echo, Foxtrot)]"), "[Alpha(Bravo, Charlie):~Delta(Echo, Foxtrot)]")
assert_equal(parse("[Func('Alpha')]"), { "tag", "Func", "Alpha" })
assert_equal(DogTag:CleanCode("[Func('Alpha')]"), '[Func("Alpha")]')
assert_equal(parse([=[[Func('Alp"ha')]]=]), { "tag", "Func", 'Alp"ha' })
assert_equal(DogTag:CleanCode([=[[Func('Alp"ha')]]=]), [=[[Func('Alp"ha')]]=])
assert_equal(parse(""), { "nil" })
assert_equal(parse("['']"), { "nil" })
assert_equal(parse('[""]'), { "nil" })
assert_equal(parse("[nil]"), { "nil" })
assert_equal(DogTag:CleanCode("[nil]"), "")
assert_equal(DogTag:CleanCode("[nil nil]"), "[nil nil]")
assert_equal(parse("['Alpha']"), "Alpha")
assert_equal(parse('["Alpha"]'), "Alpha")
assert_equal(DogTag:CleanCode("['Alpha']"), "Alpha")
assert_equal(DogTag:CleanCode('["Alpha"]'), "Alpha")
assert_equal(parse("[1234]"), 1234)
assert_equal(DogTag:CleanCode("[1234]"), "[1234]")
assert_equal(parse("[-1234]"), -1234)
assert_equal(DogTag:CleanCode("[-1234]"), "[-1234]")
assert_equal(parse("[1234.5678]"), 1234.5678)
assert_equal(DogTag:CleanCode("[-1234.5678]"), "[-1234.5678]")
assert_equal(parse("[-1234.5678]"), -1234.5678)
assert_equal(DogTag:CleanCode("[-1234.5678]"), "[-1234.5678]")
assert_equal(parse("[1234e5]"), 123400000)
assert_equal(DogTag:CleanCode("[1234e5]"), "[123400000]")
assert_equal(parse("[1234e-5]"), 0.01234)
assert_equal(DogTag:CleanCode("[1234e-5]"), "[0.01234]")
assert_equal(parse("[-1234e5]"), -123400000)
assert_equal(DogTag:CleanCode("[-1234e5]"), "[-123400000]")
assert_equal(parse("[-1234e-5]"), -0.01234)
assert_equal(DogTag:CleanCode("[-1234e-5]"), "[-0.01234]")
assert_equal(parse("[1 + 2]"), { "+", 1, 2, })
assert_equal(DogTag:CleanCode("[1 + 2]"), "[1 + 2]")
assert_equal(parse("[1 - 2]"), { "-", 1, 2, })
assert_equal(DogTag:CleanCode("[1 - 2]"), "[1 - 2]")
assert_equal(parse("[1 * 2]"), { "*", 1, 2, })
assert_equal(DogTag:CleanCode("[1 * 2]"), "[1 * 2]")
assert_equal(parse("[1 / 2]"), { "/", 1, 2, })
assert_equal(DogTag:CleanCode("[1 / 2]"), "[1 / 2]")
assert_equal(parse("[1 ^ 2]"), { "^", 1, 2, })
assert_equal(DogTag:CleanCode("[1 ^ 2]"), "[1 ^ 2]")
assert_equal(parse("[1 % 2]"), { "%", 1, 2, })
assert_equal(DogTag:CleanCode("[1 % 2]"), "[1 % 2]")
assert_equal(parse("[1 < 2]"), { "<", 1, 2 })
assert_equal(DogTag:CleanCode("[1 < 2]"), "[1 < 2]")
assert_equal(parse("[1 > 2]"), { ">", 1, 2 })
assert_equal(DogTag:CleanCode("[1 > 2]"), "[1 > 2]")
assert_equal(parse("[1 <= 2]"), { "<=", 1, 2 })
assert_equal(DogTag:CleanCode("[1 <= 2]"), "[1 <= 2]")
assert_equal(parse("[1 >= 2]"), { ">=", 1, 2 })
assert_equal(DogTag:CleanCode("[1 >= 2]"), "[1 >= 2]")
assert_equal(parse("[1 = 2]"), { "=", 1, 2 })
assert_equal(DogTag:CleanCode("[1 = 2]"), "[1 = 2]")
assert_equal(parse("[1 ~= 2]"), { "~=", 1, 2 })
assert_equal(DogTag:CleanCode("[1 ~= 2]"), "[1 ~= 2]")
assert_equal(parse("[1 and 2]"), { "and", 1, 2 })
assert_equal(DogTag:CleanCode("[1 and 2]"), "[1 and 2]")
assert_equal(parse("[1 or 2]"), { "or", 1, 2 })
assert_equal(DogTag:CleanCode("[1 or 2]"), "[1 or 2]")
assert_equal(parse("[1 & 2]"), { "&", 1, 2 })
assert_equal(DogTag:CleanCode("[1 & 2]"), "[1 & 2]")
assert_equal(parse("[1 | 2]"), { "|", 1, 2 })
assert_equal(DogTag:CleanCode("[1 | 2]"), "[1 | 2]")
assert_equal(parse("[Alpha Bravo]"), { " ", { "tag", "Alpha" }, { "tag", "Bravo"}, })
assert_equal(DogTag:CleanCode("[Alpha Bravo]"), "[Alpha Bravo]")
assert_equal(parse("[1 ? 2]"), { "?", 1, 2 })
assert_equal(DogTag:CleanCode("[1 ? 2]"), "[1 ? 2]")
assert_equal(parse("[1 ? 2 ! 3]"), { "?", 1, 2, 3 })
assert_equal(DogTag:CleanCode("[1 ? 2 ! 3]"), "[1 ? 2 ! 3]")
assert_equal(parse("[if 1 then 2]"), { "if", 1, 2 })
assert_equal(DogTag:CleanCode("[if 1 then 2]"), "[if 1 then 2]")
assert_equal(parse("[if 1 then 2 else 3]"), { "if", 1, 2, 3 })
assert_equal(parse("[Func('Hello' 'There')]"), { "tag", "Func", {" ", "Hello", "There"} })
assert_equal(DogTag:CleanCode("[Func('Hello' 'There')]"), '[Func("Hello" "There")]')
assert_equal(standardize(parse("[1 & 2]")), { "and", 1, 2 })
assert_equal(standardize(parse("[1 | 2]")), { "or", 1, 2 })
assert_equal(standardize(parse("[1 ? 2]")), { "if", 1, 2 })
assert_equal(standardize(parse("[1 ? 2 ! 3]")), { "if", 1, 2, 3 })
assert_equal(parse("[1+2]"), { "+", 1, 2, })
assert_equal(parse("[1-2]"), { "-", 1, 2, })
assert_equal(parse("[1*2]"), { "*", 1, 2, })
assert_equal(parse("[1/2]"), { "/", 1, 2, })
assert_equal(parse("[1^2]"), { "^", 1, 2, })
assert_equal(parse("[1%2]"), { "%", 1, 2, })
assert_equal(parse("[1<2]"), { "<", 1, 2 })
assert_equal(parse("[1>2]"), { ">", 1, 2 })
assert_equal(parse("[1<=2]"), { "<=", 1, 2 })
assert_equal(parse("[1>=2]"), { ">=", 1, 2 })
assert_equal(parse("[1=2]"), { "=", 1, 2 })
assert_equal(parse("[1~=2]"), { "~=", 1, 2 })
assert_equal(parse("[1&2]"), { "&", 1, 2 })
assert_equal(parse("[1|2]"), { "|", 1, 2 })
assert_equal(parse("[1?2]"), { "?", 1, 2 })
assert_equal(parse("[1?2!3]"), { "?", 1, 2, 3 })
assert_equal(parse("[1 and 2 or 3]"), { "or", { "and", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 and 2 or 3]"), "[1 and 2 or 3]")
assert_equal(parse("[1 or 2 and 3]"), { "and", { "or", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 or 2 and 3]"), "[1 or 2 and 3]")
assert_equal(parse("[1 + 2 - 3]"), { "-", { "+", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 + 2 - 3]"), "[1 + 2 - 3]")
assert_equal(parse("[1 - 2 + 3]"), { "+", { "-", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 - 2 + 3]"), "[1 - 2 + 3]")
assert_equal(parse("[1 * 2 / 3]"), { "/", { "*", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 * 2 / 3]"), "[1 * 2 / 3]")
assert_equal(parse("[1 / 2 * 3]"), { "*", { "/", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 / 2 * 3]"), "[1 / 2 * 3]")
assert_equal(parse("[1 * 2 % 3]"), { "%", { "*", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 * 2 % 3]"), "[1 * 2 % 3]")
assert_equal(parse("[1 % 2 * 3]"), { "*", { "%", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 % 2 * 3]"), "[1 % 2 * 3]")
assert_equal(parse("[1 ? 2 and 3]"), { "?", 1, { "and", 2, 3 } })
assert_equal(DogTag:CleanCode("[1 ? 2 and 3]"), "[1 ? 2 and 3]")
assert_equal(parse("[1 and 2 ? 3]"), { "?", { "and", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 and 2 ? 3]"), "[1 and 2 ? 3]")
assert_equal(parse("[1 ? 2 and 3 ! 4 or 5]"), { "?", 1, { "and", 2, 3 }, { "or", 4, 5 } })
assert_equal(DogTag:CleanCode("[1 ? 2 and 3 ! 4 or 5]"), "[1 ? 2 and 3 ! 4 or 5]")
assert_equal(parse("[1 and 2 ? 3 ! 4]"), { "?", { "and", 1, 2 }, 3, 4 })
assert_equal(DogTag:CleanCode("[1 and 2 ? 3 ! 4]"), "[1 and 2 ? 3 ! 4]")
assert_equal(parse("[1 and 2 < 3]"), { "<", { "and", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 and 2 < 3]"), "[1 and 2 < 3]")
assert_equal(parse("[1 < 2 and 3]"), { "<", 1, { "and", 2, 3 } })
assert_equal(DogTag:CleanCode("[1 < 2 and 3]"), "[1 < 2 and 3]")
assert_equal(parse("[1 + 2 and 3]"), { "and", { "+", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 + 2 and 3]"), "[1 + 2 and 3]")
assert_equal(parse("[1 and 2 + 3]"), { "and", 1, { "+", 2, 3 } })
assert_equal(DogTag:CleanCode("[1 and 2 + 3]"), "[1 and 2 + 3]")
assert_equal(parse("[1 + 2 * 3]"), { "+", 1, { "*", 2, 3 }, })
assert_equal(DogTag:CleanCode("[1 + 2 * 3]"), "[1 + 2 * 3]")
assert_equal(parse("[1 * 2 + 3]"), { "+", { "*", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 * 2 + 3]"), "[1 * 2 + 3]")
assert_equal(parse("[1 * 2 ^ 3]"), { "*", 1, { "^", 2, 3 }, })
assert_equal(DogTag:CleanCode("[1 * 2 ^ 3]"), "[1 * 2 ^ 3]")
assert_equal(parse("[1 ^ 2 * 3]"), { "*", { "^", 1, 2 }, 3 })
assert_equal(DogTag:CleanCode("[1 ^ 2 * 3]"), "[1 ^ 2 * 3]")
assert_equal(parse("[(1 ^ 2) * 3]"), { "*", { "(", { "^", 1, 2 } }, 3 })
assert_equal(parse("[[1 ^ 2] * 3]"), { "*", { "[", { "^", 1, 2 } }, 3 })
-- pointless parenthesization should stay
assert_equal(DogTag:CleanCode("[(1 ^ 2) * 3]"), "[(1 ^ 2) * 3]")
assert_equal(DogTag:CleanCode("[[1 ^ 2] * 3]"), "[[1 ^ 2] * 3]")
assert_equal(parse("[(1) * 3]"), { "*", { "(", 1 }, 3 })
assert_equal(parse("[[1] * 3]"), { "*", { "[", 1 }, 3 })
-- but parenthesization of a tag, number, or string should go away
assert_equal(DogTag:CleanCode("[(1) * 3]"), "[1 * 3]")
assert_equal(DogTag:CleanCode("[[1] * 3]"), "[1 * 3]")
assert_equal(DogTag:CleanCode("[1 * (3)]"), "[1 * 3]")
assert_equal(DogTag:CleanCode("[1 * [3]]"), "[1 * 3]")
assert_equal(DogTag:CleanCode("[Func(('Hello') 'There')]"), '[Func("Hello" "There")]')
assert_equal(DogTag:CleanCode("[Func(['Hello'] 'There')]"), '[Func("Hello" "There")]')
assert_equal(DogTag:CleanCode("[Func('Hello' ('There'))]"), '[Func("Hello" "There")]')
assert_equal(DogTag:CleanCode("[Func('Hello' ['There'])]"), '[Func("Hello" "There")]')
assert_equal(DogTag:CleanCode("[(Alpha) * Bravo]"), "[Alpha * Bravo]")
assert_equal(DogTag:CleanCode("[[Alpha] * Bravo]"), "[Alpha * Bravo]")
assert_equal(DogTag:CleanCode("[(Alpha) * Bravo]"), "[Alpha * Bravo]")
assert_equal(DogTag:CleanCode("[[Alpha] * Bravo]"), "[Alpha * Bravo]")
assert_equal(parse("[1 ^ (2 * 3)]"), { "^", 1, { "(", { "*", 2, 3 } } })
assert_equal(parse("[1 ^ [2 * 3]]"), { "^", 1, { "[", { "*", 2, 3 } } })
assert_equal(DogTag:CleanCode("[1 ^ (2 * 3)]"), "[1 ^ (2 * 3)]")
assert_equal(DogTag:CleanCode("[1 ^ [2 * 3]]"), "[1 ^ [2 * 3]]")
assert_equal(parse("[(1 + 2) * 3]"), { "*", { "(", { "+", 1, 2 } }, 3 })
assert_equal(DogTag:CleanCode("[(1 + 2) * 3]"), "[(1 + 2) * 3]")
assert_equal(parse("[1 + (2 ? 3)]"), { "+", 1, { "(", { "?", 2, 3 } } })
assert_equal(DogTag:CleanCode("[1 + (2 ? 3)]"), "[1 + (2 ? 3)]")
assert_equal(parse("[(2 ? 3 ! 4) + 1]"), { "+", { "(", { "?", 2, 3, 4 } }, 1 })
assert_equal(DogTag:CleanCode("[(2 ? 3 ! 4) + 1]"), "[(2 ? 3 ! 4) + 1]")
assert_equal(parse("[1 + (if 2 then 3)]"), { "+", 1, { "(", { "if", 2, 3 } } })
assert_equal(DogTag:CleanCode("[1 + (if 2 then 3)]"), "[1 + (if 2 then 3)]")
assert_equal(parse("[(if 2 then 3 else 4) + 1]"), { "+", { "(", { "if", 2, 3, 4 } }, 1 })
assert_equal(DogTag:CleanCode("[(if 2 then 3 else 4) + 1]"), "[(if 2 then 3 else 4) + 1]")
assert_equal(parse("[Alpha(Bravo + Charlie)]"), { "tag", "Alpha", { "+", {"tag", "Bravo"}, {"tag", "Charlie"} } })
assert_equal(DogTag:CleanCode("[Alpha(Bravo + Charlie)]"), "[Alpha(Bravo + Charlie)]")
assert_equal(parse("[Alpha (Bravo + Charlie)]"), { " ", {"tag", "Alpha"}, { "(", { "+", {"tag", "Bravo"}, {"tag", "Charlie"} } } })
assert_equal(DogTag:CleanCode("[Alpha (Bravo + Charlie)]"), "[Alpha (Bravo + Charlie)]")
assert_equal(parse("[not Alpha]"), { "not", { "tag", "Alpha" }, })
assert_equal(DogTag:CleanCode("[not Alpha]"), "[not Alpha]")
assert_equal(parse("[not not Alpha]"), { "not", { "not", { "tag", "Alpha" }, }, })
assert_equal(DogTag:CleanCode("[not not Alpha]"), "[not not Alpha]")
assert_equal(parse("[~Alpha]"), { "~", { "tag", "Alpha" }, })
assert_equal(DogTag:CleanCode("[~Alpha]"), "[~Alpha]")
assert_equal(parse("[~(1 > 2)]"), { "~", { "(", { ">", 1, 2 } }, })
assert_equal(DogTag:CleanCode("[~(1 > 2)]"), "[~(1 > 2)]")
assert_equal(parse("[not(1 > 2)]"), { "not", { "(", { ">", 1, 2 } }, })
assert_equal(DogTag:CleanCode("[not(1 > 2)]"), "[not (1 > 2)]")
assert_equal(standardize(parse("[~Alpha]")), { "not", { "tag", "Alpha" }, })
assert_equal(standardize(parse("[Alpha(bravo=(Charlie+2))]")), { "tag", "Alpha", kwarg = { bravo = { "+", { "tag", "Charlie" }, 2 } } })
assert_equal(parse("[Alpha(key=Bravo)]"), { "tag", "Alpha", kwarg = { key = { "tag", "Bravo" } } })
assert_equal(DogTag:CleanCode("[Alpha(key=Bravo)]"), "[Alpha(key=Bravo)]")
assert_equal(parse("[Alpha(Bravo, key=Charlie)]"), { "tag", "Alpha", { "tag", "Bravo" }, kwarg = { key = { "tag", "Charlie" } } })
assert_equal(DogTag:CleanCode("[Alpha(Bravo, key=Charlie)]"), "[Alpha(Bravo, key=Charlie)]")
assert_equal(parse("[Alpha(bravo=Charlie, delta=Echo)]"), { "tag", "Alpha", kwarg = { bravo = { "tag", "Charlie" }, delta = { "tag", "Echo" } } })
assert_equal(DogTag:CleanCode("[Alpha(bravo=Charlie, delta=Echo)]"), "[Alpha(bravo=Charlie, delta=Echo)]")
assert_equal(DogTag:CleanCode("[Alpha(delta=Echo, bravo=Charlie)]"), "[Alpha(bravo=Charlie, delta=Echo)]")
assert_equal(parse("[Alpha((key=Bravo))]"), { "tag", "Alpha", { "(", { "=", { "tag", "key" }, { "tag", "Bravo" } } } })
assert_equal(DogTag:CleanCode("[Alpha(key = Bravo)]"), "[Alpha(key = Bravo)]")
assert_equal(DogTag:CleanCode("[Alpha((key=Bravo))]"), "[Alpha((key = Bravo))]")
assert_equal(parse("[Class(unit='mouseovertarget')]"), { "tag", "Class", kwarg = { unit = "mouseovertarget" } })
assert_equal(parse("[Alpha(key=Bravo, Charlie)]"), { "tag", "Alpha", { "tag", "Charlie" }, kwarg = { key = { "tag", "Bravo" } } })
assert_equal(parse("[Alpha(Bravo Charlie)]"), { "tag", "Alpha", { " ", { "tag", "Bravo"}, { "tag", "Charlie" } } })
assert_equal(parse("[Alpha(Bravo ' ' Charlie)]"), { "tag", "Alpha", { " ", { "tag", "Bravo"}, " ", { "tag", "Charlie" } } })
assert_equal(DogTag:CleanCode("[Alpha(Bravo ' ' Charlie)]"), "[Alpha(Bravo \" \" Charlie)]")
assert_equal(DogTag:CleanCode("[Alpha(Bravo \" \" Charlie)]"), "[Alpha(Bravo \" \" Charlie)]")
assert_equal(parse("[Alpha:Bravo(key=Charlie)]"), { "mod", "Bravo", { "tag", "Alpha" }, kwarg = { key = { "tag", "Charlie" } } })
assert_equal(DogTag:CleanCode("[Alpha:Bravo(key=Charlie)]"), "[Alpha:Bravo(key=Charlie)]")
assert_equal(parse("[Alpha:Bravo(Charlie, key=Delta)]"), { "mod", "Bravo", { "tag", "Alpha" }, { "tag", "Charlie" }, kwarg = { key = { "tag", "Delta" } } })
assert_equal(DogTag:CleanCode("[Alpha:Bravo(Charlie, key=Delta)]"), "[Alpha:Bravo(Charlie, key=Delta)]")
assert_equal(parse("[Tag:Alpha(bravo=Charlie, delta=Echo)]"), { "mod", "Alpha", { "tag", "Tag" }, kwarg = { bravo = { "tag", "Charlie" }, delta = { "tag", "Echo" } } })
assert_equal(DogTag:CleanCode("[Tag:Alpha(bravo=Charlie, delta=Echo)]"), "[Tag:Alpha(bravo=Charlie, delta=Echo)]")
assert_equal(DogTag:CleanCode("[Tag:Alpha(delta=Echo, bravo=Charlie)]"), "[Tag:Alpha(bravo=Charlie, delta=Echo)]")
assert_equal(parse("[Tag:Alpha((key=Bravo))]"), { "mod", "Alpha", { "tag", "Tag" }, { "(", { "=", { "tag", "key" }, { "tag", "Bravo" } } } })
assert_equal(DogTag:CleanCode("[Tag:Alpha(key = Bravo)]"), "[Tag:Alpha(key = Bravo)]")
assert_equal(DogTag:CleanCode("[Tag:Alpha((key=Bravo))]"), "[Tag:Alpha((key = Bravo))]")
assert_equal(parse("[Class(unit='mouseovertarget'):ClassColor(unit='mouseovertarget')]"), { "mod", "ClassColor", { "tag", "Class", kwarg = { unit = "mouseovertarget" } }, kwarg = { unit = "mouseovertarget" } })
assert_equal(parse("[-MissingHP]"), { "unm", { "tag", "MissingHP" } })
assert_equal(DogTag:CleanCode("[-MissingHP]"), "[-MissingHP]")
assert_equal(parse("[-(-1)]"), { "unm", { "(", -1 } })
assert_equal(standardize(parse("[-(-1)]")), { "unm", -1 })
assert_equal(DogTag:Evaluate("[One]"), 1)
assert_equal(DogTag:Evaluate("[One:PlusOne]"), 2)
assert_equal(DogTag:Evaluate("[PlusOne(One):PlusOne]"), 3)
assert_equal(DogTag:Evaluate("[PlusOne(number=One)]"), 2)
assert_equal(DogTag:Evaluate("[GlobalCheck]"), "Hello World")
assert_equal(DogTag:Evaluate("[SubGlobalCheck]"), "Hello World")
myfunc_num = 0
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 1)
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 2)
assert_equal(DogTag:Evaluate("[FunctionNumberCheck] [FunctionNumberCheck]"), "3 3") -- check caching
testfunc_data = 2
assert_equal(DogTag:Evaluate("[GlobalCheck + One]"), 3)
assert_equal(DogTag:Evaluate("[One + GlobalCheck]"), 3)
assert_equal(DogTag:Evaluate("[GlobalCheck + GlobalCheck]"), 4)
assert_equal(DogTag:Evaluate("[PlusOne]"), [=[Arg #1 (number) req'd for PlusOne]=])
assert_equal(DogTag:Evaluate("[Unknown]"), [=[Unknown tag Unknown]=])
assert_equal(DogTag:Evaluate("[Subtract]"), [=[Arg #1 (left) req'd for Subtract]=])
assert_equal(DogTag:Evaluate("[Subtract(1)]"), [=[Arg #2 (right) req'd for Subtract]=])
assert_equal(DogTag:Evaluate("[Subtract(right=2)]"), [=[Arg #1 (left) req'd for Subtract]=])
assert_equal(DogTag:Evaluate("[Subtract(left=1)]"), [=[Arg #2 (right) req'd for Subtract]=])
assert_equal(DogTag:Evaluate("[Subtract(1, 2, extra='Stuff')]"), -1)
assert_equal(DogTag:Evaluate("[Subtract(1, 2, 3)]"), [=[Too many args for Subtract]=])
assert_equal(DogTag:Evaluate("[CheckNumDefault(1)]"), 1)
assert_equal(DogTag:Evaluate("[CheckNumDefault]"), 50)
assert_equal(DogTag:Evaluate("[CheckNumDefault(50)]"), 50)
assert_equal(DogTag:Evaluate("[CheckNumDefault(One)]"), 1)
assert_equal(DogTag:Evaluate("[CheckNumDefault('Test')]"), 0)
assert_equal(DogTag:Evaluate("[CheckStrDefault(1)]"), 1)
assert_equal(DogTag:Evaluate("[CheckStrDefault]"), "Value")
assert_equal(DogTag:Evaluate("[CheckStrDefault(50)]"), 50)
assert_equal(DogTag:Evaluate("[CheckStrDefault(One)]"), 1)
assert_equal(DogTag:Evaluate("[CheckStrDefault('Test')]"), "Test")
assert_equal(DogTag:Evaluate("[CheckNilDefault(1)]"), 1)
assert_equal(DogTag:Evaluate("[CheckNilDefault]"), nil)
assert_equal(DogTag:Evaluate("[CheckNilDefault(50)]"), 50)
assert_equal(DogTag:Evaluate("[CheckNilDefault('Test')]"), nil)
assert_equal(DogTag:Evaluate("[CheckNilDefault(One)]"), 1)
assert_equal(DogTag:Evaluate("[1 + 2]"), 3)
assert_equal(DogTag:Evaluate("[1 - 2]"), -1)
assert_equal(DogTag:Evaluate("[1 * 2]"), 2)
assert_equal(DogTag:Evaluate("[1 / 2]"), 1/2)
assert_equal(DogTag:Evaluate("[0 / 0]"), 0) -- odd case, good for WoW
assert_equal(standardize(parse("[1 / 0]")), { "/", 1, 0 })
assert_equal(standardize(parse("[(1 / 0)]")), { "/", 1, 0 })
assert_equal(DogTag:Evaluate("[1 / 0]"), 1/0)
assert_equal(DogTag:Evaluate("[(1 / 0)]"), 1/0)
assert_equal(DogTag:Evaluate("[-1 / 0]"), -1/0)
assert_equal(DogTag:Evaluate("[-(1 / 0)]"), -1/0)
assert_equal(parse("[(1 / 0)]"), { "(", { "/", 1, 0 } })
assert_equal(DogTag:Evaluate("[5 % 3]"), 2)
assert_equal(DogTag:Evaluate("[5 ^ 3]"), 125)
assert_equal(DogTag:Evaluate("[5 < 3]"), nil)
assert_equal(DogTag:Evaluate("[3 < 5]"), 3)
assert_equal(DogTag:Evaluate("[3 < 3]"), nil)
assert_equal(DogTag:Evaluate("[5 > 3]"), 5)
assert_equal(DogTag:Evaluate("[3 > 5]"), nil)
assert_equal(DogTag:Evaluate("[3 > 3]"), nil)
assert_equal(DogTag:Evaluate("[5 <= 3]"), nil)
assert_equal(DogTag:Evaluate("[3 <= 5]"), 3)
assert_equal(DogTag:Evaluate("[3 <= 3]"), 3)
assert_equal(DogTag:Evaluate("[5 >= 3]"), 5)
assert_equal(DogTag:Evaluate("[3 >= 5]"), nil)
assert_equal(DogTag:Evaluate("[3 >= 3]"), 3)
assert_equal(DogTag:Evaluate("[1 = 1]"), 1)
assert_equal(DogTag:Evaluate("[1 = 2]"), nil)
assert_equal(DogTag:Evaluate("[1 ~= 1]"), nil)
assert_equal(DogTag:Evaluate("[1 ~= 2]"), 1)
assert_equal(DogTag:Evaluate("[1 and 2]"), 2)
assert_equal(DogTag:Evaluate("[1 or 2]"), 1)
assert_equal(DogTag:Evaluate("[(1 = 2) and 2]"), nil)
assert_equal(DogTag:Evaluate("[(1 = 2) or 2]"), 2)
assert_equal(DogTag:Evaluate("[1 & 2]"), 2)
assert_equal(DogTag:Evaluate("[1 | 2]"), 1)
assert_equal(DogTag:Evaluate("[(1 = 2) & 2]"), nil)
assert_equal(DogTag:Evaluate("[(1 = 2) | 2]"), 2)
assert_equal(DogTag:Evaluate("[if 1 then 2]"), 2)
assert_equal(DogTag:Evaluate("[if 1 then 2 else 3]"), 2)
assert_equal(DogTag:Evaluate("[if 1 = 2 then 2]"), nil)
assert_equal(DogTag:Evaluate("[if 1 = 2 then 2 else 3]"), 3)
assert_equal(DogTag:Evaluate("[1 ? 2]"), 2)
assert_equal(DogTag:Evaluate("[1 ? 2 ! 3]"), 2)
assert_equal(DogTag:Evaluate("[1 = 2 ? 2]"), nil)
assert_equal(DogTag:Evaluate("[1 = 2 ? 2 ! 3]"), 3)
assert_equal(DogTag:Evaluate("['Hello' 'There']"), "HelloThere")
assert_equal(DogTag:Evaluate("[-(-1)]"), 1)
assert_equal(DogTag:Evaluate("[-One]"), -1)
assert_equal(DogTag:Evaluate("[not 'Hello']"), nil)
assert_equal(DogTag:Evaluate("[not not 'Hello']"), "True")
assert_equal(DogTag:Evaluate("[One + One]"), 2)
assert_equal(DogTag:Evaluate("[Subtract(1, 2)]"), -1)
assert_equal(DogTag:Evaluate("[Subtract(2, 1)]"), 1)
assert_equal(DogTag:Evaluate("[Subtract(1, right=2)]"), -1)
assert_equal(DogTag:Evaluate("[Subtract(right=1, 2)]"), 1)
assert_equal(DogTag:Evaluate("[Subtract(left=1, right=2)]"), -1)
assert_equal(DogTag:Evaluate("[Subtract(right=1, left=2)]"), 1)
assert_equal(DogTag:Evaluate("[1:Subtract(2)]"), -1)
assert_equal(DogTag:Evaluate("[2:Subtract(1)]"), 1)
assert_equal(DogTag:Evaluate("[nil]"), nil)
assert_equal(DogTag:Evaluate("[not nil]"), "True")
assert_equal(DogTag:Evaluate("['True']"), "True")
assert_equal(DogTag:Evaluate("[not 'True']"), nil)
assert_equal(DogTag:Evaluate("[nil nil]"), nil)
assert_equal(DogTag:Evaluate("[nil '' nil]"), nil)
assert_equal(DogTag:Evaluate("[not nil not '' not nil]"), "TrueTrueTrue")
assert_equal(DogTag:Evaluate("[nil 'Hello' nil]"), "Hello")
assert_equal(DogTag:Evaluate("[nil 1234 nil]"), 1234)
assert_equal(DogTag:Evaluate("[nil 1234 One nil]"), 12341)
testfunc_data = 5
assert_equal(DogTag:Evaluate("[nil 1234 GlobalCheck nil]"), 12345)
testfunc_data = 'Hello'
assert_equal(DogTag:Evaluate("[nil 1234 GlobalCheck nil]"), '1234Hello')
myfunc_num = 0
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 1)
assert_equal(DogTag:Evaluate("['True' and FunctionNumberCheck]"), 2)
assert_equal(DogTag:Evaluate("[nil and FunctionNumberCheck]"), nil) -- shouldn't call FunctionNumberCheck
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 3)
assert_equal(DogTag:Evaluate("['True' or FunctionNumberCheck]"), "True") -- shouldn't call FunctionNumberCheck
assert_equal(DogTag:Evaluate("[nil or FunctionNumberCheck]"), 4)
assert_equal(DogTag:Evaluate("[if 'True' then FunctionNumberCheck]"), 5)
assert_equal(DogTag:Evaluate("[if nil then FunctionNumberCheck]"), nil)
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 6)
assert_equal(DogTag:Evaluate("[if 'True' then 'True' else FunctionNumberCheck]"), 'True')
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 7)
assert_equal(DogTag:Evaluate("[if nil then 'True' else FunctionNumberCheck]"), 8)
myfunc_num = 0
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 1)
testfunc_data = "True"
assert_equal(DogTag:Evaluate("[GlobalCheck and FunctionNumberCheck]"), 2)
testfunc_data = nil
assert_equal(DogTag:Evaluate("[GlobalCheck and FunctionNumberCheck]"), nil) -- shouldn't call FunctionNumberCheck
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 3)
testfunc_data = "True"
assert_equal(DogTag:Evaluate("[GlobalCheck or FunctionNumberCheck]"), "True") -- shouldn't call FunctionNumberCheck
testfunc_data = nil
assert_equal(DogTag:Evaluate("[GlobalCheck or FunctionNumberCheck]"), 4)
testfunc_data = "True"
assert_equal(DogTag:Evaluate("[if GlobalCheck then FunctionNumberCheck]"), 5)
testfunc_data = nil
assert_equal(DogTag:Evaluate("[if GlobalCheck then FunctionNumberCheck]"), nil)
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 6)
testfunc_data = "True"
assert_equal(DogTag:Evaluate("[if GlobalCheck then 'True' else FunctionNumberCheck]"), 'True')
assert_equal(DogTag:Evaluate("[FunctionNumberCheck]"), 7)
testfunc_data = nil
assert_equal(DogTag:Evaluate("[if GlobalCheck then 'True' else FunctionNumberCheck]"), 8)
assert_equal(DogTag:Evaluate("[PlusOne(1 1)]"), 12)
assert_equal(DogTag:Evaluate("[CheckNumTuple(1)]"), 1)
assert_equal(DogTag:Evaluate("[CheckNumTuple(1, 2)]"), '1-2')
assert_equal(DogTag:Evaluate("[CheckNumTuple(1, 2, 3)]"), '1-2-3')
assert_equal(DogTag:Evaluate("[CheckNumTuple(1, 2, 3, 'Hello')]"), '1-2-3-0')
assert_equal(DogTag:Evaluate("[CheckNumTuple(1, 2, 3, One, 'Hello')]"), '1-2-3-1-0')
assert_equal(DogTag:Evaluate("[CheckNumTuple]"), nil)
assert_equal(DogTag:Evaluate("[CheckAnotherNumTuple(1)]"), 1)
assert_equal(DogTag:Evaluate("[CheckAnotherNumTuple(1, 2)]"), 2)
assert_equal(DogTag:Evaluate("[CheckAnotherNumTuple(1, 2, 3)]"), 3)
assert_equal(DogTag:Evaluate("[CheckAnotherNumTuple(1, -2, One:PlusOne, -3)]"), 2)
assert_equal(DogTag:Evaluate("[CheckAnotherNumTuple]"), 0) -- special cause it does math.max(0, ...), which should turn into math.max(0), not math.max(0, )
assert_equal(DogTag:Evaluate("[CheckStrTuple('Hello')]"), 'Hylly')
assert_equal(DogTag:Evaluate("[CheckStrTuple(1)]"), 1)
assert_equal(DogTag:Evaluate("[CheckStrTuple(One)]"), 1)
assert_equal(DogTag:Evaluate("[CheckStrTuple('Hello', \"There\", 'Friend')]"), 'HyllyThyryFryynd')
assert_equal(DogTag:Evaluate("[CheckStrTuple]"), nil)
assert_equal(DogTag:Evaluate("[CheckStrTuple('Hello', 52, 'Friend', One)]"), 'Hylly52Fryynd1')
assert_equal(DogTag:Evaluate("[CheckAnotherStrTuple('Hello')]"), 'Hylly')
assert_equal(DogTag:Evaluate("[CheckAnotherStrTuple(1)]"), 1)
assert_equal(DogTag:Evaluate("[CheckAnotherStrTuple(One)]"), 1)
assert_equal(DogTag:Evaluate("[CheckAnotherStrTuple('Hello', \"There\", 'Friend')]"), 'HyllyThyryFryynd')
assert_equal(DogTag:Evaluate("[CheckAnotherStrTuple]"), nil)
assert_equal(DogTag:Evaluate("[CheckAnotherStrTuple('Hello', 52, 'Friend', One)]"), 'Hylly52Fryynd1')
assert_equal(DogTag:Evaluate("[Reverse('Hello')]"), "olleH")
assert_equal(DogTag:Evaluate("[Reverse('Hello'):Reverse]"), "Hello")
assert_equal(DogTag:Evaluate("[OtherReverse('Hello')]"), "olleH")
assert_equal(DogTag:Evaluate("[OtherReverse('Hello'):OtherReverse]"), "Hello")
old_DogTag_Evaluate(DogTag, "", { left = 0, right = 0 })
assert_equal(DogTag:Evaluate("[Subtract]", { left = 2, right = 1 }), 1)
assert_equal(DogTag:Evaluate("[Subtract]", { left = 1, right = 2 }), -1)
old_DogTag_Evaluate(DogTag, "", { number = 5 })
assert_equal(DogTag:Evaluate("[PlusOne]", { number = 5 }), 6)
assert_equal(DogTag:Evaluate("[PlusOne]", { number = 6 }), 7)
assert_equal(DogTag:Evaluate("[PlusOne]", { number = 7 }), 8)
assert_equal(DogTag:Evaluate("[KwargAndTuple]"), [=[Arg #1 (value) req'd for KwargAndTuple]=])
assert_equal(DogTag:Evaluate("[KwargAndTuple(5, 1, 2, 3)]"), 15)
assert_equal(DogTag:Evaluate("[KwargAndTuple(0.5, 2, 3, 4)]"), 2)
assert_equal(DogTag:Evaluate("[KwargAndTuple(value=0.5, 2, 3, 4)]"), 2)
assert_equal(DogTag:Evaluate("[TupleAndKwarg]"), [=[Arg #2 (value) req'd for TupleAndKwarg]=])
assert_equal(DogTag:Evaluate("[TupleAndKwarg(value=0.5, 2, 3, 4)]"), 2)
assert_equal(DogTag:Evaluate("[TupleAndKwarg(2, 3, 4, value=0.5)]"), 2)