aboutsummaryrefslogtreecommitdiff
path: root/src/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse.c')
-rw-r--r--src/parse.c308
1 files changed, 254 insertions, 54 deletions
diff --git a/src/parse.c b/src/parse.c
index 79f4aba..e2b4c4d 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -22,8 +22,6 @@ find_or_init_default_mode(struct parser *parser)
}
default_mode = malloc(sizeof(struct mode));
- default_mode->line = -1;
- default_mode->cursor = -1;
default_mode->name = copy_string("default");
table_init(&default_mode->hotkey_map, 131,
@@ -74,13 +72,63 @@ keycode_from_hex(char *hex)
return result;
}
-internal char *
-parse_command(struct parser *parser)
+internal void
+parse_command(struct parser *parser, struct hotkey *hotkey)
{
struct token command = parser_previous(parser);
char *result = copy_string_count(command.text, command.length);
- printf("\tcmd: '%s'\n", result);
- return result;
+ debug("\tcmd: '%s'\n", result);
+ buf_push(hotkey->command, result);
+}
+
+internal void
+parse_process_command_list(struct parser *parser, struct hotkey *hotkey)
+{
+ if (parser_match(parser, Token_String)) {
+ struct token name_token = parser_previous(parser);
+ char *name = copy_string_count(name_token.text, name_token.length);
+ for (char *s = name; *s; ++s) *s = tolower(*s);
+ buf_push(hotkey->process_name, name);
+ if (parser_match(parser, Token_Command)) {
+ parse_command(parser, hotkey);
+ parse_process_command_list(parser, hotkey);
+ } else if (parser_match(parser, Token_Unbound)) {
+ buf_push(hotkey->command, NULL);
+ parse_process_command_list(parser, hotkey);
+ } else {
+ parser_report_error(parser, parser_peek(parser), "expected '~' or ':' followed by command\n");
+ }
+ } else if (parser_match(parser, Token_Wildcard)) {
+ if (parser_match(parser, Token_Command)) {
+ struct token command = parser_previous(parser);
+ char *result = copy_string_count(command.text, command.length);
+ debug("\tcmd: '%s'\n", result);
+ hotkey->wildcard_command = result;
+ parse_process_command_list(parser, hotkey);
+ } else if (parser_match(parser, Token_Unbound)) {
+ hotkey->wildcard_command = NULL;
+ parse_process_command_list(parser, hotkey);
+ } else {
+ parser_report_error(parser, parser_peek(parser), "expected '~' or ':' followed by command\n");
+ }
+ } else if (parser_match(parser, Token_EndList)) {
+ if (!buf_len(hotkey->process_name)) {
+ parser_report_error(parser, parser_previous(parser), "list must contain at least one value\n");
+ }
+ } else {
+ parser_report_error(parser, parser_peek(parser), "expected process command mapping or ']'\n");
+ }
+}
+
+internal void
+parse_activate(struct parser *parser, struct hotkey *hotkey)
+{
+ parse_command(parser, hotkey);
+ hotkey->flags |= Hotkey_Flag_Activate;
+
+ if (!table_find(parser->mode_map, hotkey->command[0])) {
+ parser_report_error(parser, parser_previous(parser), "undeclared identifier\n");
+ }
}
internal uint32_t
@@ -90,7 +138,7 @@ parse_key_hex(struct parser *parser)
char *hex = copy_string_count(key.text, key.length);
uint32_t keycode = keycode_from_hex(hex);
free(hex);
- printf("\tkey: '%.*s' (0x%02x)\n", key.length, key.text, keycode);
+ debug("\tkey: '%.*s' (0x%02x)\n", key.length, key.text, keycode);
return keycode;
}
@@ -100,7 +148,7 @@ parse_key(struct parser *parser)
uint32_t keycode;
struct token key = parser_previous(parser);
keycode = keycode_from_char(*key.text);
- printf("\tkey: '%c' (0x%02x)\n", *key.text, keycode);
+ debug("\tkey: '%c' (0x%02x)\n", *key.text, keycode);
return keycode;
}
@@ -146,7 +194,7 @@ parse_key_literal(struct parser *parser, struct hotkey *hotkey)
if (token_equals(key, literal_keycode_str[i])) {
handle_implicit_literal_flags(hotkey, i);
hotkey->key = literal_keycode_value[i];
- printf("\tkey: '%.*s' (0x%02x)\n", key.length, key.text, hotkey->key);
+ debug("\tkey: '%.*s' (0x%02x)\n", key.length, key.text, hotkey->key);
break;
}
}
@@ -158,7 +206,7 @@ internal enum hotkey_flag modifier_flags_value[] =
Hotkey_Flag_Shift, Hotkey_Flag_LShift, Hotkey_Flag_RShift,
Hotkey_Flag_Cmd, Hotkey_Flag_LCmd, Hotkey_Flag_RCmd,
Hotkey_Flag_Control, Hotkey_Flag_LControl, Hotkey_Flag_RControl,
- Hotkey_Flag_Fn, Hotkey_Flag_Hyper,
+ Hotkey_Flag_Fn, Hotkey_Flag_Hyper, Hotkey_Flag_Meh,
};
internal uint32_t
@@ -170,7 +218,7 @@ parse_modifier(struct parser *parser)
for (int i = 0; i < array_count(modifier_flags_str); ++i) {
if (token_equals(modifier, modifier_flags_str[i])) {
flags |= modifier_flags_value[i];
- printf("\tmod: '%s'\n", modifier_flags_str[i]);
+ debug("\tmod: '%s'\n", modifier_flags_str[i]);
break;
}
}
@@ -179,7 +227,7 @@ parse_modifier(struct parser *parser)
if (parser_match(parser, Token_Modifier)) {
flags |= parse_modifier(parser);
} else {
- parser_report_error(parser, Error_Unexpected_Token, "expected modifier");
+ parser_report_error(parser, parser_peek(parser), "expected modifier\n");
}
}
@@ -198,18 +246,18 @@ parse_mode(struct parser *parser, struct hotkey *hotkey)
if (!mode && token_equals(identifier, "default")) {
mode = find_or_init_default_mode(parser);
} else if (!mode) {
- parser_report_error(parser, Error_Undeclared_Ident, "undeclared identifier");
+ parser_report_error(parser, identifier, "undeclared identifier\n");
return;
}
buf_push(hotkey->mode_list, mode);
- printf("\tmode: '%s'\n", mode->name);
+ debug("\tmode: '%s'\n", mode->name);
if (parser_match(parser, Token_Comma)) {
if (parser_match(parser, Token_Identifier)) {
parse_mode(parser, hotkey);
} else {
- parser_report_error(parser, Error_Unexpected_Token, "expected identifier");
+ parser_report_error(parser, parser_peek(parser), "expected identifier\n");
}
}
}
@@ -221,7 +269,7 @@ parse_hotkey(struct parser *parser)
memset(hotkey, 0, sizeof(struct hotkey));
bool found_modifier;
- printf("hotkey :: #%d {\n", parser->current_token.line);
+ debug("hotkey :: #%d {\n", parser->current_token.line);
if (parser_match(parser, Token_Identifier)) {
parse_mode(parser, hotkey);
@@ -232,7 +280,7 @@ parse_hotkey(struct parser *parser)
if (buf_len(hotkey->mode_list) > 0) {
if (!parser_match(parser, Token_Insert)) {
- parser_report_error(parser, Error_Unexpected_Token, "expected '<'");
+ parser_report_error(parser, parser_peek(parser), "expected '<'\n");
goto err;
}
} else {
@@ -248,7 +296,7 @@ parse_hotkey(struct parser *parser)
if (found_modifier) {
if (!parser_match(parser, Token_Dash)) {
- parser_report_error(parser, Error_Unexpected_Token, "expected '-'");
+ parser_report_error(parser, parser_peek(parser), "expected '-'\n");
goto err;
}
}
@@ -260,7 +308,7 @@ parse_hotkey(struct parser *parser)
} else if (parser_match(parser, Token_Literal)) {
parse_key_literal(parser, hotkey);
} else {
- parser_report_error(parser, Error_Unexpected_Token, "expected key-literal");
+ parser_report_error(parser, parser_peek(parser), "expected key-literal\n");
goto err;
}
@@ -269,20 +317,23 @@ parse_hotkey(struct parser *parser)
}
if (parser_match(parser, Token_Command)) {
- hotkey->command = parse_command(parser);
+ parse_command(parser, hotkey);
+ } else if (parser_match(parser, Token_BeginList)) {
+ parse_process_command_list(parser, hotkey);
+ if (parser->error) {
+ goto err;
+ }
} else if (parser_match(parser, Token_Activate)) {
- hotkey->flags |= Hotkey_Flag_Activate;
- hotkey->command = parse_command(parser);
- if (!table_find(parser->mode_map, hotkey->command)) {
- parser_report_error(parser, Error_Undeclared_Ident, "undeclared identifier");
+ parse_activate(parser, hotkey);
+ if (parser->error) {
goto err;
}
} else {
- parser_report_error(parser, Error_Unexpected_Token, "expected ':' followed by command or ';' followed by mode");
+ parser_report_error(parser, parser_peek(parser), "expected ':' followed by command or ';' followed by mode\n");
goto err;
}
- printf("}\n");
+ debug("}\n");
return hotkey;
err:
@@ -296,8 +347,6 @@ parse_mode_decl(struct parser *parser)
struct mode *mode = malloc(sizeof(struct mode));
struct token identifier = parser_previous(parser);
- mode->line = identifier.line;
- mode->cursor = identifier.cursor;
mode->name = copy_string_count(identifier.text, identifier.length);
table_init(&mode->hotkey_map, 131,
@@ -321,32 +370,96 @@ parse_mode_decl(struct parser *parser)
void parse_declaration(struct parser *parser)
{
- struct mode *mode;
parser_match(parser, Token_Decl);
if (parser_match(parser, Token_Identifier)) {
- mode = parse_mode_decl(parser);
+ struct token identifier = parser_previous(parser);
+ struct mode *mode = parse_mode_decl(parser);
if (table_find(parser->mode_map, mode->name)) {
- parser_report_error(parser, Error_Duplicate_Ident,
- "#%d:%d duplicate declaration '%s'\n",
- mode->line, mode->cursor, mode->name);
+ parser_report_error(parser, identifier, "duplicate declaration '%s'\n", mode->name);
} else {
table_add(parser->mode_map, mode->name, mode);
}
} else {
- parser_report_error(parser, Error_Unexpected_Token, "expected identifier");
+ parser_report_error(parser, parser_peek(parser), "expected identifier\n");
+ }
+}
+
+void parse_option_blacklist(struct parser *parser)
+{
+ if (parser_match(parser, Token_String)) {
+ struct token name_token = parser_previous(parser);
+ char *name = copy_string_count(name_token.text, name_token.length);
+ for (char *s = name; *s; ++s) *s = tolower(*s);
+ debug("\t%s\n", name);
+ table_add(parser->blacklst, name, name);
+ parse_option_blacklist(parser);
+ } else if (parser_match(parser, Token_EndList)) {
+ if (parser->blacklst->count == 0) {
+ parser_report_error(parser, parser_previous(parser), "list must contain at least one value\n");
+ }
+ } else {
+ parser_report_error(parser, parser_peek(parser), "expected process name or ']'\n");
}
}
-void parse_config(struct parser *parser)
+void parse_option_load(struct parser *parser, struct token option)
+{
+ struct token filename_token = parser_previous(parser);
+ char *filename = copy_string_count(filename_token.text, filename_token.length);
+ debug("\t%s\n", filename);
+
+ if (*filename != '/') {
+ char *directory = file_directory(parser->file);
+
+ size_t directory_length = strlen(directory);
+ size_t filename_length = strlen(filename);
+ size_t total_length = directory_length + filename_length + 2;
+
+ char *absolutepath = malloc(total_length * sizeof(char));
+ snprintf(absolutepath, total_length, "%s/%s", directory, filename);
+ free(filename);
+
+ filename = absolutepath;
+ }
+
+ buf_push(parser->load_directives, ((struct load_directive) {
+ .file = filename,
+ .option = option
+ }));
+}
+
+void parse_option(struct parser *parser)
+{
+ parser_match(parser, Token_Option);
+ struct token option = parser_previous(parser);
+ if (token_equals(option, "blacklist")) {
+ if (parser_match(parser, Token_BeginList)) {
+ debug("blacklist :: #%d {\n", option.line);
+ parse_option_blacklist(parser);
+ debug("}\n");
+ } else {
+ parser_report_error(parser, option, "expected '[' followed by list of process names\n");
+ }
+ } else if (token_equals(option, "load")) {
+ if (parser_match(parser, Token_String)) {
+ debug("load :: #%d {\n", option.line);
+ parse_option_load(parser, option);
+ debug("}\n");
+ } else {
+ parser_report_error(parser, option, "expected filename\n");
+ }
+ } else {
+ parser_report_error(parser, option, "invalid option specified\n");
+ }
+}
+
+bool parse_config(struct parser *parser)
{
struct mode *mode;
struct hotkey *hotkey;
while (!parser_eof(parser)) {
- if (parser->error) {
- free_mode_map(parser->mode_map);
- return;
- }
+ if (parser->error) break;
if ((parser_check(parser, Token_Identifier)) ||
(parser_check(parser, Token_Modifier)) ||
@@ -361,10 +474,64 @@ void parse_config(struct parser *parser)
}
} else if (parser_check(parser, Token_Decl)) {
parse_declaration(parser);
+ } else if (parser_check(parser, Token_Option)) {
+ parse_option(parser);
} else {
- parser_report_error(parser, Error_Unexpected_Token, "expected decl, modifier or key-literal");
+ parser_report_error(parser, parser_peek(parser), "expected decl, modifier or key-literal\n");
}
}
+
+ if (parser->error) {
+ free_mode_map(parser->mode_map);
+ free_blacklist(parser->blacklst);
+ return false;
+ }
+
+ return true;
+}
+
+struct hotkey *
+parse_keypress(struct parser *parser)
+{
+ if ((parser_check(parser, Token_Modifier)) ||
+ (parser_check(parser, Token_Literal)) ||
+ (parser_check(parser, Token_Key_Hex)) ||
+ (parser_check(parser, Token_Key))) {
+ struct hotkey *hotkey = malloc(sizeof(struct hotkey));
+ memset(hotkey, 0, sizeof(struct hotkey));
+ bool found_modifier;
+
+ if ((found_modifier = parser_match(parser, Token_Modifier))) {
+ hotkey->flags = parse_modifier(parser);
+ if (parser->error) {
+ goto err;
+ }
+ }
+
+ if (found_modifier) {
+ if (!parser_match(parser, Token_Dash)) {
+ goto err;
+ }
+ }
+
+ if (parser_match(parser, Token_Key)) {
+ hotkey->key = parse_key(parser);
+ } else if (parser_match(parser, Token_Key_Hex)) {
+ hotkey->key = parse_key_hex(parser);
+ } else if (parser_match(parser, Token_Literal)) {
+ parse_key_literal(parser, hotkey);
+ } else {
+ goto err;
+ }
+
+ return hotkey;
+
+ err:
+ free(hotkey);
+ return NULL;
+ }
+
+ return NULL;
}
struct token
@@ -411,33 +578,58 @@ bool parser_match(struct parser *parser, enum token_type type)
return false;
}
-void parser_report_error(struct parser *parser, enum parse_error_type error_type, const char *format, ...)
+void parser_report_error(struct parser *parser, struct token token, const char *format, ...)
{
va_list args;
va_start(args, format);
+ fprintf(stderr, "#%d:%d ", token.line, token.cursor);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ parser->error = true;
+}
+
+void parser_do_directives(struct parser *parser, struct hotloader *hotloader, bool thwart_hotloader)
+{
+ bool error = false;
+
+ for (int i = 0; i < buf_len(parser->load_directives); ++i) {
+ struct load_directive load = parser->load_directives[i];
+
+ struct parser directive_parser;
+ if (parser_init(&directive_parser, parser->mode_map, parser->blacklst, load.file)) {
+ if (!thwart_hotloader) {
+ hotloader_add_file(hotloader, load.file);
+ }
+
+ if (parse_config(&directive_parser)) {
+ parser_do_directives(&directive_parser, hotloader, thwart_hotloader);
+ } else {
+ error = true;
+ }
+
+ parser_destroy(&directive_parser);
+ } else {
+ warn("skhd: could not open file '%s' from load directive #%d:%d\n", load.file, load.option.line, load.option.cursor);
+ }
- if (error_type == Error_Unexpected_Token) {
- fprintf(stderr, "#%d:%d ", parser->current_token.line, parser->current_token.cursor);
- vfprintf(stderr, format, args);
- fprintf(stderr, ", but got '%.*s'\n", parser->current_token.length, parser->current_token.text);
- } else if (error_type == Error_Undeclared_Ident) {
- fprintf(stderr, "#%d:%d ", parser->previous_token.line, parser->previous_token.cursor);
- vfprintf(stderr, format, args);
- fprintf(stderr, " '%.*s'\n", parser->previous_token.length, parser->previous_token.text);
- } else if (error_type == Error_Duplicate_Ident) {
- vfprintf(stderr, format, args);
+ free(load.file);
}
+ buf_free(parser->load_directives);
- va_end(args);
- parser->error = true;
+ if (error) {
+ free_mode_map(parser->mode_map);
+ free_blacklist(parser->blacklst);
+ }
}
-bool parser_init(struct parser *parser, struct table *mode_map, char *file)
+bool parser_init(struct parser *parser, struct table *mode_map, struct table *blacklst, char *file)
{
memset(parser, 0, sizeof(struct parser));
char *buffer = read_file(file);
if (buffer) {
+ parser->file = file;
parser->mode_map = mode_map;
+ parser->blacklst = blacklst;
tokenizer_init(&parser->tokenizer, buffer);
parser_advance(parser);
return true;
@@ -445,6 +637,14 @@ bool parser_init(struct parser *parser, struct table *mode_map, char *file)
return false;
}
+bool parser_init_text(struct parser *parser, char *text)
+{
+ memset(parser, 0, sizeof(struct parser));
+ tokenizer_init(&parser->tokenizer, text);
+ parser_advance(parser);
+ return true;
+}
+
void parser_destroy(struct parser *parser)
{
free(parser->tokenizer.buffer);