diff options
Diffstat (limited to 'nim/main.pas')
-rw-r--r-- | nim/main.pas | 313 |
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; |