You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
5.5 KiB
187 lines
5.5 KiB
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
local TSM = select(2, ...) ---@type TSM
|
|
local String = TSM.Init("Util.CustomStringClasses.String") ---@class Util.CustomStringClasses.String
|
|
local Tokenizer = TSM.Include("Util.CustomStringClasses.Tokenizer")
|
|
local AST = TSM.Include("Util.CustomStringClasses.AST")
|
|
local CodeGen = TSM.Include("Util.CustomStringClasses.CodeGen")
|
|
local Types = TSM.Include("Util.CustomStringClasses.Types")
|
|
local L = TSM.Include("Locale").GetTable()
|
|
local Math = TSM.Include("Util.Math")
|
|
local ItemString = TSM.Include("Util.ItemString")
|
|
local Log = TSM.Include("Util.Log")
|
|
local private = {
|
|
priceFunc = nil,
|
|
recursiveCalls = 0,
|
|
lastRecursiveError = nil,
|
|
}
|
|
local DEPENDENCY_SEP = "/"
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Helpers Object
|
|
-- ============================================================================
|
|
|
|
local HELPERS = {}
|
|
HELPERS.INVALID = newproxy()
|
|
HELPERS.GetBaseItemString = function(itemString)
|
|
return ItemString.GetBaseFast(itemString)
|
|
end
|
|
HELPERS.GetPrice = function(itemString, key)
|
|
local val = private.priceFunc(itemString, key)
|
|
if not val or val <= 0 then
|
|
return HELPERS.INVALID
|
|
end
|
|
return val
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Class Definition
|
|
-- ============================================================================
|
|
|
|
local CustomStringObject = TSM.Include("LibTSMClass").DefineClass("CustomStringObject") ---@class CustomStringObject
|
|
|
|
function CustomStringObject:__init()
|
|
self._str = nil
|
|
self._errType = nil
|
|
self._errTokenIndex = nil
|
|
self._tokenList = Types.CreateTokenList()
|
|
self._tree = Types.CreateNodeTree()
|
|
self._dependencies = {}
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Public Class Methods
|
|
-- ============================================================================
|
|
|
|
function CustomStringObject:SetString(str)
|
|
self._str = str
|
|
self._errType = nil
|
|
self._errTokenIndex = nil
|
|
self._tokenList:Wipe()
|
|
self._tree:Wipe()
|
|
|
|
-- Parse the string into tokens
|
|
Tokenizer.GetTokens(str, self._tokenList)
|
|
|
|
-- Generate the AST
|
|
if not self:_HandleStepResult(AST.Generate(self._tokenList, self._tree)) then
|
|
return
|
|
end
|
|
|
|
-- Get the dependencies
|
|
for _, source, itemArg, extraArg in AST.DependencyIterator(self._tree) do
|
|
self._dependencies[source] = true
|
|
if source == "convert" then
|
|
assert(extraArg)
|
|
self._dependencies[extraArg] = true
|
|
if itemArg then
|
|
self._dependencies[source..DEPENDENCY_SEP..extraArg..DEPENDENCY_SEP..itemArg] = true
|
|
else
|
|
self._dependencies[source..DEPENDENCY_SEP..extraArg] = true
|
|
end
|
|
else
|
|
assert(not extraArg)
|
|
self._dependencies[source..DEPENDENCY_SEP..(itemArg or "")] = true
|
|
end
|
|
end
|
|
|
|
-- Generate the code
|
|
self._code = self:_HandleStepResult(CodeGen.Execute(self._tree))
|
|
if not self._code then
|
|
return
|
|
end
|
|
|
|
-- Compile the code
|
|
self._func = assert(loadstring(self._code))()
|
|
end
|
|
|
|
function CustomStringObject:Validate()
|
|
if self._errType then
|
|
if self._errTokenIndex == -1 then
|
|
return false, self._errType
|
|
else
|
|
return false, self._errType, self._tokenList:GetRow(self._errTokenIndex)
|
|
end
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
|
|
function CustomStringObject:IsDependantOnSource(source)
|
|
return self._dependencies[source]
|
|
end
|
|
|
|
function CustomStringObject:Evaluate(itemString)
|
|
if self._errType then
|
|
error("Evaluating invalid custom string")
|
|
elseif not private.priceFunc then
|
|
error("No price func was set")
|
|
end
|
|
|
|
if private.recursiveCalls >= 100 then
|
|
-- We're in a custom string loop
|
|
if (private.lastRecursiveError or 0) + 1 < time() then
|
|
private.lastRecursiveError = time()
|
|
Log.PrintUser(L["Loop detected in the following custom price:"].." "..Log.ColorUserAccentText(self._str))
|
|
end
|
|
return nil
|
|
end
|
|
|
|
private.recursiveCalls = private.recursiveCalls + 1
|
|
local result = self._func(itemString, HELPERS)
|
|
private.recursiveCalls = private.recursiveCalls - 1
|
|
|
|
if result == HELPERS.INVALID or result == math.huge or Math.IsNan(result) then
|
|
return nil
|
|
end
|
|
result = result and floor(result + 0.5)
|
|
return result >= 0 and result or nil
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Class Methods
|
|
-- ============================================================================
|
|
|
|
function CustomStringObject:_HandleStepResult(result, errType, errTokenIndex)
|
|
if result then
|
|
assert(errType == nil and errTokenIndex == nil)
|
|
else
|
|
assert(errType ~= nil and errTokenIndex ~= nil)
|
|
self._errType = errType
|
|
self._errTokenIndex = errTokenIndex
|
|
end
|
|
return result
|
|
end
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Functions
|
|
-- ============================================================================
|
|
|
|
---Sets the function used to lookup a price value.
|
|
---@param priceFunc fun(itemString: string, key: string): number? The function
|
|
function String.SetPriceFunc(priceFunc)
|
|
assert(priceFunc and not private.priceFunc)
|
|
private.priceFunc = priceFunc
|
|
end
|
|
|
|
---Creates a custom string for the specified text.
|
|
---@param str string The custom string text
|
|
---@return CustomStringObject
|
|
function String.Create(str)
|
|
local obj = CustomStringObject()
|
|
obj:SetString(str)
|
|
return obj
|
|
end
|
|
|