Took a crack at it, it's big and ugly and I'm sure I missed some edge cases, 
but:

<https://play.nim-lang.org/#ix=2wrM>
    
    
    proc ifReturn(a,b,fld:NimNode):NimNode =
      newIfStmt(
        (infix(newDotExpr(a,fld),"!=",newDotExpr(b,fld)),
          nnkReturnStmt.newTree(newLit(false))
        )
      )
    macro equalsImpl[T:object](a,b:T): untyped=
      let tImpl = a.getTypeImpl
      result = newStmtList()
      result.add quote do:
        result = true
      let records = tImpl[2]
      records.expectKind(nnkRecList)
      for field in records:
        case field.kind
        of nnkIdentDefs:
          result.add(ifReturn(a,b,field[0]))
        of nnkRecCase:
          let discrim = field[0][0]
          result.add(ifReturn(a,b,discrim))
          var casestmt = newNimNode(nnkCaseStmt)
          casestmt.add newDotExpr(a,discrim)
          for ofbranch in field[1..^1]:
            case ofbranch.kind
            of nnkOfBranch:
              let testVal = ofbranch[0]
              let reclst = ofbranch[1]
              expectKind(reclst,nnkRecList)
              var ifstmts = newStmtList()
              for idDef in reclst:
                ifstmts.add(ifReturn(a,b,idDef[0]))
              casestmt.add nnkOfBranch.newTree(testVal,ifstmts)
            of nnkElse:
              let reclst = ofbranch[0]
              expectKind(reclst,nnkRecList)
              var ifstmts = newStmtList()
              for idDef in reclst:
                ifstmts.add(ifReturn(a,b,idDef[0]))
              casestmt.add nnkElse.newTree(ifstmts)
            else: error "Unsupported branch" & ofbranch.repr
          result.add casestmt
        else:
          error "Unsupported kind" & field.repr
      #echo result.repr
    
    
    proc `==`*[T:object](a,b:T):bool =
      equalsImpl(a,b)
     
    
    Run

Reply via email to