Big update to prettier-extension-monkeyc

I've posted about prettier-extension-monkeyc before, but I've added a bunch of new features that developers will probably like (well, I've been missing them, so maybe you have too).

The new features it implements for VSCode include:

  • Goto Definition. Point at a symbol, Ctrl/Cmd click, and it will take you to the definition. Or F12
  • Goto References. Right click on a symbol and select "Goto References". It will show you all the references. Or Shift-F12
  • Peek Definition/Peek References. Same as above, but in a popup window so you don't lose your place in the original document.
  • Rename Symbol. Right click on a local, function, class or module name, and select "Rename Symbol". It will rename all the references. It doesn't yet work for class members/methods.
  • Goto Symbol. Type Ctrl/Cmd-Shift-O and pick a symbol from the drop down (which has a hierarchical view of all symbols in the current file). This also appears as an outline across the top of the file.
  • Open Symbol By Name. Type Ctrl/Cmd-T, then start typing letters from a symbol name. A drop down will be populated with all matching symbols from anywhere in your project.

Older features include a prettier based formatter for monkeyc, and a monkeyc optimizer that will build/run/export an optimized version of your project.

[edit: My last couple of replies seem to have just disappeared, and the whole conversation seems to be in a jumbled order, so tldr: there's a new test-release at https://github.com/markw65/prettier-extension-monkeyc/releases/tag/v2.0.9 which seems to work for me on linux. I'll do more verification tomorrow, and push a proper update to the vscode store once I'm sure everything is working]

  • Either you have a typo above in the HanSolo project's numbers or you found some special cases that probably

    Yes, I noticed that, and the numbers are correct. Not sure yet what's going on...

    [edit: there are some generally weird results from the new compiler with that project.

    With my.optimizer turned off, the code sizes are

    11026 at -O0 (exactly the same as the old compiler) then 11110 at -O1 (so the code size goes up) then 10154 at -O2.

    With my optimizer turned on, the code sizes are

    9435 at -O0 (exactly the same as the old compiler) then 9523 at -O1 (so again, the code size goes up), and 9445 at -O2 (so better than O1, but worse than O0).

    It makes me think that -O0 actually *is* the old compiler, and then O1 is the new compiler with optimization off, and O2 is the new compiler with optimization on. I've checked a few more projects, and O1 seems to almost always be worse than O0.

    So it looks like the new code generator actually does a worse job than the old one; but the optimizations at -O2 generally improve things enough to get a win. But in the HanSolo-digital project, after my optimizer runs there's very little left for -O2 to do; so we end up with worse results.]

  • I think you could either have a setting that enables the developer to decide if they want to go for "even more" size optimization and then you can add the local variable in this case, or just keep the regular optimizations, or maybe the extension could give hints (probably only when enabled in the settings) for "manual" optimization in this case: "adding var _g = g; could reduce code size"

  • It makes me think that -O0 actually *is* the old compiler, and then O1 is the new compiler with optimization off, and O2 is the new compiler with optimization on

    I did some experiments, and that pretty much seems to be the case. The type checker is always the new one, regardless of optimization level, but at -O0 its definitely using the old compiler to generate the code, because (as noted in various bug reports I made), the lookup rules changed between the old compiler and the new. But at -O0, the new compiler has the same lookup rules as the old compiler.

    One example:

    import Toybox.Lang;
    
    module A {
        module foo {
            const K = 0;
        }
    }
    import A.foo;
    module B {
        class C {
            const K = 1;
        }
        function bar() as Number {
            var foo = new C();
            // returns <local foo>.K (ie 1) with the old compiler, or
            // the new compiler at -O0.
            // returns A.foo.K with the new compiler at -O1 or -O2
            // (and yes, thats bizarre).
            return foo.K;
        }
    }
    

  • I think you could either have a setting that enables the developer to decide if they want to go for "even more" size optimization

    Thats what prettiermonkeyc.sizeBasedPRE does...

  • I could do more, but its a bit time consuming, since the only way I know to get these numbers is to run under the simulator, open the memory panel, and then read off the values from there

    I stared at some .prg files for a while, and figured out that they're basically a bunch of sections. Each section has a 4 byte section type, followed by a 4 byte section length, followed by the section data. I don't know what the other sections are, but the text and data sections were easy to identify by looking at the size in the simulator, and then finding a section that matched that size. So now I can build everything and extract the sizes programatically.

    I've put an initial table, with some explanations here.

  • A prg is in sections with the (:background) stuff first, followed by the (:glance) stuff and then the rest.

    It is done this way so only the background part gets loaded when that runs, for example.  It doesn't load the entire prg for a glance either, but the background part is included..

    Resources can also be scoped so they are available for the background, glance, or just the main app.

  • A prg is in sections with the (:background) stuff first, followed by the (:glance) stuff and then the rest.

    Thanks... that made me dig a bit more, to make sure I wasn't missing background code size. But it looks like thats not the case. All the code goes into the code section (with the identifier 0xc0debabe), but the background code does indeed go *first* in that section. If you compile with -g, you can see that in the compiler's output, and the end of the background code is marked by a label "<endBackgroundCode>".

    I also noticed that when looking at the -g output, you can see the .prg file sections delimited by upper case words. So it looks like:

    PERMISSIONS
      Toybox_Background
      Toybox_Communications
      ... etc
    END
    DATA
    statics:
      CLASSDEF
        APPTYPE 127
        MODULEID statics
        ... etc
      END
    globals:
      ... etc
    <endBackgroundData>
      ... non background data
    END
    CODE
       ... background stuff
    <endBackgroundCode>
      ... non background code
    END
    LINKTABLE
      ...
    END
    RESOURCES
      ...
    END
    EXCEPTIONS
      ...
    END
    SETTINGS
      ...
    END
    

    So each of PERMISSIONS, DATA, CODE, LINKTABLE, RESOURCES, EXCEPTIONS, SETTINGS corresponds to a section in the .prg. Every file appears to have one more section prior to PERMISSIONS that doesn't get listed in the -g output. Not sure what that is, probably a file header of some sort.

    By comparing the -g output with the sections I found, I was able to infer a few more of the section identifiers:

    •   CODE = 0xc0debabe
    •   DATA = 0xda7ababe
    •   PERMISSIONS = 0x6000db01
    •   LINKTABLE = 0xc1a557b1
    •   EXCEPTIONS = 0x0ece7105
    •   RESOURCES = 0x0ff29ff3
    •   SETTINGS = 0x5e771465

    Some of them were clearly picked by someone with a sense of humor...

  • What does mean this numbers especial SETTINGS = 0x5e771465? Is it var symbol?

    I have a little problem with settings due to error with new installation when settings are downloaded from other server and there is lag. So when I call PRP.getValue(property_key); for first time:

    Error: Unexpected Type Error
    Details: Failed invoking <symbol>

    I can emulate the same behaviour on sim trying changing settings with full memory - after saving

    disappears from memory and error...

    So question how to check if settings are already available? I've tried a lot HAS - no success. Maybe there is hidden var/symbol to check it?

  • What does mean this numbers especial SETTINGS = 0x5e771465? Is it var symbol?
    I stared at some .prg files for a while, and figured out that they're basically a bunch of sections. Each section has a 4 byte section type, followed by a 4 byte section length, followed by the section data.

    SETTINGS is the section name in the -g (debug) output, and 0x5e771465 is the 4-byte section identifier (type) in the PRG file.

  • While reporting an error to the CIQ team I noticed that the following original code:

    mCurrentHRField = dataField.createField("h", 0 /*CURR_HR_FIELD_ID*/, Fit.DATA_TYPE_UINT8, { :nativeNum=>3, :mesgType=>Fit.MESG_TYPE_RECORD });

    was optimized as:

    mCurrentHRField = dataField.createField(
    "h",
    0 /*CURR_HR_FIELD_ID*/,
    2 as Toybox.FitContributor.DataType,
    {
    :nativeNum => 3,
    :mesgType => 20 as Toybox.FitContributor.MessageType,
    }
    );
    Note that there's and extra comma before the closing }
    Although it seems to work at least for some devices and even all of the devices that reported System Errors in ERA on this line work in the simulator, so it probably doesn't matter, but because I see a few System Errors in this line in ERA, it would make me sleep better if the future version of the optimizer could remove that extra comma.