# # Nim's Runtime Library # (c) Copyright 2015 Nim Contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## What is NRE? ## ============ ## ## A regular expression library for Nim using PCRE to do the hard work. ## ## For documentation on how to write patterns, there exists `the official PCRE ## pattern documentation ## `_. You can also ## search the internet for a wide variety of third-party documentation and ## tools. ## ## **Note**: If you love ``sequtils.toSeq`` we have bad news for you. This ## library doesn't work with it due to documented compiler limitations. As ## a workaround, use this: ## ## .. code-block:: nim ## ## import nre except toSeq ## ## ## Licencing ## --------- ## ## PCRE has `some additional terms`_ that you must agree to in order to use ## this module. ## ## .. _`some additional terms`: http://pcre.sourceforge.net/license.txt ## runnableExamples: let vowels = re"[aeoui]" let expectedResults = [ 1 .. 1, 2 .. 2, 4 .. 4, 6 .. 6, 7 .. 7, ] var i = 0 for match in "moigagoo".findIter(vowels): doAssert match.matchBounds == expectedResults[i] inc i let firstVowel = "foo".find(vowels) let hasVowel = firstVowel.isSome() if hasVowel: let matchBounds = firstVowel.get().captureBounds[-1] doAssert matchBounds.a == 1 from pcre import nil import nre/private/util import tables from strutils import `%` from math import ceil import options from unicode import runeLenAt export options # Type definitions {{{ type Regex* = ref object ## Represents the pattern that things are matched against, constructed with ## ``re(string)``. Examples: ``re"foo"``, ``re(r"(*ANYCRLF)(?x)foo # ## comment".`` ## ## ``pattern: string`` ## the string that was used to create the pattern. For details on how ## to write a pattern, please see `the official PCRE pattern ## documentation. ## `_ ## ## ``captureCount: int`` ## the number of captures that the pattern has. ## ## ``captureNameId: Table[string, int]`` ## a table from the capture names to their numeric id. ## ## ## Options ## ....... ## ## The following options may appear anywhere in the pattern, and they affect ## the rest of it. ## ## - ``(?i)`` - case insensitive ## - ``(?m)`` - multi-line: ``^`` and ``$`` match the beginning and end of ## lines, not of the subject string ## - ``(?s)`` - ``.`` also matches newline (*dotall*) ## - ``(?U)`` - expressions are not greedy by default. ``?`` can be added ## to a qualifier to make it greedy ## - ``(?x)`` - whitespace and comments (``#``) are ignored (*extended*) ## - ``(?X)`` - character escapes without special meaning (``\w`` vs. ## ``\a``) are errors (*extra*) ## ## One or a combination of these options may appear only at the beginning ## of the pattern: ## ## - ``(*UTF8)`` - treat both the pattern and subject as UTF-8 ## - ``(*UCP)`` - Unicode character properties; ``\w`` matches ``я`` ## - ``(*U)`` - a combination of the two options above ## - ``(*FIRSTLINE*)`` - fails if there is not a match on the first line ## - ``(*NO_AUTO_CAPTURE)`` - turn off auto-capture for groups; ## ``(?...)`` can be used to capture ## - ``(*CR)`` - newlines are separated by ``\r`` ## - ``(*LF)`` - newlines are separated by ``\n`` (UNIX default) ## - ``(*CRLF)`` - newlines are separated by ``\r\n`` (Windows default) ## - ``(*ANYCRLF)`` - newlines are separated by any of the above ## - ``(*ANY)`` - newlines are separated by any of the above and Unicode ## newlines: ## ## single characters VT (vertical tab, U+000B), FF (form feed, U+000C), ## NEL (next line, U+0085), LS (line separator, U+2028), and PS ## (paragraph separator, U+2029). For the 8-bit library, the last two ## are recognized only in UTF-8 mode. ## — man pcre ## ## - ``(*JAVASCRIPT_COMPAT)`` - JavaScript compatibility ## - ``(*NO_STUDY)`` - turn off studying; study is enabled by default ## ## For more details on the leading option groups, see the `Option ## Setting `_ ## and the `Newline ## Convention `_ ## sections of the `PCRE syntax ## manual `_. ## ## Some of these options are not part of PCRE and are converted by nre ## into PCRE flags. These include ``NEVER_UTF``, ``ANCHORED``, ## ``DOLLAR_ENDONLY``, ``FIRSTLINE``, ``NO_AUTO_CAPTURE``, ## ``JAVASCRIPT_COMPAT``, ``U``, ``NO_STUDY``. In other PCRE wrappers, you ## will need to pass these as seperate flags to PCRE. pattern*: string ## not nil pcreObj: ptr pcre.Pcre ## not nil pcreExtra: ptr pcre.ExtraData ## nil captureNameToId: Table[string, int] RegexMatch* = object ## Usually seen as Option[RegexMatch], it represents the result of an ## execution. On failure, it is none, on success, it is some. ## ## ``pattern: Regex`` ## the pattern that is being matched ## ## ``str: string`` ## the string that was matched against ## ## ``captures[]: string`` ## the string value of whatever was captured at that id. If the value ## is invalid, then behavior is undefined. If the id is ``-1``, then ## the whole match is returned. If the given capture was not matched, ## ``nil`` is returned. ## ## - ``"abc".match(re"(\w)").get.captures[0] == "a"`` ## - ``"abc".match(re"(?\w)").get.captures["letter"] == "a"`` ## - ``"abc".match(re"(\w)\w").get.captures[-1] == "ab"`` ## ## ``captureBounds[]: HSlice[int, int]`` ## gets the bounds of the given capture according to the same rules as ## the above. If the capture is not filled, then ``None`` is returned. ## The bounds are both inclusive. ## ## - ``"abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0`` ## - ``0 in "abc".match(re"(\w)").get.captureBounds == true`` ## - ``"abc".match(re"").get.captureBounds[-1] == 0 .. -1`` ## - ``"abc".match(re"abc").get.captureBounds[-1] == 0 .. 2`` ## ## ``match: string`` ## the full text of the match. ## ## ``matchBounds: HSlice[int, int]`` ## the bounds of the match, as in ``captureBounds[]`` ## ## ``(captureBounds|captures).toTable`` ## returns a table with each named capture as a key. ## ## ``(captureBounds|captures).toSeq`` ## returns all the captures by their number. ## ## ``$: string`` ## same as ``match`` pattern*: Regex ## The regex doing the matching. ## Not nil. str*: string ## The string that was matched against. ## Not nil. pcreMatchBounds: seq[HSlice[cint, cint]] ## First item is the bounds of the match ## Other items are the captures ## `a` is inclusive start, `b` is exclusive end Captures* = distinct RegexMatch CaptureBounds* = distinct RegexMatch RegexError* = ref object of Exception RegexInternalError* = ref object of RegexError ## Internal error in the module, this probably means that there is a bug InvalidUnicodeError* = ref object of RegexError ## Thrown when matching fails due to invalid unicode in strings pos*: int ## the location of the invalid unicode in bytes SyntaxError* = ref object of RegexError ## Thrown when there is a syntax error in the ## regular expression string passed in pos*: int ## the location of the syntax error in bytes pattern*: string ## the pattern that caused the problem StudyError* = ref object of RegexError ## Thrown when studying the regular expression failes ## for whatever reason. The message contains the error ## code. runnableExamples: # This MUST be kept in sync with the examples in RegexMatch doAssert "abc".match(re"(\w)").get.captures[0] == "a" doAssert "abc".match(re"(?\w)").get.captures["letter"] == "a" doAssert "abc".match(re"(\w)\w").get.captures[-1] == "ab" doAssert "abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0 doAssert 0 in "abc".match(re"(\w)").get.captureBounds == true doAssert "abc".match(re"").get.captureBounds[-1] == 0 .. -1 doAssert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2 # }}} proc getinfo[T](pattern: Regex, opt: cint): T = let retcode = pcre.fullinfo(pattern.pcreObj, pattern.pcreExtra, opt, addr result) if retcode < 0: # XXX Error message that doesn't expose implementation details raise newException(FieldError, "Invalid getinfo for $1, errno $2" % [$opt, $retcode]) # Regex accessors {{{ proc captureCount*(pattern: Regex): int = return getinfo[cint](pattern, pcre.INFO_CAPTURECOUNT) proc captureNameId*(pattern: Regex): Table[string, int] = return pattern.captureNameToId proc matchesCrLf(pattern: Regex): bool = let flags = uint32(getinfo[culong](pattern, pcre.INFO_OPTIONS)) let newlineFlags = flags and (pcre.NEWLINE_CRLF or pcre.NEWLINE_ANY or pcre.NEWLINE_ANYCRLF) if newLineFlags > 0u32: return true # get flags from build config var confFlags: cint if pcre.config(pcre.CONFIG_NEWLINE, addr confFlags) != 0: assert(false, "CONFIG_NEWLINE apparently got screwed up") case confFlags of 13: return false of 10: return false of (13 shl 8) or 10: return true of -2: return true of -1: return true else: return false # }}} # Capture accessors {{{ func captureBounds*(pattern: RegexMatch): CaptureBounds = return CaptureBounds(pattern) func captures*(pattern: RegexMatch): Captures = return Captures(pattern) func contains*(pattern: CaptureBounds, i: int): bool = let pattern = RegexMatch(pattern) pattern.pcreMatchBounds[i + 1].a != -1 func contains*(pattern: Captures, i: int): bool = i in CaptureBounds(pattern) func `[]`*(pattern: CaptureBounds, i: int): HSlice[int, int] = let p
discard """
  output: '''
Version 2 was called.
This has the highest precedence.
This has the second-highest precedence.
This has the lowest precedence.
baseobj ==
true
even better! ==
true
done extraI=0
test 0 complete, loops=0
done extraI=1
test 1.0 complete, loops=1
done extraI=0
done extraI passed 0
test no extra complete, loops=2
1
'''
"""


