summary refs log tree commit diff stats
path: root/nim/main.pas
diff options
context:
space:
mode:
Diffstat (limited to 'nim/main.pas')
-rw-r--r--nim/main.pas313
1 files changed, 122 insertions, 191 deletions
diff --git a/nim/main.pas b/nim/main.pas
index 6e0afda98..7cf3fbd0a 100644
--- a/nim/main.pas
+++ b/nim/main.pas
@@ -15,10 +15,11 @@ unit main;
 interface
 
 uses
-  nsystem, strutils, ast, astalgo, scanner, pnimsyn, rnimsyn, options, msgs,
-  nos, lists, condsyms, paslex, pasparse, rodgen, ropes, trees,
-  wordrecg, sem, idents, magicsys, backends, docgen, extccomp, cgen,
-  platform, ecmasgen;
+  nsystem, llstream, strutils, ast, astalgo, scanner, pnimsyn, rnimsyn, 
+  options, msgs, nos, lists, condsyms, paslex, pasparse, rodread, rodwrite,
+  ropes, trees, wordrecg, sem, semdata, idents, passes, docgen,
+  extccomp, cgen, ecmasgen, platform, ptmplsyn, interact, nimconf, importer,
+  passaux, depends, transf, evals, types;
 
 procedure MainCommand(const cmd, filename: string);
 
@@ -33,7 +34,7 @@ type
   end;
   TFileModuleMap = array of TFileModuleRec;
 var
-  compMods: TFileModuleMap = {@ignore} nil {@emit []};
+  compMods: TFileModuleMap = {@ignore} nil {@emit @[]};
     // all compiled modules
 
 procedure registerModule(const filename: string; module: PSym);
@@ -58,28 +59,17 @@ end;
 
 // ----------------------------------------------------------------------------
 
-function getFileTrunk(const filename: string): string;
-var
-  f, e, dir: string;
-begin
-  splitPath(filename, dir, f);
-  splitFilename(f, result, e);
-end;
-
-function newIsMainModuleSym(module: PSym; isMainModule: bool): PSym;
-begin
-  result := newSym(skConst, getIdent('isMainModule'), module);
-  result.info := module.info;
-  result.typ := getSysType(tyBool);
-  result.ast := newIntNode(nkIntLit, ord(isMainModule));
-  result.ast.typ := result.typ;
-  StrTableAdd(module.tab, result);
-  if isMainModule then include(module.flags, sfMainModule);
-end;
-
 function newModule(const filename: string): PSym;
 begin
-  result := newSym(skModule, getIdent(getFileTrunk(filename)), nil);
+  // We cannot call ``newSym`` here, because we have to circumvent the ID
+  // mechanism, which we do in order to assign each module a persistent ID. 
+  new(result);
+{@ignore}
+  fillChar(result^, sizeof(result^), 0);
+{@emit}
+  result.id := -1; // for better error checking
+  result.kind := skModule;
+  result.name := getIdent(getFileTrunk(filename));
   result.owner := result; // a module belongs to itself
   result.info := newLineInfo(filename, 1, 1);
   include(result.flags, sfUsed);
@@ -89,173 +79,83 @@ begin
   StrTableAdd(result.tab, result); // a module knows itself
 end;
 
