summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.comy>2011-09-07 22:05:21 +0300
committerZahary Karadjov <zahary@gmail.comy>2011-09-20 14:13:45 +0300
commitdbcca9b3b994e3339c9a03c3846b7162147679fd (patch)
treec9f4b646c0ac7b7679c1ed6da0debfb8a35e6082 /lib
parenta28cf4e9cbb7e202d355d669d16b86457932ec2a (diff)
downloadNim-dbcca9b3b994e3339c9a03c3846b7162147679fd.tar.gz
Moved the parseAST magics to evals.nim
Added string interpolation helper routines in parserutils

Added a proof-of-concept string interpolation user-land macros (currently, only as a test case):
  the interpolated expression could either be transformed to
  concat("literal string ", $(interpolated), " end") or
  "literal string $1 end" % [$(interpolated)]

Added a very initial definition of Optional[T] generic type

A new overload of ParseIdent was added in hope to get around the fact that the 
old one doesn't work correctly in macros, but the problem persists.
Diffstat (limited to 'lib')
-rwxr-xr-xlib/pure/parseutils.nim91
-rwxr-xr-xlib/system.nim9
2 files changed, 98 insertions, 2 deletions
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index d3346ecde..a046aff36 100755
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -76,6 +76,19 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
     ident = substr(s, start, i-1)
     result = i-start
 
+proc parseIdent*(s: string, start = 0): TOptional[string] =
+  ## parses an identifier and stores it in ``ident``. Returns
+  ## the number of the parsed characters or 0 in case of an error.
+  result.hasValue = false
+  var i = start
+
+  if s[i] in IdentStartChars:
+    inc(i)
+    while s[i] in IdentChars: inc(i)
+    
+    result.hasValue = true
+    result.value = substr(s, start, i-1)
+
 proc parseToken*(s: string, token: var string, validChars: set[char],
                  start = 0): int {.inline, deprecated.} =
   ## parses a token and stores it in ``token``. Returns
@@ -254,4 +267,82 @@ proc parseFloat*(s: string, number: var float, start = 0): int {.
   result = parseBiggestFloat(s, bf, start)
   number = bf
   
+proc isEscaped*(s: string, pos: int) : bool =
+  assert pos >= 0 and pos < s.len
+
+  var
+    backslashes = 0
+    j = pos - 1
+
+  while j >= 0:
+    if s[j] == '\\':
+      inc backslashes
+      dec j
+    else:
+      break
+
+  return backslashes mod 2 != 0
+
+type
+  TInterpStrFragment* = tuple[interpStart, interpEnd, exprStart, exprEnd: int]
+
+iterator interpolatedFragments*(s: string): TInterpStrFragment =
+  var i = 0
+  while i < s.len:
+    # The $ sign marks the start of an interpolation.
+    #
+    # It's followed either by a varialbe name or an opening bracket 
+    # (so it should be before the end of the string)
+    # if the dollar sign is escaped, don't trigger interpolation
+    if s[i] == '$' and i < (s.len - 1) and not isEscaped(s, i):
+      var next = s[i+1]
+      
+      if next == '{':
+        inc i
+
+        var
+          brackets = {'{', '}'}
+          nestingCount = 1
+          start = i + 1
+
+        # find closing braket, while respecting any nested brackets
+        while i < s.len:
+          inc i, skipUntil(s, brackets, i+1) + 1
+          
+          if not isEscaped(s, i):
+            if s[i] == '}':
+              dec nestingCount
+              if nestingCount == 0: break
+            else:
+              inc nestingCount
+
+        var t : TInterpStrFragment
+        t.interpStart = start - 2
+        t.interpEnd = i
+        t.exprStart = start
+        t.exprEnd = i - 1
+
+        yield t
+        
+      else:
+        var 
+          start = i + 1
+          identifier = parseIdent(s, i+1)
+        
+        if identifier.hasValue:
+          inc i, identifier.value.len
+
+          var t : TInterpStrFragment
+          t.interpStart = start - 1
+          t.interpEnd = i
+          t.exprStart = start
+          t.exprEnd = i
+
+          yield t
+
+        else:
+          raise newException(EInvalidValue, "Unable to parse a varible name at " & s[i..s.len])
+       
+    inc i
+
 {.pop.}
diff --git a/lib/system.nim b/lib/system.nim
index 2e754ece7..3fc4733b2 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -710,7 +710,7 @@ proc `&` * (x, y: string): string {.
 proc `&` * (x: char, y: string): string {.
   magic: "ConStrStr", noSideEffect, merge.}
   ## is the `concatenation operator`. It concatenates `x` and `y`.
-  
+
 # implementation note: These must all have the same magic value "ConStrStr" so
 # that the merge optimization works properly. 
 
@@ -895,7 +895,12 @@ type # these work for most platforms:
   PFloat64* = ptr Float64 ## an alias for ``ptr float64``
   PInt64* = ptr Int64 ## an alias for ``ptr int64``
   PInt32* = ptr Int32 ## an alias for ``ptr int32``
-  
+
+type TOptional*[T] = object
+  case hasValue* : bool
+  of true: value*: T
+  of false: nil
+ 
 proc toFloat*(i: int): float {.
   magic: "ToFloat", noSideEffect, importc: "toFloat".}
   ## converts an integer `i` into a ``float``. If the conversion