You are reading a single comment by @Robin and its replies. Click here to read the full conversation.
  • I've just dug a little deeper and I can reproduce even on a desktop build with:

    g = Graphics.createArrayBuffer(240,240,1);
    g.flip = x=>x;
    Modules.addCached("locale",function() {
      exports.translate = x=>x
    });
    
    E.showMenu = (function(n){g.clear(1);Bangle.setLCDPow­er(1);Bangle.drawWidgets();if(n){var q=g.getWidth()-9;g.getHeight();var f=Object.keys(n),a=n[""];a&&f.splice(f.i­ndexOf(""),1);a instanceof Object||(a={});a.fontHeight=16;a.x=0;a.x­2=q-2;a.y=24;a.y2=220;void 0===a.selected&&(a.selected=0);a.fontHei­ght||(a.fontHeight=6);var r=0|a.x,p=a.x2||g.getWidth()-1,m=0|a.y,u­=a.y2||g.getHeight()-1;a.title&&(m+=a.fo­ntHeight+2);var t=require("locale"),d={lastIdx:0,draw:fu­nction(b,c){var l=0|Math.min((u-
    m)/a.fontHeight,f.length),e=E.clip(a.sel­ected-(l>>1),0,f.length-l);e!=d.lastIdx&­&(b=void 0);d.lastIdx=e;var h=m;g.reset().setFont("6x8",2).setFontAl­ign(0,-1,0);void 0===b&&a.title&&(g.drawString(a.title,(r­+p)/2,m-a.fontHeight-2),g.drawLine(r,m-2­,p,m-2));void 0!==b&&(e<b&&(h+=a.fontHeight*(b-e),e=b)­,e+l>c&&(l=1+c-b));for(;l--;){c=f[e];b=n­[c];var k=e==a.selected&&!d.selectEdit;g.setColo­r(k?g.theme.bgH:g.theme.bg);g.fillRect(r­,h,p,h+a.fontHeight-1);g.setColor(k?g.th­eme.fgH:g.theme.fg);g.setFontAlign(-1,
    -1);g.drawString(t.translate(c),r,h);"ob­ject"==typeof b&&(c=p,k=b.value,b.format&&(k=b.format(­k)),k=t.translate(""+k),d.selectEdit&&e=­=a.selected&&(c-=25,g.setColor(g.theme.b­gH).fillRect(c-(g.stringWidth(k)+4),h,p,­h+a.fontHeight-1),g.setColor(g.theme.fgH­).drawImage("\f\u0005\u0081\x00 \u0007\x00\u00f9\u00f0\u000e\x00@",c,h+(­a.fontHeight-10)/2,{scale:2})),g.setFont­Align(1,-1),g.drawString(k,c-2,h));g.set­Color(g.theme.fg);h+=a.fontHeight;e++}g.­setFontAlign(-1,-1);l=e<f.length;g.drawI­mage("\b\b\u0001\u00108|\u00fe\u0010\u00­10\u0010\u0010",
    q,40);g.drawImage("\b\b\u0001\u0010\u001­0\u0010\u0010\u00fe|8\u0010",q,194);g.dr­awImage("\b\b\u0001\x00\b\f\u000e\u00ff\­u000e\f\b",q,116);g.setColor(l?g.theme.f­g:g.theme.bg).fillPoly([104,220,136,220,­120,228]);g.flip()},select:function(b){b­=n[f[a.selected]];if("function"==typeof b)b(d);else if("object"==typeof b){if("number"==typeof b.value)d.selectEdit=d.selectEdit?void 0:b;else if("boolean"==typeof b.value&&(b.value=!b.value),b.onchange)b­.onchange(b.value);d.draw()}},move:funct­ion(b){if(d.selectEdit){var c=
    d.selectEdit;c.value-=(b||1)*(c.step||1)­;void 0!==c.min&&c.value<c.min&&(c.value=c.min­);void 0!==c.max&&c.value>c.max&&(c.value=c.max­);if(c.onchange)c.onchange(c.value);d.dr­aw(a.selected,a.selected)}else c=a.selected,a.selected=(b+a.selected)%f­.length,0>a.selected&&(a.selected+=f.len­gth),d.draw(Math.min(c,a.selected),Math.­max(c,a.selected))}};d.draw();Bangle.set­UI("updown",b=>{b?d.move(b):d.select()})­;return d}Bangle.setUI()});
    
    var Bangle = {
      setUI : ()=>{},
      setLCDPower : ()=>{},
      drawWidgets : ()=>{}
    };
    
    var c = {};
    c.test = false;
    var main_menu = {
      "Test" : { value : c.test, format : v => v?"On":"Off", onchange : v => { c.test = v; }, },
    };
    var l = E.showMenu(main_menu);
    l.move(1);
    print(c);
    l.select();
    print(c);
    
    

    Turns out it's not a memory corruption issue or anything like that (although the Field or method "testuQå" error does seem ominous). It's to do with how the code for menu.move was minified.

    The function (after minification, and with some semblance of formatting added) is:

    move = function(b){
      if(d.selectEdit){
        var c=d.selectEdit;
        c.value-=(b||1)*(c.step||1);
        void 0!==c.min&&c.value<c.min&&(c.value=c.min­);
        void 0!==c.max&&c.value>c.max&&(c.value=c.max­);
        if(c.onchange)c.onchange(c.value);
        d.draw(a.selected,a.selected)
      } else c=a.selected,a.selected=(b+a.selected)%f­.length,0>a.selected&&(a.selected+=f.len­gth),d.draw(Math.min(c,a.selected),Math.­max(c,a.selected))
    }
    

    Unminified code is:

    move : function(dir) {
          if (l.selectEdit) {
            var item = l.selectEdit;
            item.value -= (dir||1)*(item.step||1);
            if (item.min!==undefined && item.value<item.min) item.value = item.min;
            if (item.max!==undefined && item.value>item.max) item.value = item.max;
            if (item.onchange) item.onchange(item.value);
            l.draw(options.selected,options.selected­);
          } else {
            var a=options.selected;
            options.selected = (dir+options.selected)%menuItems.length;­
            if (options.selected<0) options.selected += menuItems.length;
            l.draw(Math.min(a,options.selected), Math.max(a,options.selected));
          }
        }
    

    I guess it's valid JS, but what the minifier has done is change all variable names to c, and then it has just a single var c in the first if statement, and nowhere else. So if that if doesn't get run in Espruino, no local var is created and it assumes that the var is global, overwriting c.

    So in short:

    • Looks like global variables named c are a no-go in Espruino 2v10
    • I'll get a fix in so the minifier doesn't do this and it's fixed for 2v11
About

Avatar for Robin @Robin started