summary refs log blame commit diff stats
path: root/compiler/ropes.nim
blob: e0d5aa0d378e026320dbc144dcff7b90df2357f9 (plain) (tree)
1
2
3
4
5
6
7
8
9

 
                            
                                         




                                                   
                                                                                 
 

                                  
                                   
                                              
 
    
                                                                     
                                                                       
                                                
                                                    
                
 

                                                    
 
                                          
 
                              
 
                                     
 
                                 
                               

                   
                                   
                                

                   

                                   
             
 
                                                           
                             
                                       
                      
            
                 
       
                  
 

                                                 
                                                                   
           
                            
             
                     
                      

                                        
             
                       
              
             
              
                             
                
                  
                 
                   
                                              
                
                                                             
               
                              
                                                      
             
                               


                 
                                    


                                              
                                 
             
                                                      

                              
                                                      
             
                               
             
                        
              
             
                        
              
           
                                                    


                         
 



                                                                     
                                          
                    
 
     

                                                  
                                          
                                                            
     
                                                             

                  

              
 
            
                

                       



                                                   
                      


                                             
                                            

                                                                                     

                      
               
               
 

                                                  
 
                                                         

                                                                            
                             
                                   
            

                             
#
#
#           The Nim Compiler
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# Ropes for the C code generator. Ropes are mapped to `string` directly nowadays.

from pathutils import AbsoluteFile

when defined(nimPreviewSlimSystem):
  import std/[assertions, syncio, formatfloat]

type
  FormatStr* = string  # later we may change it to CString for better
                       # performance of the code generator (assignments
                       # copy the format strings
                       # though it is not necessary)
  Rope* = string

proc newRopeAppender*(cap = 80): string {.inline.} =
  result = newStringOfCap(cap)

proc freeze*(r: Rope) {.inline.} = discard

proc resetRopeCache* = discard

template rope*(s: string): string = s

proc rope*(i: BiggestInt): Rope =
  ## Converts an int to a rope.
  result = rope($i)

proc rope*(f: BiggestFloat): Rope =
  ## Converts a float to a rope.
  result = rope($f)

proc writeRope*(f: File, r: Rope) =
  ## writes a rope to a file.
  write(f, r)

proc writeRope*(head: Rope, filename: AbsoluteFile): bool =
  var f: File = default(File)
  if open(f, filename.string, fmWrite):
    writeRope(f, head)
    close(f)
    result = true
  else:
    result = false

proc prepend*(a: var Rope, b: string) = a = b & a

proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
  var i = 0
  result = newRopeAppender()
  var num = 0
  while i < frmt.len:
    if frmt[i] == '$':
      inc(i)                  # skip '$'
      case frmt[i]
      of '$':
        result.add("$")
        inc(i)
      of '#':
        inc(i)
        result.add(args[num])
        inc(num)
      of '0'..'9':
        var j = 0
        while true:
          j = j * 10 + ord(frmt[i]) - ord('0')
          inc(i)
          if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
        num = j
        if j > high(args) + 1:
          raiseAssert "invalid format string: " & frmt
        else:
          result.add(args[j-1])
      of '{':
        inc(i)
        var j = 0
        while frmt[i] in {'0'..'9'}:
          j = j * 10 + ord(frmt[i]) - ord('0')
          inc(i)
        num = j
        if frmt[i] == '}': inc(i)
        else:
          raiseAssert "invalid format string: " & frmt

        if j > high(args) + 1:
          raiseAssert "invalid format string: " & frmt
        else:
          result.add(args[j-1])
      of 'n':
        result.add("\n")
        inc(i)
      of 'N':
        result.add("\n")
        inc(i)
      else:
        raiseAssert "invalid format string: " & frmt
    else:
      result.add(frmt[i])
      inc(i)

proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
  runtimeFormat(frmt, args)

template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
  ## shortcut for ``add(c, frmt % args)``.
  c.add(frmt % args)

const
  bufSize = 1024              # 1 KB is reasonable

proc equalsFile*(s: Rope, f: File): bool =
  ## returns true if the contents of the file `f` equal `r`.
  var
    buf: array[bufSize, char] = default(array[bufSize, char])
    bpos = buf.len
    blen = buf.len
    btotal = 0
    rtotal = 0

  when true:
    var spos = 0
    rtotal += s.len
    while spos < s.len:
      if bpos == blen:
        # Read more data
        bpos = 0
        blen = readBuffer(f, addr(buf[0]), buf.len)
        btotal += blen
        if blen == 0:  # no more data in file
          result = false
          return
      let n = min(blen - bpos, s.len - spos)
      # TODO There's gotta be a better way of comparing here...
      if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
        result = false
        return
      spos += n
      bpos += n

  result = readBuffer(f, addr(buf[0]), 1) == 0 and
      btotal == rtotal # check that we've read all

proc equalsFile*(r: Rope, filename: AbsoluteFile): bool =
  ## returns true if the contents of the file `f` equal `r`. If `f` does not
  ## exist, false is returned.
  var f: File = default(File)
  result = open(f, filename.string)
  if result:
    result = equalsFile(r, f)
    close(f)