Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 14:53:29 -05:00
|
|
|
/*
|
|
|
|
* vim:ts=4:sw=4:expandtab
|
|
|
|
*
|
|
|
|
* i3 - an improved dynamic tiling window manager
|
|
|
|
* © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
|
|
|
|
*
|
|
|
|
* commands.c: all command functions (see commands_parser.c)
|
|
|
|
*
|
|
|
|
*/
|
2013-12-28 21:11:50 -05:00
|
|
|
#pragma once
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 14:53:29 -05:00
|
|
|
|
2012-05-02 16:01:50 -04:00
|
|
|
#include <yajl/yajl_gen.h>
|
|
|
|
|
2012-02-07 17:38:21 -05:00
|
|
|
/*
|
2014-05-18 00:44:19 -04:00
|
|
|
* Holds an intermediate represenation of the result of a call to any command.
|
|
|
|
* When calling parse_command("floating enable, border none"), the parser will
|
|
|
|
* internally use this struct when calling cmd_floating and cmd_border.
|
2012-02-07 17:38:21 -05:00
|
|
|
*/
|
2014-05-18 00:44:19 -04:00
|
|
|
struct CommandResultIR {
|
2014-05-28 02:01:50 -04:00
|
|
|
/* The JSON generator to append a reply to (may be NULL). */
|
2012-05-02 16:01:50 -04:00
|
|
|
yajl_gen json_gen;
|
2012-02-07 17:38:21 -05:00
|
|
|
|
2012-10-08 07:26:42 -04:00
|
|
|
/* The next state to transition to. Passed to the function so that we can
|
|
|
|
* determine the next state as a result of a function call, like
|
|
|
|
* cfg_criteria_pop_state() does. */
|
|
|
|
int next_state;
|
2013-06-08 09:37:41 -04:00
|
|
|
|
|
|
|
/* Whether the command requires calling tree_render. */
|
|
|
|
bool needs_tree_render;
|
2012-02-07 17:38:21 -05:00
|
|
|
};
|
|
|
|
|
2014-05-28 02:01:50 -04:00
|
|
|
typedef struct CommandResult CommandResult;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A struct that contains useful information about the result of a command as a
|
|
|
|
* whole (e.g. a compound command like "floating enable, border none").
|
|
|
|
* needs_tree_render is true if needs_tree_render of any individual command was
|
|
|
|
* true.
|
|
|
|
*/
|
|
|
|
struct CommandResult {
|
|
|
|
bool parse_error;
|
|
|
|
/* the error_message is currently only set for parse errors */
|
|
|
|
char *error_message;
|
|
|
|
bool needs_tree_render;
|
|
|
|
};
|
|
|
|
|
2014-10-01 16:50:48 -04:00
|
|
|
/**
|
|
|
|
* Parses a string (or word, if as_word is true). Extracted out of
|
|
|
|
* parse_command so that it can be used in src/workspace.c for interpreting
|
|
|
|
* workspace commands.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
char *parse_string(const char **walk, bool as_word);
|
|
|
|
|
2014-05-28 02:01:50 -04:00
|
|
|
/**
|
|
|
|
* Parses and executes the given command. If a caller-allocated yajl_gen is
|
|
|
|
* passed, a json reply will be generated in the format specified by the ipc
|
|
|
|
* protocol. Pass NULL if no json reply is required.
|
|
|
|
*
|
|
|
|
* Free the returned CommandResult with command_result_free().
|
|
|
|
*/
|
|
|
|
CommandResult *parse_command(const char *input, yajl_gen gen);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Frees a CommandResult
|
|
|
|
*/
|
|
|
|
void command_result_free(CommandResult *result);
|