• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Lua] BoolExpr (Boolean Expression)

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688

Overview

API & Documentation

Code

Example Usage

Credits

Version History

Lua:
--[[ boolexpr.lua v1.0.0 by AGD | https://www.hiveworkshop.com/threads/330817


    Description:

        Boolean expressions, a fast and lightweight alternative to
        the native <boolexpr> types, with the most minimal overhead
        possible in execution, and a capability to pass arguments
        upon evaluation and propagate them to all the leaf node
        expressions of the boolean expression tree.
        There are also additional boolean expression logics namely,
        the 'All' and 'Any' logical evaluators, which are equivalent
        to 'And' and 'Or' respectively, except that the later are only
        used to evaluate exactly 2 expresions - the left and right
        expressions, while the former are used for any arbitrary
        number of expressions.


    Requirements:

        - None

]]--
Lua:
--[[

    API:

        function BoolExpr.New(expr)
        function BoolExpr.Not(expr)
        function BoolExpr.And(left_expr, right_expr)
        function BoolExpr.Or(left_expr, right_expr)
        function BoolExpr.All(...)
        function BoolExpr.Any(...)
            - Boolean expression constructors
            - Expressions can take arguments
            - Expressions MUST be callable
            - Can construct nested boolean expressions

        function BoolExpr:__call(...)
            - Evaluates a BoolExpr
            - Optionally passes an argument to each leaf expressions
        function BoolExpr:evaluate(...)
            - Similar to the function above, but can be used for manually
              constructed BoolExprs using table (see Example Usage for a
              sample of manual construction using ordinary table)

        BoolExpr.DEF
        BoolExpr.NOT
        BoolExpr.AND
        BoolExpr.OR
        BoolExpr.ALL
        BoolExpr.ANY
            - Variables for manual BoolExpr construction

]]--
Lua:
BoolExpr = setmetatable({}, {})
do
    local boolexpr = getmetatable(BoolExpr)
    boolexpr.__index = boolexpr

    local DEF = 1
    local NOT = 2
    local AND = 3
    local OR = 4
    local ALL = 5
    local ANY = 6

    BoolExpr.DEF = DEF
    BoolExpr.NOT = NOT
    BoolExpr.AND = AND
    BoolExpr.OR = OR
    BoolExpr.ALL = ALL
    BoolExpr.ANY = ANY

    ---@param expr function
    function BoolExpr.New(expr)
        return setmetatable({DEF, expr}, boolexpr)
    end
    ---@param expr function
    function boolexpr.Not(expr)
        return setmetatable({NOT, expr}, boolexpr)
    end
    ---@param left_expr function
    ---@param right_expr function
    function boolexpr.And(left_expr, right_expr)
        return setmetatable({AND, left_expr, right_expr}, boolexpr)
    end
    ---@param left_expr function
    ---@param right_expr function
    function boolexpr.Or(left_expr, right_expr)
        return setmetatable({OR, left_expr, right_expr}, boolexpr)
    end
    function boolexpr.All(...)
        return setmetatable({ALL, ...}, boolexpr)
    end
    function boolexpr.Any(...)
        return setmetatable({ANY, ...}, boolexpr)
    end

    local operator = {
        function (expr_t, ...)
            return boolexpr.__call(expr_t[2], ...)
        end,
        function (expr_t, ...)
            return not boolexpr.__call(expr_t[2], ...)
        end,
        function (expr_t, ...)
            return boolexpr.__call(expr_t[2], ...) and boolexpr.__call(expr_t[3], ...)
        end,
        function (expr_t, ...)
            return boolexpr.__call(expr_t[2], ...) or boolexpr.__call(expr_t[3], ...)
        end,
        function (expr_t, ...)
            for i = 2, #expr_t do
                if not boolexpr.__call(expr_t[i], ...) then return false end
            end
            return true
        end,
        function (expr_t, ...)
            for i = 2, #expr_t do
                if boolexpr.__call(expr_t[i], ...) then return true end
            end
            return false
        end
    }

    function boolexpr:__call(...)
        if type(self) == 'table' then
            return operator[self[1]](self, ...)
        end
        return self(...)
    end
    function boolexpr:evaluate(...)
        return boolexpr.__call(self, ...)
    end

end
Example 1
Lua:
-- Construct a nested/tree BoolExpr
tree = BoolExpr.Any
(
    BoolExpr.All
    (
        function ()
            print('1:1:true')
            return true
        end,
        function ()
            print('1:2:true')
            return true
        end,
        BoolExpr.Or
        (
            function ()
                print('1:3:1:true')
                return true
            end,
            function ()
                print('1:3:2:false')
                return false
            end
        ),
        BoolExpr.Not(function ()
            print('1:4:false')
            return true
        end)
    ),
    BoolExpr.Or
    (
        function ()
            print('2:1:false')
            return false
        end,
        function ()
            print('2:2:true')
            return true
        end
    ),
    BoolExpr.And
    (
        function ()
            print('3:1:true')
            return true
        end,
        function ()
            print('3:2:true')
            return true
        end
    )
)

-- Evaluate BoolExpr and print result
print(tree() and 'Result: True' or 'Result: False')
Output
Code:
1:1:true
1:2:true
1:3:1:true
1:4:false
2:1:false
2:2:true
Result: True


