Re: sl command of nim
Yeah, Nmimmin' like it's 1993!
Iterator arguments
I'm trying how far I can get mimicking Lua's asymmetric coroutines in Nim, using iterators and some macros - not unlike asyncmacro. The manual is a bit vague about iterator arguments - it states that you need to provide the arguments to each call, or wrap the thing in a closure which does that for you. But I want to leverage the fact that I can pass _different_ arguments to each call - is that considered safe and well defined behaviour? It works for me now, but is this intented an something one can rely on to be like this in the future?
Re: Nim OS porting
For a "real" port, check the Git logs to see what was done for another platform, for example the nintendo switch and learn from that. For a bit more lightweight port you might be able to compile with \--os:any and -d:useMalloc; in this case Nim will have very few dependencies on your operating system, apart from some basic ANSI C functions like malloc/free/fopen/fwrite.
Re: Finally, I can do functional programming on tiny embedded systems
@foldl: Consider adding these as well: --exceptions:goto -d:noSignalHandler to further decrease your binary size.
Re: generate c++ code from .nim file
Sorry, no. The Nim-generated C and C++ code is ment to be read by - and highly optimized for - compilers, not humans.
Looking for a new home for Nimz3
Some time ago I made a little Nim binding and DSL around the Z3 theorem prover, which can be found at [https://github.com/zevv/nimz3](https://github.com/zevv/nimz3). I made this mostly for fun and learning purposes, but never got to properly maintain or document it. Nimz3 has recently be picked up by Araq for the new "DrNim" project, and I start getting some issues and pull requests on the repo as well. Unfortunately I currently lack both time and motivation to give this package the love it deserves, so I'm looking for someone who wants to adopt to prevent it from gathering dust and unanswered github issues.
Re: Equivalent of VBA With structure
Same here: I'm also interested to hear exactly what problems you are seeing with the `with` package and happy to see if I can help you out.
Re: Fizzbuzz game
@miran: I was just hinting at using the `case` as an expression. I wonder though why you missed the obvious since you are trying so hard: :) for n in 1..100:echo [$n,"Fizz","Buzz","FizzBuzz"][int(n%%3<1)+2*int(n%%5<1)] Run 78
Re: Fizzbuzz game
for i in 1..100: echo case i mod 15: of 0: "FizzBuzz" of 3,6,9,12: "Fizz" of 5,10: "Buzz" else: $i
Re: Trying to make program cycle-free with ARC
getAllocStats() only keeps track of allocations with `-d:allocStats`. It's only there for Nim's own test suite now and is of limited use, as some allocations will only be cleaned up after the main code, so these can not be properly reported from within your Nim program itself. At this time Valgrind is probably still the best tool for hunting leaks.
Re: TXT DNS lookup
On the one side it would be nice to have native DNS lookup code in Nim, as this could play nice with async and could finally make connect() and dial() and friends really asynchronous. The downside is that resolving is historically really a task for the OS, as there are more potential sources for doing lookups (/etc/hosts, DNS cache, LDAP, etc).
Re: Most efficient way to implement a stack using Nim?
I use seqs as stacks extensively in one of my projects, and I found these are generally ok _unless_ you need to unwind your stack frames more then one item at a time: I believe `setLen()` can invoke the GC and cause performance degradation. Instead, I use a seq for storage but keep my own top value and provide some access functions which merely update the top value and read/write the seq's contents.
Re: Advent of Nim 2019 megathread
I almost got convinced to defect to Ocaml, but sticking to Nim for this year: [https://github.com/zevv/aoc2019](https://github.com/zevv/aoc2019). Enjoy people!
Re: What does the ``.inject.`` pragma do? Where is it defined?
Explained in [https://nim-lang.github.io/Nim/manual.html#templates-hygiene-in-templates](https://nim-lang.github.io/Nim/manual.html#templates-hygiene-in-templates) Any variables declared in a template annotated with {.inject.} will be accessible in the scope where the template is called, effectively injecting the variable from the template into the location of the call.
Re: pegs: match without guessing openarray size
Not part of the stdlib, but NPeg shoild be able to do this for you at compile time: import npeg static: let p = peg rule: rule <- "cd" * +Space * >Alpha * ":": echo $1 discard p.match("cd c:\blue\monkey\bike") Run
Re: code to unpack (msgpack) and "cast" object to
There is the excellent msgpack4nim library that does exactly what you are requesting: [https://github.com/jangko/msgpack4nim](https://github.com/jangko/msgpack4nim) Does that not fit your needs?
Re: Is there a way to write tests & benchmarks for functions operating on NimNode?
The default unittest module also works at compile time, so you should be able to use this for your testing needs. I recently found the need for benchmarking at compile time as well, but none of the obvious methods are available at compile time. I found myself printing dots to my terminal ever 10ms and then counting dots between echo output - not the most productive method. I guess we should file an issue for this and see if we can get a basic cpuTime() and a monotonous clock available in the Nim VM.
Re: How can I limit VM addresses size using Nim type system?
Do subrange types not offer what you are looking for? type VmAddr = range[0..63] Run PS: I wrote a forth once, and it's even in production in a few embedded devices! See [https://github.com/zevv/zForth](https://github.com/zevv/zForth)
Re: getFilePos - inconsistent output
Hmm, reading the implementation of open() I just realized there is no way to _not_ open in binary mode. So then again I'm not really sure what your problem is. I'm afraid I can't help you out here, I don't have access to a windows machine to see if I can reproduce.
Re: Ebnf Lexer and Parser generator in nim
Hi @spip, Sorry, only noticed your post just now - for future communication feel free to post into the NPeg issues at github so I get properly notified. > It has its own grammar syntax for rules that does not follow (E)BNF like > Nim's pegs This is a design choice: having a grammar parseable by the Nim compiler has a number of advantages: * Reduced code size because there is no need to create a parser for the grammars itself. Of course this could be made in NPeg itself, but that's a bit of a chicken-and-egg problem :) * Implementation in Nim macros allows for smooth mixing of grammars and nim code, so there is no need for nasty tricks to get nim code back from string grammars etc * Not very important but still nice: syntax highlighting generally keeps working withing macro DSLs This said, it would probably be not too hard to create a (E)BNF compatible parser with everything that is now in place. I do see some problems with this though: (E)BNF and PEG grammers may _look_ similar, but are not trivially compatible (for example, ordered choice in PEGs). You simply can not parse any arbitrary (E)BNF grammar with a PEG, there are always things that need some reordering or rewriting to make them PEG compatible, or at least more efficient to limit backtracking. (On the other hand: the current syntax is not too far from (E)BNF. For example, take a look at src/npeg/lib/uri.nim for a PEG translation of RFC3984.) Also, the (E)BNF syntax would need a number of extensions in order to specify captures or other actions to perform at parse time, which kind of defies the purpose of having a compatible grammar to start with. Last but not least: I see no clean way to mix grammar and Nim code. I'm very much open to any ideas and experiments, so let me hear if you have any practical suggestions! > It does not support Unicode, meaning being able to parse UTF-8 strings using > Runes Like I said in the manual: there is rudimentary UTF-8 support available, and I'm not sure what exactly would be needed to make NPeg really "UTF-8 compatible". Over the last few days I added proper library support for NPeg, and started a bare minimum utf8 lib. The same applies here: I'd be glad to hear any ideas you might have and I'm happy to see if we can make NPeg suit your needs!
Return a table from a macro: "Error the field 'data' is not accessible'
I'm trying to return a Table from a macro using "quote do", but the generated AST contains fields that are no accesible outside the tables module /tmp/t.nim(8, 3) Error: the field 'data' is not accessible. Run import macros import tables macro foo(): untyped = var a = { "one": 1 }.toTable quote do: `a` let b = foo() echo b Run The AST for the table itself looks like this: (data: [(34912920694978458, "one", 1), ...], counter: 1) Run
Re: Passing a type through a macro?
So, now I ended up with this (thanks Jasper): template skel(T: untyped): untyped = let fn = proc(): T = echo "I am fn" fn proc gen(T: NimNode): NimNode = getAst skel(T) macro foo(T: typedesc): untyped = gen(T) discard foo(int)() Run I know there are very good reasons why things work the way they do, but the above is not obvious, trivial or simple. There is a thing called generics, but you can't use it for macros, and all macro arguments are NimNodes, except for typedescs. The generics/Nim-idiomatic way to do this would be something like this: template skel[T](): untyped = let fn = proc(): T = echo "I am fn" fn proc gen[T](): NimNode = getAst skel[T]() macro foo[T](): untyped = gen[T]() discard foo[int]()() Run Maybe one day in Nim 2.0 :)
Re: What text editor are you using for Nim?
I used to use Vim, but @leorize made me change to nvim because he is still refusing to port his _excellent_ nim.nvim plugin to vim8. (hint! hint!)
Re: Passing a type through a macro?
Well, do I feel _stupid_ now :) Thanks!
Re: Passing a type through a macro?
@kaushalmodi: also tried the static variants, no luck @jasper: No reason other then I just happened to write down these two of the numerous posibillities I have tried - `proc gen(T: NimNode): NimNode` also doesn't work. Have I hit some bug?
Passing a type through a macro?
I have been trying to figure out how to get this working for the last few days, but no luck yet. Consider this snippet: template skel(T: untyped): untyped = let fn = proc(): T = echo "I am fn" fn proc gen(): NimNode = result = getAst skel(int) macro foo(): untyped = gen() let f = foo() Run This is the bare minimum I can reduce my real life code to. The macro `foo()` calls proc `gen()` to generate code. `gen()` runs `getAst()` on template `skel()` which contains the code that should be generated. The code is organized like this for good reasons: in my real code `gen()` generates a bit more code which gets injected in the `skel()` template, so I think I can not easily make big structural changes. The above works, but I am looking for a way to get the type `T` all the way out as a parameter the `foo()` macro. Ideally, this is what I would like to do, although it does not compile: template skel(T: untyped): untyped = let fn = proc(): T = echo "I am fn" fn proc gen[T](): NimNode = result = getAst skel(T) # <-- error: Error: getAst takes a call, but got getAst macro foo(T: typedesc): untyped = gen[T]() let fn = foo(int) Run I do not understand what Nim is trying to say here `getAst takes a call but got getAst`? So let's pass the type as an argument: template skel(T: untyped): untyped = let fn = proc(): T = echo "I am fn" fn proc gen(T: typedesc): NimNode = result = getAst skel(T) macro foo(T: typedesc): untyped = gen(T) # <-- Error: type mismatch: got let fn = foo(int) Run Nope, doesn't work - the `typedesc` argument of the macro gets converted to a `NimNode` and I can't figure out how to turn it back into a `typedesc` I've tried numerous permutations resulting in numerous other interesting error messages, I went through the manual a number of times and I discussed this on #nim, but I am still lost. How to solve this? Thanks!
Passing a type through a macro to a generic?
How can I pass a type through a macro to instantiate a proc with the given type? Heavily reduced from my real code, I end up with something like this: import macros proc bar[T]() = var a: T echo "T=", typeof(a)# <-- T=NimNode, but want int macro foo(T: typedesc): untyped = bar[T]() foo(int) Run I
Re: Macro to create a dictionary (table) like in python!
Github pull request: [https://github.com/nim-lang/Nim/pull/11702](https://github.com/nim-lang/Nim/pull/11702).
Re: What's the most idiomatic way to call ``execCmdEx`` in parallel?
osproc execProcesses? [https://nim-lang.github.io/Nim/osproc.html#execProcesses%2CopenArray%5Bstring%5D%2Cproc%28int%29%2Cproc%28int%2CProcess%29](https://nim-lang.github.io/Nim/osproc.html#execProcesses%2CopenArray%5Bstring%5D%2Cproc%28int%29%2Cproc%28int%2CProcess%29)
Re: Trouble when converting c code to nim
It would be helpful to others to indicate your exact problem, like why does it not compile and why you can not solve this? Your above snippet has problems with converting types, because you are trying to mix Nim integers and C unsigned chars. Fixing this is not too hard: proc utf8str_codepoint_len*(s: cstring, utf8len: cint): cint = var codepointLen: cint = 0 let m4 = 128 + 64 + 32 + 16 let m3 = 128 + 64 + 32 let m2 = 128 + 64 var i: cint = 0 while i < utf8len: var c = s[i].int if (c and m4) == m4: inc(i, 3) elif (c and m3) == m3: inc(i, 2) elif (c and m2) == m2: inc(i, 1) inc(i) inc(codepointLen) return codepointLen Run As an alternative you might look into the nim unicode module which offers the runelen() proc which does almost exactly what your above code does.
Re: Modern way to pass a sequence to a c function as a void pointer and to cast it back as seq
Well, C _can_ understand it. But that does not mean you should _want_ it to :) {.emit: """ typedef long long int nim_int; struct nim_seq_hdr { nim_int len; nim_int reserved; }; struct nim_string { struct nim_seq_hdr seq; char *data[0]; }; struct nim_string_seq { struct nim_seq_hdr seq; struct nim_string *data[0]; }; void foo(void *ptr) { struct nim_string_seq *n = *(struct nim_string_seq **)ptr; nim_int i; for(i=0; iseq.len; i++) { struct nim_string *s = *(struct nim_string **)(>data[i]); printf("%d -> %d: %s\n", i, s->seq.len, s->data); } } """} proc foo(a1: pointer) {.cdecl, importc.} var a = @["one", "two", "three"] foo(addr a) Run
Re: pegs module: how to use captures in enter/leave procs?
Hi Amenhotep, Please drop an issue on the NPeg github page with a description and/or some examples of what you're trying to do, I'd be glad to help you out and see if we can get that to work. [https://github.com/zevv/npeg/issues](https://github.com/zevv/npeg/issues)
Re: Ebnf Lexer and Parser generator in nim
I'm taking the liberty to shamelessly mention my recent project here, as this seems the appropriate thread to do so: NPeg is a PEG-style parser generator which allows free mixing of grammar and Nim code, which should be suitable for the task of lexing and parsing. It can collect simple string captures, complex captures as a JSON tree, or run arbitrary Nim code at match time. NPeg is available in nimble, the manual and project page are at [https://github.com/zevv/npeg](https://github.com/zevv/npeg)
Re: scopes, templates and UFCS
Indeed, charlie was mispasted, fixed that. Thanks
scopes, templates and UFCS
Given the following three small source files below, why does the call c.dump() generate an error (attempting to call undeclared routine: 'dump'), but is it ok if I change this to dump(c)? alpha.nim: import bravo bravo() Run bravo.nim: import charlie template bravo_aux() = var c = Charlie() c.dump() template bravo*() = bravo_aux() Run charlie.nim: import charlie template bravo_aux() = var c = Charlie() c.dump() template bravo*() = bravo_aux() Run
Re: I wrote some nim code that works, but I don't understand how/why it works.
well, ignore that, as that will not yield a HashSet.
Re: symbol "&"
I'm not sure if I understand your question right, but you are trying to export a nim function to take a C++ ref, right? How about keyDown(eventType:stringHash,eventData:var variantMap) Run
Re: How to keep the output of a recursive proc?
You should be able to pass an additional variable of type 'var string' around your recursive functions, and simply use add() to add characters as you go - strings in Nim are modifiable and adding to them is cheap. When you've fully bubbled back up the call stack the result is there for you in your string.
Re: Convert float to its corresponding bytes?
Does it also use an union when compiling to C++?
Re: Convert float to its corresponding bytes?
The following should also be safe, this translates to a memcpy() at the C level. This may seem like overkill, but the C compiler should recognize the use of memcpy for type punning and optimize it away and generate a register to register move. proc flt2arr(f: var float64, a: var array[8, uint8]) = assert sizeof(a) == sizeof(f) copyMem(addr a[0], addr f, sizeof f) proc arr2flt(a: var array[8, uint8], f: var float64) = assert sizeof(a) == sizeof(f) copyMem(addr f, addr a[0], sizeof f) Run
Re: Associating data to types
> If you want to set them at the type definition you can use custom annotations That's pretty much exactly what I need - thanks for pointing that out!
Re: Best practices of meta-programming
> Write the macro transformation carefully. Ensure that the lineinfo in the > nodes remains useful. Where can I find any examples of this?
Re: Some nim builtin libs not doing enough error checking?
An empty directory is something else then a non-existing directory, IMHO. I would expect a exception in this case.
Re: Associating data to types
@deansher: Well, I was also looking for a way that would make the definition of messages nice-looking and trivial. The drum-roll-overloaded-procs are so simple I didn't even think of this, although I do not like the syntax for defining messages like this. But this is Nim: macro -> DSL to the rescue, all solved. Thanks!
Associating data to types
(asked this some time ago on #Nim, but still haven't found a solution) I'm trying to assign some data to a type, which can then be accessed by a generic instantiation using the specific type. Here is what I'm trying to do (but does not compile). import msgpack4nim import strutils import typetraits type MsgAlpha = object id: int x, y: int url: string MsgBeta = object id: int resource: string # ... const info = { MsgAlpha: (id: 1), MsgBeta: (id: 2), # ... } proc serialize[T](msg: T) = var msgcopy = msg msgcopy.id = info[msg.type].id # Too bad! echo msgcopy.pack.stringify serialize MsgAlpha(x: 10, y: 30, url: "http://foo.bar;) serialize MsgBeta(resource: "GLES2") Run My goal is to do serialization of protocol data where the caller does not have to know the details of the message being serialized (in this example the "id" field, in real life there is more message specific data). The culprit is the line marked # Too bad!. Here I'd like to get the data associated to the type T of msg. The const info above compiles, but Nim does not seem to be sure of its type. When asked (typetraits) it tells me array[0..1, tuple of (type MsgAlpha, tuple[id: int])], which is almost right, but not quite. Is there a way to do this without referencing to type names as strings?
Re: PEG.js-like API for the pegs module
I also spent some time yesterday to see what pegs needs to run at compile time. My first quick hack was the same as chrishellers: drop init() and move its contents into parsePeg. After that I ran into a few places where the pattern buffer is accessed out of bounds (always len+1). I suspect this is by design, because the PegLexer buf is declared as cstring instead of normal string, which makes this valid because of the trailing '0'. I guess this works fine at run time, but the VM does not like this trick. Fixing these three or four places results in my peg expression properly being parsed at compile time, but then I ran into this one: `Error: invalid type for const: Peg` Unfortunately, I'm lost here. It seems that inherited types can not be used for consts, but I have no clue why, and if there is a possible mitigation for this.
Re: Getting the original type of an 'upcasted' object
Thanks for pointing me to that thread, that explains some of the details I did not yet grasp. For now I'm good with a bit of redesign: I store a ref to object with some proc pointers for that specific type in each node. If this is solvable with a macro I can save a pointer per object though, which would be nice.
Re: Getting the original type of an 'upcasted' object
Here's an extract of my code. My issue is with the `proc `$`(s: SNodeAny): string =` function. Basically, it is just a long list of `if` statements (could be a `case` as well, doesn't matter) to check if the object is of some type, and then apply the `$` operator on the casted type. I feel this could be replaced by a two line macro or template, but for this I need to be able to deduce the original type of the passed SNode before I can cast and apply the `$` operator. My real code now includes 4 of these kind of functions where I need to check for every possible node kind, cast it, and apply some kind of generic function to it. import strutils type IPv4Address = distinct string IPv6Address = distinct string MacAddress = distinct string Interval = distinct float # ... many more distinct types type SNodeAny = ref object of Rootobj id: string parent: SNodeAny SNodeGroup = ref object of SNodeAny children: seq[SNodeAny] SNodeParam = ref object of SNodeAny SNode[T] = ref object of SNodeParam val: T proc newSNode[T](id: string, val: T): SNodeAny = SNode[T](id: id, val: val).SNodeAny proc newSNodeGroup(id: string, children: openarray[SNodeAny]): SNodeAny = var s = SNodeGroup(id: id) for c in children.items: s.children.add c c.parent = result return s proc `$`(v: IPv4Address): string = v.string proc `$`(v: IPv6Address): string = v.string proc `$`(v: MacAddress): string = v.string proc `$`(v: Interval): string = $ v.float proc `$`(s: SNodeAny): string = if s of SNode[bool]: result = $ s.SNode[:bool].val if s of SNode[int]: result = $ s.SNode[:int].val if s of SNode[IPv4Address]: result = $ s.SNode[:IPv4Address].val if s of SNode[IPv6Address]: result = $ s.SNode[:IPv6Address].val if s of SNode[MacAddress]: result = $ s.SNode[:MacAddress].val if s of SNode[Interval]: result = $ s.SNode[:Interval].val # many more of those proc dump(s: SNodeAny, depth: int = 0) = var l = repeat(" ", depth) l.add s.id if s of SNodeParam: l.add "=" & $ s echo l if s of SNodeGroup: for c in s.SNodeGroup.children.items: dump(c, depth+1) var s = newSNodeGroup("system", [ newSNodeGroup("identification", [ newSNode("name", "device 123"), newSNode("location", "rack J2"), newSNode("weight", 42.1), newSNode("enabled", true), newSNode("address", IPv4Address("10.0.0.3")), ]) ]) s.dump Run
Re: Getting the original type of an 'upcasted' object
Sorry Stefan, my original question was indeed lacking background info of what I am actually trying to achieve. I'm trying to port a data model which was originally implemented in Lua to Nim. This consists of a tree of nodes, of which the leaves are heterogenous containers for a relatively large number of types. (tens, and growing) My first implementation used object hierarchies, but I ran unto problems caused by mixing generics and multimethods. Araq explained that combining those is currently not a good idea, so I am looking for a way to drop the methods. Using object variants turned out to be cumbersome, so I am now back for a second try using object inheritance. This basically works now, but I find myself writing long case statements handling all the possible object types in a few places, so I am looking to generalize things to avoid code repetition. I will try to compile a compact example of my current implementation for comments.
Getting the original type of an 'upcasted' object
Hi, How can I find out the original type of an object that has been promoted/demoted/casted (what is the right term here?) to a parent type without testing for each individual type with the of operator? import macros macro test(a: typed): untyped = # how to get "T2" here? type T1 = ref object of RootObj T2 = ref object of T1 var a = T1(T2()) test a Run
Re: Unexpected behaviour
Thanks for explaining. I'll leave this thread and continue discussion in the github issue.
Re: Unexpected behaviour
https://github.com/nim-lang/Nim/issues/10038
Unexpected behaviour
I've been hunting strange behaviour in my code base which I have reduced to the following snippet. type SNodeAny = ref object of RootObj SNode[T] = ref object of SNodeAny DNode[T] = ref object method getStr(s: SNode[float]): string {.base.} = "blahblah" method newDNode(s: SNodeAny) {.base.} = echo "newDNode base" method newDNode[T](s: SNode[T]) = echo "newDNode generic" let s = SNodeAny(SNode[float]()) newDnode(s) Run What I expect to happen: variable `s` is a `SNode[float]` disguised as a `SNodeAny`. Calling `newDnode(s)` should dispatch the `newDnode[T](s: SNode[T])` and the string `newDNode generic` should be printed. Instead what happens is that the "super" method `newDnode(s: SNodeAny)` gets called, printing the string `newDnode base` Now the strangest part: when the `getStr()` method is removed from the code, the behaviour changes to the expected behaviour, and all is well. Alternatively, removing the `SNodeAny()` cast from the second last line also restores the expected behaviour. How does the existence of the `getStr()` method affect the behaviour of the `newDNode()` dispatch?
Re: Looking for efficient API for regexp library
True, it does not support UTF-8, just as the original Lua patterns do not. I guess having proper support for UTF-8 would probably include supporting Unicode as well and would complicate things a lot- for example, matching any unicode upper case character with %u would not be trivial. BTW: YEs, I've seen nim-regex, which is also very nice. The lua pattern port is mainly for my personal use, because I'm leaving Lua more then 10 years of Lua behind, but I dearly miss the patterns. The advantage is that they are much more simple then regular expressions, which often result in something that I can read and understand a year after I wrote it - which is often not the case with full fledged PCRE regular expressions. (Personally, I'd prefer pure Nim regex handing in the Nim stdlib over a PCRE based solution which requires external libs, would nim-regex not be a nice candidate?)
Re: Looking for efficient API for regexp library
This is also usable, although it requires the variables to receive the captures to be declared ahead of time: proc match(src: string, pat: string, c0: var string): bool = let caps = src.match(pat) if caps.len == 1: c0 = caps[0] return true proc match(src: string, pat: string, c0, c1: var string): bool = let caps = src.match(pat) if caps.len == 2: c0 = caps[0] c1 = caps[1] return true proc match(src: string, pat: string, c0, c1, c2: var string): bool = let caps = src.match(pat) if caps.len == 3: c0 = caps[0] c1 = caps[1] c2 = caps[1] return true let src = "3 foxes: 0x1234" var a, b: string if src.match("(%a+).*0x(%x+)", a, b): echo "a = " & a echo "b = " & b
Re: Looking for efficient API for regexp library
Yeah, I guess providing multiple functions would work, since in practice patterns are usually limited to a handful of captures. Thanks,
Looking for efficient API for regexp library
I'm working on a Nim port of the Lua pattern matching code. Lua patterns are a bit like regular expressions, but simpler. The implementation is pretty small, however, compared to regular expressions, and the port is pure Nim and does not require any shared libraries like PCRE for the re and nre libs. The current code is available at [https://github.com/zevv/nimpat](https://github.com/zevv/nimpat)/ The basic pattern matching is functional, a single proc 'match' is implemented, and can be used like this: proc match(src: string, pat: string): seq[string] let src = "3 foxes: 0x44111" let pat = "(%d+) ([^:]+): 0x(%x+)" let caps = src.match("(%d+) ([^:]+): 0x(%x+)") echo "$1 $2 $3" % [ caps[0], caps[1], caps[2]] The pattern "(%d+) ([^:]+): 0x(%x+)" translates to * (%d+): a maximum number of numeric chars * ([^:]+): all characters up to a colon * (%x+): one or more hex characters I am now looking for a friendly API for the library, as getting the returned matches in a seq is a bit cumbersome to use. Ideally I would like to do pattern captures like in Lua allowing direct assignment to variables from a proc and/or iterator: local a, b, c = src:match(pat) for a, b, c in src:gmatch(pat) do ... end In Nim that would be something like this, using tuples. let (a, b, c) = src.match(pat) for a, b, c in src.gmatch(pat): ... I have been trying to implement this in Nim, but I can not get this to work because (quote Araq) "overloading doesn't look at the return types" So this does not work: iterator gmatch(src, pat: string): (string) = let c = src.match(pat) yield (c[0]) iterator gmatch(src, pat: string): (string, string) = let c = src.match(pat) yield (c[0], c[1]) iterator gmatch(src, pat: string): (string, string, string) = let c = src.match(pat) yield (c[0], c[1], c[2]) nimpat.nim(357, 14) Error: ambiguous call; both nimpat.gmatch(src: string, pat: string)[declared in nimpat.nim(348, 9)] and nimpat.gmatch(src: string, pat: string)[declared in nimpat.nim(352, 9)] match for: (string, string) Araqs next remark was to "write a macro", but my Nim-fu is not up to that yet, I'm afraid. So, would it be possible to get this to work, and how would I proceed from here? Thanks, Ico
String pattern matching / regular expression libs
I've been looking into available libraries for string pattern matching and regular expressions, I found those: * re/nre: both come with Nim, but have dependency on pcre lib (quit large, requires .dll on win32) * peg: more of a parser, very powerful but cumbersome for quick string matching Are there any other available options, preferably something small without external dependencies? If not, I'm considering porting the Lua string pattern matching code [1] to Nim; it's pretty concise (approx 500 LOC), and handles about 99% of the matching/capturing cases I usually need in real life. 1\. [https://www.lua.org/manual/5.3/manual.html#6.4.1](https://www.lua.org/manual/5.3/manual.html#6.4.1)