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]

  • I think you (like me :) start to think about how to implement a feature even when someone just asks you what do you think about it...

    Here you seem to be talking about "the opposite" thing. I'm not sure I understood, but if I got it right then you're saying that in theory you could collect all the string literals in the program and search for common sub-strings and then do some magic? Kind of what I did in my small function.

    But this is not what I asked for (yet ;) I already did that optimization in my function, and what I ask is that the optimizer consider it (whatever I already hacked there). I think your assumptions of replacing "x + y" with eval(x+y) makes more sense for numbers, where the potential gain is more obvious (you probably gain because you remove operators, remove duplicated code, and all we have to pay is a few bytes for adding a new variable. And as you said you already know the code size of operations, adding variable, etc) To me it looks like while you can write your semantic rules also for strings (where a+b != b+a...) but this is only half the picture, because the strings size can be relatively big to numbers. Now of course you could tell exactly the same and bring this up as a potential to gain much more than with numbers :) I just think that adding some more knowledge to the optimizer could improve string optimizations, and still keep it general (and optimized for the "average" app :)

    I agree that you can't check all the possible combinations of decisions. And probably for average developer's average code (I can guess that except the 10 developers who write the most comments in the forum the optimizer does magic^2) it'll be a huge gain anyway. Maybe my "mistake" was that I looked sometimes at the generated code and started to play with it, compared different versions myself (without the optimizer) and started to pick up "good" ways to do things so my code became more and more pre-optimized, and this might in some cases produce a bit less optimized code when using the optimizer. And maybe even this is just an illusion (I know I gain way more from using the optimizer than I could do manually, unless for example I inline everything...) 

  • So when I click on the file to be opened it doesn't know which one it is

    I've not had much luck tracking this down - except in one case that I don't think applies to you. If I create a build task looking like:

      "tasks": [
        {
          "type": "omonkeyc",
          "device": "approachs60",
          "simulatorBuild": true,
          "problemMatcher": [
            "$monkeyc.error",
            "$monkeyc.fileWarning",
            "$monkeyc.genericWarning"
          ],
          "label": "Optimized Test Build",
          "group": "build"
        }
      ]
    

    where the problemMatcher field lists the three garmin monkeyc problem matchers, then those problem matchers also match the errors (in addition to my built in matchers). But garmin expects absolute paths.

    So all the errors are double reported in the problems panel. First come all the "/source..." files, with the associated errors; and then the "source..." files, with the same set of errors. clicking on the first ones fails because the files don't exist, but the second set (which you have to scroll down to) do work.

    I've made several attempts to remove any problemMatchers that the user has added, and nothing seems to work. I can't figure out how they're getting invoked. So if you do create a task like the above, you're definitely going to have issues.

    But when I just run "Build Optimized Project" from the command palette, or create a task *without* the problem matchers, everything works as you would expect.

  • But this is not what I asked for

    Not per se, no. And as I said, you can expect it to be a while before I get around to working on something like that.

    But what I'm saying is that its the only realistic way to do it. At least automatically.

    I can certainly give you options to turn off constant propagation for strings; or to turn off constant folding for strings (or both).

    But determining when it's going to be good or bad for size up front is pretty much impossible (as I've tried to describe before).

    Fixing it after the fact is probably doable, but certainly not straightforward (at least, if I want to do it without using an exponential time algorithm).

  • I tried to reproduce now and it doesn't happen. strange.

  • It happened now again Slight smile But I don't know what's different...

  • It happened now again

    Well, while trying to figure out a way to prevent the "problemMatchers" field from causing this issue, it suddenly started happening for me. This time I think it's the same issue you're seeing. Just to confirm:

    You're seeing this issue when you ctrl-click on the paths in the output pane, correct? But if you go to the "Problems" pane, the links work?

    That's what I'm seeing, at any rate. And the issue seems to be that VSCode is picking a random directory to form the paths relative to, even though I explicitly change the directory to the project root.

    To fix the problemMatchers issue, I've just changed the error message format slightly, so that Garmin's monkeyc problem matchers don't recognize my error messages. I'm not sure yet whether I can fix the issue in the output pane without resorting to full paths, and if I don't find something soon, I'm just going to give up and do that...

  • Yes, that's exactly what happens to me as well

  • I changed the settings for Prettier Monkey C: Type Check Level from "Off" and I see this new warning:
    "DataFieldAlert will only be found when compiled with compiler2 at -O1 or above"

    What does it mean?

  • DataFieldAlert will only be found when compiled with compiler2 at -O1 or above

    The lookup rules changed between compiler1 and compiler2 (ie 4.1.5 and earlier vs 4.1.6 and later) - but only if you use -O1 or above.

    After "import Toybox.WatchUi;", for example, you can say "new Menu2(...)" with compiler2 at -O1, but you have to say "new WatchUi.Menu2(...)" with compiler1, or at -O0.

    What's worse, is that the compiler1 (or -O0) type checker doesn't complain. So the code compiles, but crashes at runtime.

    Note that this is all made more complex by the fact that if you put it in a non-static method of a class that extends a class thats declared in module M, then even with compiler1, you *can* access any name from module M directly (and in this case, you don't even need the import for it to work; but the type checker will tell you that you do). ie, in the previous example, if you're writing a class that implements DataField, then its non-static methods *can* just do "new Menu2" even with compiler1. Again, my optimizer *should* recognize this, and only warn about cases that really won't work.

    I want to be able to switch back and forth (and I assume others will too), so I added a warning that lets you know when you write code that won't work at -O0, or if you switch back to 4.1.15 or earlier.

    I don't understand the TypeCheckLevel change though; there's a completely separate flag that (should) control this - "CheckCompilerLookupRules", and for me that seems to be the case. Also, the flag should default to WARNING anyway...

  • Maybe i changed multiple settings. Can the warning be clearer? Can it tell me that i forgot to import something?