formatting
This commit is contained in:
@@ -30,46 +30,46 @@ local function tokenize(expr)
|
|||||||
local tokens = {}
|
local tokens = {}
|
||||||
local i = 1
|
local i = 1
|
||||||
local len = #expr
|
local len = #expr
|
||||||
|
|
||||||
while i <= len do
|
while i <= len do
|
||||||
local char = expr:sub(i, i)
|
local char = expr:sub(i, i)
|
||||||
|
|
||||||
-- Skip whitespace
|
-- Skip whitespace
|
||||||
if char:match("%s") then
|
if char:match("%s") then
|
||||||
i = i + 1
|
i = i + 1
|
||||||
-- Number (including decimals, but NOT negative - handled separately below)
|
-- Number (including decimals, but NOT negative - handled separately below)
|
||||||
elseif char:match("%d") or (char == "." and expr:sub(i + 1, i + 1):match("%d")) then
|
elseif char:match("%d") or (char == "." and expr:sub(i + 1, i + 1):match("%d")) then
|
||||||
local numStr = ""
|
local numStr = ""
|
||||||
|
|
||||||
-- Parse integer and decimal parts
|
-- Parse integer and decimal parts
|
||||||
while i <= len and (expr:sub(i, i):match("%d") or expr:sub(i, i) == ".") do
|
while i <= len and (expr:sub(i, i):match("%d") or expr:sub(i, i) == ".") do
|
||||||
numStr = numStr .. expr:sub(i, i)
|
numStr = numStr .. expr:sub(i, i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local num = tonumber(numStr)
|
local num = tonumber(numStr)
|
||||||
if not num then
|
if not num then
|
||||||
return nil, "Invalid number: " .. numStr
|
return nil, "Invalid number: " .. numStr
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check for unit following the number
|
-- Check for unit following the number
|
||||||
local unitStr = ""
|
local unitStr = ""
|
||||||
while i <= len and expr:sub(i, i):match("[%a%%]") do
|
while i <= len and expr:sub(i, i):match("[%a%%]") do
|
||||||
unitStr = unitStr .. expr:sub(i, i)
|
unitStr = unitStr .. expr:sub(i, i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Default to px if no unit
|
-- Default to px if no unit
|
||||||
if unitStr == "" then
|
if unitStr == "" then
|
||||||
unitStr = "px"
|
unitStr = "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Validate unit
|
-- Validate unit
|
||||||
local validUnits = { px = true, ["%"] = true, vw = true, vh = true, ew = true, eh = true }
|
local validUnits = { px = true, ["%"] = true, vw = true, vh = true, ew = true, eh = true }
|
||||||
if not validUnits[unitStr] then
|
if not validUnits[unitStr] then
|
||||||
return nil, "Invalid unit: " .. unitStr
|
return nil, "Invalid unit: " .. unitStr
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(tokens, {
|
table.insert(tokens, {
|
||||||
type = TokenType.NUMBER,
|
type = TokenType.NUMBER,
|
||||||
value = num,
|
value = num,
|
||||||
@@ -83,42 +83,47 @@ local function tokenize(expr)
|
|||||||
-- Check if this is a negative number or subtraction
|
-- Check if this is a negative number or subtraction
|
||||||
-- It's a negative number if previous token is an operator or opening paren
|
-- It's a negative number if previous token is an operator or opening paren
|
||||||
local prevToken = tokens[#tokens]
|
local prevToken = tokens[#tokens]
|
||||||
if not prevToken or prevToken.type == TokenType.PLUS or prevToken.type == TokenType.MINUS
|
if
|
||||||
or prevToken.type == TokenType.MULTIPLY or prevToken.type == TokenType.DIVIDE
|
not prevToken
|
||||||
or prevToken.type == TokenType.LPAREN then
|
or prevToken.type == TokenType.PLUS
|
||||||
|
or prevToken.type == TokenType.MINUS
|
||||||
|
or prevToken.type == TokenType.MULTIPLY
|
||||||
|
or prevToken.type == TokenType.DIVIDE
|
||||||
|
or prevToken.type == TokenType.LPAREN
|
||||||
|
then
|
||||||
-- This is a negative number, continue to number parsing
|
-- This is a negative number, continue to number parsing
|
||||||
local numStr = "-"
|
local numStr = "-"
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
-- Parse integer and decimal parts
|
-- Parse integer and decimal parts
|
||||||
while i <= len and (expr:sub(i, i):match("%d") or expr:sub(i, i) == ".") do
|
while i <= len and (expr:sub(i, i):match("%d") or expr:sub(i, i) == ".") do
|
||||||
numStr = numStr .. expr:sub(i, i)
|
numStr = numStr .. expr:sub(i, i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local num = tonumber(numStr)
|
local num = tonumber(numStr)
|
||||||
if not num then
|
if not num then
|
||||||
return nil, "Invalid number: " .. numStr
|
return nil, "Invalid number: " .. numStr
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check for unit following the number
|
-- Check for unit following the number
|
||||||
local unitStr = ""
|
local unitStr = ""
|
||||||
while i <= len and expr:sub(i, i):match("[%a%%]") do
|
while i <= len and expr:sub(i, i):match("[%a%%]") do
|
||||||
unitStr = unitStr .. expr:sub(i, i)
|
unitStr = unitStr .. expr:sub(i, i)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Default to px if no unit
|
-- Default to px if no unit
|
||||||
if unitStr == "" then
|
if unitStr == "" then
|
||||||
unitStr = "px"
|
unitStr = "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Validate unit
|
-- Validate unit
|
||||||
local validUnits = { px = true, ["%"] = true, vw = true, vh = true, ew = true, eh = true }
|
local validUnits = { px = true, ["%"] = true, vw = true, vh = true, ew = true, eh = true }
|
||||||
if not validUnits[unitStr] then
|
if not validUnits[unitStr] then
|
||||||
return nil, "Invalid unit: " .. unitStr
|
return nil, "Invalid unit: " .. unitStr
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(tokens, {
|
table.insert(tokens, {
|
||||||
type = TokenType.NUMBER,
|
type = TokenType.NUMBER,
|
||||||
value = num,
|
value = num,
|
||||||
@@ -145,7 +150,7 @@ local function tokenize(expr)
|
|||||||
return nil, "Unexpected character: " .. char
|
return nil, "Unexpected character: " .. char
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(tokens, { type = TokenType.EOF })
|
table.insert(tokens, { type = TokenType.EOF })
|
||||||
return tokens
|
return tokens
|
||||||
end
|
end
|
||||||
@@ -182,7 +187,7 @@ end
|
|||||||
---@return table ast Abstract syntax tree node
|
---@return table ast Abstract syntax tree node
|
||||||
function Parser:parseExpression()
|
function Parser:parseExpression()
|
||||||
local left = self:parseTerm()
|
local left = self:parseTerm()
|
||||||
|
|
||||||
while self:current().type == TokenType.PLUS or self:current().type == TokenType.MINUS do
|
while self:current().type == TokenType.PLUS or self:current().type == TokenType.MINUS do
|
||||||
local op = self:current().type
|
local op = self:current().type
|
||||||
self:advance()
|
self:advance()
|
||||||
@@ -193,7 +198,7 @@ function Parser:parseExpression()
|
|||||||
right = right,
|
right = right,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
return left
|
return left
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -201,7 +206,7 @@ end
|
|||||||
---@return table ast Abstract syntax tree node
|
---@return table ast Abstract syntax tree node
|
||||||
function Parser:parseTerm()
|
function Parser:parseTerm()
|
||||||
local left = self:parseFactor()
|
local left = self:parseFactor()
|
||||||
|
|
||||||
while self:current().type == TokenType.MULTIPLY or self:current().type == TokenType.DIVIDE do
|
while self:current().type == TokenType.MULTIPLY or self:current().type == TokenType.DIVIDE do
|
||||||
local op = self:current().type
|
local op = self:current().type
|
||||||
self:advance()
|
self:advance()
|
||||||
@@ -212,7 +217,7 @@ function Parser:parseTerm()
|
|||||||
right = right,
|
right = right,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
return left
|
return left
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -220,7 +225,7 @@ end
|
|||||||
---@return table ast Abstract syntax tree node
|
---@return table ast Abstract syntax tree node
|
||||||
function Parser:parseFactor()
|
function Parser:parseFactor()
|
||||||
local token = self:current()
|
local token = self:current()
|
||||||
|
|
||||||
if token.type == TokenType.NUMBER then
|
if token.type == TokenType.NUMBER then
|
||||||
self:advance()
|
self:advance()
|
||||||
return {
|
return {
|
||||||
@@ -273,13 +278,13 @@ function Calc.new(expr)
|
|||||||
_error = err,
|
_error = err,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Parse
|
-- Parse
|
||||||
local parser = Parser.new(tokens)
|
local parser = Parser.new(tokens)
|
||||||
local success, ast = pcall(function()
|
local success, ast = pcall(function()
|
||||||
return parser:parse()
|
return parser:parse()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if not success then
|
if not success then
|
||||||
if Calc._ErrorHandler then
|
if Calc._ErrorHandler then
|
||||||
Calc._ErrorHandler:warn("Calc", "VAL_006", {
|
Calc._ErrorHandler:warn("Calc", "VAL_006", {
|
||||||
@@ -295,7 +300,7 @@ function Calc.new(expr)
|
|||||||
_error = ast,
|
_error = ast,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_isCalc = true,
|
_isCalc = true,
|
||||||
_expr = expr,
|
_expr = expr,
|
||||||
@@ -323,7 +328,7 @@ function Calc.resolve(calcObj, viewportWidth, viewportHeight, parentSize, elemen
|
|||||||
-- Error during parsing, return 0
|
-- Error during parsing, return 0
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Evaluate AST node recursively
|
--- Evaluate AST node recursively
|
||||||
---@param node table AST node
|
---@param node table AST node
|
||||||
---@return number value Evaluated value in pixels
|
---@return number value Evaluated value in pixels
|
||||||
@@ -332,7 +337,7 @@ function Calc.resolve(calcObj, viewportWidth, viewportHeight, parentSize, elemen
|
|||||||
-- Convert unit to pixels
|
-- Convert unit to pixels
|
||||||
local value = node.value
|
local value = node.value
|
||||||
local unit = node.unit
|
local unit = node.unit
|
||||||
|
|
||||||
if unit == "px" then
|
if unit == "px" then
|
||||||
return value
|
return value
|
||||||
elseif unit == "%" then
|
elseif unit == "%" then
|
||||||
@@ -397,7 +402,7 @@ function Calc.resolve(calcObj, viewportWidth, viewportHeight, parentSize, elemen
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return evaluate(calcObj._ast)
|
return evaluate(calcObj._ast)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user