diff options
Diffstat (limited to 'src/parser.h')
-rw-r--r-- | src/parser.h | 100 |
1 files changed, 63 insertions, 37 deletions
diff --git a/src/parser.h b/src/parser.h index 05a9715..066896f 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2023 Robin Haberkorn + * Copyright (C) 2012-2024 Robin Haberkorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,8 @@ */ #pragma once +#include <stdbool.h> + #include <glib.h> #include <Scintilla.h> @@ -23,6 +25,7 @@ #include "sciteco.h" #include "string-utils.h" #include "goto.h" +#include "undo.h" #include "qreg.h" /* @@ -36,7 +39,9 @@ typedef struct { /** how many iterations are left */ teco_int_t counter; /** Program counter of loop start command */ - guint pc : sizeof(guint)*8 - 1; + gsize pc; + /** Brace level at loop start */ + guint brace_level : sizeof(guint)*8 - 1; /** * Whether the loop represents an argument * barrier or not (it "passes through" @@ -46,7 +51,7 @@ typedef struct { * a signed integer, it's ok steal one * bit for the pass_through flag. */ - gboolean pass_through : 1; + bool pass_through : 1; } teco_loop_context_t; extern GArray *teco_loop_stack; @@ -71,8 +76,8 @@ void undo__remove_index__teco_loop_stack(guint); * FIXME: Maybe use TECO_DECLARE_VTABLE_METHOD()? */ typedef const struct { - gboolean string_building : 1; - gboolean last : 1; + bool string_building : 1; + bool last : 1; /** * Called repeatedly to process chunks of input and give interactive feedback. @@ -99,17 +104,18 @@ typedef const struct { } teco_state_expectqreg_t; typedef gboolean (*teco_state_initial_cb_t)(teco_machine_t *ctx, GError **error); -typedef teco_state_t *(*teco_state_input_cb_t)(teco_machine_t *ctx, gchar chr, GError **error); +typedef teco_state_t *(*teco_state_input_cb_t)(teco_machine_t *ctx, gunichar chr, GError **error); typedef gboolean (*teco_state_refresh_cb_t)(teco_machine_t *ctx, GError **error); typedef gboolean (*teco_state_end_of_macro_cb_t)(teco_machine_t *ctx, GError **error); typedef gboolean (*teco_state_process_edit_cmd_cb_t)(teco_machine_t *ctx, teco_machine_t *parent_ctx, - gchar key, GError **error); + gunichar key, GError **error); typedef enum { - TECO_FNMACRO_MASK_START = (1 << 0), - TECO_FNMACRO_MASK_STRING = (1 << 1), - TECO_FNMACRO_MASK_DEFAULT = ~((1 << 2)-1) -} teco_fnmacro_mask_t; + TECO_KEYMACRO_MASK_START = (1 << 0), + TECO_KEYMACRO_MASK_STRING = (1 << 1), + TECO_KEYMACRO_MASK_CASEINSENSITIVE = (1 << 2), + TECO_KEYMACRO_MASK_DEFAULT = ~((1 << 3)-1) +} teco_keymacro_mask_t; /** * A teco_machine_t state. @@ -182,19 +188,19 @@ struct teco_state_t { /** * Whether this state is a start state (ie. not within any * escape sequence etc.). - * This is separate of TECO_FNMACRO_MASK_START which is set + * This is separate of TECO_KEYMACRO_MASK_START which is set * only in the main machine's start states. */ - gboolean is_start : 1; + bool is_start : 1; /** - * Function key macro mask. + * Key macro mask. * This is not a bitmask since it is compared with values set * from TECO, so the bitorder needs to be defined. * * @fixme If we intend to "forward" masks from other state machines like * teco_machine_stringbuilding_t, this should probably be a callback. */ - teco_fnmacro_mask_t fnmacro_mask : 8; + teco_keymacro_mask_t keymacro_mask : 8; /** * Additional state-dependent callbacks and settings. @@ -214,7 +220,7 @@ struct teco_state_t { gboolean teco_state_end_of_macro(teco_machine_t *ctx, GError **error); /* in cmdline.c */ -gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gchar chr, GError **error); +gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gunichar chr, GError **error); /** * @interface TECO_DEFINE_STATE @@ -234,7 +240,7 @@ gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent .end_of_macro_cb = teco_state_end_of_macro, \ .process_edit_cmd_cb = teco_state_process_edit_cmd, \ .is_start = FALSE, \ - .fnmacro_mask = TECO_FNMACRO_MASK_DEFAULT, \ + .keymacro_mask = TECO_KEYMACRO_MASK_DEFAULT, \ ##__VA_ARGS__ \ } @@ -243,20 +249,21 @@ gboolean teco_state_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent extern teco_state_t NAME /* in cmdline.c */ -gboolean teco_state_caseinsensitive_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gchar chr, GError **error); +gboolean teco_state_caseinsensitive_process_edit_cmd(teco_machine_t *ctx, teco_machine_t *parent_ctx, gunichar chr, GError **error); /** * @interface TECO_DEFINE_STATE_CASEINSENSITIVE * @implements TECO_DEFINE_STATE * @ingroup states * - * Base class of states with case-insenstive input. + * Base class of states with case-insensitive input. * * This is meant for states accepting command characters * that can possibly be case-folded. */ #define TECO_DEFINE_STATE_CASEINSENSITIVE(NAME, ...) \ TECO_DEFINE_STATE(NAME, \ + .keymacro_mask = TECO_KEYMACRO_MASK_CASEINSENSITIVE, \ .process_edit_cmd_cb = teco_state_caseinsensitive_process_edit_cmd, \ ##__VA_ARGS__ \ ) @@ -278,6 +285,8 @@ struct teco_machine_t { * Whether side effects must be reverted on rubout. * State machines created within macro calls don't have to * even in interactive mode. + * In fact you MUST not revert side effects if this is FALSE + * as the data no longer exists on the call stack at undo-time. */ gboolean must_undo; }; @@ -296,7 +305,7 @@ teco_machine_reset(teco_machine_t *ctx, teco_state_t *initial) teco_undo_ptr(ctx->current) = initial; } -gboolean teco_machine_input(teco_machine_t *ctx, gchar chr, GError **error); +gboolean teco_machine_input(teco_machine_t *ctx, gunichar chr, GError **error); typedef enum { TECO_STRINGBUILDING_MODE_NORMAL = 0, @@ -307,9 +316,6 @@ typedef enum { /** * A stringbuilding state machine. * - * @fixme Should contain the escape char (currently in teco_machine_expectstring_t), - * so that we can escape it via ^Q. - * * @extends teco_machine_t */ typedef struct teco_machine_stringbuilding_t { @@ -327,7 +333,7 @@ typedef struct teco_machine_stringbuilding_t { * If this is `[` or `{`, it is assumed that `]` and `}` must * be escaped as well by teco_machine_stringbuilding_escape(). */ - gchar escape_char; + gunichar escape_char; /** * Q-Register table for local registers. @@ -348,11 +354,28 @@ typedef struct teco_machine_stringbuilding_t { * (see teco_state_stringbuilding_start_process_edit_cmd()). */ teco_string_t *result; + + /** + * Encoding of string in `result`. + * This is inherited from the embedding command and may depend on + * the buffer's or Q-Register's encoding. + */ + guint codepage; } teco_machine_stringbuilding_t; -void teco_machine_stringbuilding_init(teco_machine_stringbuilding_t *ctx, gchar escape_char, +void teco_machine_stringbuilding_init(teco_machine_stringbuilding_t *ctx, gunichar escape_char, teco_qreg_table_t *locals, gboolean must_undo); +static inline void +teco_machine_stringbuilding_set_codepage(teco_machine_stringbuilding_t *ctx, + guint codepage) +{ + /* NOTE: This is not safe to undo in macro calls. */ + if (ctx->parent.must_undo) + teco_undo_guint(ctx->codepage); + ctx->codepage = codepage; +} + void teco_machine_stringbuilding_reset(teco_machine_stringbuilding_t *ctx); /** @@ -365,7 +388,7 @@ void teco_machine_stringbuilding_reset(teco_machine_stringbuilding_t *ctx); * @return FALSE in case of error. */ static inline gboolean -teco_machine_stringbuilding_input(teco_machine_stringbuilding_t *ctx, gchar chr, +teco_machine_stringbuilding_input(teco_machine_stringbuilding_t *ctx, gunichar chr, teco_string_t *result, GError **error) { ctx->result = result; @@ -424,7 +447,8 @@ typedef enum { struct teco_machine_main_t { teco_machine_t parent; - gint macro_pc; + /* signed because it is sometimes set to -1 for flow control */ + gssize macro_pc; /** * Aliases bitfield with an integer. @@ -435,8 +459,8 @@ struct teco_machine_main_t { struct { teco_mode_t mode : 8; - gboolean modifier_colon : 1; - gboolean modifier_at : 1; + bool modifier_colon : 1; + bool modifier_at : 1; }; guint __flags; }; @@ -481,7 +505,7 @@ void teco_machine_main_init(teco_machine_main_t *ctx, gboolean teco_machine_main_eval_colon(teco_machine_main_t *ctx); gboolean teco_machine_main_step(teco_machine_main_t *ctx, - const gchar *macro, gint stop_pos, GError **error); + const gchar *macro, gsize stop_pos, GError **error); gboolean teco_execute_macro(const gchar *macro, gsize macro_len, teco_qreg_table_t *qreg_table_locals, GError **error); @@ -500,17 +524,18 @@ typedef const struct { */ teco_state_t *teco_machine_main_transition_input(teco_machine_main_t *ctx, teco_machine_main_transition_t *transitions, - guint len, gchar chr, GError **error); + guint len, gunichar chr, GError **error); void teco_machine_main_clear(teco_machine_main_t *ctx); G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(teco_machine_main_t, teco_machine_main_clear); -teco_state_t *teco_state_expectstring_input(teco_machine_main_t *ctx, gchar chr, GError **error); +gboolean teco_state_expectstring_initial(teco_machine_main_t *ctx, GError **error); +teco_state_t *teco_state_expectstring_input(teco_machine_main_t *ctx, gunichar chr, GError **error); gboolean teco_state_expectstring_refresh(teco_machine_main_t *ctx, GError **error); /* in cmdline.c */ -gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gchar key, GError **error); +gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error); /** * @interface TECO_DEFINE_STATE_EXPECTSTRING @@ -526,15 +551,16 @@ gboolean teco_state_expectstring_process_edit_cmd(teco_machine_main_t *ctx, teco */ #define TECO_DEFINE_STATE_EXPECTSTRING(NAME, ...) \ static teco_state_t * \ - NAME##_input(teco_machine_main_t *ctx, gchar chr, GError **error) \ + NAME##_input(teco_machine_main_t *ctx, gunichar chr, GError **error) \ { \ return teco_state_expectstring_input(ctx, chr, error); \ } \ TECO_DEFINE_STATE(NAME, \ + .initial_cb = (teco_state_initial_cb_t)teco_state_expectstring_initial, \ .refresh_cb = (teco_state_refresh_cb_t)teco_state_expectstring_refresh, \ .process_edit_cmd_cb = (teco_state_process_edit_cmd_cb_t) \ teco_state_expectstring_process_edit_cmd, \ - .fnmacro_mask = TECO_FNMACRO_MASK_STRING, \ + .keymacro_mask = TECO_KEYMACRO_MASK_STRING, \ .expectstring.string_building = TRUE, \ .expectstring.last = TRUE, \ .expectstring.process_cb = NULL, /* do nothing */ \ @@ -546,7 +572,7 @@ gboolean teco_state_expectfile_process(teco_machine_main_t *ctx, const teco_stri gsize new_chars, GError **error); /* in cmdline.c */ -gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gchar key, GError **error); +gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error); /** * @interface TECO_DEFINE_STATE_EXPECTFILE @@ -562,7 +588,7 @@ gboolean teco_state_expectfile_process_edit_cmd(teco_machine_main_t *ctx, teco_m ) /* in cmdline.c */ -gboolean teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gchar key, GError **error); +gboolean teco_state_expectdir_process_edit_cmd(teco_machine_main_t *ctx, teco_machine_t *parent_ctx, gunichar key, GError **error); /** * @interface TECO_DEFINE_STATE_EXPECTDIR |