# Copyright (C) 2015 Oleh Prypin <blaxpirit@gmail.com>
# Licensed under terms of MIT license (see LICENSE)


import std/[strutils, unicode, macros]


template any_it*(lst: typed, pred: untyped): bool =
  ## Does `pred` return true for any of the `it`s of `lst`?
  var result {.gensym.} = false
  for it {.inject.} in lst:
    if pred:
      result = true
      break
  result

template map_it*(lst, typ: typed, op: untyped): untyped =
  ## Returns `seq[typ]` that contains `op` applied to each `it` of `lst`
  var result {.gensym.}: seq[typ] = @[]
  for it {.inject.} in items(lst):
    result.add(op)
  result


proc count*[T](s: openarray[T], it: T): int =
  ## How many times this item appears in an array
  result = 0
  for x in s:
    if x == it:
      result += 1


proc partition*(s, sep: string): tuple[left, sep, right: string] =
  ## "a+b".partition("+") == ("a", "+", "b")
  ## "a+b".partition("-") == ("a+b", "", "")
  assert sep != ""
  let pos = s.find(sep)
  if pos < 0:
    (s, "", "")
  else:
    (s.substr(0, pos.pred), s.substr(pos, pos.pred+sep.len), s.substr(pos+sep.len))


proc is_upper*(s: string): bool =
  ## Is the string in uppercase (and there is at least one cased character)?
  let upper = unicode.to_upper(s)
  s == upper and upper != unicode.to_lower(s)


macro gen_class*(body: untyped): untyped =
  ## When applied to a type block, this will generate methods
  ## that return each type's name as a string.
  for typ in body[0].children:
    var meth = "method class(self: $1): string"
    if $typ[2][0][1][0] == "RootObj":
      meth &= "{.base, gcsafe.}"
    meth &= "= \"$1\""
    body.add(parse_stmt(meth.format(typ[0])))
  body
