summary refs log tree commit diff stats
path: root/nim/rodread.pas
diff options
context:
space:
mode:
Diffstat (limited to 'nim/rodread.pas')
-rwxr-xr-xnim/rodread.pas1137
1 files changed, 0 insertions, 1137 deletions
diff --git a/nim/rodread.pas b/nim/rodread.pas
deleted file mode 100755
index 457ad6cc2..000000000
--- a/nim/rodread.pas
+++ /dev/null
@@ -1,1137 +0,0 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2009 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-unit rodread;
-
-// This module is responsible for loading of rod files.
-(*
-  Reading and writing binary files are really hard to debug. Therefore we use
-  a special text format. ROD-files only describe the interface of a module.
-  Thus they are smaller than the source files most of the time. Even if they
-  are bigger, they are more efficient to process because symbols are only
-  loaded on demand.
-  It consists of:
-
-  - a header:
-    NIM:$fileversion\n
-  - the module's id (even if the module changed, its ID will not!):
-    ID:Ax3\n
-  - CRC value of this module:
-    CRC:CRC-val\n
-  - a section containing the compiler options and defines this
-    module has been compiled with:
-    OPTIONS:options\n
-    DEFINES:defines\n
-  - FILES(
-    myfile.inc
-    lib/mymodA
-    )
-  - a include file dependency section:
-    INCLUDES(
-    <fileidx> <CRC of myfile.inc>\n # fileidx is the LINE in the file section!
-    )
-  - a module dependency section:
-    DEPS: <fileidx> <fileidx>\n
-  - an interface section:
-    INTERF(
-    identifier1 id\n # id is the symbol's id
-    identifier2 id\n
-    )
-  - a compiler proc section:
-    COMPILERPROCS(
-    identifier1 id\n # id is the symbol's id    
-    )
-  - an index consisting of (ID, linenumber)-pairs:
-    INDEX(
-    id-diff idx-diff\n
-    id-diff idx-diff\n
-    )
-  - an import index consisting of (ID, moduleID)-pairs:
-    IMPORTS(
-    id-diff moduleID-diff\n
-    id-diff moduleID-diff\n
-    )
-  - a list of all exported type converters because they are needed for correct
-    semantic checking:
-    CONVERTERS:id id\n   # position of the symbol in the DATA section
-  - an AST section that contains the module's AST:
-    INIT(
-    idx\n  # position of the node in the DATA section
-    idx\n
-    )
-  - a data section, where each type, symbol or AST is stored.
-    DATA(
-    type
-    (node)
-    sym
-    )
-
-  We now also do index compression, because an index always needs to be read.
-*)
-
-interface
-
-{$include 'config.inc'}
-
-uses
-  sysutils, nsystem, nos, options, strutils, nversion, ast, astalgo, msgs,
-  platform, condsyms, ropes, idents, crc;
-
-type
-  TReasonForRecompile = (
-    rrEmpty,     // used by moddeps module
-    rrNone,      // no need to recompile
-    rrRodDoesNotExist, // rod file does not exist
-    rrRodInvalid, // rod file is invalid
-    rrCrcChange, // file has been edited since last recompilation
-    rrDefines,   // defines have changed
-    rrOptions,   // options have changed
-    rrInclDeps,  // an include has changed
-    rrModDeps    // a module this module depends on has been changed
-  );
-const
-  reasonToFrmt: array [TReasonForRecompile] of string = (
-    '',
-    'no need to recompile: $1',
-    'symbol file for $1 does not exist',
-    'symbol file for $1 has the wrong version',
-    'file edited since last compilation: $1',
-    'list of conditional symbols changed for: $1',
-    'list of options changed for: $1',
-    'an include file edited: $1',
-    'a module $1 depends on has changed'
-  );
-
-type
-  TIndex = record // an index with compression
-    lastIdxKey, lastIdxVal: int;
-    tab: TIITable;
-    r: PRope;     // writers use this
-    offset: int;  // readers use this
-  end;
-  TRodReader = object(NObject)
-    pos: int;    // position; used for parsing
-    s: string;   // the whole file in memory
-    options: TOptions;
-    reason: TReasonForRecompile;
-    modDeps: TStringSeq;
-    files: TStringSeq;
-    dataIdx: int;       // offset of start of data section
-    convertersIdx: int; // offset of start of converters section
-    initIdx, interfIdx, compilerProcsIdx, cgenIdx: int;
-    filename: string;
-    index, imports: TIndex;
-    readerIndex: int;
-    line: int;          // only used for debugging, but is always in the code
-    moduleID: int;
-    syms: TIdTable;     // already processed symbols
-  end;
-  PRodReader = ^TRodReader;
-
-const
-  FileVersion = '1012'; // modify this if the rod-format changes!
-
-var
-  rodCompilerprocs: TStrTable; // global because this is needed by magicsys
-
-
-function handleSymbolFile(module: PSym; const filename: string): PRodReader;
-function GetCRC(const filename: string): TCrc32;
-
-function loadInitSection(r: PRodReader): PNode;
-
-procedure loadStub(s: PSym);
-
-function encodeInt(x: BiggestInt): PRope;
-function encode(const s: string): PRope;
-
-implementation
-
-var
-  gTypeTable: TIdTable;
-
-function rrGetSym(r: PRodReader; id: int; const info: TLineInfo): PSym; forward;
-  // `info` is only used for debugging purposes
-
-function rrGetType(r: PRodReader; id: int; const info: TLineInfo): PType; forward;
-
-function decode(r: PRodReader): string; forward;
-function decodeInt(r: PRodReader): int; forward;
-function decodeBInt(r: PRodReader): biggestInt; forward;
-
-function encode(const s: string): PRope;
-var
-  i: int;
-  res: string;
-begin
-  res := '';
-  for i := strStart to length(s)+strStart-1 do begin
-    case s[i] of
-      'a'..'z', 'A'..'Z', '0'..'9', '_':
-        addChar(res, s[i]);
-      else
-        res := res +{&} '\' +{&} toHex(ord(s[i]), 2)
-    end
-  end;
-  result := toRope(res);
-end;
-
-procedure encodeIntAux(var str: string; x: BiggestInt);
-const
-  chars: string =
-    '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-var
-  v, rem: biggestInt;
-  d: char;
-  idx: int;
-begin
-  v := x;
-  rem := v mod 190;
-  if (rem < 0) then begin
-    str := str + '-';
-    v := -(v div 190);
-    rem := -rem;
-  end
-  else
-    v := v div 190;
-  idx := int(rem);
-  if idx < 62 then d := chars[idx+strStart]
-  else d := chr(idx - 62 + 128);
-  if (v <> 0) then encodeIntAux(str, v);
-  addChar(str, d);
-end;
-
-function encodeInt(x: BiggestInt): PRope;
-var
-  res: string;
-begin
-  res := '';
-  encodeIntAux(res, x);
-  result := toRope(res);
-end;
-
-
-procedure decodeLineInfo(r: PRodReader; var info: TLineInfo);
-begin
-  if r.s[r.pos] = '?' then begin
-    inc(r.pos);
-    if r.s[r.pos] = ',' then
-      info.col := int16(-1)
-    else
-      info.col := int16(decodeInt(r));
-    if r.s[r.pos] = ',' then begin
-      inc(r.pos);
-      if r.s[r.pos] = ',' then info.line := int16(-1)
-      else info.line := int16(decodeInt(r));
-      if r.s[r.pos] = ',' then begin
-        inc(r.pos);
-        info := newLineInfo(r.files[decodeInt(r)], info.line, info.col);
-      end
-    end
-  end
-end;
-
-function decodeNode(r: PRodReader; const fInfo: TLineInfo): PNode;
-var
-  id: int;
-  fl: string;
-begin
-  result := nil;
-  if r.s[r.pos] = '(' then begin
-    inc(r.pos);
-    if r.s[r.pos] = ')' then begin
-      inc(r.pos); exit; // nil node
-    end;
-    result := newNodeI(TNodeKind(decodeInt(r)), fInfo);
-    decodeLineInfo(r, result.info);
-    if r.s[r.pos] = '$' then begin
-      inc(r.pos);
-      result.flags := {@cast}TNodeFlags(int32(decodeInt(r)));
-    end;
-    if r.s[r.pos] = '^' then begin
-      inc(r.pos);
-      id := decodeInt(r);
-      result.typ := rrGetType(r, id, result.info);
-    end;
-    case result.kind of
-      nkCharLit..nkInt64Lit: begin
-        if r.s[r.pos] = '!' then begin
-          inc(r.pos);
-          result.intVal := decodeBInt(r);
-        end
-      end;
-      nkFloatLit..nkFloat64Lit: begin
-        if r.s[r.pos] = '!' then begin
-          inc(r.pos);
-          fl := decode(r);
-          result.floatVal := parseFloat(fl);
-        end
-      end;
-      nkStrLit..nkTripleStrLit: begin
-        if r.s[r.pos] = '!' then begin
-          inc(r.pos);
-          result.strVal := decode(r);
-        end
-        else
-          result.strVal := ''; // BUGFIX
-      end;
-      nkIdent: begin
-        if r.s[r.pos] = '!' then begin
-          inc(r.pos);
-          fl := decode(r);
-          result.ident := getIdent(fl);
-        end
-        else
-          internalError(result.info, 'decodeNode: nkIdent');
-      end;
-      nkSym: begin
-        if r.s[r.pos] = '!' then begin
-          inc(r.pos);
-          id := decodeInt(r);
-          result.sym := rrGetSym(r, id, result.info);
-        end
-        else
-          internalError(result.info, 'decodeNode: nkSym');
-      end;
-      else begin
-        while r.s[r.pos] <> ')' do
-          addSon(result, decodeNode(r, result.info));
-      end
-    end;
-    if r.s[r.pos] = ')' then inc(r.pos)
-    else internalError(result.info, 'decodeNode');
-  end
-  else InternalError(result.info, 'decodeNode ' + r.s[r.pos])
-end;
-
-procedure decodeLoc(r: PRodReader; var loc: TLoc; const info: TLineInfo);
-begin
-  if r.s[r.pos] = '<' then begin
-    inc(r.pos);
-    if r.s[r.pos] in ['0'..'9', 'a'..'z', 'A'..'Z'] then
-      loc.k := TLocKind(decodeInt(r))
-    else
-      loc.k := low(loc.k);
-    if r.s[r.pos] = '*' then begin
-      inc(r.pos);
-      loc.s := TStorageLoc(decodeInt(r));
-    end
-    else
-      loc.s := low(loc.s);
-    if r.s[r.pos] = '$' then begin
-      inc(r.pos);
-      loc.flags := {@cast}TLocFlags(int32(decodeInt(r)));
-    end
-    else
-      loc.flags := {@set}[];
-    if r.s[r.pos] = '^' then begin
-      inc(r.pos);
-      loc.t := rrGetType(r, decodeInt(r), info);
-    end
-    else
-      loc.t := nil;
-    if r.s[r.pos] = '!' then begin
-      inc(r.pos);
-      loc.r := toRope(decode(r));
-    end
-    else
-      loc.r := nil;
-    if r.s[r.pos] = '?' then begin
-      inc(r.pos);
-      loc.a := decodeInt(r);
-    end
-    else
-      loc.a := 0;
-    if r.s[r.pos] = '>' then inc(r.pos)
-    else InternalError(info, 'decodeLoc ' + r.s[r.pos]);
-  end
-end;
-
-function decodeType(r: PRodReader; const info: TLineInfo): PType;
-var
-  d: int;
-begin
-  result := nil;
-  if r.s[r.pos] = '[' then begin
-    inc(r.pos);
-    if r.s[r.pos] = ']' then begin
-      inc(r.pos); exit; // nil type
-    end;
-  end;
-  new(result);
-{@ignore}
-  FillChar(result^, sizeof(result^), 0);
-{@emit}
-  result.kind := TTypeKind(decodeInt(r));
-  if r.s[r.pos] = '+' then begin
-    inc(r.pos);
-    result.id := decodeInt(r);
-    setId(result.id);
-    if debugIds then registerID(result);
-  end
-  else
-    InternalError(info, 'decodeType: no id');
-  IdTablePut(gTypeTable, result, result); // here this also
-  // avoids endless recursion for recursive type
-  if r.s[r.pos] = '(' then
-    result.n := decodeNode(r, UnknownLineInfo());
-  if r.s[r.pos] = '$' then begin
-    inc(r.pos);
-    result.flags := {@cast}TTypeFlags(int32(decodeInt(r)));
-  end;
-  if r.s[r.pos] = '?' then begin
-    inc(r.pos);
-    result.callConv := TCallingConvention(decodeInt(r));
-  end;
-  if r.s[r.pos] = '*' then begin
-    inc(r.pos);
-    result.owner := rrGetSym(r, decodeInt(r), info);
-  end;
-  if r.s[r.pos] = '&' then begin
-    inc(r.pos);
-    result.sym := rrGetSym(r, decodeInt(r), info);
-  end;
-  if r.s[r.pos] = '/' then begin
-    inc(r.pos);
-    result.size := decodeInt(r);
-  end
-  else result.size := -1;
-  if r.s[r.pos] = '=' then begin
-    inc(r.pos);
-    result.align := decodeInt(r);
-  end
-  else result.align := 2;
-  if r.s[r.pos] = '@' then begin
-    inc(r.pos);
-    result.containerID := decodeInt(r);
-  end;
-  decodeLoc(r, result.loc, info);
-  while r.s[r.pos] = '^' do begin
-    inc(r.pos);
-    if r.s[r.pos] = '(' then begin
-      inc(r.pos);
-      if r.s[r.pos] = ')' then inc(r.pos)
-      else InternalError(info, 'decodeType ^(' + r.s[r.pos]);
-      addSon(result, nil);
-    end
-    else begin
-      d := decodeInt(r);
-      addSon(result, rrGetType(r, d, info));
-    end;
-  end
-end;
-
-function decodeLib(r: PRodReader): PLib;
-begin
-  result := nil;
-  if r.s[r.pos] = '|' then begin
-    new(result);
-  {@ignore}
-    fillChar(result^, sizeof(result^), 0);
-  {@emit}
-    inc(r.pos);
-    result.kind := TLibKind(decodeInt(r));
-    if r.s[r.pos] <> '|' then InternalError('decodeLib: 1');
-    inc(r.pos);
-    result.name := toRope(decode(r));
-    if r.s[r.pos] <> '|' then InternalError('decodeLib: 2');
-    inc(r.pos);
-    result.path := decode(r);
-  end
-end;
-
-function decodeSym(r: PRodReader; const info: TLineInfo): PSym;
-var
-  k: TSymKind;
-  id: int;
-  ident: PIdent;
-begin
-  result := nil;
-  if r.s[r.pos] = '{' then begin
-    inc(r.pos);
-    if r.s[r.pos] = '}' then begin
-      inc(r.pos); exit; // nil sym
-    end
-  end;
-  k := TSymKind(decodeInt(r));
-  if r.s[r.pos] = '+' then begin
-    inc(r.pos);
-    id := decodeInt(r);
-    setId(id);
-  end
-  else
-    InternalError(info, 'decodeSym: no id');
-  if r.s[r.pos] = '&' then begin
-    inc(r.pos);
-    ident := getIdent(decode(r));
-  end
-  else
-    InternalError(info, 'decodeSym: no ident');
-  result := PSym(IdTableGet(r.syms, id));
-  if result = nil then begin
-    new(result);
-  {@ignore}
-    FillChar(result^, sizeof(result^), 0);
-  {@emit}
-    result.id := id;
-    IdTablePut(r.syms, result, result);
-    if debugIds then registerID(result);
-  end
-  else if (result.id <> id) then
-    InternalError(info, 'decodeSym: wrong id');
-  result.kind := k;
-  result.name := ident;
-  // read the rest of the symbol description:
-  if r.s[r.pos] = '^' then begin
-    inc(r.pos);
-    result.typ := rrGetType(r, decodeInt(r), info);
-  end;
-  decodeLineInfo(r, result.info);
-  if r.s[r.pos] = '*' then begin
-    inc(r.pos);
-    result.owner := rrGetSym(r, decodeInt(r), result.info);
-  end;
-  if r.s[r.pos] = '$' then begin
-    inc(r.pos);
-    result.flags := {@cast}TSymFlags(int32(decodeInt(r)));
-  end;
-  if r.s[r.pos] = '@' then begin
-    inc(r.pos);
-    result.magic := TMagic(decodeInt(r));
-  end;
-  if r.s[r.pos] = '(' then
-    result.ast := decodeNode(r, result.info);
-  if r.s[r.pos] = '!' then begin
-    inc(r.pos);
-    result.options := {@cast}TOptions(int32(decodeInt(r)));
-  end
-  else
-    result.options := r.options;
-  if r.s[r.pos] = '%' then begin
-    inc(r.pos);
-    result.position := decodeInt(r);
-  end
-  else
-    result.position := 0; // BUGFIX: this may have been misused as reader index!
-  if r.s[r.pos] = '`' then begin
-    inc(r.pos);
-    result.offset := decodeInt(r);
-  end
-  else
-    result.offset := -1;
-  decodeLoc(r, result.loc, result.info);
-  result.annex := decodeLib(r);
-end;
-
-function decodeInt(r: PRodReader): int; // base 190 numbers
-var
-  i: int;
-  sign: int;
-begin
-  i := r.pos;
-  sign := -1;
-  assert(r.s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '-', #128..#255]);
-  if r.s[i] = '-' then begin
-    inc(i);
-    sign := 1
-  end;
-  result := 0;
-  while true do begin
-    case r.s[i] of
-      '0'..'9': result := result * 190 - (ord(r.s[i]) - ord('0'));
-      'a'..'z': result := result * 190 - (ord(r.s[i]) - ord('a') + 10);
-      'A'..'Z': result := result * 190 - (ord(r.s[i]) - ord('A') + 36);
-      #128..#255: result := result * 190 - (ord(r.s[i]) - 128 + 62);
-      else break;
-    end;
-    inc(i)
-  end;
-  result := result * sign;
-  r.pos := i
-end;
-
-function decodeBInt(r: PRodReader): biggestInt;
-var
-  i: int;
-  sign: biggestInt;
-begin
-  i := r.pos;
-  sign := -1;
-  assert(r.s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '-', #128..#255]);
-  if r.s[i] = '-' then begin
-    inc(i);
-    sign := 1
-  end;
-  result := 0;
-  while true do begin
-    case r.s[i] of
-      '0'..'9': result := result * 190 - (ord(r.s[i]) - ord('0'));
-      'a'..'z': result := result * 190 - (ord(r.s[i]) - ord('a') + 10);
-      'A'..'Z': result := result * 190 - (ord(r.s[i]) - ord('A') + 36);
-      #128..#255: result := result * 190 - (ord(r.s[i]) - 128 + 62);
-      else break;
-    end;
-    inc(i)
-  end;
-  result := result * sign;
-  r.pos := i
-end;
-
-procedure hexChar(c: char; var xi: int);
-begin
-  case c of
-    '0'..'9': xi := (xi shl 4) or (ord(c) - ord('0'));
-    'a'..'f': xi := (xi shl 4) or (ord(c) - ord('a') + 10);
-    'A'..'F': xi := (xi shl 4) or (ord(c) - ord('A') + 10);
-    else begin end
-  end
-end;
-
-function decode(r: PRodReader): string;
-var
-  i, xi: int;
-begin
-  i := r.pos;
-  result := '';
-  while true do begin
-    case r.s[i] of
-      '\': begin
-        inc(i, 3); xi := 0;
-        hexChar(r.s[i-2], xi);
-        hexChar(r.s[i-1], xi);
-        addChar(result, chr(xi));
-      end;
-      'a'..'z', 'A'..'Z', '0'..'9', '_': begin
-        addChar(result, r.s[i]);
-        inc(i);
-      end
-      else break
-    end
-  end;
-  r.pos := i;
-end;
-
-procedure skipSection(r: PRodReader);
-var
-  c: int;
-begin
-  if r.s[r.pos] = ':' then begin
-    while r.s[r.pos] > #10 do inc(r.pos);
-  end
-  else if r.s[r.pos] = '(' then begin
-    c := 0; // count () pairs
-    inc(r.pos);
-    while true do begin
-      case r.s[r.pos] of
-        #10: inc(r.line);
-        '(': inc(c);
-        ')': begin
-          if c = 0 then begin inc(r.pos); break end
-          else if c > 0 then dec(c);
-        end;
-        #0: break; // end of file
-        else begin end;
-      end;
-      inc(r.pos);
-    end
-  end
-  else
-    InternalError('skipSection ' + toString(r.line));
-end;
-
-function rdWord(r: PRodReader): string;
-begin
-  result := '';
-  while r.s[r.pos] in ['A'..'Z', '_', 'a'..'z', '0'..'9'] do begin
-    addChar(result, r.s[r.pos]);
-    inc(r.pos);
-  end;
-end;
-
-function newStub(r: PRodReader; const name: string; id: int): PSym;
-begin
-  new(result);
-{@ignore}
-  fillChar(result^, sizeof(result^), 0);
-{@emit}
-  result.kind := skStub;
-  result.id := id;
-  result.name := getIdent(name);
-  result.position := r.readerIndex;
-  setID(id);
-  //MessageOut(result.name.s);
-  if debugIds then registerID(result);
-end;
-
-procedure processInterf(r: PRodReader; module: PSym);
-var
-  s: PSym;
-  w: string;
-  key: int;
-begin
-  if r.interfIdx = 0 then InternalError('processInterf');
-  r.pos := r.interfIdx;
-  while (r.s[r.pos] > #10) and (r.s[r.pos] <> ')') do begin
-    w := decode(r);
-    inc(r.pos);
-    key := decodeInt(r);
-    inc(r.pos); // #10
-    s := newStub(r, w, key);
-    s.owner := module;
-    StrTableAdd(module.tab, s);
-    IdTablePut(r.syms, s, s);
-  end;
-end;
-
-procedure processCompilerProcs(r: PRodReader; module: PSym);
-var
-  s: PSym;
-  w: string;
-  key: int;
-begin
-  if r.compilerProcsIdx = 0 then InternalError('processCompilerProcs');
-  r.pos := r.compilerProcsIdx;
-  while (r.s[r.pos] > #10) and (r.s[r.pos] <> ')') do begin
-    w := decode(r);
-    inc(r.pos);
-    key := decodeInt(r);
-    inc(r.pos); // #10
-    s := PSym(IdTableGet(r.syms, key));
-    if s = nil then begin
-      s := newStub(r, w, key);
-      s.owner := module;
-      IdTablePut(r.syms, s, s);
-    end;
-    StrTableAdd(rodCompilerProcs, s);
-  end;
-end;
-
-procedure processIndex(r: PRodReader; var idx: TIndex);
-var
-  key, val, tmp: int;
-begin
-  inc(r.pos, 2); // skip "(\10"
-  inc(r.line);
-  while (r.s[r.pos] > #10) and (r.s[r.pos] <> ')') do begin
-    tmp := decodeInt(r);
-    if r.s[r.pos] = ' ' then begin
-      inc(r.pos);
-      key := idx.lastIdxKey + tmp;
-      val := decodeInt(r) + idx.lastIdxVal;
-    end
-    else begin
-      key := idx.lastIdxKey + 1;
-      val := tmp + idx.lastIdxVal;
-    end;
-    IITablePut(idx.tab, key, val);
-    idx.lastIdxKey := key;
-    idx.lastIdxVal := val;
-    setID(key); // ensure that this id will not be used
-    if r.s[r.pos] = #10 then begin inc(r.pos); inc(r.line) end;
-  end;
-  if r.s[r.pos] = ')' then inc(r.pos);
-end;
-
-procedure processRodFile(r: PRodReader; crc: TCrc32);
-var
-  section, w: string;
-  d, L, inclCrc: int;
-begin
-  while r.s[r.pos] <> #0 do begin
-    section := rdWord(r);
-    if r.reason <> rrNone then break; // no need to process this file further
-    if section = 'CRC' then begin
-      inc(r.pos); // skip ':'
-      if int(crc) <> decodeInt(r) then
-        r.reason := rrCrcChange
-    end
-    else if section = 'ID' then begin
-      inc(r.pos); // skip ':'
-      r.moduleID := decodeInt(r);
-      setID(r.moduleID);
-    end
-    else if section = 'OPTIONS' then begin
-      inc(r.pos); // skip ':'
-      r.options := {@cast}TOptions(int32(decodeInt(r)));
-      if options.gOptions <> r.options then r.reason := rrOptions
-    end
-    else if section = 'DEFINES' then begin
-      inc(r.pos); // skip ':'
-      d := 0;
-      while r.s[r.pos] > #10 do begin
-        w := decode(r);
-        inc(d);
-        if not condsyms.isDefined(getIdent(w)) then begin
-          r.reason := rrDefines;
-          //MessageOut('not defined, but should: ' + w);
-        end;
-        if r.s[r.pos] = ' ' then inc(r.pos);
-      end;
-      if (d <> countDefinedSymbols()) then
-        r.reason := rrDefines
-    end
-    else if section = 'FILES' then begin
-      inc(r.pos, 2); // skip "(\10"
-      inc(r.line);
-      L := 0;
-      while (r.s[r.pos] > #10) and (r.s[r.pos] <> ')') do begin
-        setLength(r.files, L+1);
-        r.files[L] := decode(r);
-        inc(r.pos); // skip #10
-        inc(r.line);
-        inc(L);
-      end;
-      if r.s[r.pos] = ')' then inc(r.pos);
-    end
-    else if section = 'INCLUDES' then begin
-      inc(r.pos, 2); // skip "(\10"
-      inc(r.line);
-      while (r.s[r.pos] > #10) and (r.s[r.pos] <> ')') do begin
-        w := r.files[decodeInt(r)];
-        inc(r.pos); // skip ' '
-        inclCrc := decodeInt(r);
-        if r.reason = rrNone then begin
-          if not ExistsFile(w) or (inclCrc <> int(crcFromFile(w))) then
-            r.reason := rrInclDeps
-        end;
-        if r.s[r.pos] = #10 then begin inc(r.pos); inc(r.line) end;
-      end;
-      if r.s[r.pos] = ')' then inc(r.pos);
-    end
-    else if section = 'DEPS' then begin
-      inc(r.pos); // skip ':'
-      L := 0;
-      while (r.s[r.pos] > #10) do begin
-        setLength(r.modDeps, L+1);
-        r.modDeps[L] := r.files[decodeInt(r)];
-        inc(L);
-        if r.s[r.pos] = ' ' then inc(r.pos);
-      end;
-    end
-    else if section = 'INTERF' then begin
-      r.interfIdx := r.pos+2;
-      skipSection(r);
-    end
-    else if section = 'COMPILERPROCS' then begin
-      r.compilerProcsIdx := r.pos+2;
-      skipSection(r);
-    end
-    else if section = 'INDEX' then begin
-      processIndex(r, r.index);
-    end
-    else if section = 'IMPORTS' then begin
-      processIndex(r, r.imports);
-    end
-    else if section = 'CONVERTERS' then begin
-      r.convertersIdx := r.pos+1;
-      skipSection(r);
-    end
-    else if section = 'DATA' then begin
-      r.dataIdx := r.pos+2; // "(\10"
-      // We do not read the DATA section here! We read the needed objects on
-      // demand.
-      skipSection(r);
-    end
-    else if section = 'INIT' then begin
-      r.initIdx := r.pos+2; // "(\10"
-      skipSection(r);
-    end
-    else if section = 'CGEN' then begin
-      r.cgenIdx := r.pos+2;
-      skipSection(r);
-    end
-    else begin
-      MessageOut('skipping section: ' + toString(r.pos));
-      skipSection(r);
-    end;
-    if r.s[r.pos] = #10 then begin inc(r.pos); inc(r.line) end;
-  end
-end;
-
-function newRodReader(const modfilename: string; crc: TCrc32;
-                      readerIndex: int): PRodReader;
-var
-  version: string;
-  r: PRodReader;
-begin
-  new(result);
-{@ignore}
-  fillChar(result^, sizeof(result^), 0);
-{@emit result.files := @[];}
-{@emit result.modDeps := @[];}
-  r := result;
-  r.reason := rrNone;
-  r.pos := strStart;
-  r.line := 1;
-  r.readerIndex := readerIndex;
-  r.filename := modfilename;    
-  InitIdTable(r.syms);
-  r.s := readFile(modfilename) {@ignore} + #0 {@emit};
-  if startsWith(r.s, 'NIM:') then begin
-    initIITable(r.index.tab);
-    initIITable(r.imports.tab);
-    // looks like a ROD file
-    inc(r.pos, 4);
-    version := '';
-    while not (r.s[r.pos] in [#0,#10]) do begin
-      addChar(version, r.s[r.pos]);
-      inc(r.pos);
-    end;
-    if r.s[r.pos] = #10 then inc(r.pos);
-    if version = FileVersion then begin
-      // since ROD files are only for caching, no backwarts compability is
-      // needed
-      processRodFile(r, crc);
-    end
-    else
-      result := nil
-  end
-  else
-    result := nil;
-end;
-
-function rrGetType(r: PRodReader; id: int; const info: TLineInfo): PType;
-var
-  oldPos, d: int;
-begin
-  result := PType(IdTableGet(gTypeTable, id));
-  if result = nil then begin
-    // load the type:
-    oldPos := r.pos;
-    d := IITableGet(r.index.tab, id);
-    if d = invalidKey then InternalError(info, 'rrGetType');
-    r.pos := d + r.dataIdx;
-    result := decodeType(r, info);
-    r.pos := oldPos;
-  end;
-end;
-
-type
-  TFileModuleRec = record
-    filename: string;
-    reason: TReasonForRecompile;
-    rd: PRodReader;
-    crc: TCrc32;
-  end;
-  TFileModuleMap = array of TFileModuleRec;
-var
-  gMods: TFileModuleMap = {@ignore} nil {@emit @[]}; // all compiled modules
-
-function decodeSymSafePos(rd: PRodReader; offset: int;
-                          const info: TLineInfo): PSym;
-var
-  oldPos: int;
-begin
-  if rd.dataIdx = 0 then InternalError(info, 'dataIdx == 0');
-  oldPos := rd.pos;
-  rd.pos := offset + rd.dataIdx;
-  result := decodeSym(rd, info);
-  rd.pos := oldPos;
-end;
-
-function rrGetSym(r: PRodReader; id: int; const info: TLineInfo): PSym;
-var
-  d, i, moduleID: int;
-  rd: PRodReader;
-begin
-  result := PSym(IdTableGet(r.syms, id));
-  if result = nil then begin
-    // load the symbol:
-    d := IITableGet(r.index.tab, id);
-    if d = invalidKey then begin
-      moduleID := IiTableGet(r.imports.tab, id);
-      if moduleID < 0 then
-        InternalError(info,
-          'missing from both indexes: +' + ropeToStr(encodeInt(id)));
-      // find the reader with the correct moduleID:
-      for i := 0 to high(gMods) do begin
-        rd := gMods[i].rd;
-        if (rd <> nil) then begin
-          if (rd.moduleID = moduleID) then begin
-            d := IITableGet(rd.index.tab, id);
-            if d <> invalidKey then begin
-              result := decodeSymSafePos(rd, d, info);
-              break
-            end
-            else
-              InternalError(info,
-                'rrGetSym: no reader found: +' + ropeToStr(encodeInt(id)));
-          end
-          else begin
-            //if IiTableGet(rd.index.tab, id) <> invalidKey then
-            // XXX expensive check!
-              //InternalError(info,
-              //'id found in other module: +' + ropeToStr(encodeInt(id)))
-          end
-        end
-      end;
-    end
-    else begin
-      // own symbol:
-      result := decodeSymSafePos(r, d, info);
-    end;
-  end;
-  if (result <> nil) and (result.kind = skStub) then loadStub(result);
-end;
-
-function loadInitSection(r: PRodReader): PNode;
-var
-  d, oldPos, p: int;
-begin
-  if (r.initIdx = 0) or (r.dataIdx = 0) then InternalError('loadInitSection');
-  oldPos := r.pos;
-  r.pos := r.initIdx;
-  result := newNode(nkStmtList);
-  while (r.s[r.pos] > #10) and (r.s[r.pos] <> ')') do begin
-    d := decodeInt(r);
-    inc(r.pos); // #10
-    p := r.pos;
-    r.pos := d + r.dataIdx;
-    addSon(result, decodeNode(r, UnknownLineInfo()));
-    r.pos := p;
-  end;
-  r.pos := oldPos;
-end;
-
-procedure loadConverters(r: PRodReader);
-var
-  d: int;
-begin
-  // We have to ensure that no exported converter is a stub anymore.
-  if (r.convertersIdx = 0) or (r.dataIdx = 0) then
-    InternalError('importConverters');
-  r.pos := r.convertersIdx;
-  while (r.s[r.pos] > #10) do begin
-    d := decodeInt(r);
-    {@discard} rrGetSym(r, d, UnknownLineInfo());
-    if r.s[r.pos] = ' ' then inc(r.pos)
-  end;
-end;
-
-function getModuleIdx(const filename: string): int;
-var
-  i: int;
-begin
-  for i := 0 to high(gMods) do
-    if sameFile(gMods[i].filename, filename) then begin
-      result := i; exit
-    end;
-  // not found, reserve space:
-  result := length(gMods);
-  setLength(gMods, result+1);
-end;
-
-function checkDep(const filename: string): TReasonForRecompile;
-var
-  crc: TCrc32;
-  r: PRodReader;
-  rodfile: string;
-  idx, i: int;
-  res: TReasonForRecompile;
-begin
-  idx := getModuleIdx(filename);
-  if gMods[idx].reason <> rrEmpty then begin
-    // reason has already been computed for this module:
-    result := gMods[idx].reason; exit
-  end;
-  crc := crcFromFile(filename);
-  gMods[idx].reason := rrNone; // we need to set it here to avoid cycles
-  gMods[idx].filename := filename;
-  gMods[idx].crc := crc;
-  result := rrNone;
-  r := nil;
-  rodfile := toGeneratedFile(filename, RodExt);
-  if ExistsFile(rodfile) then begin
-    r := newRodReader(rodfile, crc, idx);
-    if r = nil then
-      result := rrRodInvalid
-    else begin
-      result := r.reason;
-      if result = rrNone then begin
-        // check modules it depends on
-        // NOTE: we need to process the entire module graph so that no ID will
-        // be used twice! However, compilation speed does not suffer much from
-        // this, since results are cached.
-        res := checkDep(JoinPath(options.libpath, addFileExt('system', nimExt)));
-        if res <> rrNone then result := rrModDeps;
-        for i := 0 to high(r.modDeps) do begin
-          res := checkDep(r.modDeps[i]);
-          if res <> rrNone then begin
-            result := rrModDeps;
-            //break // BUGFIX: cannot break here!
-          end
-        end
-      end
-    end
-  end
-  else
-    result := rrRodDoesNotExist;
-  if (result <> rrNone) and (gVerbosity > 0) then
-    MessageOut(format(reasonToFrmt[result], [filename]));
-  if (result <> rrNone) or (optForceFullMake in gGlobalOptions) then begin
-    // recompilation is necessary:
-    r := nil;
-  end;
-  gMods[idx].rd := r;
-  gMods[idx].reason := result; // now we know better
-end;
-
-function handleSymbolFile(module: PSym; const filename: string): PRodReader;
-var
-  idx: int;
-begin
-  if not (optSymbolFiles in gGlobalOptions) then begin
-    module.id := getID();
-    result := nil;
-    exit
-  end;
-  {@discard} checkDep(filename);
-  idx := getModuleIdx(filename);
-  if gMods[idx].reason = rrEmpty then InternalError('handleSymbolFile');
-  result := gMods[idx].rd;
-  if result <> nil then begin
-    module.id := result.moduleID;
-    IdTablePut(result.syms, module, module);
-    processInterf(result, module);
-    processCompilerProcs(result, module);
-    loadConverters(result);
-  end
-  else
-    module.id := getID();
-end;
-
-function GetCRC(const filename: string): TCrc32;
-var
-  idx: int;
-begin
-  idx := getModuleIdx(filename);
-  result := gMods[idx].crc;
-end;
-
-procedure loadStub(s: PSym);
-var
-  rd: PRodReader;
-  d, theId: int;
-  rs: PSym;
-begin
-  if s.kind <> skStub then InternalError('loadStub');
-  //MessageOut('loading stub: ' + s.name.s);
-  rd := gMods[s.position].rd;
-  theId := s.id; // used for later check
-  d := IITableGet(rd.index.tab, s.id);
-  if d = invalidKey then InternalError('loadStub: invalid key');
-  rs := decodeSymSafePos(rd, d, UnknownLineInfo());
-  if rs <> s then InternalError(rs.info, 'loadStub: wrong symbol')
-  else if rs.id <> theId then InternalError(rs.info, 'loadStub: wrong ID');
-  //MessageOut('loaded stub: ' + s.name.s);
-end;
-
-initialization
-  InitIdTable(gTypeTable);
-  InitStrTable(rodCompilerProcs);
-end.