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 see in the 2.0.41 generated code that it didn't see something:

    class A {
      private var mF;
      function initialize() {
        mF = new F(); // this is the only place mF is assigned it's final
      }
      function x() {
        mF.c();
        { // this is an inlined block
          mF.s();
        }
      }
    }

    It could've replace it with:
    var pre_mF = mF and use it twice;

  • Looking at the orig vs generated code I totally agree with your idea about reusing the variables. Consider:

    function a() {
      b();
      //...
      c();
      d();
    }

    b,c,d are inlined (and possibly other functions are inlined into them)

    when I run this without prettier then all the local variables (including local copies of class members) of b() are freed before c() is called, and c's are freed before d() is called.

    With the optimizer it becomes:

    function a() {
      var pre_...;
      { // block of b()
        var b_local = ...;
        var b_x = mX;
      } // b_local is not freed yet, regarding b_x: it's also not, even if it's not used later in a()
      // ...
      { // c()'s block
        // additional local variables are allocated on the stack
        // not sure, but probably if mX is used here it's not reusing b_x even though it could be declared at the beginning of a and used
       var c_local = 34;
      }
      ...
    }

    So as you suggested moving b_local to pre_common_1 at the beginning of a() and using it instead of b_local and then c_local could spare some, but in real world code because there are huge functions inlined (and nested-inlined) all this could end up being significant.

  • Can't this return null?

    Not if mArr really is an Array<String>; and you've told it to trustDeclaredTypes, so it's going to believe you (also mArr = new [3] should generate a warning).

    So yes, the one exception is that if you say "s as String", and the type checker knows that s is *not* a string (as in your example), it will ignore the cast (we discussed that behavior after the first type propagation release). But again, it should issue a warning in that case.

    You can force it to respect the cast, and suppress the warning by first casting to "Object?". ie "s as Object? as String" will always override what the type checker thinks it knows.

  • So as you suggested moving b_local to pre_common_1 at the beginning of a() and using it instead of b_local and then c_local could spare some

    Yes. I'm going to try doing that.

    When I first implemented inlining, I made sure to insert the blocks ("{ ... }") because I just assumed that would limit the scope of the variables. But its only recently that I started to suspect that thats not the case, and a week or so ago that I actually ran the tests to prove it...

  • It could've replace it with:
    var pre_mF = mF and use it twice

    So if thats the actual code that it failed to optimize, the only reason I can think of is that the optimizer failed to prove that mF.c() can't change mF.

    It is conservative, and in the case of class objects assumes that something that might change a field on any instance, might change the field on this instance. So anything that could create a new A() would be seen as potentially modifying mF, even though in reality it can't (since its only modifying a new instance of F).

    Also, there are cases where it just gives up - eg when it sees method.invoke, or it sees a call to any method of a class whose constructor takes a Method, 

  • wow. big chaos

    [EDIT: I've just found a repro of what I hope is the same issue - very similar errors in any case. So I'm set for now]

    Revisiting this... I just realized I accidentally left some debug logging enabled in the type propagation code. Unfortunately, all the logging goes to the developer console, and its not easy to extract from there; but if you're willing to give it a go...

    First, you need to quit from vscode, and then launch it from the command line (I'm assuming you're still using linux, and have "code" on your PATH):

    % env TYPEFLOW_FUNC='$.C.c' code

    Where the name is the full qualified name of the function you want to debug. Then do a build. Then "Toggle Developer Tools" from the Help menu, and there will be pages (and pages) of debug output looking like:

    [Extension Host] Events:
    workbench.desktop.main.js:89 [Extension Host] ref: $.C.d undefined
    workbench.desktop.main.js:89 [Extension Host] mod: d(42.5) undefined
    workbench.desktop.main.js:89 [Extension Host] Succs: ExSucc:
    workbench.desktop.main.js:89 [Extension Host]% 0 (source/C.mc:7) Preds:
    workbench.desktop.main.js:89 [Extension Host] State:
    workbench.desktop.main.js:89 [Extension Host] - x = Number or Float
    workbench.desktop.main.js:89 [Extension Host] ref: $.C.d == Function<C.d>
    workbench.desktop.main.js:89 [Extension Host] mod: d(42.5)
    workbench.desktop.main.js:89 [Extension Host] merge to:
    workbench.desktop.main.js:89 [Extension Host] Succs: ExSucc:
    workbench.desktop.main.js:89 [Extension Host]% 0 (/Users/mwilliams/www/git/HRMultifield/source/C.mc:7) Preds:
    workbench.desktop.main.js:89 [Extension Host] State:

    (thats the actual start of the output for a modified version of the $.C.c you posted)

    To explain what's in there, its basically a reduced control flow graph, that just has nodes for each read ("ref") and write ("def") of each variable, together will all calls that could modify things ("mod"), and conditionals ("flw").

    I can fairly confidently say that there's no way I could reconstruct your code from it, although I would see the names of all your variables, and some functions, and get some idea of the general flow of control in the function. But if you felt ok with sharing it (eg via a GitHub gist), its possible that I can see why its reporting the errors you're seeing

  • I actually got a Mac :) I did it and it's strange: When I open VSC and then the developer console then I see there what you're looking for, but when I clean the console and then do a Prettier Monkey C: Build and Run Optimized Project then nothing's logged. I'll send it to the email you have in your github profile.

  • then nothing's logged

    You probably need to do "Prettier Monkey C: Clean Optimized Build", or it thinks its already done... but I think I've found the problem anyway...

  • v2.0.42 is out.

    This has a few minor optimization improvements, a bugfix that might address the strange warnings reported, and a big improvement to Goto Refs/Defs and the Link Provider; all of which now use types, so that eg dc.drawText will now recognize that drawText is Graphics.Dc.drawText and provide a link to the documentation. Similarly with user defined types, goto-def and goto-ref should now work when the base object is held in a variable.

  • Unfortunately I don't see any change at all: the same errors, and the code/data size is also the same as with 2.0.41. (although usually it is not necessary after switching version, I even did a clean build this time but nothing changed)