Demo: LFortran in the browser

Ubaid Shaikh (@Ubaid-Shaikh) who is this year’s Fortran-lang/LFortran GSoC student has created a demo of LFortran running fully in the browser:

It uses his WebAssembly backend that he wrote (so LFortran is compiled without LLVM, and thus it is much smaller / loads faster and it also compiles faster). The page allows you to execute Fortran code, as well as show AST, ASR, WAT and C++ translations.

You can try to break the code, either wrong syntax or wrong semantics and you should get a nice error message, in color, with the line highlighted and exact code underlined, etc.

Current limitations:

  • The LFortran runtime library is not supported yet, so you cannot use functions like sin(x). We’ll fix that later.
  • LFortran itself does not yet compile all of Fortran yet, I would say it’s somewhere between alpha and beta.
  • The ASR->WASM backend that Ubaid is writing that the above demo uses currently supports a smaller subset (much less than our default LLVM backend), that is the main task of his GSoC project to expand it to support everything

What I really like is how fast it compiles, it seems immediate for me on my phone or computer (when you click the “Run” button). And also the page seems to load very fast.

Once this is more tested, and we get the runtime library working, I would like to have it on lfortran.org page itself (probably a subpage, not the very front page).

Please let us know any feedback!

23 Likes

Amazing work and great start! I really like the AST and ASR panels, one thing you might want to consider is to decrease the indentation to 2-spaces in the AST/ASR output for things to look more readable.

I think this is a great idea. I would be curious to know if it is possible to merge this project with the Fortran Playground GSoC project.

Great job overall and I look forward to more updates.

2 Likes

Thanks @gnikit for the feedback and encouragement!

I think once the Playground has a demo, we can see if there is a way to share some of the JavaScript code, and collaborating. For LFortran most of the work is on LFortran itself, mostly working on the WASM backend, and getting the runtime library working; so it’s not a blocker for us right now.

I’m glad that LFortran is becoming more accessible. The sample code shown is

program expr2
    implicit none

    integer :: x

    x = (2+3)*5
    print *, x

end program

giving 25. Generalizing this to a loop with

program expr2
    implicit none
    integer :: i
    do i=1,5
       print *, (2+3)*i
    end do
end program

LFortran says

ERROR: The code could not be compiled. Either there is a compile-time error or there is an issue at our end.

For

program expr2
    implicit none
    integer :: i
    i = 3
    print*,i**2
end program

LFortran says

code generation error: IntegerBinop: Pow Operation not yet implemented

For the following program, which a teacher could use to demonstrate Fortran syntax,

program print_fib
implicit none
integer, parameter :: n = 10
integer :: i,fib(n)
fib(1) = 0
fib(2) = 1
do i=3,n
   fib(i) = fib(i-1) + fib(i-2)
end do
print*,fib(n)
end program print_fib

LFortran says

code generation error: Assignment: Arrays not yet supported

A known issue of LFortran is the lack of support of array constructors. For the program

program array_constructor
print*,10*[1,2]
end program array_constructor

LFortran says

ERROR: The code could not be compiled. Either there is a compile-time error or there is an issue at our end.

The programs at FortranTip, except for those demonstrating C interoperability, are single-file programs that compile to an executable. Many of them use array constructors. Once that is implemented, I would like to see what LFortran compiles and runs.

2 Likes

Thanks @Beliavsky for the feedback. All the examples work with the default LLVM backend, so it means they are not yet implemented in the WebAssembly backend that Ubaid is working on. He will implement the missing features pretty soon.

Btw, if you click on the AST or ASR tabs, you will see that your examples will load there correctly (WAT will fail).

The last one is not yet supported, so I opened up an issue: `10*[1,2]` fails (#716) · Issues · lfortran / lfortran · GitLab (it will work in the AST tab, but not ASR or WAT).

2 Likes

This is excellent and I am very glad to see the progress with LFortran. I really cannot wait until it is production-ready!

I tried it on my phone and it was also immediate, responsive and quick to load. :+1:

Incidentally, while we are discussing LFortran, is it now possible to include C headers and call C code or is this still a work in progress?

2 Likes

@general_rishkin, thanks!

Yes, C interop works very well already (I would say that part of LFortran is already “beta”). Here are the tests: integration_tests/modules_15b.f90 · master · lfortran / lfortran · GitLab, they all compile and run using the LLVM backend. If you find anything that does not work in the C interop, please let us know and we’ll fix it.

1 Like

Thanks, @certik. I will go through these.

2 Likes

Exciting possibilities. Any chance of an output window being an IFRAME or HTML5 CANVAS so the output could be graphics (ie. CANVAS, SVG, pixmap) ? I know it is very early, but in the long run that would hopefully be a feature?

4 Likes

Yes, we definitely should do that. Here is an issue about how to design these rich outputs from Fortran to work with Jupyter: Design plotting from Fortran (#209) · Issues · lfortran / lfortran · GitLab, and I think exactly the same or similar design can be used as well for this demo. Essentially instead of writing a main program, you write a module, and in there you implement a function with a special name, perhaps “lfortran_wasm_output_image”, and then you return an array with the image. We compile to WASM, find this function and call it. We have to figure out how to get the array out into JavaScript, I assume it will be similar to how the C interoperation works for arrays. Then in JavaScript we simply convert into an image and show it.

The alternative approach is to import special functions into WebAssembly that can draw on the canvas, I believe WASM can interact with it. Then we expose them as a special module, say “wasm_canvas”, that you simply “use” in your main program to draw. That might be a more versatile approach.

Brainstorming a little more, just like we have bind(c), we either could use that, or we might add bind(wasm). Either way, we would implement wasm_canvas as a regular Fortran code that uses bind(wasm) (or bind(c) if it can be made to work) to call functions from “wasm” (that would be provided by JavaScript into the wasm runtime as “import” functions).

1 Like

Something like this?

Still a very early prototype, but hopefully it shows the possibilities. Notice how incredibly fast it is — it fully compiles the code and runs it. All regular Fortran, we even piggy back on the bind(c), which the WASM extension understands and it will import the given function from JavaScript.

@Ubaid-Shaikh has done an amazing job with this.

11 Likes

@certik, most exciting, thanks for sharing! It really exemplifies what you wrote in terms of, what was then almost a vision, “why Fortran”! It’s tremendous to see how that it coming into reality.

A quick question as you advance LFortran: as you will know, the standard stipulates a specification statement/construct not be in the executable section. Does the interactive/REPL facility of LFortran also mean this constraint in the standard is to be overlooked? I ask because the Mandelbrot example has an INTERFACE block at the end of the program, within the executable section which makes it nonconforming.

1 Like

Yes, I noticed that too. I just fixed the example code in Example code: Move the interface section up by certik · Pull Request #16 · lfortran/lcompilers_frontend · GitHub.

For the bigger question how to handle this in general, it seems in a REPL case you want to be able to specify such interfaces anywhere. But when compiling code that is “well formed”, such as the Mandelbrot example above, I think LFortran should give an error message, so I opened up an issue for that: Give error message for misplaced interface block · Issue #600 · lfortran/lfortran · GitHub.

2 Likes

Just wonderful! I guess the intrinsics are not available yet? I wanted to use the classic “plasma” screen saver algorithm to empirically see how fast it would display (sometimes seen in screen savers, several examples of which at Rosetta Code, for instance) but at least the ones I have use SIN(), COS(), FLOOR(), … and I got an error indicating they are not yet available(?). Still hints at great possibilities.

3 Likes

Yes, all intrinsics that call into C are currently not implemented yet. Currently sin/cos are calling into C (libm), so we have to still implement it in WebAssembly.

1 Like