Example 2 (Manually constructed BoolExpr using ordinary tables)
Lua:
-- Create a BoolExpr from two expressions with AND
sub_expr_1 =
{
    BoolExpr.AND,
    function ()
        print('1:1:false')
        return false
    end,
    function ()
        print('1:2:true')
        return true
    end
}
-- Create a BoolExpr from multiple expressions with ANY
sub_expr_2 =
{
    BoolExpr.ANY,
    function ()
        print('2:1:false')
        return false
    end,
    function ()
        print('2:2:true')
        return true
    end,
    function ()
        print('2:3:false')
        return false
    end
}
-- Combine the previous two BoolExpr with OR
parent_expr =
{
    BoolExpr.OR,
    sub_expr_1,
    sub_expr_2
}

-- Evaluate <parent_expr> and print the output
print(BoolExpr.evaluate(parent_expr) and 'Result: True' or 'Result: False')
Output
Code:
1:1:false
2:1:false
2:2:true
Result: True
v1.0.0
- Initial Release







boolexpr.lua
Lua:
--[[ boolexpr.lua v1.0.0 by AGD | https://www.hiveworkshop.com/threads/330817


    Description:

        Boolean expressions, a fast and lightweight alternative to
        the native <boolexpr> types, with the most minimal overhead
        possible in execution, and a capability to pass arguments
        upon evaluation and propagate them to all the leaf node
        expressions of the boolean expression tree.
        There are also additional boolean expression logics namely,
        the 'All' and 'Any' logical evaluators, which are equivalent
        to 'And' and 'Or' respectively, except that the later are only
        used to evaluate exactly 2 expresions - the left and right
        expressions, while the former are used for any arbitrary
        number of expressions.


    Requirements:

        - None

]]--
--[[

    API:

        function BoolExpr.New(expr)
        function BoolExpr.Not(expr)
        function BoolExpr.And(left_expr, right_expr)
        function BoolExpr.Or(left_expr, right_expr)
        function BoolExpr.All(...)
        function BoolExpr.Any(...)
            - Boolean expression constructors
            - Expressions can take arguments
            - Expressions MUST be callable
            - Can construct nested boolean expressions

        function BoolExpr:__call(...)
            - Evaluates a BoolExpr
            - Optionally passes an argument to each leaf expressions
        function BoolExpr:evaluate(...)
            - Similar to the function above, but can be used for manually
              constructed BoolExprs using table (see Example Usage for a
              sample of manual construction using ordinary table)

        BoolExpr.DEF
        BoolExpr.NOT
        BoolExpr.AND
        BoolExpr.OR
        BoolExpr.ALL
        BoolExpr.ANY
            - Variables for manual BoolExpr construction

]]--
BoolExpr = setmetatable({}, {})
do
    local boolexpr = getmetatable(BoolExpr)
    boolexpr.__index = boolexpr

    local DEF = 1
    local NOT = 2
    local AND = 3
    local OR = 4
    local ALL = 5
    local ANY = 6

    BoolExpr.DEF = DEF
    BoolExpr.NOT = NOT
    BoolExpr.AND = AND
    BoolExpr.OR = OR
    BoolExpr.ALL = ALL
    BoolExpr.ANY = ANY

    ---@param expr function
    function BoolExpr.New(expr)
        return setmetatable({DEF, expr}, boolexpr)
    end
    ---@param expr function
    function boolexpr.Not(expr)
        return setmetatable({NOT, expr}, boolexpr)
    end
    ---@param left_expr function
    ---@param right_expr function
    function boolexpr.And(left_expr, right_expr)
        return setmetatable({AND, left_expr, right_expr}, boolexpr)
    end
    ---@param left_expr function
    ---@param right_expr function
    function boolexpr.Or(left_expr, right_expr)
        return setmetatable({OR, left_expr, right_expr}, boolexpr)
    end
    function boolexpr.All(...)
        return setmetatable({ALL, ...}, boolexpr)
    end
    function boolexpr.Any(...)
        return setmetatable({ANY, ...}, boolexpr)
    end

    local operator = {
        function (expr_t, ...)
            return boolexpr.__call(expr_t[2], ...)
        end,
        function (expr_t, ...)
            return not boolexpr.__call(expr_t[2], ...)
        end,
        function (expr_t, ...)
            return boolexpr.__call(expr_t[2], ...) and boolexpr.__call(expr_t[3], ...)
        end,
        function (expr_t, ...)
            return boolexpr.__call(expr_t[2], ...) or boolexpr.__call(expr_t[3], ...)
        end,
        function (expr_t, ...)
            for i = 2, #expr_t do
                if not boolexpr.__call(expr_t[i], ...) then return false end
            end
            return true
        end,
        function (expr_t, ...)
            for i = 2, #expr_t do
                if boolexpr.__call(expr_t[i], ...) then return true end
            end
            return false
        end
    }

    function boolexpr:__call(...)
        if type(self) == 'table' then
            return operator[self[1]](self, ...)
        end
        return self(...)
    end
    function boolexpr:evaluate(...)
        return boolexpr.__call(self, ...)
    end

end


GitHub Link (MORE UP-TO-DATE): A-G-D/BoolExpr
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I've found your latest version on:


Could you please update the code in your main thread and give reasons as to why this would want to be included in a map? JASS Boolexpr type never really took off. Are you intending to use this as some kind of event-enabler?
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
My original aim for this was to use it as an event library that supports nested callbacks and a dynamic decision making for its path of execution by returning true or false. I can't remember if there is more to it as I haven't really used this resource before to build something much greater. I only remember using this to build an event listener, which later turned out to not really need this.
 
Top