F# running on the Espruino

Posted on
  • So when I first heard of the Espruino, I quickly dismissed it. There are plenty of good dynamic-typed programming languages that I like better than JavaScript. I am not a C-only kind of person for embedded, but JavaScript just sounded lame.

    However, I thought of one big advantage of JavaScript -- lots of languages compile to it. Due to being a limited embedded device, I figure something like emscripten is out of the question. FunScript is a F# to JavaScript compiler that doesn't work the same way a lot of other compilers work (for better and worse). It doesn't treat JavaScript as an assembly language. It essentially does a syntax translation replacing one language's features with another through pre-defined patterns and macros. The resultant F# code is very verbose but pretty close to how someone would write it if a human translated it.

    I was able to get some basic FunScript programs running on the Espruino without much difficulty. The semi-colon generation rules aren't quite the same. I have to add an extra one to the end of the program and sometimes I get a warning about too many. At least for the simple things I tried, it works really well.

    I just wanted to share my positive experience. I have run F# on full Linux ARM boards (with Mono) but never something so light-weight before. There are those .Net Micro boards but they don't support F#. While I initially snubbed JavaScript, it proved to be just the ticket for doing F# on embedded.

    I searched the forums and didn't see any mention of F#. Anyone else try something similar? I am very new to Espruino, any limitations I am likely to run into?

  • Hi, thanks for letting us know - that's really neat.

    I don't know of anyone doing similar things - except http://smartmobilestudio.com/ who compile Pascal into JavaScript.

    Apart from running out of memory, and the code not being as fast as executing pure .NET bytecodes, I don't think you should hit many problems. Let me know if you do though!

    The only things I can think of the could cause issues are:

    • Regular expressions not implemented yet
    • Lack of labels on loops/etc
  • I can see the lack of regex being a limitation. FunScript translates the .Net regex library into JavaScript regex calls rather than implementing an engine itself.

    The good thing with compiler output is it tends to follow similar patterns rather than using a large mix of programming language constructs. So I doubt lack of labels will be much of an issue.

    I haven't tried anything very large but I could see it running out of memory. The code it generates defines variables and functions more often than is truly needed. I might end up running it through an optimizer first. I am sure you don't have tail call optimization -- even the more sophisticated JS engines don't have it. It would be nice, but with a mix of imperative code not a blocker. I am not too concerned with speed of execution, that limitation is expected with the software architecture.

    I am just excited that it worked, and wasn't very hard to get going either. F# has nice features like computational expressions that help simplify async code better than promises or other techniques. I also like the pattern matching, better syntax and type checking.

    While the idea of JavaScript on embedded seems odd, it is very impressive that you got it working. I am sure that was quite a challenge. I am sure I will experiment more with the platform. Right now, I am just building out foreign function interfaces for the Espruino variables and functions.

  • So I ran into a few issues that I tracked down to the way the F# compiler generates code that references global variables. Rather than just do "Serial1.print()", it generates "window.Serial1.print()". It likes to do that so it doesn't have to deal with variable name collisions for global objects it doesn't know about. I am running 1.71 on my board and some things work but I have seen some odd behavior that doesn't happen if I don't use the window object.

    I figured I would debug into it and try the latest code from github. At least compiled for Linux, there is no global "window" object.

    What is the general direction for the project? Do you want and have plans for supporting the "window" object? Or is that not desirable and you expect everyone to use the global objects directly? What I would like to decide is if it is worthwhile to dig into the source code to work out theses issues or if I should create my own "window" object with the Espruino globals as members.

  • Just experimenting some more, I found if I add: "window = this;" at the top of my program, the odd behavior is solved -- at least for the serial object.

  • I wonder if there's a way to tell it not to do that, or tell it that those functions exist?
    You could always post-process it (ie, find/replace "window." with "")

  • // minor nitpick...

    function f(scope) { scope.someFunc(); }

    // works with window = this;, but not with replace window.

  • Do you want and have plans for supporting the "window" object?

    Not really - it's not exactly a JS 'standard', and it makes very little sense on an embedded device that doesn't have windows :) For instance node.js doesn't have a window object either, it has something called global.

    global is something I'd like to add though, but as you noted it's very easy to fake it var global = this; at the start of the program.

    works with window = this;, but not with replace window.

    Not sure I understand the problem? Can you give an example of what doesn't work?

  • you can probably just delete my comment from your RAM, I doubt it illuminates anything...

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

F# running on the Espruino

Posted by Avatar for dferyance @dferyance