diff options
author | rumpf_a@web.de <> | 2009-10-21 10:20:15 +0200 |
---|---|---|
committer | rumpf_a@web.de <> | 2009-10-21 10:20:15 +0200 |
commit | 053309e60aee1eda594a4817ac8ac2fb8c18fb04 (patch) | |
tree | 0f1ce8b0de0b493045eb97eeca6ebf06542de601 /nim | |
parent | 581572b28c65bc9fe47974cfd625210a69be0f3f (diff) | |
download | Nim-053309e60aee1eda594a4817ac8ac2fb8c18fb04.tar.gz |
version 0.8.2
Diffstat (limited to 'nim')
42 files changed, 2576 insertions, 722 deletions
diff --git a/nim/ast.pas b/nim/ast.pas index cbe5b37fd..8927fc862 100755 --- a/nim/ast.pas +++ b/nim/ast.pas @@ -78,27 +78,26 @@ type nkBracket, nkBracketExpr, nkPragmaExpr, nkRange, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkIfExpr, nkElifExpr, nkElseExpr, nkLambda, nkAccQuoted, - nkTableConstr, nkQualified, nkBind, nkSymChoice, - nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkConv, - nkCast, nkAddr, nkHiddenAddr, nkHiddenDeref, - nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64, - nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray, - nkAsgn, nkFastAsgn, nkGenericParams, nkFormalParams, - nkOfInherit, nkModule, nkProcDef, nkMethodDef, - nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, - nkOfBranch, nkElifBranch, nkExceptBranch, nkElse, - nkMacroStmt, nkAsmStmt, nkPragma, nkIfStmt, - nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, - nkVarSection, nkConstSection, nkConstDef, nkTypeSection, - nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally, - nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt, - nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt, - nkFromStmt, nkIncludeStmt, nkCommentStmt, nkStmtListExpr, - nkBlockExpr, nkStmtListType, nkBlockType, nkTypeOfExpr, - nkObjectTy, nkTupleTy, nkRecList, nkRecCase, - nkRecWhen, nkRefTy, nkPtrTy, nkVarTy, - nkDistinctTy, nkProcTy, nkEnumTy, nkEnumFieldDef, - nkReturnToken); + nkTableConstr, nkBind, nkSymChoice, nkHiddenStdConv, + nkHiddenSubConv, nkHiddenCallConv, nkConv, nkCast, + nkAddr, nkHiddenAddr, nkHiddenDeref, nkObjDownConv, + nkObjUpConv, nkChckRangeF, nkChckRange64, nkChckRange, + nkStringToCString, nkCStringToString, nkPassAsOpenArray, nkAsgn, + nkFastAsgn, nkGenericParams, nkFormalParams, nkOfInherit, + nkModule, nkProcDef, nkMethodDef, nkConverterDef, + nkMacroDef, nkTemplateDef, nkIteratorDef, nkOfBranch, + nkElifBranch, nkExceptBranch, nkElse, nkMacroStmt, + nkAsmStmt, nkPragma, nkIfStmt, nkWhenStmt, + nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection, + nkConstSection, nkConstDef, nkTypeSection, nkTypeDef, + nkYieldStmt, nkTryStmt, nkFinally, nkRaiseStmt, + nkReturnStmt, nkBreakStmt, nkContinueStmt, nkBlockStmt, + nkDiscardStmt, nkStmtList, nkImportStmt, nkFromStmt, + nkIncludeStmt, nkCommentStmt, nkStmtListExpr, nkBlockExpr, + nkStmtListType, nkBlockType, nkTypeOfExpr, nkObjectTy, + nkTupleTy, nkRecList, nkRecCase, nkRecWhen, + nkRefTy, nkPtrTy, nkVarTy, nkDistinctTy, + nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken); TNodeKinds = set of TNodeKind; const NodeKindToStr: array [TNodeKind] of string = ( @@ -113,27 +112,26 @@ const 'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkRange', 'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkIfExpr', 'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkAccQuoted', - 'nkTableConstr', 'nkQualified', 'nkBind', 'nkSymChoice', - 'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', - 'nkCast', 'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', - 'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', - 'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', - 'nkAsgn', 'nkFastAsgn', 'nkGenericParams', 'nkFormalParams', - 'nkOfInherit', 'nkModule', 'nkProcDef', 'nkMethodDef', - 'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', - 'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 'nkElse', - 'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 'nkIfStmt', - 'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', - 'nkVarSection', 'nkConstSection', 'nkConstDef', 'nkTypeSection', - 'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally', - 'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', - 'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', - 'nkFromStmt', 'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr', - 'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr', - 'nkObjectTy', 'nkTupleTy', 'nkRecList', 'nkRecCase', - 'nkRecWhen', 'nkRefTy', 'nkPtrTy', 'nkVarTy', - 'nkDistinctTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', - 'nkReturnToken'); + 'nkTableConstr', 'nkBind', 'nkSymChoice', 'nkHiddenStdConv', + 'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 'nkCast', + 'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 'nkObjDownConv', + 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 'nkChckRange', + 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 'nkAsgn', + 'nkFastAsgn', 'nkGenericParams', 'nkFormalParams', 'nkOfInherit', + 'nkModule', 'nkProcDef', 'nkMethodDef', 'nkConverterDef', + 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch', + 'nkElifBranch', 'nkExceptBranch', 'nkElse', 'nkMacroStmt', + 'nkAsmStmt', 'nkPragma', 'nkIfStmt', 'nkWhenStmt', + 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 'nkVarSection', + 'nkConstSection', 'nkConstDef', 'nkTypeSection', 'nkTypeDef', + 'nkYieldStmt', 'nkTryStmt', 'nkFinally', 'nkRaiseStmt', + 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt', + 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 'nkFromStmt', + 'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', + 'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr', 'nkObjectTy', + 'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen', + 'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkDistinctTy', + 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken'); type TSymFlag = ( sfUsed, sfStar, sfMinus, sfInInterface, @@ -141,7 +139,7 @@ type sfExportc, sfVolatile, sfRegister, sfPure, sfResult, sfNoSideEffect, sfSideEffect, sfMainModule, sfSystemModule, sfNoReturn, sfAddrTaken, sfCompilerProc, - sfCppMethod, sfDiscriminant, sfDeprecated, sfInClosure, + sfProcvar, sfDiscriminant, sfDeprecated, sfInClosure, sfTypeCheck, sfCompileTime, sfThreadVar, sfMerge, sfDeadCodeElim, sfBorrow); TSymFlags = set of TSymFlag; @@ -152,7 +150,7 @@ const 'sfExportc', 'sfVolatile', 'sfRegister', 'sfPure', 'sfResult', 'sfNoSideEffect', 'sfSideEffect', 'sfMainModule', 'sfSystemModule', 'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc', - 'sfCppMethod', 'sfDiscriminant', 'sfDeprecated', 'sfInClosure', + 'sfProcvar', 'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 'sfTypeCheck', 'sfCompileTime', 'sfThreadVar', 'sfMerge', 'sfDeadCodeElim', 'sfBorrow'); type @@ -340,6 +338,7 @@ type lfNoDeepCopy, // no need for a deep copy lfNoDecl, // do not declare it in C lfDynamicLib, // link symbol to dynamic library + lfExportLib, // export symbol for dynamic library generation lfHeader // include header file for symbol ); diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas index 99d36da2d..a5789487a 100755 --- a/nim/ccgexprs.pas +++ b/nim/ccgexprs.pas @@ -1086,6 +1086,8 @@ begin app(pl, ', ') end; if (typ.sons[0] <> nil) and invalidRetType then begin + // XXX (detected by pegs module 64bit): p(result, result) is not + // correct here. Thus we always allocate a temporary: if d.k = locNone then getTemp(p, typ.sons[0], d); app(pl, addrLoc(d)); end; @@ -2212,7 +2214,7 @@ begin '); unknown symbol') end end; - nkQualified: expr(p, e.sons[1], d); + //nkQualified: expr(p, e.sons[1], d); nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit, nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin putIntoDest(p, d, e.typ, genLiteral(p, e)); diff --git a/nim/ccgtypes.pas b/nim/ccgtypes.pas index db07a6864..1c07fe5c7 100755 --- a/nim/ccgtypes.pas +++ b/nim/ccgtypes.pas @@ -221,7 +221,8 @@ begin assert(not (sfResult in s.flags)); case pt.Kind of tyObject: begin - if (optByRef in s.options) or (getSize(pt) > platform.floatSize) then + // XXX quick hack floatSize*2 for the pegs module under 64bit + if (optByRef in s.options) or (getSize(pt) > platform.floatSize*2) then result := true // requested anyway else if (tfFinal in pt.flags) and (pt.sons[0] = nil) then result := false // no need, because no subtyping possible diff --git a/nim/cgen.pas b/nim/cgen.pas index 17ae8b461..0b74f25b7 100755 --- a/nim/cgen.pas +++ b/nim/cgen.pas @@ -659,6 +659,8 @@ var begin p := newProc(prc, m); header := genProcHeader(m, prc); + if (gCmd <> cmdCompileToLLVM) and (lfExportLib in prc.loc.flags) then + header := con('N_LIB_EXPORT ', header); returnStmt := nil; assert(prc.ast <> nil); @@ -942,7 +944,11 @@ const ' call void @NimMain()$n' + ' ret i32 0$n' + '}$n'; - WinNimDllMain = WinNimMain; + WinNimDllMain = + 'N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n' + + ' int dummy[8];$n' +{&} + CommonMainBody +{&} + '}$n'; WinCDllMain = 'BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n' + ' LPVOID lpvReserved) {$n' + diff --git a/nim/cgmeth.pas b/nim/cgmeth.pas index 6b9335c4c..6b9335c4c 100644..100755 --- a/nim/cgmeth.pas +++ b/nim/cgmeth.pas diff --git a/nim/commands.pas b/nim/commands.pas index b281552c9..1663b6b93 100755 --- a/nim/commands.pas +++ b/nim/commands.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -85,7 +85,7 @@ const +{&} ' -a, --assertions:on|off code generation for assertions ON|OFF' +{&} nl +{&} ' --dead_code_elim:on|off whole program dead code elimination ON|OFF' +{&} nl +{&} ' --opt:none|speed|size optimize not at all or for speed|size' +{&} nl -+{&} ' --app:console|gui generate a console|GUI application' +{&} nl ++{&} ' --app:console|gui|lib generate a console|GUI application|dynamic library' +{&} nl +{&} ' -r, --run run the compiled program with given arguments' +{&} nl +{&} ' --advanced show advanced command line switches' +{&} nl +{&} ' -h, --help show this help' +{&} nl @@ -127,10 +127,12 @@ const +{&} ' --checkpoints:on|off turn on|off checkpoints; for debugging Nimrod' +{&} nl +{&} ' --skip_cfg do not read the general configuration file' +{&} nl +{&} ' --skip_proj_cfg do not read the project''s configuration file' +{&} nl -+{&} ' --gc:refc|boehm use Nimrod''s native GC|Boehm GC' +{&} nl ++{&} ' --gc:refc|boehm|none use Nimrod''s native GC|Boehm GC|no GC' +{&} nl +{&} ' --index:FILE use FILE to generate a documenation index file' +{&} nl +{&} ' --putenv:key=value set an environment variable' +{&} nl +{&} ' --list_cmd list the commands used to execute external programs' +{&} nl ++{&} ' --parallel_build=0|1|... perform a parallel build' +{&} nl ++{&} ' value = number of processors (0 for auto-detect)' +{&} nl +{&} ' --verbosity:0|1|2|3 set Nimrod''s verbosity level (0 is default)' +{&} nl +{&} ' -v, --version show detailed version information' +{&} nl //[[[end]]] @@ -152,7 +154,7 @@ begin if (pass = passCmd1) and not helpWritten then begin // BUGFIX 19 MessageOut(getCommandLineDesc()); - helpWritten := true; + helpWritten := true; halt(0); end end; @@ -362,10 +364,10 @@ begin wNoLinking: begin expectNoArg(switch, arg, pass, info); include(gGlobalOptions, optNoLinking); - end; - wNoMain: begin + end; + wNoMain: begin expectNoArg(switch, arg, pass, info); - include(gGlobalOptions, optNoMain); + include(gGlobalOptions, optNoMain); end; wForceBuild, wF: begin expectNoArg(switch, arg, pass, info); @@ -523,6 +525,10 @@ begin expectArg(switch, arg, pass, info); gVerbosity := parseInt(arg); end; + wParallelBuild: begin + expectArg(switch, arg, pass, info); + gNumberOfProcessors := parseInt(arg); + end; wVersion, wV: begin expectNoArg(switch, arg, pass, info); writeVersionInfo(pass); diff --git a/nim/depends.pas b/nim/depends.pas index d8b978142..c5b844044 100755 --- a/nim/depends.pas +++ b/nim/depends.pas @@ -51,12 +51,12 @@ begin case n.kind of nkImportStmt: begin for i := 0 to sonsLen(n)-1 do begin - imported := getFileTrunk(getModuleFile(n.sons[i])); + imported := extractFileTrunk(getModuleFile(n.sons[i])); addDependencyAux(g.module.name.s, imported); end end; nkFromStmt: begin - imported := getFileTrunk(getModuleFile(n.sons[0])); + imported := extractFileTrunk(getModuleFile(n.sons[0])); addDependencyAux(g.module.name.s, imported); end; nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: begin diff --git a/nim/docgen.pas b/nim/docgen.pas index 4d94a2a68..468dd1bc9 100755 --- a/nim/docgen.pas +++ b/nim/docgen.pas @@ -19,7 +19,7 @@ interface uses nsystem, charsets, ast, astalgo, strutils, nhashes, options, nversion, msgs, - nos, ropes, idents, wordrecg, nmath, pnimsyn, rnimsyn, scanner, rst, ntime, + nos, ropes, idents, wordrecg, nmath, syntaxes, rnimsyn, scanner, rst, ntime, highlite; procedure CommandDoc(const filename: string); @@ -85,7 +85,7 @@ var dummyHasToc: bool; begin if gIndexFile = '' then exit; - gIndexFile := appendFileExt(gIndexFile, 'txt'); + gIndexFile := addFileExt(gIndexFile, 'txt'); d.indexValFilename := changeFileExt(extractFilename(d.filename), HtmlExt); if ExistsFile(gIndexFile) then begin d.indexFile := rstParse(readFile(gIndexFile), false, gIndexFile, 0, 1, @@ -1135,7 +1135,7 @@ var ast: PNode; d: PDoc; begin - ast := parseFile(appendFileExt(filename, nimExt)); + ast := parseFile(addFileExt(filename, nimExt)); if ast = nil then exit; d := newDocumentor(filename); initIndexFile(d); @@ -1152,7 +1152,7 @@ var rst: PRstNode; code: PRope; begin - filen := appendFileExt(filename, 'txt'); + filen := addFileExt(filename, 'txt'); d := newDocumentor(filen); initIndexFile(d); rst := rstParse(readFile(filen), false, filen, 0, 1, d.hasToc); diff --git a/nim/ecmasgen.pas b/nim/ecmasgen.pas index 8edd2605a..59cb3c330 100755 --- a/nim/ecmasgen.pas +++ b/nim/ecmasgen.pas @@ -1096,7 +1096,7 @@ begin end; end; nkCheckedFieldExpr: genCheckedFieldAddr(p, n, r); - nkDotExpr, nkQualified: genFieldAddr(p, n, r); + nkDotExpr: genFieldAddr(p, n, r); nkBracketExpr: genArrayAddr(p, n, r); else InternalError(n.info, 'genAddr'); end diff --git a/nim/evals.pas b/nim/evals.pas index 3787ff371..bb6c8a2b1 100755 --- a/nim/evals.pas +++ b/nim/evals.pas @@ -1324,7 +1324,7 @@ begin nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef, nkIncludeStmt, nkImportStmt, nkFromStmt: begin end; nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, - nkQualified, nkLambda, nkContinueStmt, nkIdent: + nkLambda, nkContinueStmt, nkIdent: stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]); else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]); end; diff --git a/nim/extccomp.pas b/nim/extccomp.pas index 9e7c7e4cc..aab4febb7 100755 --- a/nim/extccomp.pas +++ b/nim/extccomp.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -304,10 +304,10 @@ procedure setCC(const ccname: string); var i: TSystemCC; begin - linkOptions := ''; ccompiler := nameToCC(ccname); if ccompiler = ccNone then rawMessage(errUnknownCcompiler, ccname); compileOptions := getConfigVar(CC[ccompiler].name + '.options.always'); + linkOptions := getConfigVar(CC[ccompiler].name + '.options.linker'); ccompilerpath := getConfigVar(CC[ccompiler].name + '.path'); for i := low(CC) to high(CC) do undefSymbol(CC[i].name); defineSymbol(CC[ccompiler].name); @@ -323,6 +323,7 @@ begin if gCmd = cmdCompileToCpp then cExt := '.cpp'; addCompileOption(getConfigVar(CC[ccompiler].name + '.options.always')); + addLinkOption(getConfigVar(CC[ccompiler].name + '.options.linker')); if length(ccompilerPath) = 0 then ccompilerpath := getConfigVar(CC[ccompiler].name + '.path'); end; @@ -387,8 +388,8 @@ end; procedure execExternalProgram(const cmd: string); begin if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then - MessageOut('Executing: ' +{&} nl +{&} cmd); - if executeCommand(cmd) <> 0 then + MessageOut(cmd); + if execCmd(cmd) <> 0 then rawMessage(errExecutionOfProgramFailed); end; @@ -398,7 +399,7 @@ var begin splitPath(projectFile, path, scriptname); SplitFilename(scriptname, name, ext); - name := appendFileExt('compile_' + name, platform.os[targetOS].scriptExt); + name := addFileExt('compile_' + name, platform.os[targetOS].scriptExt); WriteRope(script, joinPath(path, name)); end; @@ -437,7 +438,7 @@ var begin c := ccompiler; options := compileOptions; - trunk := getFileTrunk(cfilename); + trunk := extractFileTrunk(cfilename); if optCDebug in gGlobalOptions then begin key := trunk + '.debug'; if existsConfigVar(key) then @@ -468,7 +469,7 @@ begin key := cc[c].name + '.exe'; if existsConfigVar(key) then exe := getConfigVar(key); - if targetOS = osWindows then exe := appendFileExt(exe, 'exe'); + if targetOS = osWindows then exe := addFileExt(exe, 'exe'); if (optGenDynLib in gGlobalOptions) and (ospNeedsPIC in platform.OS[targetOS].props) then @@ -494,7 +495,7 @@ begin objfile := toObjFile(cfile) else objfile := completeCFilePath(toObjFile(cfile)); - cfile := quoteIfContainsWhite(AppendFileExt(cfile, cExt)); + cfile := quoteIfContainsWhite(AddFileExt(cfile, cExt)); objfile := quoteIfContainsWhite(objfile); result := quoteIfContainsWhite(format(compilePattern, @@ -517,7 +518,9 @@ begin end; procedure CompileCFile(const list: TLinkedList; - var script: PRope; isExternal: Boolean); + var script: PRope; + var cmds: TStringSeq; + isExternal: Boolean); var it: PStrEntry; compileCmd: string; @@ -528,7 +531,7 @@ begin // call the C compiler for the .c file: compileCmd := getCompileCFileCmd(it.data, isExternal); if not (optCompileOnly in gGlobalOptions) then - execExternalProgram(compileCmd); + add(cmds, compileCmd); //execExternalProgram(compileCmd); if (optGenScript in gGlobalOptions) then begin app(script, compileCmd); app(script, tnl); @@ -543,6 +546,8 @@ var linkCmd, objfiles, exefile, buildgui, builddll, linkerExe: string; c: TSystemCC; // an alias to ccompiler script: PRope; + cmds: TStringSeq; + res, i: int; begin if (gGlobalOptions * [optCompileOnly, optGenScript] = [optCompileOnly]) then exit; // speed up that call if only compiling and no script shall be @@ -551,41 +556,53 @@ begin fileCounter := 0; c := ccompiler; script := nil; - CompileCFile(toCompile, script, false); - CompileCFile(externalToCompile, script, true); - + cmds := {@ignore} nil {@emit @[]}; + CompileCFile(toCompile, script, cmds, false); + CompileCFile(externalToCompile, script, cmds, true); + if not (optCompileOnly in gGlobalOptions) then begin + if gNumberOfProcessors = 0 then + gNumberOfProcessors := countProcessors(); + if gNumberOfProcessors <= 1 then begin + res := 0; + for i := 0 to high(cmds) do res := max(execCmd(cmds[i]), res); + end + else if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then + res := execProcesses(cmds, {@set}[poEchoCmd, poUseShell, poParentStreams], + gNumberOfProcessors) + else + res := execProcesses(cmds, {@set}[poUseShell, poParentStreams], + gNumberOfProcessors); + if res <> 0 then + rawMessage(errExecutionOfProgramFailed); + end; + if not (optNoLinking in gGlobalOptions) then begin // call the linker: linkerExe := getConfigVar(cc[c].name + '.linkerexe'); if length(linkerExe) = 0 then linkerExe := cc[c].linkerExe; - if targetOS = osWindows then linkerExe := appendFileExt(linkerExe, 'exe'); + if targetOS = osWindows then linkerExe := addFileExt(linkerExe, 'exe'); if (platform.hostOS <> targetOS) then linkCmd := quoteIfContainsWhite(linkerExe) else linkCmd := quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe)); - if optGenDynLib in gGlobalOptions then - buildDll := cc[c].buildDll - else - buildDll := ''; if optGenGuiApp in gGlobalOptions then buildGui := cc[c].buildGui else buildGui := ''; - - if optGenDynLib in gGlobalOptions then - exefile := platform.os[targetOS].dllPrefix - else - exefile := ''; + + if optGenDynLib in gGlobalOptions then begin + exefile := format(platform.os[targetOS].dllFrmt, + [extractFileTrunk(projectFile)]); + buildDll := cc[c].buildDll; + end + else begin + exefile := extractFileTrunk(projectFile) +{&} platform.os[targetOS].exeExt; + buildDll := ''; + end; if targetOS = platform.hostOS then - add(exefile, projectFile) - else - add(exefile, extractFileName(projectFile)); - if optGenDynLib in gGlobalOptions then - add(exefile, platform.os[targetOS].dllExt) - else - add(exefile, platform.os[targetOS].exeExt); + exefile := joinPath(extractDir(projectFile), exefile); exefile := quoteIfContainsWhite(exefile); it := PStrEntry(toLink.head); @@ -639,7 +656,7 @@ begin result := nil; it := PStrEntry(list.head); while it <> nil do begin - appf(result, '--file:r"$1"$n', [toRope(AppendFileExt(it.data, cExt))]); + appf(result, '--file:r"$1"$n', [toRope(AddFileExt(it.data, cExt))]); it := PStrEntry(it.next); end; end; diff --git a/nim/filters.pas b/nim/filters.pas new file mode 100755 index 000000000..95f628fe2 --- /dev/null +++ b/nim/filters.pas @@ -0,0 +1,137 @@ +// +// +// The Nimrod Compiler +// (c) Copyright 2009 Andreas Rumpf +// +// See the file "copying.txt", included in this +// distribution, for details about the copyright. +// +unit filters; + +// This module implements Nimrod's simple filters and helpers for filters. + +{$include config.inc} + +interface + +uses + nsystem, llstream, nos, charsets, wordrecg, idents, strutils, + ast, astalgo, msgs, options, rnimsyn; + +function filterReplace(input: PLLStream; const filename: string; + call: PNode): PLLStream; +function filterStrip(input: PLLStream; const filename: string; + call: PNode): PLLStream; + +// helpers to retrieve arguments: +function charArg(n: PNode; const name: string; pos: int; default: Char): Char; +function strArg(n: PNode; const name: string; pos: int; + const default: string): string; +function boolArg(n: PNode; const name: string; pos: int; default: bool): bool; + +implementation + +procedure invalidPragma(n: PNode); +begin + liMessage(n.info, errXNotAllowedHere, renderTree(n, {@set}[renderNoComments])); +end; + +function getArg(n: PNode; const name: string; pos: int): PNode; +var + i: int; +begin + result := nil; + if n.kind in [nkEmpty..nkNilLit] then exit; + for i := 1 to sonsLen(n)-1 do + if n.sons[i].kind = nkExprEqExpr then begin + if n.sons[i].sons[0].kind <> nkIdent then invalidPragma(n); + if IdentEq(n.sons[i].sons[0].ident, name) then begin + result := n.sons[i].sons[1]; + exit + end + end + else if i = pos then begin + result := n.sons[i]; exit + end +end; + +function charArg(n: PNode; const name: string; pos: int; default: Char): Char; +var + x: PNode; +begin + x := getArg(n, name, pos); + if x = nil then result := default + else if x.kind = nkCharLit then result := chr(int(x.intVal)) + else invalidPragma(n); +end; + +function strArg(n: PNode; const name: string; pos: int; + const default: string): string; +var + x: PNode; +begin + x := getArg(n, name, pos); + if x = nil then result := default + else if x.kind in [nkStrLit..nkTripleStrLit] then result := x.strVal + else invalidPragma(n); +end; + +function boolArg(n: PNode; const name: string; pos: int; default: bool): bool; +var + x: PNode; +begin + x := getArg(n, name, pos); + if x = nil then result := default + else if (x.kind = nkIdent) and IdentEq(x.ident, 'true') then result := true + else if (x.kind = nkIdent) and IdentEq(x.ident, 'false') then result := false + else invalidPragma(n); +end; + +// -------------------------- strip filter ----------------------------------- + +function filterStrip(input: PLLStream; const filename: string; + call: PNode): PLLStream; +var + line, pattern, stripped: string; + leading, trailing: bool; +begin + pattern := strArg(call, 'startswith', 1, ''); + leading := boolArg(call, 'leading', 2, true); + trailing := boolArg(call, 'trailing', 3, true); + + result := LLStreamOpen(''); + while not LLStreamAtEnd(input) do begin + line := LLStreamReadLine(input); + {@ignore} + stripped := strip(line); + {@emit + stripped := strip(line, leading, trailing); + } + if (length(pattern) = 0) or startsWith(stripped, pattern) then + LLStreamWriteln(result, stripped) + else + LLStreamWriteln(result, line) + end; + LLStreamClose(input); +end; + +// -------------------------- replace filter --------------------------------- + +function filterReplace(input: PLLStream; const filename: string; + call: PNode): PLLStream; +var + line, sub, by: string; +begin + sub := strArg(call, 'sub', 1, ''); + if length(sub) = 0 then invalidPragma(call); + by := strArg(call, 'by', 2, ''); + + result := LLStreamOpen(''); + while not LLStreamAtEnd(input) do begin + line := LLStreamReadLine(input); + LLStreamWriteln(result, replace(line, sub, by)) + end; + LLStreamClose(input); +end; + +end. diff --git a/nim/importer.pas b/nim/importer.pas index d031ffe3a..a1ed57978 100755 --- a/nim/importer.pas +++ b/nim/importer.pas @@ -29,9 +29,8 @@ implementation function findModule(const info: TLineInfo; const modulename: string): string; // returns path to module begin - result := options.FindFile(AppendFileExt(modulename, nimExt)); - if result = '' then - liMessage(info, errCannotOpenFile, modulename); + result := options.FindFile(AddFileExt(modulename, nimExt)); + if result = '' then liMessage(info, errCannotOpenFile, modulename); end; function getModuleFile(n: PNode): string; diff --git a/nim/llstream.pas b/nim/llstream.pas index df4c823a6..30d9c0287 100755 --- a/nim/llstream.pas +++ b/nim/llstream.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -25,7 +25,7 @@ type kind: TLLStreamKind; // accessible for low-level access (lexbase uses this) f: TBinaryFile; s: string; - pos: int; // for string streams + rd, wr: int; // for string streams end; PLLStream = ^TLLStream; @@ -46,6 +46,8 @@ procedure LLStreamWrite(s: PLLStream; const data: string); overload; procedure LLStreamWrite(s: PLLStream; data: Char); overload; procedure LLStreamWrite(s: PLLStream; buf: pointer; buflen: int); overload; +procedure LLStreamWriteln(s: PLLStream; const data: string); + function LLStreamAtEnd(s: PLLStream): bool; implementation @@ -97,7 +99,6 @@ begin {@emit} result.kind := llsStdIn; result.s := ''; - result.pos := -1; end; procedure LLStreamClose(s: PLLStream); @@ -114,7 +115,7 @@ var L: int; begin s.s := ''; - s.pos := 0; + s.rd := 0; while true do begin write(output, 'Nimrod> '); line := readLine(input); @@ -123,10 +124,10 @@ begin add(s.s, nl); if (L > 0) and (line[L-1+strStart] = '#') then break; end; - result := min(bufLen, length(s.s)-s.pos); + result := min(bufLen, length(s.s)-s.rd); if result > 0 then begin - copyMem(buf, addr(s.s[strStart+s.pos]), result); - inc(s.pos, result) + copyMem(buf, addr(s.s[strStart+s.rd]), result); + inc(s.rd, result) end end; @@ -135,10 +136,10 @@ begin case s.kind of llsNone: result := 0; llsString: begin - result := min(bufLen, length(s.s)-s.pos); + result := min(bufLen, length(s.s)-s.rd); if result > 0 then begin - copyMem(buf, addr(s.s[strStart+s.pos]), result); - inc(s.pos, result) + copyMem(buf, addr(s.s[strStart+s.rd]), result); + inc(s.rd, result) end end; llsFile: result := readBuffer(s.f, buf, bufLen); @@ -152,20 +153,20 @@ begin llsNone: result := ''; llsString: begin result := ''; - while s.pos < length(s.s) do begin - case s.s[s.pos+strStart] of + while s.rd < length(s.s) do begin + case s.s[s.rd+strStart] of #13: begin - inc(s.pos); - if s.s[s.pos+strStart] = #10 then inc(s.pos); + inc(s.rd); + if s.s[s.rd+strStart] = #10 then inc(s.rd); break end; - #10: begin inc(s.pos); break end; + #10: begin inc(s.rd); break end; else begin - addChar(result, s.s[s.pos+strStart]); - inc(s.pos); + addChar(result, s.s[s.rd+strStart]); + inc(s.rd); end end - end + end end; llsFile: result := readLine(s.f); llsStdIn: result := readLine(input); @@ -176,7 +177,7 @@ function LLStreamAtEnd(s: PLLStream): bool; begin case s.kind of llsNone: result := true; - llsString: result := s.pos < length(s.s); + llsString: result := s.rd >= length(s.s); llsFile: result := endOfFile(s.f); llsStdIn: result := false; end @@ -186,9 +187,15 @@ procedure LLStreamWrite(s: PLLStream; const data: string); overload; begin case s.kind of llsNone, llsStdIn: begin end; - llsString: add(s.s, data); + llsString: begin add(s.s, data); inc(s.wr, length(data)) end; llsFile: nimWrite(s.f, data); - end + end; +end; + +procedure LLStreamWriteln(s: PLLStream; const data: string); +begin + LLStreamWrite(s, data); + LLStreamWrite(s, nl); end; procedure LLStreamWrite(s: PLLStream; data: Char); overload; @@ -197,7 +204,7 @@ var begin case s.kind of llsNone, llsStdIn: begin end; - llsString: addChar(s.s, data); + llsString: begin addChar(s.s, data); inc(s.wr); end; llsFile: begin c := data; {@discard} writeBuffer(s.f, addr(c), sizeof(c)); @@ -212,8 +219,8 @@ begin llsString: begin if bufLen > 0 then begin setLength(s.s, length(s.s) + bufLen); - copyMem(addr(s.s[strStart+s.pos]), buf, bufLen); - inc(s.pos, bufLen); + copyMem(addr(s.s[strStart+s.wr]), buf, bufLen); + inc(s.wr, bufLen); end end; llsFile: {@discard} writeBuffer(s.f, buf, bufLen); @@ -229,9 +236,9 @@ begin case s.kind of llsNone, llsStdIn: result := ''; llsString: begin - if s.pos = 0 then result := s.s - else result := ncopy(s.s, s.pos+strStart); - s.pos := length(s.s); + if s.rd = 0 then result := s.s + else result := ncopy(s.s, s.rd+strStart); + s.rd := length(s.s); end; llsFile: begin result := newString(bufSize); diff --git a/nim/lookups.pas b/nim/lookups.pas index d68095635..e4c07224f 100755 --- a/nim/lookups.pas +++ b/nim/lookups.pas @@ -177,7 +177,7 @@ begin if ambiguousCheck and IntSetContains(c.AmbiguousSymbols, result.id) then liMessage(n.info, errUseQualifier, n.sym.name.s) end; - nkDotExpr, nkQualified: begin + nkDotExpr: begin result := nil; m := qualifiedLookUp(c, n.sons[0], false); if (m <> nil) and (m.kind = skModule) then begin @@ -237,7 +237,7 @@ begin result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name); end; *) end; - nkDotExpr, nkQualified: begin + nkDotExpr: begin o.mode := oimOtherModule; o.m := qualifiedLookUp(c, n.sons[0], false); if (o.m <> nil) and (o.m.kind = skModule) then begin diff --git a/nim/main.pas b/nim/main.pas index 1bb2ce586..c3f2cbd85 100755 --- a/nim/main.pas +++ b/nim/main.pas @@ -15,10 +15,10 @@ unit main; interface uses - nsystem, llstream, strutils, ast, astalgo, scanner, pnimsyn, rnimsyn, + nsystem, llstream, strutils, ast, astalgo, scanner, syntaxes, 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, + extccomp, cgen, ecmasgen, platform, interact, nimconf, importer, passaux, depends, transf, evals, types; procedure MainCommand(const cmd, filename: string); @@ -69,7 +69,7 @@ begin {@emit} result.id := -1; // for better error checking result.kind := skModule; - result.name := getIdent(getFileTrunk(filename)); + result.name := getIdent(extractFileTrunk(filename)); result.owner := result; // a module belongs to itself result.info := newLineInfo(filename, 1, 1); include(result.flags, sfUsed); @@ -101,7 +101,7 @@ var f: string; begin rd := nil; - f := appendFileExt(filename, nimExt); + f := addFileExt(filename, nimExt); result := newModule(filename); if isMainFile then include(result.flags, sfMainModule); if isSystemFile then include(result.flags, sfSystemModule); @@ -118,8 +118,8 @@ end; procedure CompileProject(const filename: string); begin {@discard} CompileModule( - JoinPath(options.libpath, appendFileExt('system', nimExt)), false, true); - {@discard} CompileModule(appendFileExt(filename, nimExt), true, false); + JoinPath(options.libpath, addFileExt('system', nimExt)), false, true); + {@discard} CompileModule(addFileExt(filename, nimExt), true, false); end; procedure semanticPasses; @@ -137,7 +137,7 @@ begin compileProject(filename); generateDot(filename); execExternalProgram('dot -Tpng -o' +{&} changeFileExt(filename, 'png') +{&} - ' ' +{&} changeFileExt(filename, 'dot')); + ' ' +{&} changeFileExt(filename, 'dot')); end; procedure CommandCheck(const filename: string); @@ -185,7 +185,7 @@ begin // load system module: {@discard} CompileModule( - JoinPath(options.libpath, appendFileExt('system', nimExt)), false, true); + JoinPath(options.libpath, addFileExt('system', nimExt)), false, true); m := newModule('stdin'); m.id := getID(); @@ -228,7 +228,7 @@ procedure CommandExportSymbols(const filename: string); var module: PNode; begin - module := parseFile(appendFileExt(filename, NimExt)); + module := parseFile(addFileExt(filename, NimExt)); if module <> nil then begin exSymbols(module); renderModule(module, getOutFile(filename, 'pretty.'+NimExt)); @@ -239,7 +239,7 @@ procedure CommandPretty(const filename: string); var module: PNode; begin - module := parseFile(appendFileExt(filename, NimExt)); + module := parseFile(addFileExt(filename, NimExt)); if module <> nil then renderModule(module, getOutFile(filename, 'pretty.'+NimExt)); end; @@ -255,7 +255,7 @@ begin fillChar(tok, sizeof(tok), 0); fillChar(L, sizeof(L), 0); {@emit} - f := appendFileExt(filename, 'pas'); + f := addFileExt(filename, 'pas'); stream := LLStreamOpen(f, fmRead); if stream <> nil then begin OpenLexer(L, f, stream); @@ -277,7 +277,7 @@ var f: string; stream: PLLStream; begin - f := appendFileExt(filename, 'pas'); + f := addFileExt(filename, 'pas'); stream := LLStreamOpen(f, fmRead); if stream <> nil then begin OpenPasParser(p, f, stream); @@ -300,7 +300,7 @@ begin {@ignore} fillChar(tok^, sizeof(tok^), 0); {@emit} - f := appendFileExt(filename, nimExt); + f := addFileExt(filename, nimExt); stream := LLStreamOpen(f, fmRead); if stream <> nil then begin openLexer(L, f, stream); @@ -331,8 +331,7 @@ begin prependStr(searchPaths, dir); end; setID(100); - passes.gIncludeFile := parseFile; - passes.gIncludeTmplFile := ptmplsyn.parseTmplFile; + passes.gIncludeFile := syntaxes.parseFile; passes.gImportModule := importModule; case whichKeyword(cmd) of @@ -408,7 +407,7 @@ begin wParse: begin gCmd := cmdParse; wantFile(filename); - {@discard} parseFile(appendFileExt(filename, nimExt)); + {@discard} parseFile(addFileExt(filename, nimExt)); end; wScan: begin gCmd := cmdScan; diff --git a/nim/msgs.pas b/nim/msgs.pas index 9d421a5bf..f1a3a200a 100755 --- a/nim/msgs.pas +++ b/nim/msgs.pas @@ -127,7 +127,7 @@ type errOverOrUnderflow, errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, - errDotRequiresRecordOrObjectType, + errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, errIndexOutOfBounds, @@ -182,7 +182,7 @@ type errButExpectedX, errAmbiguousCallXYZ, errWrongNumberOfArguments, - errInlineProcHasNoAddress, + errXCannotBePassedToProcVar, errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, @@ -215,7 +215,6 @@ type errATypeHasNoValue, errXisNoType, errCircumNeedsPointer, - errInvalidContextForBuiltinX, errInvalidExpression, errInvalidExpressionX, errEnumHasNoValueX, @@ -272,6 +271,7 @@ type warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored, + warnXisPassedToProcVar, warnUser, hintSuccess, hintSuccessX, @@ -365,7 +365,7 @@ const 'over- or underflow', 'cannot evalutate ''$1'' because type is not defined completely', '''chr'' expects an int in the range 0..255', - '''.'' requires a record or object type', + '''dynlib'' requires ''exportc''', 'undeclared field: ''$1''', 'attempt to access a nil address', 'index out of bounds', @@ -420,7 +420,7 @@ const 'but expected ''$1''', 'ambiguous call; both $1 and $2 match for: $3', 'wrong number of arguments', - 'an inline proc has no address', + '''$1'' cannot be passed to a procvar', '$1 cannot be declared in parameter declaration', 'pragmas are only in the header of a proc allowed', 'implementation of ''$1'' is not allowed', @@ -453,7 +453,6 @@ const 'a type has no value', 'invalid type: ''$1''', '''^'' needs a pointer or reference type', - 'invalid context for builtin ''$1''', 'invalid expression', 'invalid expression: ''$1''', 'enum has no value ''$1''', @@ -510,6 +509,7 @@ const 'unknown substitution ''$1'' [UnknownSubstitutionX]', 'language ''$1'' not supported [LanguageXNotSupported]', 'comment ''$1'' ignored [CommentXIgnored]', + '''$1'' is passed to a procvar; deprecated [XisPassedToProcVar]', '$1 [User]', 'operation successful [Success]', 'operation successful ($1 lines compiled; $2 sec total) [SuccessX]', @@ -526,7 +526,7 @@ const '$1 [User]' ); const - WarningsToStr: array [0..13] of string = ( + WarningsToStr: array [0..14] of string = ( 'CannotOpenFile', 'OctalEscape', 'XIsNeverRead', @@ -540,6 +540,7 @@ const 'UnknownSubstitutionX', 'LanguageXNotSupported', 'CommentXIgnored', + 'XisPassedToProcVar', 'User' ); const diff --git a/nim/nimrod.pas b/nim/nimrod.pas index 728325ccc..b3247bff0 100755 --- a/nim/nimrod.pas +++ b/nim/nimrod.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2006 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -28,15 +28,27 @@ var procedure ProcessCmdLine(pass: TCmdLinePass; var command, filename: string); var p: TOptParser; + bracketLe: int; + key, val: string; begin p := parseopt.init(); while true do begin parseopt.next(p); case p.kind of cmdEnd: break; - cmdLongOption, cmdShortOption: - ProcessSwitch(p.key, p.val, pass, cmdLineInfo); - cmdArgument: begin + cmdLongOption, cmdShortOption: begin + // hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") + // we fix this here + bracketLe := strutils.find(p.key, '['); + if bracketLe >= strStart then begin + key := ncopy(p.key, strStart, bracketLe-1); + val := ncopy(p.key, bracketLe+1) +{&} ':' +{&} p.val; + ProcessSwitch(key, val, pass, cmdLineInfo); + end + else + ProcessSwitch(p.key, p.val, pass, cmdLineInfo); + end; + cmdArgument: begin if command = '' then command := p.key else if filename = '' then begin filename := unixToNativePath(p.key); diff --git a/nim/nos.pas b/nim/nos.pas index 2edb0864e..7b9d2ee09 100755 --- a/nim/nos.pas +++ b/nim/nos.pas @@ -74,7 +74,7 @@ function GetConfigDir(): string; procedure SplitFilename(const filename: string; out name, extension: string); function ExistsFile(const filename: string): Boolean; -function AppendFileExt(const filename, ext: string): string; +function AddFileExt(const filename, ext: string): string; function ChangeFileExt(const filename, ext: string): string; procedure createDir(const dir: string); @@ -84,8 +84,20 @@ function UnixToNativePath(const path: string): string; function sameFile(const path1, path2: string): boolean; + +function extractFileTrunk(const filename: string): string; + + implementation +function extractFileTrunk(const filename: string): string; +var + f, e, dir: string; +begin + splitPath(filename, dir, f); + splitFilename(f, result, e); +end; + function GetConfigDir(): string; begin {$ifdef windows} @@ -103,7 +115,7 @@ end; function UnixToNativePath(const path: string): string; begin if dirSep <> '/' then - result := replaceStr(path, '/', dirSep) + result := replace(path, '/', dirSep) else result := path; end; @@ -150,7 +162,7 @@ begin result := extSep + ext end; -function AppendFileExt(const filename, ext: string): string; +function AddFileExt(const filename, ext: string): string; var extPos: int; begin diff --git a/nim/nsystem.pas b/nim/nsystem.pas index 49d17b172..4cdfade93 100755 --- a/nim/nsystem.pas +++ b/nim/nsystem.pas @@ -56,6 +56,11 @@ const snil = ''; type + TStringSeq = array of string; + TCharSet = set of Char; + + +type Natural = 0..high(int); Positive = 1..high(int); NObject = object // base type for all objects, cannot use @@ -214,9 +219,11 @@ function readFile(const filename: string): string; procedure nimWrite(var f: tBinaryFile; const str: string); overload; -procedure add(var x: string; const y: string); +procedure add(var x: string; const y: string); overload; // Pascal version of string appending. Terminating zero is ignored. +procedure add(var s: TStringSeq; const y: string); overload; + function isNil(s: string): bool; implementation @@ -238,6 +245,15 @@ begin else x := x + y; end end; + +procedure add(var s: TStringSeq; const y: string); overload; +var + L: int; +begin + L := length(s); + setLength(s, L+1); + s[L] := y; +end; {@emit} function alloc(size: int): Pointer; diff --git a/nim/nversion.pas b/nim/nversion.pas index b2ba371f6..20ab5cc77 100755 --- a/nim/nversion.pas +++ b/nim/nversion.pas @@ -31,10 +31,10 @@ const //cog.outl('VersionMinor = %s;' % ver[1]) //cog.outl('VersionPatch = %s;' % ver[2]) //]]] - VersionAsString = '0.8.1'; + VersionAsString = '0.8.2'; VersionMajor = 0; VersionMinor = 8; - VersionPatch = 1; + VersionPatch = 2; //[[[[end]]]] implementation diff --git a/nim/options.pas b/nim/options.pas index d210f3b44..d03a24f2a 100755 --- a/nim/options.pas +++ b/nim/options.pas @@ -101,6 +101,7 @@ var gCmd: TCommands = cmdNone; // the command gVerbosity: int; // how verbose the compiler is + gNumberOfProcessors: int; // number of processors function FindFile(const f: string): string; @@ -111,7 +112,6 @@ const HtmlExt = 'html'; TexExt = 'tex'; IniExt = 'ini'; - TmplExt = 'tmpl'; DocConfig = 'nimdoc.cfg'; DocTexConfig = 'nimdoc.tex.cfg'; @@ -124,8 +124,6 @@ function toGeneratedFile(const path, ext: string): string; function getPrefixDir: string; // gets the application directory -function getFileTrunk(const filename: string): string; - // additional configuration variables: var gConfigVars: PStringTable; @@ -185,14 +183,6 @@ begin SplitPath(appdir, result, bin); end; -function getFileTrunk(const filename: string): string; -var - f, e, dir: string; -begin - splitPath(filename, dir, f); - splitFilename(f, result, e); -end; - function shortenDir(const dir: string): string; var prefix: string; diff --git a/nim/osproc.pas b/nim/osproc.pas index dd6bd10f0..485daaf67 100755 --- a/nim/osproc.pas +++ b/nim/osproc.pas @@ -17,14 +17,42 @@ interface uses nsystem, nos; - -function executeCommand(const cmd: string): int; + +type + TProcessOption = (poEchoCmd, poUseShell, poStdErrToStdOut, poParentStreams); + TProcessOptions = set of TProcessOption; + +function execCmd(const cmd: string): int; +function execProcesses(const cmds: array of string; + options: TProcessOptions; + n: int): int; + +function countProcessors(): int; implementation -function executeCommand(const cmd: string): int; -begin +function execCmd(const cmd: string): int; +begin + writeln(output, cmd); result := executeShellCommand(cmd); end; + +function execProcesses(const cmds: array of string; + options: TProcessOptions; + n: int): int; +var + i: int; +begin + result := 0; + for i := 0 to high(cmds) do begin + //if poEchoCmd in options then writeln(output, cmds[i]); + result := max(result, execCmd(cmds[i])) + end +end; + +function countProcessors(): int; +begin + result := 1; +end; end. diff --git a/nim/pasparse.pas b/nim/pasparse.pas index c44c735d6..dbfbf0437 100755 --- a/nim/pasparse.pas +++ b/nim/pasparse.pas @@ -61,7 +61,7 @@ const ('len', 'length'), ('setlength', 'setlen') ); - nimReplacements: array [1..34] of TReplaceTuple = ( + nimReplacements: array [1..35] of TReplaceTuple = ( ('nimread', 'read'), ('nimwrite', 'write'), ('nimclosefile', 'close'), @@ -98,7 +98,8 @@ const ('ttextfile', 'tfile'), ('tbinaryfile', 'tfile'), ('strstart', '0'+''), - ('nl', '"\n"') + ('nl', '"\n"'), + ('tostring', '$'+'') {, ('NL', '"\n"'), ('tabulator', '''\t'''), @@ -455,7 +456,7 @@ begin skipCom(p, result); if p.tok.xkind = pxSymbol then begin a := result; - result := newNodeI(nkQualified, a.info); + result := newNodeI(nkDotExpr, a.info); addSon(result, a); addSon(result, createIdentNodeP(p.tok.ident, p)); getTok(p); @@ -1279,6 +1280,13 @@ begin noBody := true; getTok(p); opt(p, pxSemicolon); end; + wProcVar: begin + // This is a fake for the Nimrod compiler. There is no ``procvar`` + // directive in Pascal. + if result = nil then result := newNodeP(nkPragma, p); + addSon(result, newIdentNodeP(getIdent('procvar'), p)); + getTok(p); opt(p, pxSemicolon); + end; wVarargs: begin if result = nil then result := newNodeP(nkPragma, p); addSon(result, newIdentNodeP(getIdent('varargs'), p)); diff --git a/nim/passes.pas b/nim/passes.pas index 8d961e5d3..c280a75b1 100755 --- a/nim/passes.pas +++ b/nim/passes.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -19,7 +19,7 @@ uses nsystem, charsets, strutils, lists, options, ast, astalgo, llstream, msgs, platform, nos, condsyms, idents, rnimsyn, types, - extccomp, nmath, magicsys, nversion, nimsets, pnimsyn, ntime, rodread; + extccomp, nmath, magicsys, nversion, nimsets, syntaxes, ntime, rodread; type TPassContext = object(NObject) // the pass's context @@ -61,7 +61,6 @@ function astNeeded(s: PSym): bool; var gImportModule: function (const filename: string): PSym; gIncludeFile: function (const filename: string): PNode; - gIncludeTmplFile: function (const filename: string): PNode; implementation @@ -165,7 +164,7 @@ end; procedure processModule(module: PSym; const filename: string; stream: PLLStream; rd: PRodReader); var - p: TParser; + p: TParsers; n: PNode; a: TPassContextArray; s: PLLStream; @@ -183,13 +182,13 @@ begin else s := stream; while true do begin - openParser(p, filename, s); + openParsers(p, filename, s); while true do begin n := parseTopLevelStmt(p); if n = nil then break; processTopLevelStmt(n, a) end; - closeParser(p); + closeParsers(p); if s.kind <> llsStdIn then break; end; closePasses(a); diff --git a/nim/pbraces.pas b/nim/pbraces.pas new file mode 100755 index 000000000..d362fac65 --- /dev/null +++ b/nim/pbraces.pas @@ -0,0 +1,1499 @@ +// +// +// The Nimrod Compiler +// (c) Copyright 2009 Andreas Rumpf +// +// See the file "copying.txt", included in this +// distribution, for details about the copyright. +// +unit pbraces; + +{$include config.inc} + +interface + +uses + nsystem, llstream, scanner, idents, strutils, ast, msgs, pnimsyn; + +function ParseAll(var p: TParser): PNode; + +function parseTopLevelStmt(var p: TParser): PNode; +// implements an iterator. Returns the next top-level statement or nil if end +// of stream. + +implementation + +// ------------------- Expression parsing ------------------------------------ + +function parseExpr(var p: TParser): PNode; forward; +function parseStmt(var p: TParser): PNode; forward; + +function parseTypeDesc(var p: TParser): PNode; forward; +function parseParamList(var p: TParser): PNode; forward; + +function optExpr(var p: TParser): PNode; // [expr] +begin + if (p.tok.tokType <> tkComma) and (p.tok.tokType <> tkBracketRi) + and (p.tok.tokType <> tkDotDot) then + result := parseExpr(p) + else + result := nil; +end; + +function dotdotExpr(var p: TParser; first: PNode = nil): PNode; +begin + result := newNodeP(nkRange, p); + addSon(result, first); + getTok(p); + optInd(p, result); + addSon(result, optExpr(p)); +end; + +function indexExpr(var p: TParser): PNode; +// indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr] +var + a, b: PNode; +begin + if p.tok.tokType = tkDotDot then + result := dotdotExpr(p) + else begin + a := parseExpr(p); + case p.tok.tokType of + tkEquals: begin + result := newNodeP(nkExprEqExpr, p); + addSon(result, a); + getTok(p); + if p.tok.tokType = tkDotDot then + addSon(result, dotdotExpr(p)) + else begin + b := parseExpr(p); + if p.tok.tokType = tkDotDot then b := dotdotExpr(p, b); + addSon(result, b); + end + end; + tkDotDot: result := dotdotExpr(p, a); + else result := a + end + end +end; + +function indexExprList(var p: TParser; first: PNode): PNode; +var + a: PNode; +begin + result := newNodeP(nkBracketExpr, p); + addSon(result, first); + getTok(p); + optInd(p, result); + while (p.tok.tokType <> tkBracketRi) and (p.tok.tokType <> tkEof) + and (p.tok.tokType <> tkSad) do begin + a := indexExpr(p); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + optSad(p); + eat(p, tkBracketRi); +end; + +function exprColonEqExpr(var p: TParser; kind: TNodeKind; + tok: TTokType): PNode; +var + a: PNode; +begin + a := parseExpr(p); + if p.tok.tokType = tok then begin + result := newNodeP(kind, p); + getTok(p); + //optInd(p, result); + addSon(result, a); + addSon(result, parseExpr(p)); + end + else + result := a +end; + +procedure exprListAux(var p: TParser; elemKind: TNodeKind; + endTok, sepTok: TTokType; result: PNode); +var + a: PNode; +begin + getTok(p); + optInd(p, result); + while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin + a := exprColonEqExpr(p, elemKind, sepTok); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + eat(p, endTok); +end; + +function qualifiedIdent(var p: TParser): PNode; +var + a: PNode; +begin + result := parseSymbol(p); + if p.tok.tokType = tkDot then begin + getTok(p); + optInd(p, result); + a := result; + result := newNodeI(nkDotExpr, a.info); + addSon(result, a); + addSon(result, parseSymbol(p)); + end; +end; + +procedure qualifiedIdentListAux(var p: TParser; endTok: TTokType; + result: PNode); +var + a: PNode; +begin + getTok(p); + optInd(p, result); + while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) do begin + a := qualifiedIdent(p); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + eat(p, endTok); +end; + +procedure exprColonEqExprListAux(var p: TParser; elemKind: TNodeKind; + endTok, sepTok: TTokType; result: PNode); +var + a: PNode; +begin + getTok(p); + optInd(p, result); + while (p.tok.tokType <> endTok) and (p.tok.tokType <> tkEof) + and (p.tok.tokType <> tkSad) do begin + a := exprColonEqExpr(p, elemKind, sepTok); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + optSad(p); + eat(p, endTok); +end; + +function exprColonEqExprList(var p: TParser; kind, elemKind: TNodeKind; + endTok, sepTok: TTokType): PNode; +begin + result := newNodeP(kind, p); + exprColonEqExprListAux(p, elemKind, endTok, sepTok, result); +end; + +function parseCast(var p: TParser): PNode; +begin + result := newNodeP(nkCast, p); + getTok(p); + eat(p, tkBracketLe); + optInd(p, result); + addSon(result, parseTypeDesc(p)); + optSad(p); + eat(p, tkBracketRi); + eat(p, tkParLe); + optInd(p, result); + addSon(result, parseExpr(p)); + optSad(p); + eat(p, tkParRi); +end; + +function parseAddr(var p: TParser): PNode; +begin + result := newNodeP(nkAddr, p); + getTok(p); + eat(p, tkParLe); + optInd(p, result); + addSon(result, parseExpr(p)); + optSad(p); + eat(p, tkParRi); +end; + +procedure setBaseFlags(n: PNode; base: TNumericalBase); +begin + case base of + base10: begin end; + base2: include(n.flags, nfBase2); + base8: include(n.flags, nfBase8); + base16: include(n.flags, nfBase16); + end +end; + +function identOrLiteral(var p: TParser): PNode; +begin + case p.tok.tokType of + tkSymbol: begin + result := newIdentNodeP(p.tok.ident, p); + getTok(p) + end; + tkAccent: result := accExpr(p); + // literals + tkIntLit: begin + result := newIntNodeP(nkIntLit, p.tok.iNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkInt8Lit: begin + result := newIntNodeP(nkInt8Lit, p.tok.iNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkInt16Lit: begin + result := newIntNodeP(nkInt16Lit, p.tok.iNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkInt32Lit: begin + result := newIntNodeP(nkInt32Lit, p.tok.iNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkInt64Lit: begin + result := newIntNodeP(nkInt64Lit, p.tok.iNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkFloatLit: begin + result := newFloatNodeP(nkFloatLit, p.tok.fNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkFloat32Lit: begin + result := newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkFloat64Lit: begin + result := newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p); + setBaseFlags(result, p.tok.base); + getTok(p); + end; + tkStrLit: begin + result := newStrNodeP(nkStrLit, p.tok.literal, p); + getTok(p); + end; + tkRStrLit: begin + result := newStrNodeP(nkRStrLit, p.tok.literal, p); + getTok(p); + end; + tkTripleStrLit: begin + result := newStrNodeP(nkTripleStrLit, p.tok.literal, p); + getTok(p); + end; + tkCallRStrLit: begin + result := newNodeP(nkCallStrLit, p); + addSon(result, newIdentNodeP(p.tok.ident, p)); + addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)); + getTok(p); + end; + tkCallTripleStrLit: begin + result := newNodeP(nkCallStrLit, p); + addSon(result, newIdentNodeP(p.tok.ident, p)); + addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p)); + getTok(p); + end; + tkCharLit: begin + result := newIntNodeP(nkCharLit, ord(p.tok.literal[strStart]), p); + getTok(p); + end; + tkNil: begin + result := newNodeP(nkNilLit, p); + getTok(p); + end; + tkParLe: begin // () constructor + result := exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi, + tkColon); + end; + tkCurlyLe: begin // {} constructor + result := exprColonEqExprList(p, nkCurly, nkRange, tkCurlyRi, tkDotDot); + end; + tkBracketLe: begin // [] constructor + result := exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi, + tkColon); + end; + tkCast: result := parseCast(p); + tkAddr: result := parseAddr(p); + else begin + parMessage(p, errExprExpected, tokToStr(p.tok)); + getTok(p); // we must consume a token here to prevend endless loops! + result := nil + end + end +end; + +function primary(var p: TParser): PNode; +var + a: PNode; +begin + // prefix operator? + if (p.tok.tokType = tkNot) or (p.tok.tokType = tkOpr) then begin + result := newNodeP(nkPrefix, p); + a := newIdentNodeP(p.tok.ident, p); + addSon(result, a); + getTok(p); + optInd(p, a); + addSon(result, primary(p)); + exit + end + else if p.tok.tokType = tkBind then begin + result := newNodeP(nkBind, p); + getTok(p); + optInd(p, result); + addSon(result, primary(p)); + exit + end; + result := identOrLiteral(p); + while true do begin + case p.tok.tokType of + tkParLe: begin + a := result; + result := newNodeP(nkCall, p); + addSon(result, a); + exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result); + end; + tkDot: begin + a := result; + result := newNodeP(nkDotExpr, p); + addSon(result, a); + getTok(p); // skip '.' + optInd(p, result); + addSon(result, parseSymbol(p)); + end; + tkHat: begin + a := result; + result := newNodeP(nkDerefExpr, p); + addSon(result, a); + getTok(p); + end; + tkBracketLe: result := indexExprList(p, result); + else break + end + end +end; + +function lowestExprAux(var p: TParser; out v: PNode; limit: int): PToken; +var + op, nextop: PToken; + opPred: int; + v2, node, opNode: PNode; +begin + v := primary(p); + // expand while operators have priorities higher than 'limit' + op := p.tok; + opPred := getPrecedence(p.tok); + while (opPred > limit) do begin + node := newNodeP(nkInfix, p); + opNode := newIdentNodeP(op.ident, p); + // skip operator: + getTok(p); + optInd(p, opNode); + + // read sub-expression with higher priority + nextop := lowestExprAux(p, v2, opPred); + addSon(node, opNode); + addSon(node, v); + addSon(node, v2); + v := node; + op := nextop; + opPred := getPrecedence(nextop); + end; + result := op; // return first untreated operator +end; + +function lowestExpr(var p: TParser): PNode; +begin +{@discard} lowestExprAux(p, result, -1); +end; + +function parseIfExpr(var p: TParser): PNode; +// if (expr) expr else expr +var + branch: PNode; +begin + result := newNodeP(nkIfExpr, p); + while true do begin + getTok(p); // skip `if`, `elif` + branch := newNodeP(nkElifExpr, p); + eat(p, tkParLe); + addSon(branch, parseExpr(p)); + eat(p, tkParRi); + addSon(branch, parseExpr(p)); + addSon(result, branch); + if p.tok.tokType <> tkElif then break + end; + branch := newNodeP(nkElseExpr, p); + eat(p, tkElse); + addSon(branch, parseExpr(p)); + addSon(result, branch); +end; + +function parsePragma(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkPragma, p); + getTok(p); + optInd(p, result); + while (p.tok.tokType <> tkCurlyDotRi) and (p.tok.tokType <> tkCurlyRi) + and (p.tok.tokType <> tkEof) and (p.tok.tokType <> tkSad) do begin + a := exprColonEqExpr(p, nkExprColonExpr, tkColon); + addSon(result, a); + if p.tok.tokType = tkComma then begin + getTok(p); + optInd(p, a) + end + end; + optSad(p); + if (p.tok.tokType = tkCurlyDotRi) or (p.tok.tokType = tkCurlyRi) then + getTok(p) + else + parMessage(p, errTokenExpected, '.}'); +end; + +function identVis(var p: TParser): PNode; // identifier with visability +var + a: PNode; +begin + a := parseSymbol(p); + if p.tok.tokType = tkOpr then begin + result := newNodeP(nkPostfix, p); + addSon(result, newIdentNodeP(p.tok.ident, p)); + addSon(result, a); + getTok(p); + end + else + result := a; +end; + +function identWithPragma(var p: TParser): PNode; +var + a: PNode; +begin + a := identVis(p); + if p.tok.tokType = tkCurlyDotLe then begin + result := newNodeP(nkPragmaExpr, p); + addSon(result, a); + addSon(result, parsePragma(p)); + end + else + result := a +end; + +type + TDeclaredIdentFlag = ( + withPragma, // identifier may have pragma + withBothOptional // both ':' and '=' parts are optional + ); + TDeclaredIdentFlags = set of TDeclaredIdentFlag; + +function parseIdentColonEquals(var p: TParser; + flags: TDeclaredIdentFlags): PNode; +var + a: PNode; +begin + result := newNodeP(nkIdentDefs, p); + while true do begin + case p.tok.tokType of + tkSymbol, tkAccent: begin + if withPragma in flags then + a := identWithPragma(p) + else + a := parseSymbol(p); + if a = nil then exit; + end; + else break; + end; + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + if p.tok.tokType = tkColon then begin + getTok(p); optInd(p, result); + addSon(result, parseTypeDesc(p)); + end + else begin + addSon(result, nil); + if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then + parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok)) + end; + if p.tok.tokType = tkEquals then begin + getTok(p); optInd(p, result); + addSon(result, parseExpr(p)); + end + else + addSon(result, nil); +end; + +function parseTuple(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkTupleTy, p); + getTok(p); + eat(p, tkBracketLe); + optInd(p, result); + while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin + a := parseIdentColonEquals(p, {@set}[]); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + optSad(p); + eat(p, tkBracketRi); +end; + +function parseParamList(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkFormalParams, p); + addSon(result, nil); // return type + if p.tok.tokType = tkParLe then begin + getTok(p); + optInd(p, result); + while true do begin + case p.tok.tokType of + tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]); + tkParRi: break; + else begin parMessage(p, errTokenExpected, ')'+''); break; end; + end; + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + optSad(p); + eat(p, tkParRi); + end; + if p.tok.tokType = tkColon then begin + getTok(p); + optInd(p, result); + result.sons[0] := parseTypeDesc(p) + end +end; + +function parseProcExpr(var p: TParser; isExpr: bool): PNode; +// either a proc type or a anonymous proc +var + pragmas, params: PNode; + info: TLineInfo; +begin + info := parLineInfo(p); + getTok(p); + params := parseParamList(p); + if p.tok.tokType = tkCurlyDotLe then pragmas := parsePragma(p) + else pragmas := nil; + if (p.tok.tokType = tkCurlyLe) and isExpr then begin + result := newNodeI(nkLambda, info); + addSon(result, nil); // no name part + addSon(result, nil); // no generic parameters + addSon(result, params); + addSon(result, pragmas); + //getTok(p); skipComment(p, result); + addSon(result, parseStmt(p)); + end + else begin + result := newNodeI(nkProcTy, info); + addSon(result, params); + addSon(result, pragmas); + end +end; + +function parseTypeDescKAux(var p: TParser; kind: TNodeKind): PNode; +begin + result := newNodeP(kind, p); + getTok(p); + optInd(p, result); + addSon(result, parseTypeDesc(p)); +end; + +function parseExpr(var p: TParser): PNode; +(* +expr ::= lowestExpr + | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr + | 'var' expr + | 'ref' expr + | 'ptr' expr + | 'type' expr + | 'tuple' tupleDesc + | 'proc' paramList [pragma] ['=' stmt] +*) +begin + case p.tok.toktype of + tkVar: result := parseTypeDescKAux(p, nkVarTy); + tkRef: result := parseTypeDescKAux(p, nkRefTy); + tkPtr: result := parseTypeDescKAux(p, nkPtrTy); + tkType: result := parseTypeDescKAux(p, nkTypeOfExpr); + tkTuple: result := parseTuple(p); + tkProc: result := parseProcExpr(p, true); + tkIf: result := parseIfExpr(p); + else result := lowestExpr(p); + end +end; + +function parseTypeDesc(var p: TParser): PNode; +begin + if p.tok.toktype = tkProc then result := parseProcExpr(p, false) + else result := parseExpr(p); +end; + +// ---------------------- statement parser ------------------------------------ +function isExprStart(const p: TParser): bool; +begin + case p.tok.tokType of + tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind, + tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, + tkVar, tkRef, tkPtr, tkTuple, tkType: result := true; + else result := false; + end; +end; + +function parseExprStmt(var p: TParser): PNode; +var + a, b, e: PNode; +begin + a := lowestExpr(p); + if p.tok.tokType = tkEquals then begin + getTok(p); + optInd(p, result); + b := parseExpr(p); + result := newNodeI(nkAsgn, a.info); + addSon(result, a); + addSon(result, b); + end + else begin + result := newNodeP(nkCommand, p); + result.info := a.info; + addSon(result, a); + while true do begin + if not isExprStart(p) then break; + e := parseExpr(p); + addSon(result, e); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a); + end; + if sonsLen(result) <= 1 then result := a + else a := result; + if p.tok.tokType = tkCurlyLe then begin // macro statement + result := newNodeP(nkMacroStmt, p); + result.info := a.info; + addSon(result, a); + getTok(p); + skipComment(p, result); + if (p.tok.tokType = tkInd) + or not (p.tok.TokType in [tkOf, tkElif, tkElse, tkExcept]) then + addSon(result, parseStmt(p)); + while true do begin + if p.tok.tokType = tkSad then getTok(p); + case p.tok.tokType of + tkOf: begin + b := newNodeP(nkOfBranch, p); + exprListAux(p, nkRange, tkCurlyLe, tkDotDot, b); + end; + tkElif: begin + b := newNodeP(nkElifBranch, p); + getTok(p); + optInd(p, b); + addSon(b, parseExpr(p)); + eat(p, tkCurlyLe); + end; + tkExcept: begin + b := newNodeP(nkExceptBranch, p); + qualifiedIdentListAux(p, tkCurlyLe, b); + skipComment(p, b); + end; + tkElse: begin + b := newNodeP(nkElse, p); + getTok(p); + eat(p, tkCurlyLe); + end; + else break; + end; + addSon(b, parseStmt(p)); + eat(p, tkCurlyRi); + addSon(result, b); + if b.kind = nkElse then break; + end; + eat(p, tkCurlyRi); + end + end +end; + +function parseImportStmt(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkImportStmt, p); + getTok(p); // skip `import` + optInd(p, result); + while true do begin + case p.tok.tokType of + tkEof, tkSad, tkDed: break; + tkSymbol, tkAccent: a := parseSymbol(p); + tkRStrLit: begin + a := newStrNodeP(nkRStrLit, p.tok.literal, p); + getTok(p) + end; + tkStrLit: begin + a := newStrNodeP(nkStrLit, p.tok.literal, p); + getTok(p); + end; + tkTripleStrLit: begin + a := newStrNodeP(nkTripleStrLit, p.tok.literal, p); + getTok(p) + end; + else begin + parMessage(p, errIdentifierExpected, tokToStr(p.tok)); + break + end + end; + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; +end; + +function parseIncludeStmt(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkIncludeStmt, p); + getTok(p); // skip `include` + optInd(p, result); + while true do begin + case p.tok.tokType of + tkEof, tkSad, tkDed: break; + tkSymbol, tkAccent: a := parseSymbol(p); + tkRStrLit: begin + a := newStrNodeP(nkRStrLit, p.tok.literal, p); + getTok(p) + end; + tkStrLit: begin + a := newStrNodeP(nkStrLit, p.tok.literal, p); + getTok(p); + end; + tkTripleStrLit: begin + a := newStrNodeP(nkTripleStrLit, p.tok.literal, p); + getTok(p) + end; + else begin + parMessage(p, errIdentifierExpected, tokToStr(p.tok)); + break + end; + end; + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; +end; + +function parseFromStmt(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkFromStmt, p); + getTok(p); // skip `from` + optInd(p, result); + case p.tok.tokType of + tkSymbol, tkAccent: a := parseSymbol(p); + tkRStrLit: begin + a := newStrNodeP(nkRStrLit, p.tok.literal, p); + getTok(p) + end; + tkStrLit: begin + a := newStrNodeP(nkStrLit, p.tok.literal, p); + getTok(p); + end; + tkTripleStrLit: begin + a := newStrNodeP(nkTripleStrLit, p.tok.literal, p); + getTok(p) + end; + else begin + parMessage(p, errIdentifierExpected, tokToStr(p.tok)); exit + end + end; + addSon(result, a); + //optInd(p, a); + eat(p, tkImport); + optInd(p, result); + while true do begin + case p.tok.tokType of + tkEof, tkSad, tkDed: break; + tkSymbol, tkAccent: a := parseSymbol(p); + else begin + parMessage(p, errIdentifierExpected, tokToStr(p.tok)); + break + end; + end; + //optInd(p, a); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; +end; + +function parseReturnOrRaise(var p: TParser; kind: TNodeKind): PNode; +begin + result := newNodeP(kind, p); + getTok(p); + optInd(p, result); + case p.tok.tokType of + tkEof, tkSad, tkDed: addSon(result, nil); + else addSon(result, parseExpr(p)); + end; +end; + +function parseYieldOrDiscard(var p: TParser; kind: TNodeKind): PNode; +begin + result := newNodeP(kind, p); + getTok(p); + optInd(p, result); + addSon(result, parseExpr(p)); +end; + +function parseBreakOrContinue(var p: TParser; kind: TNodeKind): PNode; +begin + result := newNodeP(kind, p); + getTok(p); + optInd(p, result); + case p.tok.tokType of + tkEof, tkSad, tkDed: addSon(result, nil); + else addSon(result, parseSymbol(p)); + end; +end; + +function parseIfOrWhen(var p: TParser; kind: TNodeKind): PNode; +var + branch: PNode; +begin + result := newNodeP(kind, p); + while true do begin + getTok(p); // skip `if`, `when`, `elif` + branch := newNodeP(nkElifBranch, p); + optInd(p, branch); + eat(p, tkParLe); + addSon(branch, parseExpr(p)); + eat(p, tkParRi); + skipComment(p, branch); + addSon(branch, parseStmt(p)); + skipComment(p, branch); + addSon(result, branch); + if p.tok.tokType <> tkElif then break + end; + if p.tok.tokType = tkElse then begin + branch := newNodeP(nkElse, p); + eat(p, tkElse); + skipComment(p, branch); + addSon(branch, parseStmt(p)); + addSon(result, branch); + end +end; + +function parseWhile(var p: TParser): PNode; +begin + result := newNodeP(nkWhileStmt, p); + getTok(p); + optInd(p, result); + eat(p, tkParLe); + addSon(result, parseExpr(p)); + eat(p, tkParRi); + skipComment(p, result); + addSon(result, parseStmt(p)); +end; + +function parseCase(var p: TParser): PNode; +var + b: PNode; + inElif: bool; +begin + result := newNodeP(nkCaseStmt, p); + getTok(p); + eat(p, tkParLe); + addSon(result, parseExpr(p)); + eat(p, tkParRi); + skipComment(p, result); + inElif := false; + while true do begin + if p.tok.tokType = tkSad then getTok(p); + case p.tok.tokType of + tkOf: begin + if inElif then break; + b := newNodeP(nkOfBranch, p); + exprListAux(p, nkRange, tkColon, tkDotDot, b); + end; + tkElif: begin + inElif := true; + b := newNodeP(nkElifBranch, p); + getTok(p); + optInd(p, b); + addSon(b, parseExpr(p)); + eat(p, tkColon); + end; + tkElse: begin + b := newNodeP(nkElse, p); + getTok(p); + eat(p, tkColon); + end; + else break; + end; + skipComment(p, b); + addSon(b, parseStmt(p)); + addSon(result, b); + if b.kind = nkElse then break; + end +end; + +function parseTry(var p: TParser): PNode; +var + b: PNode; +begin + result := newNodeP(nkTryStmt, p); + getTok(p); + eat(p, tkColon); + skipComment(p, result); + addSon(result, parseStmt(p)); + b := nil; + while true do begin + if p.tok.tokType = tkSad then getTok(p); + case p.tok.tokType of + tkExcept: begin + b := newNodeP(nkExceptBranch, p); + qualifiedIdentListAux(p, tkColon, b); + end; + tkFinally: begin + b := newNodeP(nkFinally, p); + getTok(p); + eat(p, tkColon); + end; + else break; + end; + skipComment(p, b); + addSon(b, parseStmt(p)); + addSon(result, b); + if b.kind = nkFinally then break; + end; + if b = nil then parMessage(p, errTokenExpected, 'except'); +end; + +function parseFor(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkForStmt, p); + getTok(p); + optInd(p, result); + a := parseSymbol(p); + addSon(result, a); + while p.tok.tokType = tkComma do begin + getTok(p); + optInd(p, a); + a := parseSymbol(p); + addSon(result, a); + end; + eat(p, tkIn); + addSon(result, exprColonEqExpr(p, nkRange, tkDotDot)); + eat(p, tkColon); + skipComment(p, result); + addSon(result, parseStmt(p)) +end; + +function parseBlock(var p: TParser): PNode; +begin + result := newNodeP(nkBlockStmt, p); + getTok(p); + optInd(p, result); + case p.tok.tokType of + tkEof, tkSad, tkDed, tkColon: addSon(result, nil); + else addSon(result, parseSymbol(p)); + end; + eat(p, tkColon); + skipComment(p, result); + addSon(result, parseStmt(p)); +end; + +function parseAsm(var p: TParser): PNode; +begin + result := newNodeP(nkAsmStmt, p); + getTok(p); + optInd(p, result); + if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p)) + else addSon(result, nil); + case p.tok.tokType of + tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p)); + tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)); + tkTripleStrLit: + addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p)); + else begin + parMessage(p, errStringLiteralExpected); + addSon(result, nil); exit + end; + end; + getTok(p); +end; + +function parseGenericParamList(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkGenericParams, p); + getTok(p); + optInd(p, result); + while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin + a := parseIdentColonEquals(p, {@set}[withBothOptional]); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + optSad(p); + eat(p, tkBracketRi); +end; + +function parseRoutine(var p: TParser; kind: TNodeKind): PNode; +begin + result := newNodeP(kind, p); + getTok(p); + optInd(p, result); + addSon(result, identVis(p)); + if p.tok.tokType = tkBracketLe then addSon(result, parseGenericParamList(p)) + else addSon(result, nil); + addSon(result, parseParamList(p)); + if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p)) + else addSon(result, nil); + if p.tok.tokType = tkEquals then begin + getTok(p); skipComment(p, result); + addSon(result, parseStmt(p)); + end + else + addSon(result, nil); + indAndComment(p, result); // XXX: document this in the grammar! +end; + +function newCommentStmt(var p: TParser): PNode; +begin + result := newNodeP(nkCommentStmt, p); + result.info.line := result.info.line - int16(1); +end; + +type + TDefParser = function (var p: TParser): PNode; + +function parseSection(var p: TParser; kind: TNodeKind; + defparser: TDefParser): PNode; +var + a: PNode; +begin + result := newNodeP(kind, p); + getTok(p); + skipComment(p, result); + case p.tok.tokType of + tkInd: begin + pushInd(p.lex^, p.tok.indent); + getTok(p); skipComment(p, result); + while true do begin + case p.tok.tokType of + tkSad: getTok(p); + tkSymbol, tkAccent: begin + a := defparser(p); + skipComment(p, a); + addSon(result, a); + end; + tkDed: begin getTok(p); break end; + tkEof: break; // BUGFIX + tkComment: begin + a := newCommentStmt(p); + skipComment(p, a); + addSon(result, a); + end; + else begin + parMessage(p, errIdentifierExpected, tokToStr(p.tok)); + break + end + end + end; + popInd(p.lex^); + end; + tkSymbol, tkAccent, tkParLe: begin + // tkParLe is allowed for ``var (x, y) = ...`` tuple parsing + addSon(result, defparser(p)); + end + else parMessage(p, errIdentifierExpected, tokToStr(p.tok)); + end +end; + +function parseConstant(var p: TParser): PNode; +begin + result := newNodeP(nkConstDef, p); + addSon(result, identWithPragma(p)); + if p.tok.tokType = tkColon then begin + getTok(p); optInd(p, result); + addSon(result, parseTypeDesc(p)); + end + else + addSon(result, nil); + eat(p, tkEquals); + optInd(p, result); + addSon(result, parseExpr(p)); + indAndComment(p, result); // XXX: special extension! +end; + +function parseEnum(var p: TParser): PNode; +var + a, b: PNode; +begin + result := newNodeP(nkEnumTy, p); + a := nil; + getTok(p); + optInd(p, result); + if p.tok.tokType = tkOf then begin + a := newNodeP(nkOfInherit, p); + getTok(p); optInd(p, a); + addSon(a, parseTypeDesc(p)); + addSon(result, a) + end + else addSon(result, nil); + + while true do begin + case p.tok.tokType of + tkEof, tkSad, tkDed: break; + else a := parseSymbol(p); + end; + optInd(p, a); + if p.tok.tokType = tkEquals then begin + getTok(p); + optInd(p, a); + b := a; + a := newNodeP(nkEnumFieldDef, p); + addSon(a, b); + addSon(a, parseExpr(p)); + skipComment(p, a); + end; + if p.tok.tokType = tkComma then begin + getTok(p); + optInd(p, a) + end; + addSon(result, a); + end +end; + +function parseObjectPart(var p: TParser): PNode; forward; + +function parseObjectWhen(var p: TParser): PNode; +var + branch: PNode; +begin + result := newNodeP(nkRecWhen, p); + while true do begin + getTok(p); // skip `when`, `elif` + branch := newNodeP(nkElifBranch, p); + optInd(p, branch); + addSon(branch, parseExpr(p)); + eat(p, tkColon); + skipComment(p, branch); + addSon(branch, parseObjectPart(p)); + skipComment(p, branch); + addSon(result, branch); + if p.tok.tokType <> tkElif then break + end; + if p.tok.tokType = tkElse then begin + branch := newNodeP(nkElse, p); + eat(p, tkElse); eat(p, tkColon); + skipComment(p, branch); + addSon(branch, parseObjectPart(p)); + addSon(result, branch); + end +end; + +function parseObjectCase(var p: TParser): PNode; +var + a, b: PNode; +begin + result := newNodeP(nkRecCase, p); + getTok(p); + a := newNodeP(nkIdentDefs, p); + addSon(a, identWithPragma(p)); + eat(p, tkColon); + addSon(a, parseTypeDesc(p)); + addSon(a, nil); + addSon(result, a); + skipComment(p, result); + while true do begin + if p.tok.tokType = tkSad then getTok(p); + case p.tok.tokType of + tkOf: begin + b := newNodeP(nkOfBranch, p); + exprListAux(p, nkRange, tkColon, tkDotDot, b); + end; + tkElse: begin + b := newNodeP(nkElse, p); + getTok(p); + eat(p, tkColon); + end; + else break; + end; + skipComment(p, b); + addSon(b, parseObjectPart(p)); + addSon(result, b); + if b.kind = nkElse then break; + end +end; + +function parseObjectPart(var p: TParser): PNode; +begin + case p.tok.tokType of + tkInd: begin + result := newNodeP(nkRecList, p); + pushInd(p.lex^, p.tok.indent); + getTok(p); skipComment(p, result); + while true do begin + case p.tok.tokType of + tkSad: getTok(p); + tkCase, tkWhen, tkSymbol, tkAccent, tkNil: begin + addSon(result, parseObjectPart(p)); + end; + tkDed: begin getTok(p); break end; + tkEof: break; + else begin + parMessage(p, errIdentifierExpected, tokToStr(p.tok)); + break + end + end + end; + popInd(p.lex^); + end; + tkWhen: result := parseObjectWhen(p); + tkCase: result := parseObjectCase(p); + tkSymbol, tkAccent: begin + result := parseIdentColonEquals(p, {@set}[withPragma]); + skipComment(p, result); + end; + tkNil: begin + result := newNodeP(nkNilLit, p); + getTok(p); + end; + else result := nil + end +end; + +function parseObject(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkObjectTy, p); + getTok(p); + if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p)) + else addSon(result, nil); + if p.tok.tokType = tkOf then begin + a := newNodeP(nkOfInherit, p); + getTok(p); + addSon(a, parseTypeDesc(p)); + addSon(result, a); + end + else addSon(result, nil); + skipComment(p, result); + addSon(result, parseObjectPart(p)); +end; + +function parseDistinct(var p: TParser): PNode; +begin + result := newNodeP(nkDistinctTy, p); + getTok(p); + optInd(p, result); + addSon(result, parseTypeDesc(p)); +end; + +function parseTypeDef(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkTypeDef, p); + addSon(result, identWithPragma(p)); + if p.tok.tokType = tkBracketLe then addSon(result, parseGenericParamList(p)) + else addSon(result, nil); + if p.tok.tokType = tkEquals then begin + getTok(p); optInd(p, result); + case p.tok.tokType of + tkObject: a := parseObject(p); + tkEnum: a := parseEnum(p); + tkDistinct: a := parseDistinct(p); + else a := parseTypeDesc(p); + end; + addSon(result, a); + end + else + addSon(result, nil); + indAndComment(p, result); // special extension! +end; + +function parseVarTuple(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkVarTuple, p); + getTok(p); // skip '(' + optInd(p, result); + while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin + a := identWithPragma(p); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + addSon(result, nil); // no type desc + optSad(p); + eat(p, tkParRi); + eat(p, tkEquals); + optInd(p, result); + addSon(result, parseExpr(p)); +end; + +function parseVariable(var p: TParser): PNode; +begin + if p.tok.tokType = tkParLe then + result := parseVarTuple(p) + else + result := parseIdentColonEquals(p, {@set}[withPragma]); + indAndComment(p, result); // special extension! +end; + +function simpleStmt(var p: TParser): PNode; +begin + case p.tok.tokType of + tkReturn: result := parseReturnOrRaise(p, nkReturnStmt); + tkRaise: result := parseReturnOrRaise(p, nkRaiseStmt); + tkYield: result := parseYieldOrDiscard(p, nkYieldStmt); + tkDiscard: result := parseYieldOrDiscard(p, nkDiscardStmt); + tkBreak: result := parseBreakOrContinue(p, nkBreakStmt); + tkContinue: result := parseBreakOrContinue(p, nkContinueStmt); + tkCurlyDotLe: result := parsePragma(p); + tkImport: result := parseImportStmt(p); + tkFrom: result := parseFromStmt(p); + tkInclude: result := parseIncludeStmt(p); + tkComment: result := newCommentStmt(p); + else begin + if isExprStart(p) then + result := parseExprStmt(p) + else + result := nil; + end + end; + if result <> nil then + skipComment(p, result); +end; + +function complexOrSimpleStmt(var p: TParser): PNode; +begin + case p.tok.tokType of + tkIf: result := parseIfOrWhen(p, nkIfStmt); + tkWhile: result := parseWhile(p); + tkCase: result := parseCase(p); + tkTry: result := parseTry(p); + tkFor: result := parseFor(p); + tkBlock: result := parseBlock(p); + tkAsm: result := parseAsm(p); + tkProc: result := parseRoutine(p, nkProcDef); + tkMethod: result := parseRoutine(p, nkMethodDef); + tkIterator: result := parseRoutine(p, nkIteratorDef); + tkMacro: result := parseRoutine(p, nkMacroDef); + tkTemplate: result := parseRoutine(p, nkTemplateDef); + tkConverter: result := parseRoutine(p, nkConverterDef); + tkType: result := parseSection(p, nkTypeSection, parseTypeDef); + tkConst: result := parseSection(p, nkConstSection, parseConstant); + tkWhen: result := parseIfOrWhen(p, nkWhenStmt); + tkVar: result := parseSection(p, nkVarSection, parseVariable); + else result := simpleStmt(p); + end +end; + +function parseStmt(var p: TParser): PNode; +var + a: PNode; +begin + if p.tok.tokType = tkInd then begin + result := newNodeP(nkStmtList, p); + pushInd(p.lex^, p.tok.indent); + getTok(p); + while true do begin + case p.tok.tokType of + tkSad: getTok(p); + tkEof: break; + tkDed: begin getTok(p); break end; + else begin + a := complexOrSimpleStmt(p); + if a = nil then break; + addSon(result, a); + end + end + end; + popInd(p.lex^); + end + else begin + // the case statement is only needed for better error messages: + case p.tok.tokType of + tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, + tkProc, tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar: begin + parMessage(p, errComplexStmtRequiresInd); + result := nil + end + else begin + result := simpleStmt(p); + if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok)); + if p.tok.tokType = tkSad then getTok(p); + end + end + end +end; + +function parseAll(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkStmtList, p); + while true do begin + case p.tok.tokType of + tkSad: getTok(p); + tkDed, tkInd: parMessage(p, errInvalidIndentation); + tkEof: break; + else begin + a := complexOrSimpleStmt(p); + if a = nil then parMessage(p, errExprExpected, tokToStr(p.tok)); + addSon(result, a); + end + end + end +end; + +function parseTopLevelStmt(var p: TParser): PNode; +begin + result := nil; + while true do begin + case p.tok.tokType of + tkSad: getTok(p); + tkDed, tkInd: begin + parMessage(p, errInvalidIndentation); + break; + end; + tkEof: break; + else begin + result := complexOrSimpleStmt(p); + if result = nil then parMessage(p, errExprExpected, tokToStr(p.tok)); + break + end + end + end +end; + +end. diff --git a/nim/platform.pas b/nim/platform.pas index 9f8d30f60..c2fa711b9 100755 --- a/nim/platform.pas +++ b/nim/platform.pas @@ -1,7 +1,7 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. @@ -59,9 +59,8 @@ type TInfoOS = record{@tuple} name: string; parDir: string; - dllExt: string; + dllFrmt: string; altDirSep: string; - dllPrefix: string; objExt: string; newLine: string; pathSep: string; @@ -77,9 +76,8 @@ const ( name: 'DOS'; parDir: '..'; - dllExt: '.dll'; + dllFrmt: '$1.dll'; altDirSep: '/'+''; - dllPrefix: ''; objExt: '.obj'; newLine: #13#10; pathSep: ';'+''; @@ -93,9 +91,8 @@ const ( name: 'Windows'; parDir: '..'; - dllExt: '.dll'; + dllFrmt: '$1.dll'; altDirSep: '/'+''; - dllPrefix: ''; objExt: '.obj'; newLine: #13#10; pathSep: ';'+''; @@ -109,9 +106,8 @@ const ( name: 'OS2'; parDir: '..'; - dllExt: '.dll'; + dllFrmt: '$1.dll'; altDirSep: '/'+''; - dllPrefix: ''; objExt: '.obj'; newLine: #13#10; pathSep: ';'+''; @@ -125,9 +121,8 @@ const ( name: 'Linux'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -141,9 +136,8 @@ const ( name: 'MorphOS'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -157,9 +151,8 @@ const ( name: 'SkyOS'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -173,9 +166,8 @@ const ( name: 'Solaris'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -189,9 +181,8 @@ const ( name: 'Irix'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -205,9 +196,8 @@ const ( name: 'NetBSD'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -221,9 +211,8 @@ const ( name: 'FreeBSD'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -237,9 +226,8 @@ const ( name: 'OpenBSD'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -253,9 +241,8 @@ const ( name: 'AIX'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -269,9 +256,8 @@ const ( name: 'PalmOS'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -285,9 +271,8 @@ const ( name: 'QNX'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -301,9 +286,8 @@ const ( name: 'Amiga'; parDir: '..'; - dllExt: '.library'; + dllFrmt: '$1.library'; altDirSep: '/'+''; - dllPrefix: ''; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -317,9 +301,8 @@ const ( name: 'Atari'; parDir: '..'; - dllExt: '.dll'; + dllFrmt: '$1.dll'; altDirSep: '/'+''; - dllPrefix: ''; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -333,9 +316,8 @@ const ( name: 'Netware'; parDir: '..'; - dllExt: '.nlm'; + dllFrmt: '$1.nlm'; altDirSep: '/'+''; - dllPrefix: ''; objExt: ''; newLine: #13#10; pathSep: ':'+''; @@ -349,9 +331,8 @@ const ( name: 'MacOS'; parDir: '::'; - dllExt: 'Lib'; + dllFrmt: '$1Lib'; altDirSep: ':'+''; - dllPrefix: ''; objExt: '.o'; newLine: #13+''; pathSep: ','+''; @@ -365,9 +346,8 @@ const ( name: 'MacOSX'; parDir: '..'; - dllExt: '.dylib'; + dllFrmt: 'lib$1.dylib'; altDirSep: ':'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -381,9 +361,8 @@ const ( name: 'EcmaScript'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; @@ -397,9 +376,8 @@ const ( name: 'NimrodVM'; parDir: '..'; - dllExt: '.so'; + dllFrmt: 'lib$1.so'; altDirSep: '/'+''; - dllPrefix: 'lib'; objExt: '.o'; newLine: #10+''; pathSep: ':'+''; diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas index 724a85a38..bf964fda1 100755 --- a/nim/pnimsyn.pas +++ b/nim/pnimsyn.pas @@ -22,7 +22,7 @@ interface uses nsystem, llstream, scanner, idents, strutils, ast, msgs; -function ParseFile(const filename: string): PNode; +// function ParseFile(const filename: string): PNode; type TParser = record // a TParser object represents a module that @@ -31,10 +31,7 @@ type tok: PToken; // the current token end; -function ParseModule(var p: TParser): PNode; -// Note: The module's tree must always be valid. -function parseExpr(var p: TParser): PNode; -function parseStmt(var p: TParser): PNode; +function ParseAll(var p: TParser): PNode; procedure openParser(var p: TParser; const filename: string; inputstream: PLLStream); @@ -44,21 +41,43 @@ function parseTopLevelStmt(var p: TParser): PNode; // implements an iterator. Returns the next top-level statement or nil if end // of stream. -implementation -function ParseFile(const filename: string): PNode; -var - p: TParser; - f: TBinaryFile; -begin - if not OpenFile(f, filename) then begin - rawMessage(errCannotOpenFile, filename); - exit - end; - OpenParser(p, filename, LLStreamOpen(f)); - result := ParseModule(p); - CloseParser(p); -end; +// helpers for the other parsers +function getPrecedence(tok: PToken): int; +function isOperator(tok: PToken): bool; + +procedure getTok(var p: TParser); + +procedure parMessage(const p: TParser; const msg: TMsgKind; + const arg: string = ''); +procedure skipComment(var p: TParser; node: PNode); + +function newNodeP(kind: TNodeKind; const p: TParser): PNode; +function newIntNodeP(kind: TNodeKind; const intVal: BiggestInt; + const p: TParser): PNode; +function newFloatNodeP(kind: TNodeKind; const floatVal: BiggestFloat; + const p: TParser): PNode; +function newStrNodeP(kind: TNodeKind; const strVal: string; + const p: TParser): PNode; +function newIdentNodeP(ident: PIdent; const p: TParser): PNode; + +procedure expectIdentOrKeyw(const p: TParser); +procedure ExpectIdent(const p: TParser); +procedure expectIdentOrOpr(const p: TParser); +function parLineInfo(const p: TParser): TLineInfo; +procedure Eat(var p: TParser; TokType: TTokType); + +procedure skipInd(var p: TParser); +procedure optSad(var p: TParser); +procedure optInd(var p: TParser; n: PNode); +procedure indAndComment(var p: TParser; n: PNode); + + +function parseSymbol(var p: TParser): PNode; +function accExpr(var p: TParser): PNode; + + +implementation procedure initParser(var p: TParser); begin @@ -211,6 +230,9 @@ end; // ------------------- Expression parsing ------------------------------------ +function parseExpr(var p: TParser): PNode; forward; +function parseStmt(var p: TParser): PNode; forward; + function parseTypeDesc(var p: TParser): PNode; forward; function parseParamList(var p: TParser): PNode; forward; @@ -364,43 +386,35 @@ begin addSon(result, optExpr(p)); end; -function parseTypeDescK(var p: TParser): PNode; forward; - -function namedTypeOrExpr(var p: TParser): PNode; +function indexExpr(var p: TParser): PNode; +// indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr] var a, b: PNode; begin - case p.tok.tokType of - tkDotDot: result := dotdotExpr(p); - tkVar, tkRef, tkPtr, tkProc, tkTuple, tkType: result := parseTypeDescK(p); - else begin - a := parseExpr(p); - case p.tok.tokType of - tkEquals: begin - result := newNodeP(nkExprEqExpr, p); - addSon(result, a); - getTok(p); - //optInd(p, result); - case p.tok.tokType of - tkVar, tkRef, tkPtr, tkProc: - addSon(result, parseTypeDescK(p)); - tkDotDot: addSon(result, dotdotExpr(p)); - else begin - b := parseExpr(p); - if p.tok.tokType = tkDotDot then - b := dotdotExpr(p, b); - addSon(result, b); - end - end - end; - tkDotDot: result := dotdotExpr(p, a); - else result := a - end + if p.tok.tokType = tkDotDot then + result := dotdotExpr(p) + else begin + a := parseExpr(p); + case p.tok.tokType of + tkEquals: begin + result := newNodeP(nkExprEqExpr, p); + addSon(result, a); + getTok(p); + if p.tok.tokType = tkDotDot then + addSon(result, dotdotExpr(p)) + else begin + b := parseExpr(p); + if p.tok.tokType = tkDotDot then b := dotdotExpr(p, b); + addSon(result, b); + end + end; + tkDotDot: result := dotdotExpr(p, a); + else result := a end end end; -function namedTypeOrExprList(var p: TParser; first: PNode): PNode; +function indexExprList(var p: TParser; first: PNode): PNode; var a: PNode; begin @@ -410,7 +424,7 @@ begin optInd(p, result); while (p.tok.tokType <> tkBracketRi) and (p.tok.tokType <> tkEof) and (p.tok.tokType <> tkSad) do begin - a := namedTypeOrExpr(p); + a := indexExpr(p); addSon(result, a); if p.tok.tokType <> tkComma then break; getTok(p); @@ -464,7 +478,7 @@ begin getTok(p); optInd(p, result); a := result; - result := newNodeI(nkQualified, a.info); + result := newNodeI(nkDotExpr, a.info); addSon(result, a); addSon(result, parseSymbol(p)); end; @@ -632,7 +646,6 @@ begin result := newNodeP(nkNilLit, p); getTok(p); end; - tkParLe: begin // () constructor result := exprColonEqExprList(p, nkPar, nkExprColonExpr, tkParRi, tkColon); @@ -698,7 +711,7 @@ begin addSon(result, a); getTok(p); end; - tkBracketLe: result := namedTypeOrExprList(p, result); + tkBracketLe: result := indexExprList(p, result); else break end end @@ -712,11 +725,6 @@ var begin v := primary(p); // expand while operators have priorities higher than 'limit' - (*if p.tok.tokType = tkInd then begin // BUGFIX: parser allowed too much - getTok(p); - if getPrecedence(p.tok) < 0 then - parMessage(p, errOperatorExpected, tokToStr(p.tok)); - end; *) op := p.tok; opPred := getPrecedence(p.tok); while (opPred > limit) do begin @@ -724,8 +732,6 @@ begin opNode := newIdentNodeP(op.ident, p); // skip operator: getTok(p); - //skipComment(p, opNode); - //skipInd(p); optInd(p, opNode); // read sub-expression with higher priority @@ -745,8 +751,6 @@ begin {@discard} lowestExprAux(p, result, -1); end; -function parseLambda(var p: TParser): PNode; forward; - function parseIfExpr(var p: TParser): PNode; var branch: PNode; @@ -755,12 +759,9 @@ begin while true do begin getTok(p); // skip `if`, `elif` branch := newNodeP(nkElifExpr, p); - //optInd(p, branch); addSon(branch, parseExpr(p)); eat(p, tkColon); - //optInd(p, branch); addSon(branch, parseExpr(p)); - //optInd(p, branch); addSon(result, branch); if p.tok.tokType <> tkElif then break end; @@ -770,16 +771,6 @@ begin addSon(result, branch); end; -function parseExpr(var p: TParser): PNode; -begin - case p.tok.toktype of - tkLambda: result := parseLambda(p); - tkIf: result := parseIfExpr(p); - else result := lowestExpr(p); - end -end; - -// ------------------------- pragma parser ----------------------------------- function parsePragma(var p: TParser): PNode; var a: PNode; @@ -803,12 +794,203 @@ begin parMessage(p, errTokenExpected, '.}'); end; +function identVis(var p: TParser): PNode; // identifier with visability +var + a: PNode; +begin + a := parseSymbol(p); + if p.tok.tokType = tkOpr then begin + result := newNodeP(nkPostfix, p); + addSon(result, newIdentNodeP(p.tok.ident, p)); + addSon(result, a); + getTok(p); + end + else + result := a; +end; + +function identWithPragma(var p: TParser): PNode; +var + a: PNode; +begin + a := identVis(p); + if p.tok.tokType = tkCurlyDotLe then begin + result := newNodeP(nkPragmaExpr, p); + addSon(result, a); + addSon(result, parsePragma(p)); + end + else + result := a +end; + +type + TDeclaredIdentFlag = ( + withPragma, // identifier may have pragma + withBothOptional // both ':' and '=' parts are optional + ); + TDeclaredIdentFlags = set of TDeclaredIdentFlag; + +function parseIdentColonEquals(var p: TParser; + flags: TDeclaredIdentFlags): PNode; +var + a: PNode; +begin + result := newNodeP(nkIdentDefs, p); + while true do begin + case p.tok.tokType of + tkSymbol, tkAccent: begin + if withPragma in flags then + a := identWithPragma(p) + else + a := parseSymbol(p); + if a = nil then exit; + end; + else break; + end; + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + if p.tok.tokType = tkColon then begin + getTok(p); optInd(p, result); + addSon(result, parseTypeDesc(p)); + end + else begin + addSon(result, nil); + if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then + parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok)) + end; + if p.tok.tokType = tkEquals then begin + getTok(p); optInd(p, result); + addSon(result, parseExpr(p)); + end + else + addSon(result, nil); +end; + +function parseTuple(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkTupleTy, p); + getTok(p); + eat(p, tkBracketLe); + optInd(p, result); + while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin + a := parseIdentColonEquals(p, {@set}[]); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + optSad(p); + eat(p, tkBracketRi); +end; + +function parseParamList(var p: TParser): PNode; +var + a: PNode; +begin + result := newNodeP(nkFormalParams, p); + addSon(result, nil); // return type + if p.tok.tokType = tkParLe then begin + getTok(p); + optInd(p, result); + while true do begin + case p.tok.tokType of + tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]); + tkParRi: break; + else begin parMessage(p, errTokenExpected, ')'+''); break; end; + end; + //optInd(p, a); + addSon(result, a); + if p.tok.tokType <> tkComma then break; + getTok(p); + optInd(p, a) + end; + optSad(p); + eat(p, tkParRi); + end; + if p.tok.tokType = tkColon then begin + getTok(p); + optInd(p, result); + result.sons[0] := parseTypeDesc(p) + end +end; + +function parseProcExpr(var p: TParser; isExpr: bool): PNode; +// either a proc type or a anonymous proc +var + pragmas, params: PNode; + info: TLineInfo; +begin + info := parLineInfo(p); + getTok(p); + params := parseParamList(p); + if p.tok.tokType = tkCurlyDotLe then pragmas := parsePragma(p) + else pragmas := nil; + if (p.tok.tokType = tkEquals) and isExpr then begin + result := newNodeI(nkLambda, info); + addSon(result, nil); // no name part + addSon(result, nil); // no generic parameters + addSon(result, params); + addSon(result, pragmas); + getTok(p); skipComment(p, result); + addSon(result, parseStmt(p)); + end + else begin + result := newNodeI(nkProcTy, info); + addSon(result, params); + addSon(result, pragmas); + end +end; + +function parseTypeDescKAux(var p: TParser; kind: TNodeKind): PNode; +begin + result := newNodeP(kind, p); + getTok(p); + optInd(p, result); + addSon(result, parseTypeDesc(p)); +end; + +function parseExpr(var p: TParser): PNode; +(* +expr ::= lowestExpr + | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr + | 'var' expr + | 'ref' expr + | 'ptr' expr + | 'type' expr + | 'tuple' tupleDesc + | 'proc' paramList [pragma] ['=' stmt] +*) +begin + case p.tok.toktype of + tkVar: result := parseTypeDescKAux(p, nkVarTy); + tkRef: result := parseTypeDescKAux(p, nkRefTy); + tkPtr: result := parseTypeDescKAux(p, nkPtrTy); + tkType: result := parseTypeDescKAux(p, nkTypeOfExpr); + tkTuple: result := parseTuple(p); + tkProc: result := parseProcExpr(p, true); + tkIf: result := parseIfExpr(p); + else result := lowestExpr(p); + end +end; + +function parseTypeDesc(var p: TParser): PNode; +begin + if p.tok.toktype = tkProc then result := parseProcExpr(p, false) + else result := parseExpr(p); +end; + // ---------------------- statement parser ------------------------------------ function isExprStart(const p: TParser): bool; begin case p.tok.tokType of - tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda, tkBind, - tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit: result := true; + tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind, + tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, + tkVar, tkRef, tkPtr, tkTuple, tkType: result := true; else result := false; end; end; @@ -1051,7 +1233,6 @@ begin addSon(result, branch); if p.tok.tokType <> tkElif then break end; - //PrintTok(p.tok); if p.tok.tokType = tkElse then begin branch := newNodeP(nkElse, p); eat(p, tkElse); eat(p, tkColon); @@ -1201,175 +1382,6 @@ begin getTok(p); end; -function identVis(var p: TParser): PNode; // identifier with visability -var - a: PNode; -begin - a := parseSymbol(p); - if p.tok.tokType = tkOpr then begin - result := newNodeP(nkPostfix, p); - addSon(result, newIdentNodeP(p.tok.ident, p)); - addSon(result, a); - getTok(p); - end - else - result := a; -end; - -function identWithPragma(var p: TParser): PNode; -var - a: PNode; -begin - a := identVis(p); - if p.tok.tokType = tkCurlyDotLe then begin - result := newNodeP(nkPragmaExpr, p); - addSon(result, a); - addSon(result, parsePragma(p)); - end - else - result := a -end; - -type - TDeclaredIdentFlag = ( - withPragma, // identifier may have pragma - withBothOptional // both ':' and '=' parts are optional - ); - TDeclaredIdentFlags = set of TDeclaredIdentFlag; - -function parseIdentColonEquals(var p: TParser; - flags: TDeclaredIdentFlags): PNode; -var - a: PNode; -begin - result := newNodeP(nkIdentDefs, p); - while true do begin - case p.tok.tokType of - tkSymbol, tkAccent: begin - if withPragma in flags then - a := identWithPragma(p) - else - a := parseSymbol(p); - if a = nil then exit; - end; - else break; - end; - addSon(result, a); - if p.tok.tokType <> tkComma then break; - getTok(p); - optInd(p, a) - end; - if p.tok.tokType = tkColon then begin - getTok(p); optInd(p, result); - addSon(result, parseTypeDesc(p)); - end - else begin - addSon(result, nil); - if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then - parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok)) - end; - if p.tok.tokType = tkEquals then begin - getTok(p); optInd(p, result); - addSon(result, parseExpr(p)); - end - else - addSon(result, nil); -end; - -function parseParamList(var p: TParser): PNode; -var - a: PNode; -begin - result := newNodeP(nkFormalParams, p); - addSon(result, nil); // return type - if p.tok.tokType = tkParLe then begin - getTok(p); - optInd(p, result); - while true do begin - case p.tok.tokType of - tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]); - tkParRi: break; - else begin parMessage(p, errTokenExpected, ')'+''); break; end; - end; - //optInd(p, a); - addSon(result, a); - if p.tok.tokType <> tkComma then break; - getTok(p); - optInd(p, a) - end; - optSad(p); - eat(p, tkParRi); - end; - if p.tok.tokType = tkColon then begin - getTok(p); - optInd(p, result); - result.sons[0] := parseTypeDesc(p) - end -end; - -function parseTypeDescKAux(var p: TParser; kind: TNodeKind): PNode; -begin - result := newNodeP(kind, p); - getTok(p); - optInd(p, result); - addSon(result, parseTypeDesc(p)); -end; - -function parseTypeDescK(var p: TParser): PNode; -var - a: PNode; -begin - case p.tok.tokType of - tkVar: result := parseTypeDescKAux(p, nkVarTy); - tkRef: result := parseTypeDescKAux(p, nkRefTy); - tkPtr: result := parseTypeDescKAux(p, nkPtrTy); - tkType: begin - result := newNodeP(nkTypeOfExpr, p); - getTok(p); - optInd(p, result); - addSon(result, parseExpr(p)) - end; - tkProc: begin - result := newNodeP(nkProcTy, p); - getTok(p); - optInd(p, result); - addSon(result, parseParamList(p)); - if p.tok.tokType = tkCurlyDotLe then - addSon(result, parsePragma(p)) - else - addSon(result, nil); - end; - tkTuple: begin - result := newNodeP(nkTupleTy, p); - getTok(p); - eat(p, tkBracketLe); - optInd(p, result); - while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin - a := parseIdentColonEquals(p, {@set}[]); - addSon(result, a); - if p.tok.tokType <> tkComma then break; - getTok(p); - optInd(p, a) - end; - optSad(p); - eat(p, tkBracketRi); - end; - else begin - InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK'); - result := nil - end - end -end; - -function parseTypeDesc(var p: TParser): PNode; -begin - case p.tok.tokType of - tkVar, tkRef, tkPtr, tkProc, tkType, tkTuple: - result := parseTypeDescK(p); - else result := primary(p) - end -end; - function parseGenericParamList(var p: TParser): PNode; var a: PNode; @@ -1408,26 +1420,6 @@ begin indAndComment(p, result); // XXX: document this in the grammar! end; -function parseLambda(var p: TParser): PNode; -begin - result := newNodeP(nkLambda, p); - getTok(p); - optInd(p, result); - addSon(result, nil); // no name part - addSon(result, nil); // no generic parameters - addSon(result, parseParamList(p)); - if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p)) - else addSon(result, nil); - if p.tok.tokType = tkEquals then begin - getTok(p); skipComment(p, result); - addSon(result, parseStmt(p)); - end - else begin - addSon(result, nil); - parMessage(p, errTokenExpected, tokTypeToStr[tkEquals]); - end -end; - function newCommentStmt(var p: TParser): PNode; begin result := newNodeP(nkCommentStmt, p); @@ -1803,7 +1795,7 @@ begin end end; -function parseModule(var p: TParser): PNode; +function parseAll(var p: TParser): PNode; var a: PNode; begin diff --git a/nim/pragmas.pas b/nim/pragmas.pas index fc354cd2c..e8d07d52d 100755 --- a/nim/pragmas.pas +++ b/nim/pragmas.pas @@ -27,7 +27,7 @@ const procPragmas = {@set}[FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wCompilerProc, wPure, - wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge, + wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wBorrow]; converterPragmas = procPragmas; methodPragmas = procPragmas; @@ -258,11 +258,13 @@ begin if (sym = nil) or (sym.kind = skModule) then POptionEntry(c.optionStack.tail).dynlib := getLib(c, libDynamic, expectStrLit(c, n)) - else begin + else if n.kind = nkExprColonExpr then begin lib := getLib(c, libDynamic, expectStrLit(c, n)); addToLib(lib, sym); include(sym.loc.flags, lfDynamicLib) end + else + include(sym.loc.flags, lfExportLib) end; procedure processNote(c: PContext; n: PNode); @@ -475,12 +477,7 @@ begin if n = nil then exit; for i := 0 to sonsLen(n)-1 do begin it := n.sons[i]; - if it.kind = nkExprColonExpr then begin - key := it.sons[0]; - end - else begin - key := it; - end; + if it.kind = nkExprColonExpr then key := it.sons[0] else key := it; if key.kind = nkIdent then begin k := whichKeyword(key.ident); if k in validPragmas then begin @@ -540,9 +537,9 @@ begin include(sym.flags, sfUsed); // suppress all those stupid warnings registerCompilerProc(sym); end; - wCppMethod: begin - makeExternImport(sym, getOptionalStr(c, it, sym.name.s)); - include(sym.flags, sfCppMethod); + wProcvar: begin + noVal(it); + include(sym.flags, sfProcVar); end; wDeprecated: begin noVal(it); @@ -615,6 +612,8 @@ begin end; end; if (sym <> nil) and (sym.kind <> skModule) then begin + if (lfExportLib in sym.loc.flags) and not (sfExportc in sym.flags) then + liMessage(n.info, errDynlibRequiresExportc); lib := POptionEntry(c.optionstack.tail).dynlib; if ([lfDynamicLib, lfHeader] * sym.loc.flags = []) and (sfImportc in sym.flags) and diff --git a/nim/ptmplsyn.pas b/nim/ptmplsyn.pas index 2368b22c7..717da6ee0 100755 --- a/nim/ptmplsyn.pas +++ b/nim/ptmplsyn.pas @@ -1,28 +1,31 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. // unit ptmplsyn; -// This module implements the parser of the Nimrod Template files. +// This module implements Nimrod's standard template filter. {$include config.inc} interface uses - nsystem, llstream, nos, charsets, wordrecg, strutils, - ast, astalgo, msgs, options, pnimsyn; + nsystem, llstream, nos, charsets, wordrecg, idents, strutils, + ast, astalgo, msgs, options, rnimsyn, filters; -function ParseTmplFile(const filename: string): PNode; +function filterTmpl(input: PLLStream; const filename: string; + call: PNode): PLLStream; +// #! template(subsChar='$', metaChar='#') | standard(version="0.7.2") +implementation type - TParseState = (psDirective, psMultiDir, psTempl); + TParseState = (psDirective, psTempl); TTmplParser = record inp: PLLStream; state: TParseState; @@ -30,19 +33,11 @@ type indent, par: int; x: string; // the current input line outp: PLLStream; // the ouput will be parsed by pnimsyn - subsChar: Char; + subsChar, NimDirective: Char; + emit, conc, toStr: string; end; -function ParseTmpl(var p: TTmplParser): PNode; - -procedure openTmplParser(var p: TTmplParser; const filename: string; - inputStream: PLLStream); -procedure closeTmplParser(var p: TTmplParser); - -implementation - const - NimDirective = '#'; PatternChars = ['a'..'z', 'A'..'Z', '0'..'9', #128..#255, '.', '_']; procedure newLine(var p: TTmplParser); @@ -59,73 +54,45 @@ var begin j := strStart; while p.x[j] = ' ' do inc(j); - if p.state = psMultiDir then begin - newLine(p); - if p.x[j] = '*' then begin - inc(j); - if p.x[j] = NimDirective then p.state := psTempl; - // ignore the rest of the line - end - else - LLStreamWrite(p.outp, p.x); // simply add the whole line - end - else if p.x[j] = NimDirective then begin + if (p.x[strStart] = p.NimDirective) and (p.x[strStart+1] = '!') then + newLine(p) + else if (p.x[j] = p.NimDirective) then begin newLine(p); inc(j); while p.x[j] = ' ' do inc(j); d := j; - if p.x[j] = '*' then begin + keyw := ''; + while p.x[j] in PatternChars do begin + addChar(keyw, p.x[j]); inc(j); - p.state := psMultiDir; - LLStreamWrite(p.outp, repeatChar(p.indent)); - LLStreamWrite(p.outp, '#*'); - LLStreamWrite(p.outp, ncopy(p.x, j)); // simply add the whole line - end - else begin - keyw := ''; - while p.x[j] in PatternChars do begin - addChar(keyw, p.x[j]); - inc(j); - end; - case whichKeyword(keyw) of - wEnd: begin - if p.indent >= 2 then - dec(p.indent, 2) - else begin - p.info.col := int16(j); - liMessage(p.info, errXNotAllowedHere, 'end'); - end; - LLStreamWrite(p.outp, repeatChar(p.indent)); - LLStreamWrite(p.outp, '#end'); - end; - wSubsChar: begin - LLStreamWrite(p.outp, repeatChar(p.indent)); - LLStreamWrite(p.outp, '#subschar'); - while p.x[j] = ' ' do inc(j); - if p.x[j] in ['+', '-', '*', '/', '<', '>', '!', '?', '^', '.', - '|', '=', '%', '&', '$', '@', '~'] then p.subsChar := p.x[j] - else begin - p.info.col := int16(j); - liMessage(p.info, errXNotAllowedHere, p.x[j]+''); - end - end; - wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator, - wConverter, wMacro, wTemplate: begin - LLStreamWrite(p.outp, repeatChar(p.indent)); - LLStreamWrite(p.outp, ncopy(p.x, d)); - inc(p.indent, 2); - end; - wElif, wOf, wElse, wExcept, wFinally: begin - LLStreamWrite(p.outp, repeatChar(p.indent-2)); - LLStreamWrite(p.outp, ncopy(p.x, d)); - end + end; + case whichKeyword(keyw) of + wEnd: begin + if p.indent >= 2 then + dec(p.indent, 2) else begin - LLStreamWrite(p.outp, repeatChar(p.indent)); - LLStreamWrite(p.outp, ncopy(p.x, d)); - end + p.info.col := int16(j); + liMessage(p.info, errXNotAllowedHere, 'end'); + end; + LLStreamWrite(p.outp, repeatChar(p.indent)); + LLStreamWrite(p.outp, '#end'); + end; + wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator, + wConverter, wMacro, wTemplate, wMethod: begin + LLStreamWrite(p.outp, repeatChar(p.indent)); + LLStreamWrite(p.outp, ncopy(p.x, d)); + inc(p.indent, 2); end; - p.state := psDirective; - end + wElif, wOf, wElse, wExcept, wFinally: begin + LLStreamWrite(p.outp, repeatChar(p.indent-2)); + LLStreamWrite(p.outp, ncopy(p.x, d)); + end + else begin + LLStreamWrite(p.outp, repeatChar(p.indent)); + LLStreamWrite(p.outp, ncopy(p.x, d)); + end + end; + p.state := psDirective end else begin // data line @@ -133,17 +100,18 @@ begin case p.state of psTempl: begin // next line of string literal: - LLStreamWrite(p.outp, ' &'+nl); + LLStreamWrite(p.outp, p.conc); + LLStreamWrite(p.outp, nl); LLStreamWrite(p.outp, repeatChar(p.indent + 2)); LLStreamWrite(p.outp, '"'+''); end; psDirective: begin newLine(p); LLStreamWrite(p.outp, repeatChar(p.indent)); - LLStreamWrite(p.outp, 'add(result, "'); + LLStreamWrite(p.outp, p.emit); + LLStreamWrite(p.outp, '("'); inc(p.par); - end; - else InternalError(p.info, 'parser in invalid state'); + end end; p.state := psTempl; while true do begin @@ -162,7 +130,10 @@ begin case p.x[j] of '{': begin p.info.col := int16(j); - LLStreamWrite(p.outp, '" & $('); + LLStreamWrite(p.outp, '"'); + LLStreamWrite(p.outp, p.conc); + LLStreamWrite(p.outp, p.toStr); + LLStreamWrite(p.outp, '('); inc(j); curly := 0; while true do begin @@ -171,13 +142,13 @@ begin '{': begin inc(j); inc(curly); - LLStreamWrite(p.outp, '{'+''); + LLStreamWrite(p.outp, '{'); end; '}': begin inc(j); if curly = 0 then break; if curly > 0 then dec(curly); - LLStreamWrite(p.outp, '}'+''); + LLStreamWrite(p.outp, '}'); end; else begin LLStreamWrite(p.outp, p.x[j]); @@ -185,15 +156,22 @@ begin end end end; - LLStreamWrite(p.outp, ') & "') + LLStreamWrite(p.outp, ')'); + LLStreamWrite(p.outp, p.conc); + LLStreamWrite(p.outp, '"'); end; - 'A'..'Z', 'a'..'z', '_': begin - LLStreamWrite(p.outp, '" & $'); + 'a'..'z', 'A'..'Z', #128..#255: begin + LLStreamWrite(p.outp, '"'); + LLStreamWrite(p.outp, p.conc); + LLStreamWrite(p.outp, p.toStr); + LLStreamWrite(p.outp, '('); while p.x[j] in PatternChars do begin LLStreamWrite(p.outp, p.x[j]); inc(j) end; - LLStreamWrite(p.outp, ' & "') + LLStreamWrite(p.outp, ')'); + LLStreamWrite(p.outp, p.conc); + LLStreamWrite(p.outp, '"') end; else if p.x[j] = p.subsChar then begin LLStreamWrite(p.outp, p.subsChar); @@ -203,7 +181,7 @@ begin p.info.col := int16(j); liMessage(p.info, errInvalidExpression, '$'+''); end - end; + end end else begin LLStreamWrite(p.outp, p.x[j]); @@ -215,56 +193,30 @@ begin end end; -function ParseTmpl(var p: TTmplParser): PNode; +function filterTmpl(input: PLLStream; const filename: string; + call: PNode): PLLStream; var - q: TParser; + p: TTmplParser; begin +{@ignore} + FillChar(p, sizeof(p), 0); +{@emit} + p.info := newLineInfo(filename, 0, 0); + p.outp := LLStreamOpen(''); + p.inp := input; + p.subsChar := charArg(call, 'subschar', 1, '$'); + p.nimDirective := charArg(call, 'metachar', 2, '#'); + p.emit := strArg(call, 'emit', 3, 'result.add'); + p.conc := strArg(call, 'conc', 4, ' & '); + p.toStr := strArg(call, 'tostring', 5, '$'+''); while not LLStreamAtEnd(p.inp) do begin p.x := LLStreamReadLine(p.inp) {@ignore} + #0 {@emit}; p.info.line := p.info.line + int16(1); parseLine(p); end; newLine(p); - if gVerbosity >= 2 then begin - rawMessage(hintCodeBegin); - messageOut(p.outp.s); - rawMessage(hintCodeEnd); - end; - openParser(q, toFilename(p.info), p.outp); - result := ParseModule(q); - closeParser(q); -end; - -procedure openTmplParser(var p: TTmplParser; const filename: string; - inputStream: PLLStream); -begin -{@ignore} - FillChar(p, sizeof(p), 0); -{@emit} - p.info := newLineInfo(filename, 0, 0); - p.outp := LLStreamOpen(''); - p.inp := inputStream; - p.subsChar := '$'; -end; - -procedure CloseTmplParser(var p: TTmplParser); -begin + result := p.outp; LLStreamClose(p.inp); end; -function ParseTmplFile(const filename: string): PNode; -var - p: TTmplParser; - f: TBinaryFile; -begin - if not OpenFile(f, filename) then begin - rawMessage(errCannotOpenFile, filename); - result := nil; - exit - end; - OpenTmplParser(p, filename, LLStreamOpen(f)); - result := ParseTmpl(p); - CloseTmplParser(p); -end; - end. diff --git a/nim/rnimsyn.pas b/nim/rnimsyn.pas index 1ad1c9408..ec1e9571e 100755 --- a/nim/rnimsyn.pas +++ b/nim/rnimsyn.pas @@ -498,7 +498,7 @@ begin nkPar, nkCurly, nkBracket: result := lcomma(n)+2; nkSymChoice: result := lsons(n) + length('()') + sonsLen(n)-1; nkTupleTy: result := lcomma(n)+length('tuple[]'); - nkQualified, nkDotExpr: result := lsons(n)+1; + nkDotExpr: result := lsons(n)+1; nkBind: result := lsons(n)+length('bind_'); nkCheckedFieldExpr: result := lsub(n.sons[0]); nkLambda: result := lsons(n)+length('lambda__=_'); @@ -1047,7 +1047,7 @@ begin gcomma(g, n, c); put(g, tkBracketRi, ']'+''); end; - nkQualified, nkDotExpr: begin + nkDotExpr: begin gsub(g, n.sons[0]); put(g, tkDot, '.'+''); gsub(g, n.sons[1]); diff --git a/nim/rodread.pas b/nim/rodread.pas index dc3630a45..457ad6cc2 100755 --- a/nim/rodread.pas +++ b/nim/rodread.pas @@ -1057,8 +1057,7 @@ begin // 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, - appendFileExt('system', nimExt))); + 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]); diff --git a/nim/rst.pas b/nim/rst.pas index d5cde5c7e..fb29b7d9f 100755 --- a/nim/rst.pas +++ b/nim/rst.pas @@ -314,6 +314,9 @@ begin len := length(tokens); L.buf := PChar(buffer); L.line := 1; + // skip UTF-8 BOM + if (L.buf[0] = #239) and (L.buf[1] = #187) and (L.buf[2] = #191) then + inc(L.bufpos, 3); L.skipPounds := skipPounds; if skipPounds then begin if L.buf[L.bufpos] = '#' then inc(L.bufpos); diff --git a/nim/scanner.pas b/nim/scanner.pas index 05f903622..c03ae9224 100755 --- a/nim/scanner.pas +++ b/nim/scanner.pas @@ -143,19 +143,16 @@ type // or float literals literal: string; // the parsed (string) literal; and // documentation comments are here too - next: PToken; // next token; used for arbitrary look-ahead + next: PToken; // next token; can be used for arbitrary look-ahead end; PLexer = ^TLexer; TLexer = object(TBaseLexer) - // lexers can be put into a stack through the next pointer; - // this feature is currently unused, however filename: string; - next: PLexer; indentStack: array of int; // the indentation stack dedent: int; // counter for DED token generation indentAhead: int; // if > 0 an indendation has already been read - // this is needed because scanning # comments + // this is needed because scanning comments // needs so much look-ahead end; @@ -920,7 +917,6 @@ begin // got an documentation comment or tkIndent, return that: if tok.toktype <> tkInvalid then exit; - // to the parser c := L.buf[L.bufpos]; if c in SymStartChars - ['r', 'R', 'l'] then // common case first getSymbol(L, tok) diff --git a/nim/semexprs.pas b/nim/semexprs.pas index 43eb9ac6f..91c909dfd 100755 --- a/nim/semexprs.pas +++ b/nim/semexprs.pas @@ -374,15 +374,34 @@ begin end end; -function isAssignable(n: PNode): bool; +type + TAssignableResult = ( + arNone, // no l-value and no discriminant + arLValue, // is an l-value + arDiscriminant // is a discriminant + ); + +function isAssignable(n: PNode): TAssignableResult; begin - result := false; + result := arNone; case n.kind of - nkSym: result := (n.sym.kind in [skVar, skTemp]); - nkDotExpr, nkQualified, nkBracketExpr: begin + nkSym: begin + if (n.sym.kind in [skVar, skTemp]) then + result := arLValue + end; + nkDotExpr: begin + checkMinSonsLen(n, 1); + if skipTypes(n.sons[0].typ, abstractInst).kind in [tyVar, tyPtr, tyRef] then + result := arLValue + else + result := isAssignable(n.sons[0]); + if (result = arLValue) and (sfDiscriminant in n.sons[1].sym.flags) then + result := arDiscriminant + end; + nkBracketExpr: begin checkMinSonsLen(n, 1); if skipTypes(n.sons[0].typ, abstractInst).kind in [tyVar, tyPtr, tyRef] then - result := true + result := arLValue else result := isAssignable(n.sons[0]); end; @@ -393,7 +412,7 @@ begin if skipTypes(n.typ, abstractPtrs).kind in [tyOpenArray, tyTuple, tyObject] then result := isAssignable(n.sons[1]) end; - nkHiddenDeref, nkDerefExpr: result := true; + nkHiddenDeref, nkDerefExpr: result := arLValue; nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: result := isAssignable(n.sons[0]); else begin end @@ -409,7 +428,7 @@ begin else begin result := newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)); addSon(result, n); - if not isAssignable(n) then begin + if isAssignable(n) <> arLValue then begin liMessage(n.info, errVarForOutParamNeeded); end end @@ -425,7 +444,7 @@ begin result := newHiddenAddrTaken(c, n); end end; - nkDotExpr, nkQualified: begin + nkDotExpr: begin checkSonsLen(n, 2); if n.sons[1].kind <> nkSym then internalError(n.info, 'analyseIfAddressTaken'); @@ -499,7 +518,7 @@ begin prc := n.sons[0]; checkMinSonsLen(n, 1); case n.sons[0].kind of - nkDotExpr, nkQualified: begin + nkDotExpr: begin checkSonsLen(n.sons[0], 2); n.sons[0] := semDotExpr(c, n.sons[0]); if n.sons[0].kind = nkDotCall then begin // it is a static call! @@ -595,7 +614,7 @@ begin else result := SymtabGet(c.Tab, n.ident); // no need for stub loading end; - nkDotExpr, nkQualified: begin + nkDotExpr: begin result := nil; if onlyCurrentScope then exit; checkSonsLen(n, 2); @@ -1174,8 +1193,14 @@ begin liMessage(n.info, errATypeHasNoValue); case s.kind of skProc, skMethod, skIterator, skConverter: begin - if (s.magic <> mNone) then - liMessage(n.info, errInvalidContextForBuiltinX, s.name.s); + if not (sfProcVar in s.flags) + and (s.typ.callConv = ccDefault) + and (getModule(s).id <> c.module.id) then + liMessage(n.info, warnXisPassedToProcVar, s.name.s); + // XXX change this to errXCannotBePassedToProcVar after version 0.8.2 + // TODO VERSION 0.8.4 + //if (s.magic <> mNone) then + // liMessage(n.info, errInvalidContextForBuiltinX, s.name.s); result := symChoice(c, n, s); end; skConst: begin @@ -1253,10 +1278,7 @@ begin (*s := n.sym; include(s.flags, sfUsed); if (s.kind = skType) and not (efAllowType in flags) then - liMessage(n.info, errATypeHasNoValue); - if (s.magic <> mNone) and - (s.kind in [skProc, skMethod, skIterator, skConverter]) then - liMessage(n.info, errInvalidContextForBuiltinX, s.name.s); *) + liMessage(n.info, errATypeHasNoValue);*) // because of the changed symbol binding, this does not mean that we // don't have to check the symbol for semantics here again! result := semSym(c, n, n.sym, flags); @@ -1279,7 +1301,7 @@ begin if result.typ = nil then result.typ := getSysType(tyString); nkCharLit: if result.typ = nil then result.typ := getSysType(tyChar); - nkQualified, nkDotExpr: begin + nkDotExpr: begin result := semDotExpr(c, n, flags); if result.kind = nkDotCall then begin result.kind := nkCall; @@ -1364,7 +1386,8 @@ begin result := n; checkSonsLen(n, 1); n.sons[0] := semExprWithType(c, n.sons[0]); - if not isAssignable(n.sons[0]) then liMessage(n.info, errExprHasNoAddress); + if isAssignable(n.sons[0]) <> arLValue then + liMessage(n.info, errExprHasNoAddress); n.typ := makePtrType(c, n.sons[0].typ); end; nkHiddenAddr, nkHiddenDeref: begin diff --git a/nim/semstmts.pas b/nim/semstmts.pas index b4b72a25b..1ece72023 100755 --- a/nim/semstmts.pas +++ b/nim/semstmts.pas @@ -127,7 +127,7 @@ var str, sub: string; a, b, c: int; e: PSym; - marker: Char; + marker: char; begin result := n; checkSonsLen(n, 2); @@ -243,7 +243,7 @@ begin checkSonsLen(n, 2); a := n.sons[0]; case a.kind of - nkDotExpr, nkQualified: begin + nkDotExpr: begin // r.f = x // --> `f=` (r, x) checkSonsLen(a, 2); @@ -298,7 +298,8 @@ begin n.sons[1] := semExprWithType(c, n.sons[1]); le := n.sons[0].typ; if (skipTypes(le, {@set}[tyGenericInst]).kind <> tyVar) - and not IsAssignable(n.sons[0]) then begin + and (IsAssignable(n.sons[0]) = arNone) then begin + // Direct assignment to a discriminant is allowed! liMessage(n.sons[0].info, errXCannotBeAssignedTo, renderTree(n.sons[0], {@set}[renderNoComments])); end @@ -1014,8 +1015,7 @@ end; function evalInclude(c: PContext; n: PNode): PNode; var i, fileIndex: int; - x: PNode; - f, name, ext: string; + f: string; begin result := newNodeI(nkStmtList, n.info); addSon(result, n); // the rodwriter needs include information! @@ -1024,13 +1024,7 @@ begin fileIndex := includeFilename(f); if IntSetContainsOrIncl(c.includedFiles, fileIndex) then liMessage(n.info, errRecursiveDependencyX, f); - SplitFilename(f, name, ext); - if cmpIgnoreCase(ext, '.'+TmplExt) = 0 then - x := gIncludeTmplFile(f) - else - x := gIncludeFile(f); - x := semStmt(c, x); - addSon(result, x); + addSon(result, semStmt(c, gIncludeFile(f))); IntSetExcl(c.includedFiles, fileIndex); end; end; diff --git a/nim/semtempl.pas b/nim/semtempl.pas index 8e37a1ea3..e639960d3 100755 --- a/nim/semtempl.pas +++ b/nim/semtempl.pas @@ -34,7 +34,7 @@ begin if n = nil then begin result := false; exit end; case n.kind of nkIdent, nkSym, nkType: result := true; - nkDotExpr, nkQualified, nkBracketExpr: begin + nkDotExpr, nkBracketExpr: begin for i := 0 to sonsLen(n)-1 do if not isTypeDesc(n.sons[i]) then begin result := false; exit diff --git a/nim/semtypes.pas b/nim/semtypes.pas index c0b86be86..e2a0d2185 100755 --- a/nim/semtypes.pas +++ b/nim/semtypes.pas @@ -758,6 +758,10 @@ begin nkTypeOfExpr: begin result := semExprWithType(c, n, {@set}[efAllowType]).typ; end; + nkPar: begin + if sonsLen(n) = 1 then result := semTypeNode(c, n.sons[0], prev) + else liMessage(n.info, errTypeExpected); + end; nkBracketExpr: begin checkMinSonsLen(n, 2); s := semTypeIdent(c, n.sons[0]); @@ -771,7 +775,7 @@ begin else result := semGeneric(c, n, s, prev); end end; - nkIdent, nkDotExpr, nkQualified, nkAccQuoted: begin + nkIdent, nkDotExpr, nkAccQuoted: begin s := semTypeIdent(c, n); if s.typ = nil then liMessage(n.info, errTypeExpected); diff --git a/nim/strutils.pas b/nim/strutils.pas index be20b52b2..afd8b4766 100755 --- a/nim/strutils.pas +++ b/nim/strutils.pas @@ -50,7 +50,7 @@ function ToString(b: PChar): string; overload; function IntToStr(i: BiggestInt; minChars: int): string; function find(const s, sub: string; start: int = 1): int; overload; -function replaceStr(const s, search, by: string): string; +function replace(const s, search, by: string): string; procedure deleteStr(var s: string; first, last: int); function ToLower(const s: string): string; @@ -63,9 +63,6 @@ function ParseFloat(const s: string; checkEnd: Boolean = True): Real; function repeatChar(count: int; c: Char = ' '): string; -type - TStringSeq = array of string; - TCharSet = set of Char; function split(const s: string; const seps: TCharSet): TStringSeq; function startsWith(const s, prefix: string): bool; @@ -278,7 +275,7 @@ begin end end; -function replaceStr(const s, search, by: string): string; +function replace(const s, search, by: string): string; var i, j: int; begin diff --git a/nim/syntaxes.pas b/nim/syntaxes.pas index 1068064ce..19035028e 100755 --- a/nim/syntaxes.pas +++ b/nim/syntaxes.pas @@ -1,64 +1,234 @@ // // // The Nimrod Compiler -// (c) Copyright 2008 Andreas Rumpf +// (c) Copyright 2009 Andreas Rumpf // // See the file "copying.txt", included in this // distribution, for details about the copyright. // unit syntaxes; -// Defines the common interface of all parsers & renderers. -// All parsers and renderers need to register here! -// This file is currently unused. +// Implements the dispatcher for the different parsers. {$include 'config.inc'} interface uses - nsystem, strutils, ast, scanner, pnimsyn, rnimsyn, options, msgs, - nos, lists, condsyms, paslex, pasparse, rodgen, ropes, trees; - -// how to handle the different keyword sets? -// PIdent does not support multiple ids! But I want to allow -// constant expressions, else the case-statement wouldn't work -// resulting in ugly code -> let the build system deal with it! -// IDEA: the scanner changes the IDs for its keywords: Won't work! -// How to deal with the `` operator? + nsystem, strutils, llstream, ast, astalgo, idents, scanner, options, msgs, + pnimsyn, ptmplsyn, filters, rnimsyn; type - TSyntaxes = (synStandard, synCurly, synLisp); + TFilterKind = (filtNone, filtTemplate, filtReplace, filtStrip); + TParserKind = (skinStandard, skinBraces, skinEndX); + +const + parserNames: array [TParserKind] of string = ('standard', 'braces', 'endx'); + filterNames: array [TFilterKind] of string = ('none', 'stdtmpl', 'replace', + 'strip'); + +type + TParsers = record + skin: TParserKind; + parser: TParser; + end; + +{@ignore} +function ParseFile(const filename: string): PNode; +{@emit +function ParseFile(const filename: string): PNode; procvar; +} + +procedure openParsers(var p: TParsers; const filename: string; + inputstream: PLLStream); +procedure closeParsers(var p: TParsers); +function parseAll(var p: TParsers): PNode; + +function parseTopLevelStmt(var p: TParsers): PNode; +// implements an iterator. Returns the next top-level statement or nil if end +// of stream. -function parseFile(const filename: string): PNode; implementation -type - TFileParser = function (const filename: string): PNode; - TBufferParser = function (const buf, filename: string; - line, column: int): PNode; - TRenderer = function (n: PNode): string; - THeadParser = function (const line: string): bool; - TSyntax = record - name: string; // name of the syntax - headParser: THeadParser; // the head parser - parser: TParser; // the parser for the syntax - renderer: TRenderer; // renderer of the syntax; may be nil +function ParseFile(const filename: string): PNode; +var + p: TParsers; + f: TBinaryFile; +begin + if not OpenFile(f, filename) then begin + rawMessage(errCannotOpenFile, filename); + exit end; + OpenParsers(p, filename, LLStreamOpen(f)); + result := ParseAll(p); + CloseParsers(p); +end; +function parseAll(var p: TParsers): PNode; +begin + case p.skin of + skinStandard: result := pnimsyn.parseAll(p.parser); + skinBraces, skinEndX: InternalError('parser to implement'); + // skinBraces: result := pbraces.parseAll(p.parser); + // skinEndX: result := pendx.parseAll(p.parser); + end +end; + +function parseTopLevelStmt(var p: TParsers): PNode; +begin + case p.skin of + skinStandard: result := pnimsyn.parseTopLevelStmt(p.parser); + skinBraces, skinEndX: InternalError('parser to implement'); + //skinBraces: result := pbraces.parseTopLevelStmt(p.parser); + //skinEndX: result := pendx.parseTopLevelStmt(p.parser); + end +end; + +function UTF8_BOM(const s: string): int; +begin + if (s[strStart] = #239) and (s[strStart+1] = #187) + and (s[strStart+2] = #191) then result := 3 + else result := 0 +end; + +function containsShebang(const s: string; i: int): bool; var - syntaxes: array [TSyntaxes] of TSyntax; + j: int; +begin + result := false; + if (s[i] = '#') and (s[i+1] = '!') then begin + j := i+2; + while s[j] in WhiteSpace do inc(j); + result := s[j] = '/' + end +end; -procedure addSyntax(const s: TSyntax); +function parsePipe(const filename: string; inputStream: PLLStream): PNode; var - len: int; + line: string; + s: PLLStream; + i: int; + q: TParser; begin - len := length(syntaxes); - setLength(syntaxes, len+1); - syntaxes[len] := s; + result := nil; + s := LLStreamOpen(filename, fmRead); + if s <> nil then begin + line := LLStreamReadLine(s) {@ignore} + #0 {@emit}; + i := UTF8_Bom(line) + strStart; + if containsShebang(line, i) then begin + line := LLStreamReadLine(s) {@ignore} + #0 {@emit}; + i := strStart; + end; + if (line[i] = '#') and (line[i+1] = '!') then begin + inc(i, 2); + while line[i] in WhiteSpace do inc(i); + OpenParser(q, filename, LLStreamOpen(ncopy(line, i))); + result := pnimsyn.parseAll(q); + CloseParser(q); + end; + LLStreamClose(s); + end +end; + +function getFilter(ident: PIdent): TFilterKind; +var + i: TFilterKind; +begin + for i := low(TFilterKind) to high(TFilterKind) do + if IdentEq(ident, filterNames[i]) then begin + result := i; exit + end; + result := filtNone +end; + +function getParser(ident: PIdent): TParserKind; +var + i: TParserKind; +begin + for i := low(TParserKind) to high(TParserKind) do + if IdentEq(ident, parserNames[i]) then begin + result := i; exit + end; + rawMessage(errInvalidDirectiveX, ident.s); +end; + +function getCallee(n: PNode): PIdent; +begin + if (n.kind = nkCall) and (n.sons[0].kind = nkIdent) then + result := n.sons[0].ident + else if n.kind = nkIdent then result := n.ident + else rawMessage(errXNotAllowedHere, renderTree(n)); +end; + +function applyFilter(var p: TParsers; n: PNode; const filename: string; + input: PLLStream): PLLStream; +var + ident: PIdent; + f: TFilterKind; +begin + ident := getCallee(n); + f := getFilter(ident); + case f of + filtNone: begin + p.skin := getParser(ident); + result := input + end; + filtTemplate: result := filterTmpl(input, filename, n); + filtStrip: result := filterStrip(input, filename, n); + filtReplace: result := filterReplace(input, filename, n); + end; + if f <> filtNone then begin + if gVerbosity >= 2 then begin + rawMessage(hintCodeBegin); + messageOut(result.s); + rawMessage(hintCodeEnd); + end + end +end; + +function evalPipe(var p: TParsers; n: PNode; const filename: string; + start: PLLStream): PLLStream; +var + i: int; +begin + result := start; + if n = nil then exit; + if (n.kind = nkInfix) and (n.sons[0].kind = nkIdent) + and IdentEq(n.sons[0].ident, '|'+'') then begin + for i := 1 to 2 do begin + if n.sons[i].kind = nkInfix then + result := evalPipe(p, n.sons[i], filename, result) + else + result := applyFilter(p, n.sons[i], filename, result) + end + end + else if n.kind = nkStmtList then + result := evalPipe(p, n.sons[0], filename, result) + else + result := applyFilter(p, n, filename, result) +end; + +procedure openParsers(var p: TParsers; const filename: string; + inputstream: PLLStream); +var + pipe: PNode; + s: PLLStream; +begin + p.skin := skinStandard; + pipe := parsePipe(filename, inputStream); + if pipe <> nil then + s := evalPipe(p, pipe, filename, inputStream) + else + s := inputStream; + case p.skin of + skinStandard, skinBraces, skinEndX: + pnimsyn.openParser(p.parser, filename, s); + end +end; + +procedure closeParsers(var p: TParsers); +begin + pnimsyn.closeParser(p.parser); end; -initialization - syntaxes[synStandard].name = 'Standard'; - end. diff --git a/nim/transf.pas b/nim/transf.pas index d5b0bb6f8..192d76a84 100755 --- a/nim/transf.pas +++ b/nim/transf.pas @@ -652,7 +652,7 @@ end; f: proc (x: int, c: PClosure): int proc map(f: PClosure, a: seq[int]): seq[int] = - result = [] + result = @[] for elem in a: add result, f.f(a, f) @@ -737,6 +737,7 @@ end; function transformCase(c: PTransf; n: PNode): PNode; // removes `elif` branches of a case stmt +// adds ``else: nil`` if needed for the code generator var len, i, j: int; ifs, elsen: PNode; @@ -754,6 +755,14 @@ begin setLength(n.sons, i+2); addSon(elsen, ifs); n.sons[i+1] := elsen; + end + else if (n.sons[len-1].kind <> nkElse) and + not (skipTypes(n.sons[0].Typ, abstractVarRange).Kind in + [tyInt..tyInt64, tyChar, tyEnum]) then begin + //MessageOut(renderTree(n)); + elsen := newNodeI(nkElse, n.info); + addSon(elsen, newNodeI(nkNilLit, n.info)); + addSon(n, elsen) end; result := n; for j := 0 to sonsLen(n)-1 do result.sons[j] := transform(c, n.sons[j]); diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas index 9bf3de256..c18969877 100755 --- a/nim/wordrecg.pas +++ b/nim/wordrecg.pas @@ -63,9 +63,9 @@ type wMagic, wTypeCheck, wFinal, wProfiler, wObjChecks, wImportc, wExportc, wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader, wNosideeffect, wNoreturn, - wMerge, wLib, wDynlib, wCompilerproc, wCppmethod, wFatal, + wMerge, wLib, wDynlib, wCompilerproc, wProcVar, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, - wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wPragma, + wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wParallelBuild, wLink, wCompile, wLinksys, wDeprecated, wVarargs, wByref, wCallconv, wBreakpoint, wDebugger, wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, wFastcall, wClosure, @@ -136,9 +136,9 @@ const 'magic', 'typecheck', 'final', 'profiler', 'objchecks', 'importc', 'exportc', 'align', 'nodecl', 'pure', 'volatile', 'register', 'sideeffect', 'header', 'nosideeffect', 'noreturn', - 'merge', 'lib', 'dynlib', 'compilerproc', 'cppmethod', 'fatal', + 'merge', 'lib', 'dynlib', 'compilerproc', 'procvar', 'fatal', 'error', 'warning', 'hint', 'line', 'push', 'pop', - 'define', 'undef', 'linedir', 'stacktrace', 'linetrace', 'pragma', + 'define', 'undef', 'linedir', 'stacktrace', 'linetrace', 'parallelbuild', 'link', 'compile', 'linksys', 'deprecated', 'varargs', 'byref', 'callconv', 'breakpoint', 'debugger', 'nimcall', 'stdcall', 'cdecl', 'safecall', 'syscall', 'inline', 'noinline', 'fastcall', 'closure', |