Added proper itemscript
This commit is contained in:
parent
cfe8cc8a20
commit
f76c72019a
|
@ -5,120 +5,258 @@ Author: Andrew Lalis <andrewlalisofficial@gmail.com>
|
||||||
|
|
||||||
|
|
||||||
]]--
|
]]--
|
||||||
VERSION = "0.0.1"
|
|
||||||
|
|
||||||
local t = turtle
|
|
||||||
|
|
||||||
-- The itemscript module. Functions defined within this table are exported.
|
-- The itemscript module. Functions defined within this table are exported.
|
||||||
local itemscript = {}
|
local itemscript = {}
|
||||||
|
itemscript.VERSION = "0.0.1"
|
||||||
|
|
||||||
-- Determines if an item stack matches the given name.
|
-- Determines if an item stack matches the given name.
|
||||||
-- If fuzzy, then the item name will be matched against the given name.
|
-- If fuzzy, then the item name will be matched against the given name.
|
||||||
local function stackMatches(itemStack, name, fuzzy)
|
local function stackMatches(itemStack, name, fuzzy)
|
||||||
return itemStack ~= nil and
|
if itemStack == nil or itemStack.name == nil then return false end
|
||||||
(
|
if fuzzy then return string.find(itemStack.name, name) ~= nil end
|
||||||
(not fuzzy and itemStack.name == name) or
|
return itemStack.name == name
|
||||||
string.find(itemStack.name, name)
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function notFilter(filter)
|
local function splitString(str, sep)
|
||||||
return function(item)
|
if sep == nil then sep = "%s" end
|
||||||
return not filter(item)
|
local result = {}
|
||||||
|
for s in string.gmatch(str, "([^"..sep.."]+)") do
|
||||||
|
table.insert(result, s)
|
||||||
end
|
end
|
||||||
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
local function andFilter(filters)
|
-- Parses a filter expression string and returns a table representing the syntax tree.
|
||||||
return function(item)
|
-- An error is thrown if compilation fails.
|
||||||
for _, filter in pairs(filters) do
|
|
||||||
if not filter(item) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function orFilter(filters)
|
|
||||||
return function(item)
|
|
||||||
for _, filter in pairs(filters) do
|
|
||||||
if filter(item) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Parses a filter expression string and returns a filter that implements it.
|
|
||||||
--[[
|
--[[
|
||||||
Item Filter Expressions:
|
Item Filter Expressions:
|
||||||
|
|
||||||
A filter expression is a way to define a complex method of matching item
|
A filter expression is a way to define a complex method of matching item
|
||||||
stacks.
|
stacks.
|
||||||
|
|
||||||
Prepending ! will match any item stack whose name does not match.
|
Grammar:
|
||||||
Prepending # will do a fuzzy match using string.find.
|
|
||||||
|
|
||||||
|
word = %a[%w%-_:]* A whole or substring of an item's name.
|
||||||
|
number = %d+
|
||||||
|
expr = word Matches item stacks whose name matches the given word.
|
||||||
|
= #word Matches item stacks whose name contains the given word.
|
||||||
|
= (expr)
|
||||||
|
= !expr Matches item stacks that don't match the given expression.
|
||||||
|
= expr | expr Matches item stacks that match any of the given expressions (OR).
|
||||||
|
= expr & expr Matches item stacks that match all of the given expressions (AND).
|
||||||
|
= expr > %d Matches item stacks that match the given expression, and have more than N items.
|
||||||
|
= expr >= %d Matches item stacks that match the given expression, and have more than or equal to N items.
|
||||||
|
= expr < %d Matches item stacks that match the given expression, and have less than N items.
|
||||||
|
= expr <= %d Matches item stacks that match the given expression, and have less than or equal to N items.
|
||||||
|
= expr = %d Matches item stacks that match the given expression, and have exactly N items.
|
||||||
|
= expr != %d Matches item stacks that match the given expression, and do not have exactly N items.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
"coal" matches only "minecraft:coal" items
|
"#log > 10" matches any items containing the word "log", that have more than 10 items in the stack.
|
||||||
"!#wood" matches all items except any that contain the phrase "wood"
|
"10% coal, 90% iron_ore" matches coal 10% of the time, and iron_ore 90% of the time.
|
||||||
"#iron" matches all items that contain the phrase "iron"
|
|
||||||
]]--
|
]]--
|
||||||
local function parseItemFilterExpression(expr)
|
function itemscript.parseFilterExpression(str)
|
||||||
local prefixIdx, prefixIdxEnd = string.find(expr, "^[!#]+")
|
str = str:gsub("^%s*(.-)%s*$", "%1") -- Trim whitespace from the beginning and end of the string.
|
||||||
local fuzzy = false
|
print("Parsing expr: " .. str)
|
||||||
local negated = false
|
|
||||||
if prefixIdx ~= nil then
|
-- Parse group constructs
|
||||||
for i = prefixIdx, prefixIdxEnd do
|
local ignoreRange = nil
|
||||||
local char = string.sub(expr, i, i)
|
if string.sub(str, 1, 1) == "(" then
|
||||||
if char == "!" then
|
local idx1, idx2 = string.find(str, "%b()")
|
||||||
negated = true
|
if idx1 == nil then
|
||||||
elseif char == "#" then
|
error("Invalid group construct: \"" .. str .. "\".")
|
||||||
fuzzy = true
|
end
|
||||||
|
-- If the group is the whole expression, parse it. Otherwise, defer parsing to later.
|
||||||
|
if idx2 == #str then
|
||||||
|
print("Found GROUP")
|
||||||
|
return itemscript.parseFilterExpression(string.sub(str, idx1 + 1, idx2 - 1))
|
||||||
|
else
|
||||||
|
ignoreRange = {idx1, idx2}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Parse logical group operators (OR and AND)
|
||||||
|
local logicalGroupOperators = {
|
||||||
|
{ name = "OR", token = "|" },
|
||||||
|
{ name = "AND", token = "&" }
|
||||||
|
}
|
||||||
|
for _, operator in pairs(logicalGroupOperators) do
|
||||||
|
local idx = string.find(str, operator.token)
|
||||||
|
if idx ~= nil and (ignoreRange == nil or idx < ignoreRange[1] or idx > ignoreRange[2]) then
|
||||||
|
print("Found " .. operator.name)
|
||||||
|
return {
|
||||||
|
type = operator.name,
|
||||||
|
children = {
|
||||||
|
itemscript.parseFilterExpression(string.sub(str, 1, idx - 1)),
|
||||||
|
itemscript.parseFilterExpression(string.sub(str, idx + 1, -1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Parse item count arithmetic operators
|
||||||
|
local arithmeticOperators = {
|
||||||
|
["LESS_THAN"] = "<",
|
||||||
|
["LESS_THAN_OR_EQUAL_TO"] = "<=",
|
||||||
|
["GREATER_THAN"] = ">",
|
||||||
|
["GREATER_THAN_OR_EQUAL_TO"] = ">=",
|
||||||
|
["EQUALS"] = "=",
|
||||||
|
["NOT_EQUALS"] = "!="
|
||||||
|
}
|
||||||
|
for typeName, token in pairs(arithmeticOperators) do
|
||||||
|
local idx = string.find(str, token)
|
||||||
|
if idx ~= nil and (ignoreRange == nil or idx < ignoreRange[1] or idx > ignoreRange[2]) then
|
||||||
|
print("Found " .. typeName)
|
||||||
|
local subExpr = itemscript.parseFilterExpression(string.sub(str, 1, idx - 1))
|
||||||
|
local numberExprIdx1, numberExprIdx2 = string.find(str, "%d+", idx + 1)
|
||||||
|
if numberExprIdx1 == nil then
|
||||||
|
error("Could not find number expression (%d+) in string: \"" .. string.sub(str, idx + 1, -1) .. "\".")
|
||||||
end
|
end
|
||||||
|
local numberValue = tonumber(string.sub(str, numberExprIdx1, numberExprIdx2))
|
||||||
|
if numberValue == nil then
|
||||||
|
error("Could not parse number from string: \"" .. string.sub(str, numberExprIdx1, numberExprIdx2) .. "\".")
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
type = typeName,
|
||||||
|
expr = subExpr,
|
||||||
|
value = numberValue
|
||||||
|
}
|
||||||
end
|
end
|
||||||
expr = string.sub(expr, prefixIdxEnd + 1, string.len(expr))
|
|
||||||
end
|
end
|
||||||
local namespaceSeparatorIdx = string.find(expr, ":")
|
|
||||||
if namespaceSeparatorIdx == nil and not fuzzy then
|
-- Parse NOT operator.
|
||||||
expr = "minecraft:" .. expr
|
if string.sub(str, 1, 1) == "!" then
|
||||||
|
print("Found NOT")
|
||||||
|
return {
|
||||||
|
type = "NOT",
|
||||||
|
expr = itemscript.parseFilterExpression(string.sub(str, 2, -1))
|
||||||
|
}
|
||||||
end
|
end
|
||||||
return function(item)
|
|
||||||
if item == nil then return false end
|
-- Parse fuzzy and plain words.
|
||||||
local matches = stackMatches(item, expr, fuzzy)
|
local fuzzy = false
|
||||||
if negated then
|
if string.sub(str, 1, 1) == "#" then
|
||||||
matches = not matches
|
fuzzy = true
|
||||||
|
str = string.sub(str, 2, -1)
|
||||||
|
end
|
||||||
|
local wordIdx1, wordIdx2 = string.find(str, "%a[%w%-_]*")
|
||||||
|
if wordIdx1 ~= nil then
|
||||||
|
local value = string.sub(str, wordIdx1, wordIdx2)
|
||||||
|
if not fuzzy and string.find(value, ":") == nil then
|
||||||
|
value = "minecraft:" .. value
|
||||||
end
|
end
|
||||||
return matches
|
return {
|
||||||
|
type = "WORD",
|
||||||
|
value = value,
|
||||||
|
fuzzy = fuzzy
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
error("Invalid filter expression syntax: " .. str)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Compiles a filter function from a filter expression syntax tree.
|
||||||
|
function itemscript.compileFilter(expr)
|
||||||
|
if expr.type == "WORD" then
|
||||||
|
return function(item)
|
||||||
|
return stackMatches(item, expr.value, expr.fuzzy)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "NOT" then
|
||||||
|
local subFilter = itemscript.compileFilter(expr.expr)
|
||||||
|
return function (item)
|
||||||
|
return not subFilter(item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "LESS_THAN" then
|
||||||
|
local subFilter = itemscript.compileFilter(expr.expr)
|
||||||
|
return function (item)
|
||||||
|
return subFilter(item) and item.count < expr.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "GREATER_THAN" then
|
||||||
|
local subFilter = itemscript.compileFilter(expr.expr)
|
||||||
|
return function (item)
|
||||||
|
return subFilter(item) and item.count > expr.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "LESS_THAN_OR_EQUAL_TO" then
|
||||||
|
local subFilter = itemscript.compileFilter(expr.expr)
|
||||||
|
return function (item)
|
||||||
|
return subFilter(item) and item.count <= expr.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "GREATER_THAN_OR_EQUAL_TO" then
|
||||||
|
local subFilter = itemscript.compileFilter(expr.expr)
|
||||||
|
return function (item)
|
||||||
|
return subFilter(item) and item.count >= expr.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "EQUALS" then
|
||||||
|
local subFilter = itemscript.compileFilter(expr.expr)
|
||||||
|
return function (item)
|
||||||
|
return subFilter(item) and item.count == expr.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "NOT_EQUALS" then
|
||||||
|
local subFilter = itemscript.compileFilter(expr.expr)
|
||||||
|
return function (item)
|
||||||
|
return subFilter(item) and item.count ~= expr.value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "AND" then
|
||||||
|
local subFilters = {}
|
||||||
|
for _, childExpr in pairs(expr.children) do
|
||||||
|
table.insert(subFilters, itemscript.compileFilter(childExpr))
|
||||||
|
end
|
||||||
|
return function (item)
|
||||||
|
for _, subFilter in pairs(subFilters) do
|
||||||
|
if not subFilter(item) then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if expr.type == "OR" then
|
||||||
|
local subFilters = {}
|
||||||
|
for _, childExpr in pairs(expr.children) do
|
||||||
|
table.insert(subFilters, itemscript.compileFilter(childExpr))
|
||||||
|
end
|
||||||
|
return function (item)
|
||||||
|
for _, subFilter in pairs(subFilters) do
|
||||||
|
if subFilter(item) then return true end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error("Invalid filter expression syntax tree item: " .. expr.type)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Converts an arbitrary value to a filter function that can be applied to item
|
||||||
|
stacks for filtering operations. The following types are supported:
|
||||||
|
- strings are parsed and compiled to filter functions.
|
||||||
|
- functions are assumed to be filter functions that take an item stack as
|
||||||
|
a single parameter, and return true for a match, and false otherwise.
|
||||||
|
- tables are assumed to be pre-parsed filter expression syntax trees.
|
||||||
|
]]--
|
||||||
|
function itemscript.filterize(value)
|
||||||
|
if type(value) == "string" then
|
||||||
|
return itemscript.compileFilter(itemscript.parseFilterExpression(value))
|
||||||
|
elseif type(value) == "table" then
|
||||||
|
return itemscript.compileFilter(value)
|
||||||
|
elseif type(value) == "function" then
|
||||||
|
return value
|
||||||
|
else
|
||||||
|
error("Invalid filterizable value. Expected filter expression string, syntax tree table, or filter function.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Converts an arbitrary variable into a filter; useful for any function that's public, so users can supply any filter.
|
|
||||||
-- It converts the following:
|
|
||||||
-- filter function tables directly.
|
|
||||||
-- strings and lists of strings are translated into an item names filter.
|
|
||||||
-- Functions are added with default fuzzy and whitelist parameters.
|
|
||||||
local function convertToFilter(var)
|
|
||||||
if type(var) == "table" and #var > 0 and type(var[1]) == "string" then
|
|
||||||
local filters = {}
|
|
||||||
for _, expr in pairs(var) do
|
|
||||||
table.insert(filters, parseItemFilterExpression(expr))
|
|
||||||
end
|
|
||||||
return orFilter(filters)
|
|
||||||
elseif type(var) == "string" then
|
|
||||||
return parseItemFilterExpression(var)
|
|
||||||
elseif type(var) == "function" then
|
|
||||||
return var
|
|
||||||
else
|
|
||||||
error("Unsupported filter type: " .. type(var))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Gets the total number of items in the turtle's inventory that match the given expression.
|
-- Gets the total number of items in the turtle's inventory that match the given expression.
|
||||||
function itemscript.totalCount(filterExpr)
|
function itemscript.totalCount(filterExpr)
|
||||||
local filter = convertToFilter(filterExpr)
|
local filter = itemscript.filterize(filterExpr)
|
||||||
local count = 0
|
local count = 0
|
||||||
for i = 1, 16 do
|
for i = 1, 16 do
|
||||||
local item = t.getItemDetail(i)
|
local item = t.getItemDetail(i)
|
||||||
|
@ -129,56 +267,81 @@ function itemscript.totalCount(filterExpr)
|
||||||
return count
|
return count
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Selects a slot containing at least one of the given item type.
|
-- Select the first slot containing a matching item stack for a filter.
|
||||||
-- Returns a boolean indicating whether we could find and select the item.
|
-- Returns a boolean indicating whether we could find and select the item.
|
||||||
function itemscript.select(filterExpr)
|
function itemscript.select(filterExpr)
|
||||||
local filter = convertToFilter(filterExpr)
|
local filter = itemscript.filterize(filterExpr)
|
||||||
for i = 1, 16 do
|
for i = 1, 16 do
|
||||||
local item = t.getItemDetail(i)
|
local item = turtle.getItemDetail(i)
|
||||||
if filter(item) then
|
if filter(item) then
|
||||||
t.select(i)
|
turtle.select(i)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Selects a random slot containing a matching item stack.
|
||||||
|
function itemscript.selectRandom(filterExpr)
|
||||||
|
local filter = itemscript.filterize(filterExpr)
|
||||||
|
local eligibleSlots = {}
|
||||||
|
for i = 1, 16 do
|
||||||
|
local item = turtle.getItemDetail(i)
|
||||||
|
if filter(item) then
|
||||||
|
table.insert(eligibleSlots, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #eligibleSlots == 0 then return false end
|
||||||
|
local slot = eligibleSlots[math.random(1, #eligibleSlots)]
|
||||||
|
turtle.select(slot)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
-- Selects a slot containing at least minCount (or 1) of an item type matching
|
-- Selects a slot containing at least minCount (or 1) of an item type matching
|
||||||
-- the given filter expression.
|
-- the given filter expression.
|
||||||
function itemscript.selectOrWait(filterExpr, minCount)
|
function itemscript.selectOrWait(filterExpr, minCount)
|
||||||
minCount = minCount or 1
|
minCount = minCount or 1
|
||||||
while itemscript.totalCount(filterExpr) < minCount do
|
local filter = itemscript.filterize(filterExpr)
|
||||||
|
while itemscript.totalCount(filter) < minCount do
|
||||||
print("Couldn't find at least " .. minCount .. " item(s) matching the filter expression: \"" .. filterExpr .. "\". Please add it.")
|
print("Couldn't find at least " .. minCount .. " item(s) matching the filter expression: \"" .. filterExpr .. "\". Please add it.")
|
||||||
os.pullEvent("turtle_inventory")
|
os.pullEvent("turtle_inventory")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Helper function to drop items in a flexible way, using a drop function and filtering function.
|
-- Selects an empty slot.
|
||||||
local function dropFiltered(dropFunction, filter)
|
function itemscript.selectEmpty()
|
||||||
for i = 1, 16 do
|
for i = 1, 16 do
|
||||||
local item = t.getItemDetail(i)
|
local item = turtle.getItemDetail(i)
|
||||||
|
if item == nil then
|
||||||
|
turtle.select(i)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Helper function to drop items in a flexible way, using a drop function and filtering function.
|
||||||
|
local function dropFiltered(dropFunction, filterExpr)
|
||||||
|
local filter = itemscript.filterize(filterExpr)
|
||||||
|
for i = 1, 16 do
|
||||||
|
local item = turtle.getItemDetail(i)
|
||||||
if filter(item) then
|
if filter(item) then
|
||||||
t.select(i)
|
turtle.select(i)
|
||||||
dropFunction()
|
dropFunction()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function itemscript.dropAll(filterExpr)
|
function itemscript.dropAll(filterExpr)
|
||||||
dropFiltered(t.drop, convertToFilter(filterExpr))
|
dropFiltered(turtle.drop, filterExpr)
|
||||||
end
|
end
|
||||||
|
|
||||||
function itemscript.dropAllDown(filterExpr)
|
function itemscript.dropAllDown(filterExpr)
|
||||||
dropFiltered(t.dropDown, convertToFilter(filterExpr))
|
dropFiltered(turtle.dropDown, filterExpr)
|
||||||
end
|
end
|
||||||
|
|
||||||
function itemscript.dropAllUp(filterExpr)
|
function itemscript.dropAllUp(filterExpr)
|
||||||
dropFiltered(t.dropUp, convertToFilter(filterExpr))
|
dropFiltered(turtle.dropUp, filterExpr)
|
||||||
end
|
|
||||||
|
|
||||||
-- Cleans up the turtle's inventory by compacting all stacks of items.
|
|
||||||
function itemscript.organize()
|
|
||||||
error("Not yet implemented.")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return itemscript
|
return itemscript
|
|
@ -7,8 +7,6 @@ Movescript provides a simpler, conciser way to program "turtles" (robots), so
|
||||||
that you don't need to get tired of typing "turtle.forward()" over and over.
|
that you don't need to get tired of typing "turtle.forward()" over and over.
|
||||||
|
|
||||||
]]--
|
]]--
|
||||||
VERSION = "0.0.1"
|
|
||||||
|
|
||||||
local t = turtle
|
local t = turtle
|
||||||
-- For testing purposes, if the turtle API is not present, we inject our own.
|
-- For testing purposes, if the turtle API is not present, we inject our own.
|
||||||
if not t then t = {
|
if not t then t = {
|
||||||
|
@ -17,6 +15,7 @@ if not t then t = {
|
||||||
|
|
||||||
-- The movescript module. Functions defined within this table are exported.
|
-- The movescript module. Functions defined within this table are exported.
|
||||||
local movescript = {}
|
local movescript = {}
|
||||||
|
movescript.VERSION = "0.0.1"
|
||||||
|
|
||||||
movescript.defaultSettings = {
|
movescript.defaultSettings = {
|
||||||
debug = false,
|
debug = false,
|
||||||
|
|
27
tester.lua
27
tester.lua
|
@ -24,12 +24,23 @@ function print_r (t, name, indent)
|
||||||
-- local ms = require("src/movescript")
|
-- local ms = require("src/movescript")
|
||||||
-- print_r(ms.parse("35(2F(safe=false)R 3(L(delay=0.25, file=file.txt)UB))", {debug=true}))
|
-- print_r(ms.parse("35(2F(safe=false)R 3(L(delay=0.25, file=file.txt)UB))", {debug=true}))
|
||||||
|
|
||||||
local bs = require("src/buildscript")
|
-- local bs = require("src/buildscript")
|
||||||
local args = {...}
|
-- local args = {...}
|
||||||
local spec = {
|
-- local spec = {
|
||||||
num = { type = "number", required = true, idx = 1 },
|
-- num = { type = "number", required = true, idx = 1 },
|
||||||
name = { name = "name", type = "bool", required = true }
|
-- name = { name = "name", type = "bool", required = true }
|
||||||
|
-- }
|
||||||
|
-- local success, result = bs.parseArgs(args, spec)
|
||||||
|
-- print(success)
|
||||||
|
-- print_r(result)
|
||||||
|
|
||||||
|
local is = require("src/itemscript")
|
||||||
|
local t = is.parseFilterExpression("!log")
|
||||||
|
print_r(t, "filter_expression_syntax_tree", " ")
|
||||||
|
local filter = is.compileFilter(t)
|
||||||
|
local item = {
|
||||||
|
name = "minecraft:oak_log",
|
||||||
|
count = 54
|
||||||
}
|
}
|
||||||
local success, result = bs.parseArgs(args, spec)
|
local matches = filter(item)
|
||||||
print(success)
|
print(matches)
|
||||||
print_r(result)
|
|
||||||
|
|
Loading…
Reference in New Issue