# issue 4675
import importA  # comment this out to make it work
import importB

var x: Foo[float]
var y: Foo[float]
let r = t1(x) + t2(y)



# Bug: https://github.com/nim-lang/Nim/issues/4475
# Fix: https://github.com/nim-lang/Nim/pull/4477
proc test(x: varargs[string], y: int) = discard
test(y = 1)



# bug #2220
when true:
  type A[T] = object
  type B = A[int]

  proc q[X](x: X) =
    echo "Version 1 was called."

  proc q(x: B) =
    echo "Version 2 was called."

  q(B()) # This call reported as ambiguous.



# bug #2219
template testPred(a: untyped) =
  block:
    type A = object of RootObj
    type B = object of A
    type SomeA = A|A # A hack to make "A" a typeclass.

    when a >= 3:
      proc p[X: A](x: X) =
        echo "This has the highest precedence."
    when a == 2:
      proc p[X: SomeA](x: X) =
        echo "This has the second-highest precedence."
    when a >= 1:
      proc p[X](x: X) =
        echo "This has the lowest precedence."

    p(B())

testPred(3)
testPred(2)
testPred(1)



# bug #6526
type
  BaseObj = ref object of RootObj
  DerivedObj = ref object of BaseObj
  OtherDerivate = ref object of BaseObj

proc `==`*[T1,