diff options
| author | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-10-31 13:46:11 +0100 |
|---|---|---|
| committer | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-10-31 21:13:19 +0100 |
| commit | 4aa2b717f9e050783b567540d9bb0193d692e3e9 (patch) | |
| tree | 39b3734c464655e6d1c21390945209a66f952654 /src/qreg.c | |
| parent | e0bf13622b0922252439e3fa8b43df9877678d75 (diff) | |
support floating point numbers
* Extends the SciTECO type system. A number on the expression stack
or in a Q-register can be either an integer or a float.
* Floating point constants begin with a digit (like all other
numbers), are followed by a `.` and an optional fractional part.
Exponents cannot currently be written.
E.g. `1.` == `1.0`. But `.0` would still be `.,0`.
(!) To push an integer followed by dot, you must now write e.g. `1,.` or `1 .`.
* All of the basic arithmetic operators operate like this:
If both operands are integers, the result is also an integer (integer arithmetics).
If at least one of the operands is a float, the result is also a float (float arithmetics).
* All of the binary operators (AND, OR, XOR) always cast all
operands to integer and the result is always an integer as well.
* You can "cast" integers to float by `*1.` or `/1.`.
You can "cast" floats to integers using `#0`.
* Most commands still accept only integers. Floats are implicitly casted to integers.
Float-aware commands are: =, \, ^W, Qq, Uq, %q and the conditionals.
* `%q` will not change the current type of register q.
* Numeric part of "lexer.font" is now a float (in points).
* You cannot currently print octal and hexadecimal floats.
`==` and `===` are identical to `=` on floats.
* `===` is now printing hex integers in lower case.
This is because SciTECO's coding style for hex constants is also lower case.
* `--with-teco-integer` renamed to `--with-teco-number`.
Diffstat (limited to 'src/qreg.c')
| -rw-r--r-- | src/qreg.c | 116 |
1 files changed, 68 insertions, 48 deletions
@@ -58,6 +58,12 @@ teco_qreg_t *teco_qreg_current = NULL; */ teco_qreg_table_t teco_qreg_table_globals; +typedef struct teco_qreg_flags_t teco_qreg_flags_t; +TECO_DEFINE_UNDO_SCALAR(teco_qreg_flags_t); + +#define teco_undo_qreg_flags(VAR) \ + (*teco_undo_object_teco_qreg_flags_t_push(&(VAR))) + /** @private @static @memberof teco_qreg_t */ static teco_qreg_t * teco_qreg_new(teco_qreg_vtable_t *vtable, const gchar *name, gsize len) @@ -103,7 +109,7 @@ teco_qreg_execute(teco_qreg_t *qreg, teco_qreg_table_t *qreg_table_locals, GErro void teco_qreg_undo_set_eol_mode(teco_qreg_t *qreg) { - if (!qreg->must_undo) + if (!qreg->flags.must_undo) return; /* @@ -112,7 +118,7 @@ teco_qreg_undo_set_eol_mode(teco_qreg_t *qreg) */ teco_doc_update(&qreg->string, teco_qreg_view); - if (teco_qreg_current && teco_qreg_current->must_undo) // FIXME + if (teco_qreg_current && teco_qreg_current->flags.must_undo) // FIXME teco_doc_undo_edit(&teco_qreg_current->string); undo__teco_view_ssm(teco_qreg_view, SCI_SETEOLMODE, @@ -136,18 +142,23 @@ teco_qreg_set_eol_mode(teco_qreg_t *qreg, gint mode) } static gboolean -teco_qreg_plain_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error) +teco_qreg_plain_set_number(teco_qreg_t *qreg, teco_number_t value, gboolean is_float, GError **error) { - if (qreg->must_undo) // FIXME - teco_undo_int(qreg->integer); - qreg->integer = value; + if (qreg->flags.must_undo) { // FIXME + teco_undo_number(qreg->number); + teco_undo_qreg_flags(qreg->flags); + } + qreg->number = value; + qreg->flags.is_float = is_float; return TRUE; } static gboolean -teco_qreg_plain_get_integer(teco_qreg_t *qreg, teco_int_t *ret, GError **error) +teco_qreg_plain_get_number(teco_qreg_t *qreg, teco_number_t *ret, + gboolean *is_float, GError **error) { - *ret = qreg->integer; + *ret = qreg->number; + *is_float = qreg->flags.is_float; return TRUE; } @@ -162,7 +173,7 @@ teco_qreg_plain_set_string(teco_qreg_t *qreg, const gchar *str, gsize len, static gboolean teco_qreg_plain_undo_set_string(teco_qreg_t *qreg, GError **error) { - if (qreg->must_undo) // FIXME + if (qreg->flags.must_undo) // FIXME teco_doc_undo_set_string(&qreg->string); return TRUE; } @@ -177,14 +188,14 @@ teco_qreg_plain_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GE if (!len) return TRUE; - if (qreg->must_undo) { // FIXME + if (qreg->flags.must_undo) { // FIXME /* * Necessary, so that upon rubout the * string's parameters are restored. */ teco_doc_update(&qreg->string, teco_qreg_view); - if (teco_qreg_current && teco_qreg_current->must_undo) // FIXME + if (teco_qreg_current && teco_qreg_current->flags.must_undo) // FIXME teco_doc_undo_edit(&teco_qreg_current->string); teco_doc_undo_reset(&qreg->string); @@ -208,7 +219,7 @@ teco_qreg_plain_append_string(teco_qreg_t *qreg, const gchar *str, gsize len, GE * so that teco_doc_edit() always initializes the document and * the default codepage. */ - if (qreg->must_undo) // FIXME + if (qreg->flags.must_undo) // FIXME teco_doc_undo_edit(&qreg->string); return TRUE; @@ -273,7 +284,7 @@ teco_qreg_plain_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **err static gboolean teco_qreg_plain_undo_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GError **error) { - if (qreg->must_undo) // FIXME + if (qreg->flags.must_undo) // FIXME teco_doc_undo_exchange(&qreg->string); teco_doc_undo_exchange(src); return TRUE; @@ -301,7 +312,7 @@ teco_qreg_plain_undo_edit(teco_qreg_t *qreg, GError **error) */ teco_doc_update(&qreg->string, teco_qreg_view); - if (!qreg->must_undo) // FIXME + if (!qreg->flags.must_undo) // FIXME return TRUE; undo__teco_interface_info_update_qreg(qreg); @@ -363,8 +374,8 @@ teco_qreg_plain_save(teco_qreg_t *qreg, const gchar *filename, GError **error) * These store their string part as teco_docs. */ #define TECO_INIT_QREG(...) { \ - .set_integer = teco_qreg_plain_set_integer, \ - .get_integer = teco_qreg_plain_get_integer, \ + .set_number = teco_qreg_plain_set_number, \ + .get_number = teco_qreg_plain_get_number, \ .set_string = teco_qreg_plain_set_string, \ .undo_set_string = teco_qreg_plain_undo_set_string, \ .append_string = teco_qreg_plain_append_string, \ @@ -391,9 +402,12 @@ teco_qreg_plain_new(const gchar *name, gsize len) /* see also teco_state_start_jump() */ static gboolean -teco_qreg_dot_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error) +teco_qreg_dot_set_number(teco_qreg_t *qreg, teco_number_t value, gboolean is_float, GError **error) { - gssize pos = teco_interface_glyphs2bytes_absdot(value); + if (is_float) + value.i = value.f; + + gssize pos = teco_interface_glyphs2bytes_absdot(value.i); if (pos < 0) { g_set_error_literal(error, TECO_ERROR, TECO_ERROR_MOVE, "Attempt to move pointer off page when setting Q-Register \":\""); @@ -405,16 +419,17 @@ teco_qreg_dot_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error) teco_interface_ssm(SCI_GETCURRENTPOS, 0, 0), 0); teco_interface_ssm(SCI_GOTOPOS, pos, 0); - teco_current_doc_set_dot(value); + teco_current_doc_set_dot(value.i); return TRUE; } -/* see also teco_state_start_dot() */ static gboolean -teco_qreg_dot_get_integer(teco_qreg_t *qreg, teco_int_t *ret, GError **error) +teco_qreg_dot_get_number(teco_qreg_t *qreg, teco_number_t *ret, + gboolean *is_float, GError **error) { - *ret = teco_current_doc_get_dot(); + ret->i = teco_current_doc_get_dot(); + *is_float = FALSE; return TRUE; } @@ -423,8 +438,8 @@ teco_qreg_t * teco_qreg_dot_new(void) { static teco_qreg_vtable_t vtable = TECO_INIT_QREG( - .set_integer = teco_qreg_dot_set_integer, - .get_integer = teco_qreg_dot_get_integer + .set_number = teco_qreg_dot_set_number, + .get_number = teco_qreg_dot_get_number ); /* @@ -435,18 +450,18 @@ teco_qreg_dot_new(void) } static gboolean -teco_qreg_radix_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error) +teco_qreg_radix_set_number(teco_qreg_t *qreg, teco_number_t value, gboolean is_float, GError **error) { - if (value < 2) { - g_set_error_literal(error, TECO_ERROR, TECO_ERROR_FAILED, - "Invalid radix"); + if (is_float) + value.i = value.f; + + if (value.i < 2) { + g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED, + "Invalid radix %" TECO_INT_FORMAT, value.i); return FALSE; } - if (qreg->must_undo) // FIXME - teco_undo_int(qreg->integer); - qreg->integer = value; - return TRUE; + return teco_qreg_plain_set_number(qreg, value, FALSE, error); } /** @static @memberof teco_qreg_t */ @@ -454,11 +469,11 @@ static teco_qreg_t * teco_qreg_radix_new(void) { static teco_qreg_vtable_t vtable = TECO_INIT_QREG( - .set_integer = teco_qreg_radix_set_integer + .set_number = teco_qreg_radix_set_number ); teco_qreg_t *qreg = teco_qreg_new(&vtable, "\x12", 1); /* ^R */ - qreg->integer = 10; + qreg->number.i = 10; return qreg; } @@ -514,7 +529,7 @@ teco_qreg_external_undo_exchange_string(teco_qreg_t *qreg, teco_doc_t *src, GErr { if (!qreg->vtable->undo_set_string(qreg, error)) return FALSE; - if (qreg->must_undo) // FIXME + if (qreg->flags.must_undo) // FIXME teco_doc_undo_set_string(src); return TRUE; } @@ -537,7 +552,7 @@ teco_qreg_external_get_character(teco_qreg_t *qreg, teco_int_t position, /* * Make sure that the -1/-2 error values are preserved. * The sign bit in UCS-4/UTF-32 is unused, so this will even - * suffice if TECO_INTEGER == 32. + * suffice if TECO_NUMBER == 32. */ *chr = *p ? (gint32)g_utf8_get_char_validated(p, -1) : 0; return TRUE; @@ -622,16 +637,18 @@ teco_qreg_external_save(teco_qreg_t *qreg, const gchar *filename, GError **error * NOTE: The integer-component is currently unused on the "*" special register. */ static gboolean -teco_qreg_bufferinfo_set_integer(teco_qreg_t *qreg, teco_int_t value, GError **error) +teco_qreg_bufferinfo_set_number(teco_qreg_t *qreg, teco_number_t value, gboolean is_float, GError **error) { return teco_current_doc_undo_edit(error) && - teco_ring_edit(value, error); + teco_ring_edit(is_float ? (teco_int_t)value.f : value.i, error); } static gboolean -teco_qreg_bufferinfo_get_integer(teco_qreg_t *qreg, teco_int_t *ret, GError **error) +teco_qreg_bufferinfo_get_number(teco_qreg_t *qreg, teco_number_t *ret, + gboolean *is_float, GError **error) { - *ret = teco_ring_get_id(teco_ring_current); + ret->i = teco_ring_get_id(teco_ring_current); + *is_float = FALSE; return TRUE; } @@ -690,8 +707,8 @@ teco_qreg_t * teco_qreg_bufferinfo_new(void) { static teco_qreg_vtable_t vtable = TECO_INIT_QREG_EXTERNAL( - .set_integer = teco_qreg_bufferinfo_set_integer, - .get_integer = teco_qreg_bufferinfo_get_integer, + .set_number = teco_qreg_bufferinfo_set_number, + .get_number = teco_qreg_bufferinfo_get_number, .set_string = teco_qreg_bufferinfo_set_string, .undo_set_string = teco_qreg_bufferinfo_undo_set_string, .append_string = teco_qreg_bufferinfo_append_string, @@ -944,7 +961,7 @@ teco_qreg_clipboard_new(const gchar *name) * This is configurable via the integer cell. */ if (qreg->head.name.len == 1) - qreg->integer = 'C'; + qreg->number.i = 'C'; return qreg; } @@ -987,7 +1004,7 @@ TECO_DEFINE_UNDO_CALL(teco_qreg_table_remove, teco_qreg_t *); static inline void teco_qreg_table_undo_remove(teco_qreg_t *qreg) { - if (qreg->must_undo) + if (qreg->flags.must_undo) undo__teco_qreg_table_remove(qreg); } @@ -1169,8 +1186,11 @@ teco_qreg_table_clear(teco_qreg_table_t *table) } typedef struct { - teco_int_t integer; + teco_number_t number; teco_doc_t string; + + /** whether the number cell is an integer or float */ + gboolean is_float; } teco_qreg_stack_entry_t; static inline void @@ -1199,11 +1219,11 @@ TECO_DEFINE_UNDO_CALL(teco_qreg_stack_remove_last); gboolean teco_qreg_stack_push(teco_qreg_t *qreg, GError **error) { - teco_qreg_stack_entry_t entry; + teco_qreg_stack_entry_t entry = {0}; g_auto(teco_string_t) string = {NULL, 0}; guint codepage; - if (!qreg->vtable->get_integer(qreg, &entry.integer, error) || + if (!qreg->vtable->get_number(qreg, &entry.number, &entry.is_float, error) || !qreg->vtable->get_string(qreg, &string.data, &string.len, &codepage, error)) return FALSE; teco_doc_init(&entry.string); @@ -1247,7 +1267,7 @@ teco_qreg_stack_pop(teco_qreg_t *qreg, GError **error) teco_qreg_stack_entry_t *entry; entry = &g_array_index(teco_qreg_stack, teco_qreg_stack_entry_t, teco_qreg_stack->len-1); - if (!qreg->vtable->set_integer(qreg, entry->integer, error)) + if (!qreg->vtable->set_number(qreg, entry->number, entry->is_float, error)) return FALSE; /* exchange document ownership between stack entry and Q-Register */ |
