WorldEdit icon indicating copy to clipboard operation
WorldEdit copied to clipboard

Create a command argument parser

Open NiLSPACE opened this issue 8 years ago • 14 comments

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?

NiLSPACE avatar Feb 26 '17 15:02 NiLSPACE

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?

madmaxoft avatar Feb 26 '17 15:02 madmaxoft

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 avatar Feb 26 '17 16:02 NiLSPACE

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.

NiLSPACE avatar Feb 26 '17 16:02 NiLSPACE

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

madmaxoft avatar Feb 26 '17 16:02 madmaxoft

You mean the whole idea of the command parser?

NiLSPACE avatar Feb 26 '17 16:02 NiLSPACE

@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

sphinxc0re avatar Feb 26 '17 17:02 sphinxc0re

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.

NiLSPACE avatar Feb 26 '17 21:02 NiLSPACE

This sounds very interesting...

HelenaKitty avatar Feb 27 '17 10:02 HelenaKitty

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

NiLSPACE avatar Feb 27 '17 10:02 NiLSPACE

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

HelenaKitty avatar Feb 27 '17 10:02 HelenaKitty

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 avatar Feb 27 '17 18:02 NiLSPACE

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

NiLSPACE avatar Feb 27 '17 20:02 NiLSPACE

Any thoughts?

NiLSPACE avatar Mar 02 '17 07:03 NiLSPACE

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.

madmaxoft avatar Mar 02 '17 11:03 madmaxoft