GithubHelp home page GithubHelp logo

Comments (14)

krux02 avatar krux02 commented on August 16, 2024

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.

alehander92 avatar alehander92 commented on August 16, 2024

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.

krux02 avatar krux02 commented on August 16, 2024

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.

alehander92 avatar alehander92 commented on August 16, 2024

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.

krux02 avatar krux02 commented on August 16, 2024

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.

alehander92 avatar alehander92 commented on August 16, 2024

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.

alehander92 avatar alehander92 commented on August 16, 2024

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.

alehander92 avatar alehander92 commented on August 16, 2024

so, should I implement some of those ideas when I have time this week?

from ast-pattern-matching.

krux02 avatar krux02 commented on August 16, 2024

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.

alehander92 avatar alehander92 commented on August 16, 2024

Yeah, I plan to, I was very busy these days

from ast-pattern-matching.

krux02 avatar krux02 commented on August 16, 2024

Well I won't pay you anyway, so no reason to be sorry about it.

from ast-pattern-matching.

alehander92 avatar alehander92 commented on August 16, 2024

I never said I was sorry! 😆

from ast-pattern-matching.

krux02 avatar krux02 commented on August 16, 2024

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.

krux02 avatar krux02 commented on August 16, 2024

I am closing this issue here, because the discussion is now in the PR

from ast-pattern-matching.

Related Issues (5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.