From 23b5ef45e7939a00addff726d02d6c29243177af Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Thu, 23 Feb 2023 21:40:04 +0100
Subject: 2023-02-23 21:26:00

---
 source/luametatex/source/lua/lmtinterface.c   |  2 +
 source/luametatex/source/lua/lmtinterface.h   |  5 ++
 source/luametatex/source/lua/lmtnodelib.c     |  8 +++
 source/luametatex/source/lua/lmttexlib.c      | 42 +++++++------
 source/luametatex/source/luametatex.h         |  2 +-
 source/luametatex/source/tex/texcommands.c    |  2 +
 source/luametatex/source/tex/texcommands.h    |  1 +
 source/luametatex/source/tex/texdumpdata.h    |  2 +-
 source/luametatex/source/tex/texequivalents.h | 28 ++-------
 source/luametatex/source/tex/texmath.c        | 33 ++++++++--
 source/luametatex/source/tex/texmath.h        |  3 +
 source/luametatex/source/tex/texmlist.c       | 79 ++++++++++++++++++++----
 source/luametatex/source/tex/texnodes.c       |  6 ++
 source/luametatex/source/tex/texnodes.h       | 86 ++++++++++++++-------------
 14 files changed, 197 insertions(+), 102 deletions(-)

(limited to 'source')

diff --git a/source/luametatex/source/lua/lmtinterface.c b/source/luametatex/source/lua/lmtinterface.c
index 9156f0aaf..2c94feb6f 100644
--- a/source/luametatex/source/lua/lmtinterface.c
+++ b/source/luametatex/source/lua/lmtinterface.c
@@ -435,6 +435,7 @@ void lmt_initialize_interface(void)
 
     set_math_parameter_value(math_parameter_delimiter_percent,                  math_int_parameter,    delimiterpercent);
     set_math_parameter_value(math_parameter_delimiter_shortfall,                math_dimen_parameter,  delimitershortfall);
+    set_math_parameter_value(math_parameter_delimiter_extend_margin,            math_dimen_parameter,  delimiterextendmargin);
 
     set_math_parameter_value(math_parameter_over_line_variant,                  math_style_parameter,  overlinevariant);
     set_math_parameter_value(math_parameter_under_line_variant,                 math_style_parameter,  underlinevariant);
@@ -548,4 +549,5 @@ void lmt_initialize_interface(void)
     set_math_font_parameter(FlattenedAccentBottomShiftDown,           math_dimen_parameter);
     set_math_font_parameter(DelimiterPercent,                         math_int_parameter);
     set_math_font_parameter(DelimiterShortfall,                       math_dimen_parameter);
+    set_math_font_parameter(DelimiterExtendMargin,                    math_dimen_parameter);
 }
diff --git a/source/luametatex/source/lua/lmtinterface.h b/source/luametatex/source/lua/lmtinterface.h
index 59ef808c8..26481d075 100644
--- a/source/luametatex/source/lua/lmtinterface.h
+++ b/source/luametatex/source/lua/lmtinterface.h
@@ -560,6 +560,7 @@ make_lua_key(L, data);\
 make_lua_key(L, deep_frozen_cs_dont_expand);\
 make_lua_key(L, deep_frozen_cs_end_template);\
 make_lua_key(L, def);\
+make_lua_key(L, deferred);\
 make_lua_key(L, define_char_code);\
 make_lua_key(L, define_family);\
 make_lua_key(L, define_font);\
@@ -572,6 +573,8 @@ make_lua_key(L, delimiter);\
 make_lua_key(L, delimiter_number);\
 make_lua_key(L, delimiterover);\
 make_lua_key(L, delimiterovervariant);\
+make_lua_key(L, DelimiterExtendMargin);\
+make_lua_key(L, delimiterextendmargin);\
 make_lua_key(L, DelimiterPercent);\
 make_lua_key(L, delimiterpercent);\
 make_lua_key(L, DelimiterShortfall);\
@@ -749,6 +752,7 @@ make_lua_key(L, indentskip);\
 make_lua_key(L, index);\
 make_lua_key(L, info);\
 make_lua_key(L, Info);\
+make_lua_key(L, inherited);\
 make_lua_key(L, inner);\
 make_lua_key(L, innerlocation);\
 make_lua_key(L, innerxoffset);\
@@ -1126,6 +1130,7 @@ make_lua_key(L, ScriptScriptPercentScaleDown);\
 make_lua_key(L, scriptscriptscale);\
 make_lua_key(L, second);\
 make_lua_key(L, semisimple);\
+make_lua_key(L, semiprotected);\
 make_lua_key(L, set);\
 make_lua_key(L, set_auxiliary);\
 make_lua_key(L, set_box);\
