Comments (14)
ok thank you so far. I can't give full feedback right now, because I am really too tired for it. The one thing I see at the moment is, that I would not want to support the last example, where you match a sub sequence and call it last. last
is not a @[1,2] is not contained in the seq @[0,1,2], it is just not how sequence types are structured. A seq is not like lisp list with a car and a cdr. You also can't construct @[0,1,2]
with @[0, @[1,2]]
, so why should you be able to match a seq that way?
from ast-pattern-matching.
Maybe I used the wrong syntax and
@[0, `last` @ *_]
@[0, `last` @ varargs]
@[0, `last` @ *element]
would be better.
I like the construction argument, but you also don't construct stuff with nnkCall(e, f)
(you use newTree
): a lot of the current dsl takes shortcuts. I think a varargs shortcut would be very valuable for collections.
Do you have any alternative ideas? @[0] ++ last
?
from ast-pattern-matching.
I am not saying your way to match strings is not useful, but it is just not the way the seq type is structured. I only want to support a matching that represents the structure of a type, and a seq only contains it's elements, and not another shorter seq with just some of it's members. Therefore I won't support it, no matter how the syntax is. So please just drop it. Your last syntax allows to create a lot of ambiguous matchings like `a` ++ `b` ++ `c`
.
from ast-pattern-matching.
I understand your argument, but the current dsl doesn't conform to it at all:
quote:
e = 2
# leads to
nnkAsgn(ident"e", nnkInt(intVal=2))
is matched by
of nnkAsgn(ident"e", 2)
Well, you can't construct neither nnkAsgn nor the children seq with 2
. a seq of NimNodes doesn't include 2, it includes nnkIntLit(2)
Anyway, I don't care so much about this feature, I can drop it, does the plan for other objects and sequences without *
look good?
Btw I see you use A(b = 2)
currently for fields, do you have pref between that and A(b: 2)
? the second one might be more consistent
from ast-pattern-matching.
Syntactically it looks ok, but I don't the extension mechanisms work. Can you add for each example the code that they should generate for the pattern matching and how custom matchers are resolved?
from ast-pattern-matching.
Ok, so here are some examples
First, the matchLit macro will just overload a litMapping
proc:
static:
proc litMapping[T](objType: typedesc, litType: typedesc, enumType: typedesc[T]): set[T] {.compileTime.} =
{}
macro matchLit(objType: typed, litType: typed, enumValues: typed): untyped =
result = quote:
static:
proc litMapping[T](objType: type `objType`, litType: type `litType`, enumType: typedesc[T]): set[T] {.compileTime.} =
{`enumValues`}
you call it like
matchLit NimNode, int, nnkIntLit
# it will be extended to also support sets for all nnkInt kinds: we'll check if they actually has a single int value in NimNode
This way you'll be able to check the return value of litMapping(objType, litType, enumType) in macros and either generate match for the literal or for a node with a single int field == literal
Now, here are some examples with my idea of generated code. From what I saw it seems the generated matches can be still optimized in some cases, also the auto error collection should be optional (maybe with some kind of debug dsl switch), as usually you don't want it in runtime code
import ast_pattern_matching, strformat, macros, unittest
type
H = enum HInt, HString, HContainer
C = enum CArray, CSeq
Container = ref object
case kind: C:
of CArray:
items: seq[A]
of CSeq:
elements: seq[A]
A = ref object
case kind: H:
of HInt:
i: int
of HString:
s: string
of HContainer:
c: Container
proc `$`(a: A): string =
case a.kind:
of HInt:
&"A({a.i})"
of HString:
&"A({a.s})"
of HContainer:
&"A([..])"
proc hInt(i: int): A =
A(kind: HInt, i: i)
proc hString(s: string): A =
A(kind: HString, s: s)
let container = A(
kind: HContainer,
c: Container(
kind: CSeq,
elements: @[
A(
kind: HInt,
i: 0)]))
suite "plan":
matchtest "match different object":
container.match:
of HContainer(c: CSeq(elements: @[`value`])):
echo value
check value.kind == HInt and value.i == 0
succeed
else:
discard
# block match0:
# var error0: MatchingError
# block branch0:
# if not (container.kind == HContainer):
# error0 = ..
# break branch0
# if not (container.c.kind == CSeq):
# error0 = ..
# break branch0
# if not (container.c.elements.len == 0): # elements[0] is true
# error0 = ..
# break branch0
# let value = container.c.elements[0]
# echo value
# check value.kind == HInt and value.i == 0
# succeed
# break match0
# discard
matchtest "match variant field":
var a = A(kind: HInt, i: 0)
a.match:
of HInt(i: `i`):
check i == 0
succeed
else:
discard
matchtest "match variant literal":
A.matchLit int, HInt
A.matchLit string, HString
var a = A(kind: HInt, i: 0)
var b = A(kind: HString, s: "e")
a.match:
of 0:
succeed
else:
discard
# block match0:
# var error0: MatchingError
# block branch0:
# if not (a.kind == HInt and a.i == 0):
# error0 = ..
# break branch0
# succeed
# break match0
# discard
b.match:
of "f":
discard
of "e":
succeed
else:
discard
# block match0:
# var error0: MatchingError
# block branch0:
# if not (a.kind == HString and a.s == "f"):
# error0 = ..
# break branch0
# break match0
# var error1: MatchingError
# block branch1:
# if not (a.kind == HString and a.s == "e"):
# error1 = ..
# break branch1
# succeed
# break match0
# discard
matchtest "match variant args with auto":
Container.matchArgs elements
var a = Container(kind: CSeq, elements: @[A(kind: HInt, i: 2), A(kind: HInt, i: 4)])
a.match:
of CSeq(HInt(2), HInt(4)):
succeed
else:
discard
matchtest "match normal objects":
type
Obj = object
a*: int
b*: int
var a = Obj(a: 0, b: 0)
a.match:
of Obj(a: `a`, b: 0):
check a == 0
succeed
else:
discard
matchtest "match seq":
var a = @[0, 1, 2]
a.match:
of @[0]:
discard
of @[0, 1, `last`]:
check last == 2
succeed
else:
discard
a.match:
of @[`first`]:
discard
of @[0, *`last`]:
check last == @[1, 2]
succeed
else:
discard
I was afraid that that using variant kinds might be problematic, but I realized we know the object/field type anyway. One possible issue is variant objects with two discriminators, but that's too edgy
from ast-pattern-matching.
For the seq:
a.match:
of @[0]:
discard
of @[0, 1, `last`]:
check last == 2
succeed
else:
discard
# block match0:
# var error0: ..
# block branch0:
# if not (a.len == 1 and a[0] == 0):
# error0 = ..
# break branch0
# var error1: ..
# block branch1:
# if not (a.len == 3 and a[0] == 0 and a[1] == 1):
# error1 = ..
# break branch1
# let last = a[2]
# check last == 2
# succeed
You can have similar patterns for sets
a.match:
of {A, B}:
discard
of {A, B, `other`}:
check last == 2
succeed
else:
discard
# similar but instead of `a[0] == A` .. `A in a` and support for one submatch matching as `a - {A, B}`
Also arrays and hashtables. I assume most of those literals wouldn't be too important for now, just documenting possible support
from ast-pattern-matching.
so, should I implement some of those ideas when I have time this week?
from ast-pattern-matching.
Well you can implement these ideas if you want to. If it has some design flaws, you will see them early enough.
from ast-pattern-matching.
Yeah, I plan to, I was very busy these days
from ast-pattern-matching.
Well I won't pay you anyway, so no reason to be sorry about it.
from ast-pattern-matching.
I never said I was sorry! 😆
from ast-pattern-matching.
can you change this "issue" into a PR where you put all the syntax that you want to have into a test case? The test case would of course not compile, but it would provide a better overview of the consens of the discussion.
from ast-pattern-matching.
I am closing this issue here, because the discussion is now in the PR
from ast-pattern-matching.
Related Issues (5)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ast-pattern-matching.