cuberite / WorldEdit

WorldEdit plugin for Cuberite
https://cuberite.org/
Apache License 2.0
41 stars 18 forks source link

Create a command argument parser #117

Open NiLSPACE opened 7 years ago

NiLSPACE commented 7 years ago

Currently every command has to be manually parsed to check if all the parameters are correct and the extract the values from them. If we'd create some kind of parser that would allow us to do this automatically creating new commands would get allot easier. I had something like this in mind:

function HandleCommand(a_Split, a_Player)
    -- //command <radius> <block> [hollow]
    local parser, errorMsg = cCommandParser:new("<CommandName> <radius:number> <block:block> [hollow:bool]")
        :Parse(a_Split)

    if (not parser) then
        a_Player:SendMessage(cChatColor.Rose .. errorMsg)
        return true
    end

    DoSomething(parser.radius, parser.block, parser.hollow)
    return true;
end

Any thoughts?

madmaxoft commented 7 years ago

It might be easier to specify the parameters in a Lua table, rather than a string:

cCommandParser:new({
  { name = "radius", type = "number"},
  { name = "block", type = "block"},
  { name = "ishollow", type = "bool", optional = true}
})

How about commands with multiple syntaxes?

NiLSPACE commented 7 years ago

Yeah, that's probably nicer. If multiple syntaxes are allowed we could provide an array of command objects. Handling whatever the parser returns might be a little harder to do nicely though. Are there even any commands with multiple syntaxes?

NiLSPACE commented 7 years ago

Perhaps instead of providing a type for the argument we provide a function. I could for example provide the GetBlockDst function which chooses the right BlockTypeSource depending on the argument.

madmaxoft commented 7 years ago

I'm a bit worried that this is an "inner platform"...

NiLSPACE commented 7 years ago

You mean the whole idea of the command parser?

sphinxc0re commented 7 years ago

@madmaxoft I thought about that as well. When this feature makes it easier to create plugins, then it should be part of the server and exported as an API

NiLSPACE commented 7 years ago

I have an idea on how to do this which is actually pretty simple. I'd like to try it out first, but I think it could work.

HelenaKitty commented 7 years ago

This sounds very interesting...

NiLSPACE commented 7 years ago

I'm afraid the user won't notice allot, but it makes creating new commands a little easier and nicer.

HelenaKitty commented 7 years ago

Agreed, that's exactly what makes it sound interesting.

NiLSPACE commented 7 years ago

It seems to be working. A JSON dump of the result gives this:

{
        "Arguments" :
        {
                "block" :
                {
                        "m_BlockTable" :
                        [
                                {
                                        "BlockMeta" : 0,
                                        "BlockType" : 12,
                                        "Chance" : 0.5
                                },
                                {
                                        "BlockMeta" : 0,
                                        "BlockType" : 8,
                                        "Chance" : 1
                                }
                        ]
                },
                "depth" : 2,
                "radius" : 20
        },
        "Flags" :
        {
                "fancyname" : false,
                "hollow" : true
        }
}

While this code is used in the command handler:

local success, cCommandParser:new(2)
    :Arguments({
        { name = "block",  extractor = Extractors.Block},
        { name = "radius", extractor = Extractors.Number},
        { name = "depth",  extractor = Extractors.Number, optional = true },
    })
    :Flags({
        { name = 'hollow', character = 'h' },
        { name = 'fancyname', character = 'o' }
    })
    :Parse(arguments, player)

The input of the user looks like this:

//fill -h sand,water 20 2

The overal parser is a little under 200 lines, but I do have to include a few things.

NiLSPACE commented 7 years ago

I uploaded my initial version here: https://github.com/cuberite/WorldEdit/tree/CommandParser

NiLSPACE commented 7 years ago

Any thoughts?

madmaxoft commented 7 years ago

It'd be nice if the parsed usage was documented somewhere in the parser's implementation file. An example usage, input and output should be given, too.