diff --git a/source/luametatex/source/lua/lmtnodelib.c b/source/luametatex/source/lua/lmtnodelib.c
index 72b9918e4..997115267 100644
--- a/source/luametatex/source/lua/lmtnodelib.c
+++ b/source/luametatex/source/lua/lmtnodelib.c
@@ -6763,6 +6763,10 @@ static int nodelib_common_getfield(lua_State *L, int direct, halfword n)
                                             nodelib_push_direct_or_node(L, direct, radical_left_delimiter(n));
                                         } else if (lua_key_eq(s, right)) {
                                             nodelib_push_direct_or_node(L, direct, radical_right_delimiter(n));
+                                        } else if (lua_key_eq(s, top)) {
+                                            nodelib_push_direct_or_node(L, direct, radical_top_delimiter(n));
+                                        } else if (lua_key_eq(s, bottom)) {
+                                            nodelib_push_direct_or_node(L, direct, radical_bottom_delimiter(n));
                                         } else if (lua_key_eq(s, degree)) {
                                             nodelib_push_direct_or_node(L, direct, radical_degree(n));
                                         } else if (lua_key_eq(s, width)) {
@@ -7436,6 +7440,10 @@ static int nodelib_common_setfield(lua_State *L, int direct, halfword n)
                                             radical_left_delimiter(n) = nodelib_direct_or_node_from_index(L, direct, 3);
                                         } else if (lua_key_eq(s, right)) {
                                             radical_right_delimiter(n) = nodelib_direct_or_node_from_index(L, direct, 3);
+                                        } else if (lua_key_eq(s, top)) {
+                                            radical_top_delimiter(n) = nodelib_direct_or_node_from_index(L, direct, 3);
+                                        } else if (lua_key_eq(s, bottom)) {
+                                            radical_bottom_delimiter(n) = nodelib_direct_or_node_from_index(L, direct, 3);
                                         } else if (lua_key_eq(s, degree)) {
                                             radical_degree(n) = nodelib_direct_or_node_from_index(L, direct, 3);
                                         } else if (lua_key_eq(s, width)) {
diff --git a/source/luametatex/source/lua/lmttexlib.c b/source/luametatex/source/lua/lmttexlib.c
index 0afd6cdf6..38c8e3fa8 100644
--- a/source/luametatex/source/lua/lmttexlib.c
+++ b/source/luametatex/source/lua/lmttexlib.c
@@ -4928,23 +4928,28 @@ static int texlib_getautomigrationvalues(lua_State *L)
 
 static int texlib_getflagvalues(lua_State *L)
 {
-    lua_createtable(L, 2, 15);
-    lua_push_key_at_index(L, frozen,      frozen_flag_bit);
-    lua_push_key_at_index(L, permanent,   permanent_flag_bit);
-    lua_push_key_at_index(L, immutable,   immutable_flag_bit);
-    lua_push_key_at_index(L, primitive,   primitive_flag_bit);
-    lua_push_key_at_index(L, mutable,     mutable_flag_bit);
-    lua_push_key_at_index(L, noaligned,   noaligned_flag_bit);
-    lua_push_key_at_index(L, instance,    instance_flag_bit);
-    lua_push_key_at_index(L, untraced,    untraced_flag_bit);
-    lua_push_key_at_index(L, global,      global_flag_bit);
-    lua_push_key_at_index(L, tolerant,    tolerant_flag_bit);
-    lua_push_key_at_index(L, protected,   protected_flag_bit);
-    lua_push_key_at_index(L, overloaded,  overloaded_flag_bit);
-    lua_push_key_at_index(L, aliased,     aliased_flag_bit);
-    lua_push_key_at_index(L, immediate,   immediate_flag_bit);
-    lua_push_key_at_index(L, conditional, conditional_flag_bit);
-    lua_push_key_at_index(L, value,       value_flag_bit);
+    lua_createtable(L, 2, 18); 
+    /* what about the rest */
+    lua_push_key_at_index(L, frozen,        frozen_flag_bit);
+    lua_push_key_at_index(L, permanent,     permanent_flag_bit);
+    lua_push_key_at_index(L, immutable,     immutable_flag_bit);
+    lua_push_key_at_index(L, primitive,     primitive_flag_bit);
+    lua_push_key_at_index(L, mutable,       mutable_flag_bit);
+    lua_push_key_at_index(L, noaligned,     noaligned_flag_bit);
+    lua_push_key_at_index(L, instance,      instance_flag_bit);
+    lua_push_key_at_index(L, untraced,      untraced_flag_bit);
+    lua_push_key_at_index(L, global,        global_flag_bit);
+    lua_push_key_at_index(L, tolerant,      tolerant_flag_bit);
+    lua_push_key_at_index(L, protected,     protected_flag_bit);
+    lua_push_key_at_index(L, overloaded,    overloaded_flag_bit);
+    lua_push_key_at_index(L, aliased,       aliased_flag_bit);
+    lua_push_key_at_index(L, immediate,     immediate_flag_bit);
+    lua_push_key_at_index(L, conditional,   conditional_flag_bit);
+    lua_push_key_at_index(L, value,         value_flag_bit);
+    lua_push_key_at_index(L, semiprotected, semiprotected_flag_bit);
+    lua_push_key_at_index(L, inherited,     inherited_flag_bit);
+    lua_push_key_at_index(L, constant,      constant_flag_bit);
+    lua_push_key_at_index(L, deferred,      deferred_flag_bit);
     return 1;
 }
 
@@ -5240,7 +5245,7 @@ static int texlib_getdiscstatevalues(lua_State *L)
 
 static int texlib_getmathcontrolvalues(lua_State *L)
 {
-    lua_createtable(L, 2, 23);
+    lua_createtable(L, 2, 24);
     lua_set_string_by_index(L, math_control_use_font_control,            "usefontcontrol");
     lua_set_string_by_index(L, math_control_over_rule,                   "overrule");
     lua_set_string_by_index(L, math_control_under_rule,                  "underrule");
@@ -5266,6 +5271,7 @@ static int texlib_getmathcontrolvalues(lua_State *L)
     lua_set_string_by_index(L, math_control_ignore_kern_dimensions,      "ignorekerndimensions");
     lua_set_string_by_index(L, math_control_ignore_flat_accents,         "ignoreflataccents");
     lua_set_string_by_index(L, math_control_extend_accents,              "extendaccents");
+    lua_set_string_by_index(L, math_control_extend_delimiters,           "extenddelimiters");
     return 1;
 }
 
diff --git a/source/luametatex/source/luametatex.h b/source/luametatex/source/luametatex.h
index 19175a487..410d4dd68 100644
--- a/source/luametatex/source/luametatex.h
+++ b/source/luametatex/source/luametatex.h
@@ -92,7 +92,7 @@
 # define luametatex_version          210
 # define luametatex_revision         06
 # define luametatex_version_string   "2.10.06"
-# define luametatex_development_id   20230209
+# define luametatex_development_id   20230224
 
 # define luametatex_name_camelcase   "LuaMetaTeX"
 # define luametatex_name_lowercase   "luametatex"
diff --git a/source/luametatex/source/tex/texcommands.c b/source/luametatex/source/tex/texcommands.c
index e52825b33..76b171789 100644
--- a/source/luametatex/source/tex/texcommands.c
+++ b/source/luametatex/source/tex/texcommands.c
@@ -990,6 +990,7 @@ void tex_initialize_commands(void)
         tex_primitive(luatex_command, "overloaded",                     prefix_cmd,             overloaded_code,                          0);
         tex_primitive(luatex_command, "aliased",                        prefix_cmd,             aliased_code,                             0);
         tex_primitive(luatex_command, "immediate",                      prefix_cmd,             immediate_code,                           0);
+        tex_primitive(luatex_command, "deferred",                       prefix_cmd,             deferred_code,                            0);
         tex_primitive(luatex_command, "semiprotected",                  prefix_cmd,             semiprotected_code,                       0);
         tex_primitive(luatex_command, "enforced",                       prefix_cmd,             enforced_code,                            0);
         tex_primitive(luatex_command, "inherited",                      prefix_cmd,             inherited_code,                           0);
@@ -1216,6 +1217,7 @@ void tex_initialize_commands(void)
         /* */
         tex_primitive(luatex_command, "Umathdelimiterpercent",          set_math_parameter_cmd, math_parameter_delimiter_percent,                0);
         tex_primitive(luatex_command, "Umathdelimitershortfall",        set_math_parameter_cmd, math_parameter_delimiter_shortfall,              0);
+        tex_primitive(luatex_command, "Umathdelimiterextendmargin",     set_math_parameter_cmd, math_parameter_delimiter_extend_margin,          0);
         /* */
         tex_primitive(luatex_command, "Umathoverlinevariant",           set_math_parameter_cmd, math_parameter_over_line_variant,                0);
         tex_primitive(luatex_command, "Umathunderlinevariant",          set_math_parameter_cmd, math_parameter_under_line_variant,               0);
diff --git a/source/luametatex/source/tex/texcommands.h b/source/luametatex/source/tex/texcommands.h
index 57dc30f4f..faeb38247 100644
--- a/source/luametatex/source/tex/texcommands.h
+++ b/source/luametatex/source/tex/texcommands.h
@@ -831,6 +831,7 @@ typedef enum prefix_codes {
     overloaded_code,
     aliased_code,
     immediate_code,
+    deferred_code,
  /* conditional_code */
  /* value_code */
     semiprotected_code,
diff --git a/source/luametatex/source/tex/texdumpdata.h b/source/luametatex/source/tex/texdumpdata.h
index 87d987421..847bfa46f 100644
--- a/source/luametatex/source/tex/texdumpdata.h
+++ b/source/luametatex/source/tex/texdumpdata.h
@@ -55,7 +55,7 @@
 
 */
 
-# define luametatex_format_fingerprint 684
+# define luametatex_format_fingerprint 686
 
 /* These end up in the string pool. */
 
diff --git a/source/luametatex/source/tex/texequivalents.h b/source/luametatex/source/tex/texequivalents.h
index d64c78807..cc7f74ffc 100644
--- a/source/luametatex/source/tex/texequivalents.h
+++ b/source/luametatex/source/tex/texequivalents.h
@@ -1163,6 +1163,7 @@ typedef enum flag_bit {
     semiprotected_flag_bit = 0x10000,
     inherited_flag_bit     = 0x20000,
     constant_flag_bit      = 0x40000,
+    deferred_flag_bit      = 0x80000, /* this might move up */
 } flag_bits;
 
 /*tex Flags: */
@@ -1185,6 +1186,7 @@ typedef enum flag_bit {
 # define add_overloaded_flag(a)     ((a) | overloaded_flag_bit)
 # define add_aliased_flag(a)        ((a) | aliased_flag_bit)
 # define add_immediate_flag(a)      ((a) | immediate_flag_bit)
+# define add_deferred_flag(a)       ((a) | deferred_flag_bit)
 # define add_conditional_flag(a)    ((a) | conditional_flag_bit)
 # define add_value_flag(a)          ((a) | value_flag_bit)
 # define add_inherited_flag(a)      ((a) | inherited_flag_bit)
@@ -1207,32 +1209,10 @@ typedef enum flag_bit {
 # define remove_overloaded_flag(a)  ((a) & ~overloaded_flag_bit)
 # define remove_aliased_flag(a)     ((a) & ~aliased_flag_bit)
 # define remove_immediate_flag(a)   ((a) & ~immediate_flag_bit)
+# define remove_deferred_flag(a)    ((a) & ~deferred_flag_bit)
 # define remove_conditional_flag(a) ((a) & ~conditional_flag_bit)
 # define remove_value_flag(a)       ((a) & ~value_flag_bit)
 
-// do we really need the == here 
-
-// # define is_frozen(a)               (((a) & frozen_flag_bit)    == frozen_flag_bit)
-// # define is_permanent(a)            (((a) & permanent_flag_bit) == permanent_flag_bit)
-// # define is_immutable(a)            (((a) & immutable_flag_bit) == immutable_flag_bit)
-// # define is_primitive(a)            (((a) & primitive_flag_bit) == primitive_flag_bit)
-// # define is_mutable(a)              (((a) & mutable_flag_bit)   == mutable_flag_bit)
-// # define is_noaligned(a)            (((a) & noaligned_flag_bit) == noaligned_flag_bit)
-// # define is_instance(a)             (((a) & instance_flag_bit)  == instance_flag_bit)
-// # define is_untraced(a)             (((a) & untraced_flag_bit)  == untraced_flag_bit)
-// 
-// # define is_global(a)               (((a) & global_flag_bit)        == global_flag_bit)
-// # define is_tolerant(a)             (((a) & tolerant_flag_bit)      == tolerant_flag_bit)
-// # define is_protected(a)            (((a) & protected_flag_bit)     == protected_flag_bit)
-// # define is_semiprotected(a)        (((a) & semiprotected_flag_bit) == semiprotected_flag_bit)
-// # define is_overloaded(a)           (((a) & overloaded_flag_bit)    == overloaded_flag_bit)
-// # define is_aliased(a)              (((a) & aliased_flag_bit)       == aliased_flag_bit)
-// # define is_immediate(a)            (((a) & immediate_flag_bit)     == immediate_flag_bit)
-// # define is_conditional(a)          (((a) & conditional_flag_bit)   == conditional_flag_bit)
-// # define is_value(a)                (((a) & value_flag_bit)         == value_flag_bit)
-// # define is_inherited(a)            (((a) & inherited_flag_bit)     == inherited_flag_bit)
-// # define is_constant(a)             (((a) & constant_flag_bit)      == constant_flag_bit)
-
 # define is_frozen(a)               (((a) & frozen_flag_bit))
 # define is_permanent(a)            (((a) & permanent_flag_bit))
 # define is_immutable(a)            (((a) & immutable_flag_bit))
@@ -1249,12 +1229,12 @@ typedef enum flag_bit {
 # define is_overloaded(a)           (((a) & overloaded_flag_bit))
 # define is_aliased(a)              (((a) & aliased_flag_bit))
 # define is_immediate(a)            (((a) & immediate_flag_bit))
+# define is_deferred(a)             (((a) & deferred_flag_bit))
 # define is_conditional(a)          (((a) & conditional_flag_bit))
 # define is_value(a)                (((a) & value_flag_bit))
 # define is_inherited(a)            (((a) & inherited_flag_bit))
 # define is_constant(a)             (((a) & constant_flag_bit))
 
-
 # define is_expandable(cmd)         (cmd > max_command_cmd)
 
 # define global_or_local(a)         (is_global(a) ? level_one : cur_level)
diff --git a/source/luametatex/source/tex/texmath.c b/source/luametatex/source/tex/texmath.c
index 0820b2405..1b62a389c 100644
--- a/source/luametatex/source/tex/texmath.c
+++ b/source/luametatex/source/tex/texmath.c
@@ -1037,7 +1037,7 @@ static void tex_aux_display_simple_noad(halfword n, int threshold, int max)
     tex_aux_display_common_noad(n, threshold, max);
 }
 
-static void tex_aux_display_radical_noad(halfword n, int threshold, int max)
+static void tex_aux_display_radical_noad(halfword n, int threshold, int max) /* todo: more fields */
 {
     if (noad_width(n)) {
         tex_print_format(", width %D", noad_width(n), pt_unit);
@@ -1071,7 +1071,7 @@ static void tex_aux_display_radical_noad(halfword n, int threshold, int max)
     tex_aux_display_common_noad(n, threshold, max);
 }
 
-static void tex_aux_display_accent_noad(halfword n, int threshold, int max)
+static void tex_aux_display_accent_noad(halfword n, int threshold, int max) /* todo: more fields */
 {
     halfword top_char = accent_top_character(n);
     halfword bottom_char = accent_bottom_character(n);
@@ -1129,7 +1129,7 @@ static void tex_aux_display_accent_noad(halfword n, int threshold, int max)
     tex_aux_display_common_noad(n, threshold, max);
 }
 
-static void tex_aux_display_fence_noad(halfword n, int threshold, int max)
+static void tex_aux_display_fence_noad(halfword n, int threshold, int max) /* todo: more fields */
 {
     if (noad_height(n)) {
         tex_print_format(", height %D", noad_height(n), pt_unit);
@@ -1163,7 +1163,7 @@ static void tex_aux_display_fence_noad(halfword n, int threshold, int max)
     tex_print_node_list(fence_delimiter_bottom(n), "bottom", threshold, max);
 }
 
-static void tex_aux_display_fraction_noad(halfword n, int threshold, int max)
+static void tex_aux_display_fraction_noad(halfword n, int threshold, int max) /* todo: more fields */
 {
     halfword leftdelimiter = tex_aux_valid_delimiter(fraction_left_delimiter(n));
     halfword rightdelimiter = tex_aux_valid_delimiter(fraction_right_delimiter(n));
@@ -2660,9 +2660,11 @@ void tex_run_math_radical(void)
     halfword variant = 0; /* quad, harmless */
     halfword attrlist = null;
     tex_tail_append(radical);
+    halfword top = null;
+    halfword bottom = null;
     /* only kewords to UI ones? */
     while (1) {
-        switch (tex_scan_character("abeswlmrhndABESWLMRHDN", 0, 1, 0)) {
+        switch (tex_scan_character("abeswlmrhndtABESWLMRHDNT", 0, 1, 0)) {
             case 0:
                 goto DONE;
             case 'a': case 'A':
@@ -2675,6 +2677,16 @@ void tex_run_math_radical(void)
                     options = options | noad_option_exact;
                 }
                 break;
+            case 'b': case 'B':
+                if (tex_scan_mandate_keyword("bottom", 1)) {
+                    bottom = 1;
+                }
+                break;
+            case 't': case 'T':
+                if (tex_scan_mandate_keyword("top", 1)) {
+                    top = 1;
+                }
+                break;
             case 's': case 'S':
                 switch (tex_scan_character("itoITO", 0, 0, 0)) {
                     case 't': case 'T':
@@ -2824,6 +2836,16 @@ void tex_run_math_radical(void)
                 tex_confusion("scan math radical");
                 break;
         }
+        if (top) { 
+            top = tex_new_node(delimiter_node, 0);
+            radical_top_delimiter(radical) = top;
+            tex_aux_scan_delimiter(top, umath_mathcode, unset_noad_class);
+        }
+        if (bottom) { 
+            bottom = tex_new_node(delimiter_node, 0);
+            radical_bottom_delimiter(radical) = bottom;
+            tex_aux_scan_delimiter(bottom, umath_mathcode, unset_noad_class);
+        }
     }
     switch (code) {
         case h_extensible_radical_subtype:
@@ -5199,6 +5221,7 @@ void tex_fixup_math_parameters(int fam, int size, int f, int level)
     tex_aux_define_all_math_parameters(size, math_parameter_flattened_accent_bottom_shift_down, math_parameter(f, FlattenedAccentBottomShiftDown),  level); /* engine, undefined */
     tex_aux_define_all_math_parameters(size, math_parameter_delimiter_percent,                  math_parameter(f, DelimiterPercent),                level); /* engine, undefined */
     tex_aux_define_all_math_parameters(size, math_parameter_delimiter_shortfall,                math_parameter(f, DelimiterShortfall),              level); /* engine, undefined */
+    tex_aux_define_all_math_parameters(size, math_parameter_delimiter_extend_margin,            math_parameter(f, DelimiterExtendMargin),           level); /* engine, undefined */
 
     tex_aux_define_all_math_parameters(size, math_parameter_radical_extensible_after,           math_parameter(f, RadicalKernAfterExtensible),      level); /* engine, undefined */
     tex_aux_define_all_math_parameters(size, math_parameter_radical_extensible_before,          math_parameter(f, RadicalKernBeforeExtensible),     level); /* engine, undefined */
diff --git a/source/luametatex/source/tex/texmath.h b/source/luametatex/source/tex/texmath.h
index 79f40c13b..ba02e8373 100644
--- a/source/luametatex/source/tex/texmath.h
+++ b/source/luametatex/source/tex/texmath.h
@@ -169,6 +169,7 @@ typedef enum math_parameters {
     /* */
     math_parameter_delimiter_percent,
     math_parameter_delimiter_shortfall,
+    math_parameter_delimiter_extend_margin,
     /* */
     math_parameter_over_line_variant,
     math_parameter_under_line_variant,
@@ -514,6 +515,7 @@ typedef enum math_parameter_codes {
     FlattenedAccentBottomShiftDown,           
     DelimiterPercent,                       
     DelimiterShortfall,
+    DelimiterExtendMargin,
     /* done */
     math_parameter_last_code,
 } math_parameter_codes;
@@ -682,6 +684,7 @@ typedef enum math_control_codes {
     math_control_ignore_kern_dimensions      = 0x0400000, /* for bad fonts (like xits fence depths) */
     math_control_ignore_flat_accents         = 0x0800000, 
     math_control_extend_accents              = 0x1000000, 
+    math_control_extend_delimiters           = 0x2000000, 
 } math_control_codes;
 
 /*tex This is what we use for \OPENTYPE\ in \CONTEXT: */
diff --git a/source/luametatex/source/tex/texmlist.c b/source/luametatex/source/tex/texmlist.c
index 8409f8df3..56b780506 100644
--- a/source/luametatex/source/tex/texmlist.c
+++ b/source/luametatex/source/tex/texmlist.c
@@ -309,6 +309,21 @@ inline static void tex_aux_make_style(halfword current, halfword *current_style,
     }
 }
 
+/*tex 
+    There is no need to be more subtle, if needed we can always do some extensive checking for the 
+    combined styles. Basically this is just a catch for |\allmathstyles|. Also keep in mind that
+    there no grouping inside a formula: we can cook up something but in the end one always has some 
+    synchronization problem because the next atom is likely outside the group anyway. 
+*/
+
+inline static void tex_aux_set_parameter(halfword current, halfword style)
+{ 
+    if (is_valid_math_style(node_subtype(current))) { 
+        style = node_subtype(current);
+    }
+    tex_def_math_parameter(style, parameter_name(current), parameter_value(current), cur_level + lmt_math_state.level, indirect_math_regular);
+}
+
 void tex_set_math_text_font(halfword style, int usetextfont)
 {
      halfword size = tex_aux_set_style_to_size(style);
@@ -753,9 +768,20 @@ static halfword tex_aux_fraction_rule(scaled width, scaled height, halfword att,
 
 */
 
-static halfword tex_aux_overbar(halfword box, scaled gap, scaled height, scaled krn, halfword att, quarterword index, halfword size, halfword fam)
+static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int size, scaled targetsize, int flat, int style, int shift, int *stack, scaled *delta, scaled tolerance, int nooverflow, delimiterextremes *extremes, scaled move);
+
+static halfword tex_aux_overbar(halfword box, scaled gap, scaled height, scaled krn, halfword att, quarterword index, halfword size, halfword fam, halfword topdelimiter, halfword style)
 {
-    halfword rule = tex_aux_fraction_rule(box_width(box), height, att, index, size, fam);
+    halfword rule = topdelimiter 
+        ? tex_aux_make_delimiter(null, topdelimiter, size, box_width(box), 1, style, 0, NULL, NULL, 0, 0, NULL, 0)
+        : tex_aux_fraction_rule(box_width(box), height, att, index, size, fam);
+    /*tex Safeguard: */
+    if (topdelimiter && box_width(rule) > box_width(box)) {
+        halfword delta = (box_width(rule) - box_width(box)) / 2;
+        tex_aux_prepend_hkern_to_box_list(box, delta, horizontal_math_kern_subtype, "narrow delimiter");
+        tex_aux_append_hkern_to_box_list(box, delta, horizontal_math_kern_subtype, "narrow delimiter");
+        box_width(box) = box_width(rule);
+    }
     if (gap) {
         halfword kern = tex_new_kern_node(gap, vertical_math_kern_subtype);
         tex_attach_attribute_list_attribute(kern, att);
@@ -1504,6 +1530,24 @@ static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int
                 added. See (**).
             */
             result = tex_aux_char_box(fnt, chr, att, delta, glyph_math_delimiter_subtype, flat ? targetsize : 0, style);
+            if (flat) { 
+                /* This will be done when we have a reasonable example. */
+            } else {
+                if (box_total(result) < targetsize && tex_aux_math_engine_control(fnt, math_control_extend_delimiters) && tex_char_has_tag_from_font(fnt, chr, extend_last_tag)) {
+                    halfword glyph = box_list(result);
+                    if (glyph && node_type(glyph) == glyph_node) {
+                        scaled margin = tex_get_math_y_parameter_default(style, math_parameter_delimiter_extend_margin, 0);
+                        scaled amount = targetsize - 2 * margin;
+                        if (amount > 0) { 
+                            double ratio = (double) amount/box_total(result);
+                            glyph_y_scale(glyph) = lround((double) glyph_y_scale(glyph) * ratio);
+                            glyph_y_offset(glyph) = lround((double) box_total(glyph) * ratio);
+                            box_height(result) = lround((double) box_height(result) * ratio);
+                            box_depth(result) = lround((double) box_depth(result) * ratio);
+                        }
+                    }
+                }
+            }
             if (stack) {
                 *stack = 0 ;
             }
@@ -1532,7 +1576,7 @@ static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int
         }
     }
     if (do_parts) {
-        if (has_noad_option_phantom(target) || has_noad_option_void(target)) {
+        if (target && (has_noad_option_phantom(target) || has_noad_option_void(target))) {
             result = tex_aux_make_list_phantom(result, has_noad_option_void(target), att);
         } else {
             result = register_extensible(fnt, chr, size, result, att);
@@ -2158,7 +2202,8 @@ static void tex_aux_make_over(halfword target, halfword style, halfword size, ha
         halfword result = tex_aux_overbar(
             tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_over_line_variant), style, math_nucleus_list, 0, NULL),
             vgap, thickness, kern,
-            get_attribute_list(noad_nucleus(target)), math_over_rule_subtype, size, fam
+            get_attribute_list(noad_nucleus(target)), math_over_rule_subtype, size, fam,
+            null, style
         );
         node_subtype(result) = math_over_list;
         kernel_math_list(noad_nucleus(target)) = result;
@@ -2324,6 +2369,7 @@ static void tex_aux_make_root_radical(halfword target, int style, int size, kern
     scaled fam = delimiter_small_family(radical_left_delimiter(target));
     halfword leftdelimiter = radical_left_delimiter(target);
     halfword rightdelimiter = radical_right_delimiter(target);
+    halfword topdelimiter = radical_top_delimiter(target);
     halfword delimiter = leftdelimiter ? leftdelimiter : rightdelimiter;
     halfword companion = leftdelimiter ? rightdelimiter : null;
     halfword radical = null;
@@ -2411,7 +2457,7 @@ static void tex_aux_make_root_radical(halfword target, int style, int size, kern
     }
     {
         halfword total = box_total(delimiter);
-        halfword list = tex_aux_overbar(nucleus, clearance, theta, kern, get_attribute_list(delimiter), math_radical_rule_subtype, size, fam);
+        halfword list = tex_aux_overbar(nucleus, clearance, theta, kern, get_attribute_list(delimiter), math_radical_rule_subtype, size, fam, topdelimiter, style);
         radical = tex_aux_link_radical(list, delimiter, companion, rightdelimiter);
         if (radical_degree(target)) {
             halfword degree = tex_aux_clean_box(radical_degree(target), script_script_style, style, math_degree_list, 0, NULL);
@@ -3501,9 +3547,16 @@ static halfword tex_aux_make_stretched_fraction(halfword target, int style, int
     if (box_width(middle) < box_width(fraction)) {
         /*tex It's always in the details: */
         scaled delta = (box_width(fraction) - box_width(middle)) / 2;
-        tex_aux_prepend_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "bad delimiter");
-        tex_aux_append_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "bad delimiter");
+        tex_aux_prepend_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "narrow delimiter");
+        tex_aux_append_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "narrow delimiter");
         box_width(middle) = box_width(fraction);
+    } else if (box_width(middle) > box_width(fraction)) {
+        scaled delta = (box_width(middle) - box_width(fraction)) / 2;
+        tex_aux_prepend_hkern_to_box_list(numerator, delta, horizontal_math_kern_subtype, "wide delimiter");
+        tex_aux_append_hkern_to_box_list(numerator, delta, horizontal_math_kern_subtype, "wide delimiter");
+        tex_aux_prepend_hkern_to_box_list(denominator, delta, horizontal_math_kern_subtype, "wide delimiter");
+        tex_aux_append_hkern_to_box_list(denominator, delta, horizontal_math_kern_subtype, "wide delimiter");
+        box_width(fraction) = box_width(middle);
     }
     tex_aux_compensate_fraction_rule(target, fraction, middle, thickness);
     box_list(fraction) = tex_aux_assemble_fraction(target, style, size, numerator, denominator, middle, delta, shift_up, shift_down);
@@ -4950,7 +5003,7 @@ static void tex_aux_make_scripts(halfword target, halfword kernel, scaled italic
         }
     }
     /*tex 
-        Each of the scripts gets treated. Traditionally a super and subscript are looked and and 
+        Each of the scripts gets treated. Traditionally a super and subscript are looked at and 
         vercially spaced out together which in turn results in the staricase kerns needing that 
         information. Prescripts we handle differently: they are always aligned, so there the 
         maximum kern wins. 
@@ -6337,7 +6390,7 @@ static void tex_mlist_to_hlist_preroll_radicals(mliststate *state)
                 tex_aux_make_style(current, &current_style, NULL);
                 break;
             case parameter_node:
-                tex_def_math_parameter(node_subtype(current), parameter_name(current), parameter_value(current), cur_level + lmt_math_state.level, indirect_math_regular);
+                tex_aux_set_parameter(current, current_style);
                 break;
         }
         current = node_next(current);
@@ -6530,7 +6583,7 @@ static void tex_mlist_to_hlist_preroll_dimensions(mliststate *state)
                 goto DONE_WITH_NODE;
             case parameter_node:
                 /* maybe not needed as we do a first pass */
-                tex_def_math_parameter(node_subtype(current), parameter_name(current), parameter_value(current), cur_level + lmt_math_state.level, indirect_math_regular);
+                tex_aux_set_parameter(current, current_style);
                 goto DONE_WITH_NODE;
             case insert_node:
             case mark_node:
@@ -6612,7 +6665,7 @@ static void tex_mlist_to_hlist_size_fences(mliststate *state)
                 break;
             case parameter_node:
                 /* tricky as this is sort of persistent, we need to reset it at the start */
-                tex_def_math_parameter(node_subtype(current), parameter_name(current), parameter_value(current), cur_level + lmt_math_state.level, indirect_math_regular);
+                tex_aux_set_parameter(current, current_style);
                 break;
         }
         current = node_next(current);
@@ -6788,7 +6841,7 @@ static void tex_mlist_to_hlist_finalize_list(mliststate *state)
                 tex_aux_wipe_noad(recent);
                 goto RESTART;
             case parameter_node:
-                tex_def_math_parameter(node_subtype(current), parameter_name(current), parameter_value(current), cur_level + lmt_math_state.level, indirect_math_regular);
+                tex_aux_set_parameter(current, current_style);
                 recent = current;
                 current = node_next(current);
                 tex_aux_wipe_noad(recent);
@@ -6910,7 +6963,7 @@ static void tex_mlist_to_hlist_finalize_list(mliststate *state)
         }
         if (current_type == simple_noad) {
             pre_penalty = tex_aux_math_penalty(state->main_style, 1, current_subtype);
-            post_penalty = tex_aux_math_penalty(state->main_style,0, current_subtype);
+            post_penalty = tex_aux_math_penalty(state->main_style, 0, current_subtype);
         }
         /*tex Dirty trick: */ /* todo: use kerns info */
         current_plus_glyph = tex_aux_get_plus_glyph(current);
diff --git a/source/luametatex/source/tex/texnodes.c b/source/luametatex/source/tex/texnodes.c
index 625a4346b..09aa74d57 100644
--- a/source/luametatex/source/tex/texnodes.c
+++ b/source/luametatex/source/tex/texnodes.c
@@ -1205,6 +1205,8 @@ halfword tex_copy_node(halfword p) /* how about null */
                         case radical_noad:
                             copy_sub_node(radical_left_delimiter(r), radical_left_delimiter(p)) ;
                             copy_sub_node(radical_right_delimiter(r), radical_right_delimiter(p)) ;
+                            copy_sub_node(radical_top_delimiter(r), radical_top_delimiter(p)) ;
+                            copy_sub_node(radical_bottom_delimiter(r), radical_bottom_delimiter(p)) ;
                             copy_sub_list(radical_degree(r), radical_degree(p)) ;
                             break;
                         case fraction_noad:
@@ -1394,6 +1396,8 @@ void tex_flush_node(halfword p)
                         case radical_noad:
                             tex_aux_free_sub_node(radical_left_delimiter(p));
                             tex_aux_free_sub_node(radical_right_delimiter(p));
+                            tex_aux_free_sub_node(radical_top_delimiter(p));
+                            tex_aux_free_sub_node(radical_bottom_delimiter(p));
                             tex_aux_free_sub_node_list(radical_degree(p));
                             break;
                         case accent_noad:
@@ -1510,6 +1514,8 @@ static void tex_aux_check_node(halfword p)
                     tex_aux_node_range_test(p, radical_degree(p));
                     tex_aux_node_range_test(p, radical_left_delimiter(p));
                     tex_aux_node_range_test(p, radical_right_delimiter(p));
+                    tex_aux_node_range_test(p, radical_top_delimiter(p));
+                    tex_aux_node_range_test(p, radical_bottom_delimiter(p));
                     break;
                 case fraction_noad:
                  // tex_aux_node_range_test(p, fraction_numerator(p));
diff --git a/source/luametatex/source/tex/texnodes.h b/source/luametatex/source/tex/texnodes.h
index e19ff933d..f3f9276a6 100644
--- a/source/luametatex/source/tex/texnodes.h
+++ b/source/luametatex/source/tex/texnodes.h
@@ -1576,36 +1576,38 @@ typedef enum simple_choice_subtypes {
 
     \starttabulate[|l|l|l|l|l|l|]
     \FL
-    \BC            \BC noad       \BC accent            \BC fraction         \BC radical         \NC fence        \NC \NR
-    \ML                                                                                          \NC              
-    \NC vlink  2   \NC new_hlist  \NC                   \NC                  \NC                 \NC              \NC \NR
-    \ML                                                                                          \NC              
-    \NC vinfo  2   \NC nucleus    \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vlink  3   \NC supscr     \NC                   \NC numerator        \NC                 \NC              \NC \NR
-    \NC vinfo  3   \NC subscr     \NC                   \NC denominator      \NC                 \NC              \NC \NR
-    \NC vlink  4   \NC supprescr  \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vinfo  4   \NC subprescr  \NC                   \NC                  \NC                 \NC              \NC \NR
-    \ML                                                                                          \NC              
-    \NC vlink  5   \NC italic     \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vinfo  5   \NC width      \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vlink  6   \NC height     \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vinfo  6   \NC depth      \NC                   \NC                  \NC                 \NC              \NC \NR
-    \ML                                                                                          \NC              
-    \NC vlink  7   \NC options    \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vinfo  7   \NC style      \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vlink  8   \NC family     \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vinfo  8   \NC class      \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vlink  9   \NC source     \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vinfo  9   \NC prime      \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vlink 10   \NC leftslack  \NC                   \NC                  \NC                 \NC              \NC \NR
-    \NC vinfo 10   \NC rightslack \NC                   \NC                  \NC                 \NC              \NC \NR
-    \ML                                                                                          \NC              
-    \NC vlink 11   \NC extra_1    \NC top_character     \NC rule_thickness   \NC degree          \NC list         \NC \NR
-    \NC vinfo 11   \NC extra_2    \NC bot_character     \NC left_delimiter   \NC left_delimiter  \NC source       \NC \NR
-    \NC vlink 12   \NC extra_3    \NC overlay_character \NC right_delimiter  \NC right_delimiter \NC top          \NC \NR
-    \NC vinfo 12   \NC extra_4    \NC fraction          \NC middle_delimiter \NC                 \NC bottom       \NC \NR
-    \NC vlink 13   \NC extra_5    \NC topovershoot      \NC                  \NC height          \NC topovershoot \NC \NR
-    \NC vinfo 13   \NC extra_6    \NC botovershoot      \NC                  \NC depth           \NC botovershoot \NC \NR
+    \BC            \BC noad       \BC accent            \BC fraction         \BC radical          \NC fence        \NC \NR
+    \ML                                                                                           
+    \NC vlink  2   \NC new_hlist  \NC                   \NC                  \NC                  \NC              \NC \NR
+    \ML                                                                                           
+    \NC vinfo  2   \NC nucleus    \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vlink  3   \NC supscr     \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo  3   \NC subscr     \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vlink  4   \NC supprescr  \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo  4   \NC subprescr  \NC                   \NC                  \NC                  \NC              \NC \NR
+    \ML                                                                                           
+    \NC vlink  5   \NC italic     \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo  5   \NC width      \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vlink  6   \NC height     \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo  6   \NC depth      \NC                   \NC                  \NC                  \NC              \NC \NR
+    \ML                                                                                           
+    \NC vlink  7   \NC options    \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo  7   \NC style      \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vlink  8   \NC family     \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo  8   \NC class      \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vlink  9   \NC source     \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo  9   \NC prime      \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vlink 10   \NC leftslack  \NC                   \NC                  \NC                  \NC              \NC \NR
+    \NC vinfo 10   \NC rightslack \NC                   \NC                  \NC                  \NC              \NC \NR
+    \ML                                                                                           
+    \NC vlink 11   \NC extra_1    \NC top_character     \NC rule_thickness   \NC degree           \NC list         \NC \NR
+    \NC vinfo 11   \NC extra_2    \NC bot_character     \NC left_delimiter   \NC left_delimiter   \NC source       \NC \NR
+    \NC vlink 12   \NC extra_3    \NC overlay_character \NC right_delimiter  \NC right_delimiter  \NC top          \NC \NR
+    \NC vinfo 12   \NC extra_4    \NC fraction          \NC middle_delimiter \NC size             \NC bottom       \NC \NR
+    \NC vlink 13   \NC extra_5    \NC topovershoot      \NC h_factor         \NC height           \NC topovershoot \NC \NR
+    \NC vinfo 13   \NC extra_6    \NC botovershoot      \NC v_factor         \NC depth            \NC botovershoot \NC \NR
+    \NC vlink 14   \NC extra_7    \NC                   \NC numerator        \NC top_delimiter    \NC              \NC \NR
+    \NC vinfo 14   \NC extra_8    \NC                   \NC denominator      \NC bottom_delimiter \NC              \NC \NR
     \LL
     \stoptabulate
 
@@ -1627,7 +1629,7 @@ typedef enum simple_choice_subtypes {
 //define noad_state_toptotal(a)    vlink(a,5)
 //define noad_state_bottomtotal(a) vinfo(a,5)
 
-# define noad_size            14
+# define noad_size            15
 # define noad_new_hlist(a)    vlink(a,2)    /*tex the translation of an mlist; a bit confusing name */
 # define noad_nucleus(a)      vinfo(a,2)
 # define noad_supscr(a)       vlink(a,3)
@@ -1663,6 +1665,8 @@ typedef enum simple_choice_subtypes {
 # define noad_extra_4(a)      vinfo(a,12)
 # define noad_extra_5(a)      vlink(a,13)
 # define noad_extra_6(a)      vinfo(a,13)
+# define noad_extra_7(a)      vlink(a,14)
+# define noad_extra_8(a)      vinfo(a,14)
 
 # define noad_total(a) (noad_height(a) + noad_depth(a))
 
@@ -1980,14 +1984,14 @@ typedef enum fence_subtypes {
 */
 
 # define fraction_noad_size        noad_size
-# define fraction_numerator        noad_supprescr /* ! */
-# define fraction_denominator      noad_subprescr /* ! */
 # define fraction_rule_thickness   noad_extra_1
 # define fraction_left_delimiter   noad_extra_2
 # define fraction_right_delimiter  noad_extra_3
 # define fraction_middle_delimiter noad_extra_4
 # define fraction_h_factor         noad_extra_5
 # define fraction_v_factor         noad_extra_6
+# define fraction_numerator        noad_extra_7
+# define fraction_denominator      noad_extra_8
 
 typedef enum fraction_subtypes {
     over_fraction_subtype,
@@ -2004,13 +2008,15 @@ typedef enum fraction_subtypes {
     used for extensibles (over, under, etc) so the name is is somewhat confusing.
 */
 
-# define radical_noad_size       noad_size
-# define radical_degree          noad_extra_1
-# define radical_left_delimiter  noad_extra_2
-# define radical_right_delimiter noad_extra_3
-# define radical_size            noad_extra_4
-# define radical_height          noad_extra_5
-# define radical_depth           noad_extra_6
+# define radical_noad_size        noad_size
+# define radical_degree           noad_extra_1
+# define radical_left_delimiter   noad_extra_2
+# define radical_right_delimiter  noad_extra_3
+# define radical_size             noad_extra_4
+# define radical_height           noad_extra_5
+# define radical_depth            noad_extra_6
+# define radical_top_delimiter    noad_extra_7
+# define radical_bottom_delimiter noad_extra_8
 
 typedef enum radical_subtypes {
     normal_radical_subtype,
-- 
cgit v1.2.3