Easy WASM with Nim / nlvm
Here's a little mini-tutorial on using the latest WASM support in nlvm to call a Nim function from a web page - it's actually surprisingly easy :) WASM is a simple IR / instruction format that comes with a virtual machine specification, similar - well - to any other virtual machine out there. What's particular about it is that it enjoys broad browser support, giving developers an easy way to deploy high-performance code. It can also be used standalone - using Wasmer ([https://wasmer.io/](https://wasmer.io/)) for example. Let's start with a function we want to use from the web: proc fib2(term, val, prev: int): int = if term == 0: prev else: fib2(term - 1, val + prev, val) proc fib(term: int): int {.exportc.} = fib2(term, 1, 0) Run WASM works by compiling code to a binary format, a `.wasm` file. This file is loaded in the browser, and the code therein can be accessed as if it were JavaScript. Compiling to WASM can be done in many ways - a popular way until now has been to compile to C, then use either Emscripten or clang to compile to WASM, sometimes with the help of tooling from the Binaryen project. Recently, I threw in LLVM v8 support in nlvm which comes with a library for linking - lld. In the future, this library will be used to make nlvm completely standalone - no gcc or msvc needed - but for now, only WASM is enabled. Linking in the C world is surprisingly onerous and full of thorny legacy / compatibility issues. Fortunately, compiling fib to wasm is a simple single-step process: nlvm c -d:release --nlvm.target=wasm32 --gc:none -l:--no-entry fib Run wasm32 mode in nlvm implies `--os:standalone` \- the normal `C` functions like `printf` are not available here. Depending on where the wasm code runs, it will have a sandboxed environment available, such as the browser or WASI - but accessing this will require a little bit more work on both the nlvm and Nim standard library sides. `--os:standalone` means that a panicoverride file is needed for the Nim standard library - we'll start with a bare-bones version of it - name it panicoverride.nim and drop it next to fib.nim: proc rawoutput(s: string) = discard proc panic(s: string) = rawoutput(s) Run The final piece of the puzzle is to load the wasm file in the browser: http://www.w3.org/1999/xhtml;> Fib // response.arrayBuffer() ).then(bytes => WebAssembly.instantiate(bytes) ).then(obj => { document.getElementById("btn").addEventListener("click", function() { document.getElementById("here").textContent = obj.instance.exports.fib(document.getElementById("x").value); }, false); }); //]]> Answer: Run Type in 10, and hopefully you get 55 back - type in 50, and a surprise is waiting for you - bonus points if you can figure it out :) You can tell I stopped writing HTML when blink was still around. Behind the scenes, nlvm will translate the Nim code to LLVM IR that looks like this: ; ModuleID = 'fib' source_filename = "fib" target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32" @nim_program_result = local_unnamed_addr global i32 0 ; Function Attrs: norecurse nounwind readnone define i32 @main(i32, i8** nocapture readnone) local_unnamed_addr #0 { secArgs: ret i32 0 } ; Function Attrs: nounwind readnone define i32 @fib(i32 %n) local_unnamed_addr #1 { secAlloca: switch i32 %n, label %ifx.false.fib.2.13 [ i32 0, label %ifx.end.fib.2.1 i32 1, label %ifx.true.fib.2.12 ] ifx.true.fib.2.12:; preds = %secAlloca br label %ifx.end.fib.2.1 ifx.false.fib.2.13: ; preds = %secAlloca %binop.Sub.fib.4.12 = add i32 %n, -1 %call.res.fib.4.10 = tail call i32 @fib(i32 %binop.Sub.fib.4.12) %binop.Sub.fib.4.24 = add i32 %n, -2 %call.res.fib.4.21 = tail call i32 @fib(i32 %binop.Sub.fib.4.24) %binop.Add.fib.4.16 = add i32 %call.res.fib.4.21, %call.res.fib.4.10 ret i32 %binop.Add.fib.4.16 ifx.end.fib.2.1: ; preds = %secAlloca, %ifx.true.fib.2.12 %ifx.res.fib.2.1.0 = phi i32 [ 1, %ifx.true.fib.2.12 ], [ %n, %secAlloca ] ret i32 %ifx.res.fib.2.1.0 } attributes #0 = { norecurse nounwind readnone } attributes #1 = { nounwind readnone "no-frame-pointer-elim"="true" } Run Notice how there's some cruft in there - a main function and the `nim_program_result` global. What's nice however is that `llvm` has been able to transform the recursive
Re: Ebnf Lexer and Parser generator in nim
Add option and repeat in [https://github.com/loloiccl/nimly/pull/22](https://github.com/loloiccl/nimly/pull/22)
create lib*.so
trying to link a library created in Nim to R proc sumTillNegative(x: varargs[int]): int = for i in x: if i < 0: return result = result + i proc sumTillNegative(): int {.cdecl, exportc, dynlib.} # compiled with nim c --app:lib test.nim # in R x<-dyn.load("libtest.so") getDLLRegisteredRoutines(x) >data frame with 0 columns and 0 rows what went wrong? Thanks in advance!
Re: Why Nim so inconsistent?
Let me question Java/Go/Nim readability... What is more readable? addConstraint(x.plus(y).lessThanOrEqual(x.times(newConst(5).plus(z)) Run or addConstraint(x + t <= x * (5 + z)) Run I would say, if you want to write readable code nim gives you means to do so. If you want to write unreadable code, no language shall prevent you from doing that.
Re: nimpretty non installed by choosenim stable
or you could just clone the nim repo and build it yourself
Re: nimpretty non installed by choosenim stable
Then to install it have I only to wait next releases?
Re: Why Nim so inconsistent?
> Human beings write code. YMMV, but most devs I know read a lot more code than they write - their own and others' \- optimizing for human reading seems like a reasonable priority then, if you're trying to save time.. it compounds too - if a dev is able to read somebody else's code, they might not have to write any code at all :)
Printing Unicode characters (Runes) and UTF8 Strings
Hi guys. I'm trying to use the box-drawing characters of Unicode to draw some fancy dialogs at the terminal. I could do it without problems but I'm trying to find if there is a more "straightforward" form. The codepoints are defined as: type DialogBorderRunes = enum dbrHLine = 0x2500 dbrVLine = 0x2502 dbrTopLeft = 0x250C dbrTopRight =0x2510 dbrBottomLeft = 0x2514 dbrBottomRight = 0x2518 Run I can "draw"the top of the dialog with styledWrite in this manner: setCursorPos(left, top) stdout.styledWrite(bg, Rune(dbrTopLeft).toUTF8() & Rune(dbrHLine).toUTF8().repeat(dlgWidth-2) & Rune(dbrTopRight).toUTF8()) Run All works ok, but how about the efficiency in instancing `Rune` and converting to UTF8 repeatedly? Considering that Nim string is UTF8, I'm wondering if I can do something like: stdout.styledWrite(bg, "\x250C") & "\x2500".repeat(dlgWidth-2) & "\x2510) Run I mean embedding the character codepoint in the string itself instead of creating a Rune a converting it to UTF8 subsequently? Thank you very much.
Re: nimpretty non installed by choosenim stable
You're not doing anything wrong, choosenim just hasn't been updated yet to support installing nimpretty..
nimpretty non installed by choosenim stable
I have installed nim on Ubuntu with choosenim the stable channel, nim-0.19.4. The installed tools are: choosenim, nim, nimble, nimgrep, nimsuggest. Why nimpretty has not been installed? What I'm doing wrong? Thanks in advance for any help.
Re: Are the docs wrong, or is there a compiler bug?
@mratsim I don't like this change and as we can see, it doesn't even work.
Re: Are the docs wrong, or is there a compiler bug?
I thought "type" was supposed to replace typedesc in parameter passing?
Re: getch() vs Cyrillic on Windows.
Winim library from Ward has a lot of facilities to deal with windows strings. Look it up on github.
Re: getch() vs Cyrillic on Windows.
Feel your pain. I gave up and ended with this project myself already: [https://github.com/Guevara-chan/ConIO](https://github.com/Guevara-chan/ConIO)
Re: Owned refs
> Don't try the templates, they will lead you into a dead end... "People who think they know everything really annoy those of us who know we don't." > I had a pool allocator in mind, where the allocator draws memspace from a > list of memory regions and the refcount bookkeeps the refs (summarized) into > entire regions. When such a refcount becomes zero, then the entire memory > region will get freed and therefore, you will get some speed. That's coarse grained refcounting, you save the inner-region pointer update RC ops, but the stack RC ops remain. It also has nothing to do with Bacon/Dingle. Just like a > if there are some. The primary problem of Bacon/Dingle are the abundant > refcount updates coming from local refs on the stack. Something that the > recent GC avoids. Deterministic deallocation is not automatically making > Bacon/Dingle a better design. No, indeed, it's not automatically better, but I wrote about its benefits, for Nim, and I don't like repeating myself.