-procedure msgCompiling(const modname: string);
-begin
-  if optVerbose in gGlobalOptions then MessageOut('compiling: ' + modname);
-end;
-
-procedure msgCompiled(const modname: string);
-begin
-  if optVerbose in gGlobalOptions then MessageOut('compiled: ' + modname);
-end;
-
-function CompileModule(const filename: string; backend: PBackend;
+function CompileModule(const filename: string;
                        isMainFile, isSystemFile: bool): PSym; forward;
 
-function importModule(const filename: string; backend: PBackend): PSym;
+function importModule(const filename: string): PSym;
 // this is called by the semantic checking phase
 begin
   result := getModule(filename);
   if result = nil then begin
     // compile the module
-    // XXX: here caching could be implemented
-    result := compileModule(filename, backend, false, false);
+    result := compileModule(filename, false, false);
   end
   else if sfSystemModule in result.flags then
     liMessage(result.info, errAttemptToRedefine, result.Name.s);
 end;
 
-function CompileModule(const filename: string; backend: PBackend;
+function CompileModule(const filename: string;
                        isMainFile, isSystemFile: bool): PSym;
 var
-  ast: PNode;
-  c: PContext;
+  rd: PRodReader;
+  f: string;
 begin
+  rd := nil;
+  f := appendFileExt(filename, nimExt);
   result := newModule(filename);
-  result.info := newLineInfo(filename, 1, 1);
-  msgCompiling(result.name.s);
-  ast := parseFile(appendFileExt(filename, nimExt));
-  if ast = nil then exit;
-  c := newContext(filename);
-  c.b := backend.backendCreator(backend, result, filename);
-  c.module := result;
-  c.includeFile := parseFile;
-  c.importModule := importModule;
-  openScope(c.tab); // scope for imported symbols
-  SymTabAdd(c.tab, result);
-  if not isSystemFile then begin
-    SymTabAdd(c.tab, magicsys.SystemModule); // import the "System" identifier
-    importAllSymbols(c, magicsys.SystemModule);
-    SymTabAdd(c.tab, newIsMainModuleSym(result, isMainFile));
+  if isMainFile then include(result.flags, sfMainModule);
+  if isSystemFile then include(result.flags, sfSystemModule);
+  if (gCmd = cmdCompileToC) or (gCmd = cmdCompileToCpp) then begin
+    rd := handleSymbolFile(result, f);
+    if result.id < 0 then
+      InternalError('handleSymbolFile should have set the module''s ID');
   end
-  else begin
-    include(result.flags, sfSystemModule);
-    magicsys.SystemModule := result; // set global variable!
-    InitSystem(c.tab); // adds magics like "int", "ord" to the system module
-  end;
-  {@discard} semModule(c, ast);
-  rawCloseScope(c.tab); // imported symbols; don't check for unused ones!
-  msgCompiled(result.name.s);
+  else
+    result.id := getID();
+  processModule(result, f, nil, rd);
 end;
 
-procedure CompileProject(const filename: string; backend: PBackend);
+procedure CompileProject(const filename: string);
 begin
   {@discard} CompileModule(
-    JoinPath(options.libpath, appendFileExt('system', nimExt)),
-    backend, false, true);
-  {@discard} CompileModule(filename, backend, true, false);
+    JoinPath(options.libpath, appendFileExt('system', nimExt)), false, true);
+  {@discard} CompileModule(filename, true, false);
 end;
 
-// ------------ dependency generator ----------------------------------------
-
-var
-  gDotGraph: PRope; // the generated DOT file; we need a global variable
-
-procedure addDependencyAux(importing, imported: PSym);
+procedure semanticPasses;
 begin
-  appf(gDotGraph, '$1 -> $2;$n', [toRope(importing.name.s),
-                                  toRope(imported.name.s)]);
-  //    s1 -> s2_4 [label="[0-9]"];
-end;
-
-procedure addDotDependency(b: PBackend; n: PNode);
-var
-  i: int;
-begin
-  if n = nil then exit;
-  case n.kind of
-    nkEmpty..nkNilLit: begin end; // atom
-    nkImportStmt: begin
-      for i := 0 to sonsLen(n)-1 do begin
-        assert(n.sons[i].kind = nkSym);
-        addDependencyAux(b.module, n.sons[i].sym);
-      end
-    end;
-    nkFromStmt: begin
-      assert(n.sons[0].kind = nkSym);
-      addDependencyAux(b.module, n.sons[0].sym);
-    end;
-    nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: begin
-      for i := 0 to sonsLen(n)-1 do addDotDependency(b, n.sons[i]);
-    end
-    else begin end
-  end
-end;
-
-procedure generateDot(const project: string);
-begin
-  writeRope(
-    ropef('digraph $1 {$n$2}$n', [
-      toRope(changeFileExt(extractFileName(project), '')), gDotGraph]),
-    changeFileExt(project, 'dot') );
-end;
-
-function genDependCreator(b: PBackend; module: PSym;
-                          const filename: string): PBackend;
-begin
-  result := newBackend(module, filename);
-  include(result.eventMask, eAfterModule);
-  result.afterModuleEvent := addDotDependency;
-  result.backendCreator := genDependCreator;
+  registerPass(verbosePass());
+  registerPass(sem.semPass());
+  registerPass(transf.transfPass());
+  registerPass(rodwrite.rodwritePass());
 end;
 
 procedure CommandGenDepend(const filename: string);
-var
-  b: PBackend;
 begin
-  b := genDependCreator(nil, nil, filename);
-  compileProject(filename, b);
+  semanticPasses();
+  registerPass(genDependPass());
+  registerPass(cleanupPass());
+  compileProject(filename);
   generateDot(filename);
   execExternalProgram('dot -Tpng -o' +{&} changeFileExt(filename, 'png') +{&}
                       ' ' +{&} changeFileExt(filename, 'dot'));
 end;
 
-// --------------------------------------------------------------------------
-
-procedure genDebugTrans(b: PBackend; module: PNode);
-begin
-  if module <> nil then
-    renderModule(module, getOutFile(b.filename, 'pretty.'+NimExt));
-end;
-
-function genDebugTransCreator(b: PBackend; module: PSym;
-                              const filename: string): PBackend;
-begin
-  result := newBackend(module, filename);
-  include(result.eventMask, eAfterModule);
-  result.backendCreator := genDebugTransCreator;
-  result.afterModuleEvent := genDebugTrans;
-end;
-
-procedure CommandDebugTrans(const filename: string);
-var
-  b: PBackend;
-begin
-  b := genDebugTransCreator(nil, nil, filename);
-  compileProject(filename, b);
-end;
-
-// --------------------------------------------------------------------------
-
 procedure CommandCheck(const filename: string);
 begin
+  semanticPasses();
   // use an empty backend for semantic checking only
-  compileProject(filename, newBackend(nil, filename));
+  compileProject(filename);
 end;
 
 procedure CommandCompileToC(const filename: string);
 begin
-  compileProject(filename, CBackend(nil, nil, filename));
+  semanticPasses();
+  registerPass(cgen.cgenPass());
+  registerPass(cleanupPass());
+  compileProject(filename);
+  //for i := low(TTypeKind) to high(TTypeKind) do
+  //  MessageOut('kind: ' +{&} typeKindToStr[i] +{&} ' = ' +{&} toString(sameTypeA[i]));
   extccomp.CallCCompiler(changeFileExt(filename, ''));
 end;
 
@@ -264,7 +164,33 @@ begin
   include(gGlobalOptions, optSafeCode);
   setTarget(osEcmaScript, cpuEcmaScript);
   initDefines();
-  compileProject(filename, EcmasBackend(nil, nil, filename));
+
+  semanticPasses();
+  registerPass(ecmasgenPass());
+  compileProject(filename);
+end;
+
+procedure CommandInteractive();
+var
+  m: PSym;
+begin
+  include(gGlobalOptions, optSafeCode);
+  setTarget(osNimrodVM, cpuNimrodVM);
+  initDefines();
+
+  registerPass(verbosePass());
+  registerPass(sem.semPass());
+  registerPass(transf.transfPass());
+  registerPass(evals.evalPass());
+  
+  // load system module:
+  {@discard} CompileModule(
+    JoinPath(options.libpath, appendFileExt('system', nimExt)), false, true);
+
+  m := newModule('stdin');
+  m.id := getID();
+  include(m.flags, sfMainModule);
+  processModule(m, 'stdin', LLStreamOpenStdIn(), nil);
 end;
 
 // --------------------------------------------------------------------------
@@ -322,12 +248,17 @@ procedure CommandLexPas(const filename: string);
 var
   L: TPasLex;
   tok: TPasTok;
+  f: string;
+  stream: PLLStream;
 begin
 {@ignore}
   fillChar(tok, sizeof(tok), 0);
   fillChar(L, sizeof(L), 0);
 {@emit}
-  if OpenLexer(L, appendFileExt(filename, 'pas')) = success then begin
+  f := appendFileExt(filename, 'pas');
+  stream := LLStreamOpen(f, fmRead);
+  if stream <> nil then begin
+    OpenLexer(L, f, stream);
     getPasTok(L, tok);
     while tok.xkind <> pxEof do begin
       printPasTok(tok);
@@ -335,7 +266,7 @@ begin
     end
   end
   else
-    rawMessage(errCannotOpenFile, appendFileExt(filename, 'pas'));
+    rawMessage(errCannotOpenFile, f);
   closeLexer(L);
 end;
 
@@ -343,47 +274,44 @@ procedure CommandPas(const filename: string);
 var
   p: TPasParser;
   module: PNode;
+  f: string;
+  stream: PLLStream;
 begin
-  if OpenPasParser(p, appendFileExt(filename, 'pas')) = failure then begin
-    rawMessage(errCannotOpenFile, appendFileExt(filename, 'pas'));
-    exit
-  end;
-  module := parseUnit(p);
-  closePasParser(p);
-  renderModule(module, getOutFile(filename, NimExt));
-end;
-
-procedure CommandTestRod(const filename: string);
-var
-  module, rod: PNode;
-begin
-  module := parseFile(appendFileExt(filename, nimExt));
-  if module <> nil then begin
-    generateRod(module, changeFileExt(filename, rodExt));
-    rod := readRod(changeFileExt(filename, rodExt), {@set}[]);
-    assert(rod <> nil);
-    assert(sameTree(module, rod));
+  f := appendFileExt(filename, 'pas');
+  stream := LLStreamOpen(f, fmRead);
+  if stream <> nil then begin
+    OpenPasParser(p, f, stream);
+    module := parseUnit(p);
+    closePasParser(p);
+    renderModule(module, getOutFile(filename, NimExt));
   end
+  else
+    rawMessage(errCannotOpenFile, f);
 end;
 
 procedure CommandScan(const filename: string);
 var
   L: TLexer;
   tok: PToken;
+  f: string;
+  stream: PLLStream;
 begin
   new(tok);
 {@ignore}
   fillChar(tok^, sizeof(tok^), 0);
 {@emit}
-  if openLexer(L, appendFileExt(filename, nimExt)) = Success then begin
+  f := appendFileExt(filename, nimExt);
+  stream := LLStreamOpen(f, fmRead);
+  if stream <> nil then begin 
+    openLexer(L, f, stream);
     repeat
       rawGetTok(L, tok^);
-      PrintTok(tok)
+      PrintTok(tok);
     until tok.tokType = tkEof;
-    CloseLexer(L)
+    CloseLexer(L);
   end
   else
-    rawMessage(errCannotOpenFile, appendFileExt(filename, nimExt));
+    rawMessage(errCannotOpenFile, f);
 end;
 
 procedure WantFile(const filename: string);
@@ -396,16 +324,19 @@ procedure MainCommand(const cmd, filename: string);
 var
   dir, f: string;
 begin
+  appendStr(searchPaths, options.libpath);
   if filename <> '' then begin
-    appendStr(searchPaths, options.libpath);
-
     splitPath(filename, dir, f);
     // current path is always looked first for modules
     prependStr(searchPaths, dir);
   end;
+  setID(100);
+  passes.gIncludeFile := parseFile;
+  passes.gIncludeTmplFile := ptmplsyn.parseTmplFile;
+  passes.gImportModule := importModule;
 
   case whichKeyword(cmd) of
-    wCompile, wCompileToC: begin
+    wCompile, wCompileToC, wC, wCC: begin
       // compile means compileToC currently
       gCmd := cmdCompileToC;
       wantFile(filename);
@@ -422,7 +353,6 @@ begin
       CommandCompileToEcmaScript(filename);
     end;
     wPretty: begin
-      // compile means compileToC currently
       gCmd := cmdPretty;
       wantFile(filename);
       //CommandExportSymbols(filename);
@@ -430,9 +360,16 @@ begin
     end;
     wDoc: begin
       gCmd := cmdDoc;
+      LoadSpecialConfig(DocConfig);
       wantFile(filename);
       CommandDoc(filename);
     end;
+    wRst2html: begin
+      gCmd := cmdRst2html;
+      LoadSpecialConfig(DocConfig);
+      wantFile(filename);
+      CommandRst2Html(filename);
+    end;
     wPas: begin
       gCmd := cmdPas;
       wantFile(filename);
@@ -468,16 +405,10 @@ begin
       CommandScan(filename);
       MessageOut('Beware: Indentation tokens depend on the parser''s state!');
     end;
-    wDebugTrans: begin
-      gCmd := cmdDebugTrans;
-      wantFile(filename);
-      CommandDebugTrans(filename);
+    wI: begin
+      gCmd := cmdInteractive;
+      CommandInteractive();
     end;
-    wRst2html: begin
-      gCmd := cmdRst2html;
-      wantFile(filename);
-      CommandRst2Html(filename);
-    end
     else rawMessage(errInvalidCommandX, cmd);
   end
 end;