bugfixes: macros; splitFile; strutils.split; iterator.method

This commit is contained in:
rumpf_a@web.de
2009-10-27 22:28:02 +01:00
parent 053309e60a
commit d5acb88ccc
31 changed files with 177 additions and 95 deletions

View File

@@ -247,6 +247,7 @@
'StrToIdent',
'IdentToStr',
'EqIdent',
'EqNimrodNode',
'NHint',
'NWarning',
'NError'

View File

@@ -201,7 +201,7 @@
{'errXNeedsReturnType': '$1 needs a return type'},
{'errInvalidCommandX': "invalid command: '$1'"},
{'errXOnlyAtModuleScope': "'$1' is only allowed at top level"},
{'errTemplateInstantiationTooNested': 'template instantiation too nested'},
{'errTemplateInstantiationTooNested': 'template/macro instantiation too nested'},
{'errInstantiationFrom': 'instantiation from here'},
{'errInvalidIndexValueForTuple': 'invalid index value for tuple subscript'},
{'errCommandExpectsFilename': 'command expects a filename argument'},

View File

@@ -8,7 +8,7 @@
.. contents::
Abstraction is layering ignorance on top of reality. -- unknown
"Abstraction is layering ignorance on top of reality." -- unknown
Directory structure

View File

@@ -7,7 +7,7 @@ Nimrod Standard Library
..
The good thing about reinventing the wheel is that you can get a round one.
"The good thing about reinventing the wheel is that you can get a round one."
Though the Nimrod Standard Library is still evolving, it is already quite
usable. It is divided into *pure libraries*, *impure libraries* and *wrappers*.

View File

@@ -760,7 +760,7 @@ An example:
nkIf # an if statement
PNode = ref TNode
TNode = object
case kind: TNodeKind # the ``kind`` field is the discriminator
case kind: TNodeKind # the ``kind`` field is the discriminant
of nkInt: intVal: int
of nkFloat: floavVal: float
of nkString: strVal: string
@@ -1648,7 +1648,7 @@ required. ``Elif`` parts are also allowed (but unlikely to be good
style).
Type convertions
Type conversions
~~~~~~~~~~~~~~~~
Syntactically a `type conversion` is like a procedure call, but a
type name replaces the procedure name. A type conversion is always

View File

@@ -6,7 +6,7 @@
:Version: |nimrodversion|
.. contents::
Introduction
============

View File

@@ -871,7 +871,7 @@ type:
var
x = 0.0 # x is of type ``float``
y = 0.0'f32 # y is of type ``float32``
z = 0.0'f64 # z is of type ``int64``
z = 0.0'f64 # z is of type ``float64``
The common operators ``+ - * / < <= == != > >=`` are defined for
floats and follow the IEEE standard.
@@ -1318,7 +1318,7 @@ This is best illustrated by an example:
main()
.. code-block:: nimrod
# Module B
import A # A is not parsed here! Only the already known symbols
# of A are imported.
@@ -1338,9 +1338,11 @@ imported by a third one:
# Module A
var x*: string
.. code-block:: nimrod
# Module B
var x*: int
.. code-block:: nimrod
# Module C
import A, B
write(stdout, x) # error: x is ambiguous
@@ -1357,9 +1359,11 @@ rules apply:
# Module A
proc x*(a: int): string = return $a
.. code-block:: nimrod
# Module B
proc x*(a: string): string = return $a
.. code-block:: nimrod
# Module C
import A, B
write(stdout, x(3)) # no error: A.x is called

13
koch.py
View File

@@ -12,7 +12,7 @@ from pycompab import *
# --------------------- constants ----------------------------------------
NIMROD_VERSION = '0.8.2'
NIMROD_VERSION = '0.8.3'
# This string contains Nimrod's version. It is the only place
# where the version needs to be updated. The rest is done by
# the build process automatically. It is replaced **everywhere**!
@@ -362,7 +362,7 @@ def cmd_rod(options):
if Exists(ExeExt("bin/nimrod")):
c.success()
# ------------------- constants -----------------------------------------------
# -----------------------------------------------------------------------------
HELP = Subs("""\
+-----------------------------------------------------------------+
@@ -426,6 +426,7 @@ def main(args):
elif cmd == "inno": cmd_inno()
elif cmd == "csource": cmd_csource(join(args[i+1:]))
elif cmd == "install": cmd_install() # for backwards compability
#elif cmd == "llvmdebug": cmd_llvm(debug=true)
else: Error("illegal command: " + cmd)
def cmd_csource(args):
@@ -443,6 +444,14 @@ def cmd_inno():
def cmd_install():
Exec("sh ./build.sh")
def cmd_llvm(debug=true):
if not debug: release = "--enable-optimized"
else: release = ""
Exec(Subs("./configure --enable-bindings $1 --enable-shared" +
" --enable-targets=host", release))
Exec("make")
Echo("Type [sudo] make install!")
# -------------------------- bootstrap ----------------------------------------

View File

@@ -122,8 +122,11 @@ proc `!` *(s: string): TNimrodIdent {.magic: "StrToIdent".}
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
## converts a Nimrod identifier to a string
proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent".}
proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
## compares two Nimrod identifiers
proc `==`* (a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
## compares two Nimrod nodes
proc len*(n: PNimrodNode): int {.magic: "NLen".}
## returns the number of children of `n`.

View File

@@ -10,7 +10,6 @@
## This module contains basic operating system facilities like
## retrieving environment variables, reading command line arguments,
## working with directories, running shell commands, etc.
## This module is -- like any other basic library -- platform independant.
{.deadCodeElim: on.}
{.push debugger: off.}
@@ -384,10 +383,13 @@ proc SplitPath*(path: string): tuple[head, tail: string] {.noSideEffect.} =
## Splits a directory into (head, tail), so that
## ``JoinPath(head, tail) == path``.
##
## Example: After ``SplitPath("usr/local/bin", head, tail)``,
## `head` is "usr/local" and `tail` is "bin".
## Example: After ``SplitPath("usr/local/bin/", head, tail)``,
## `head` is "usr/local/bin" and `tail` is "".
## Examples:
## .. code-block:: nimrod
## SplitPath("usr/local/bin") -> ("usr/local", "bin")
## SplitPath("usr/local/bin/") -> ("usr/local/bin", "")
## SplitPath("bin") -> ("", "bin")
## SplitPath("/bin") -> ("", "bin")
## SplitPath("") -> ("", "")
var
sepPos = -1
for i in countdown(len(path)-1, 0):
@@ -431,8 +433,9 @@ proc normExt(ext: string): string =
else: result = extSep & ext
proc searchExtPos(s: string): int =
# BUGFIX: do not search until 0! .DS_Store is no file extension!
result = -1
for i in countdown(len(s)-1, 0):
for i in countdown(len(s)-1, 1):
if s[i] == extsep:
result = i
break
@@ -447,10 +450,11 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {.noSideEffect.} =
## Example:
##
## .. code-block:: nimrod
## var (dir, name, ext) = splitFile("usr/local/nimrodc.html")
## assert dir == "usr/local"
## assert name == "nimrodc"
## assert ext == ".html"
## var (dir, name, ext) = splitFile("usr/local/nimrodc.html")
## assert dir == "usr/local"
## assert name == "nimrodc"
## assert ext == ".html"
##
## If `path` has no extension, `ext` is the empty string.
## If `path` has no directory component, `dir` is the empty string.
## If `path` has no filename component, `name` and `ext` are empty strings.
@@ -461,7 +465,7 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {.noSideEffect.} =
var dotPos = path.len
for i in countdown(len(path)-1, 0):
if path[i] == ExtSep:
if dotPos == path.len: dotPos = i
if dotPos == path.len and i > 0: dotPos = i
elif path[i] in {dirsep, altsep}:
sepPos = i
break
@@ -877,9 +881,9 @@ iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string =
## filter meaning
## --------------------- ---------------------------------------------
## ``pcFile`` yield real files
## ``pcLinkToFile`` yield symbol links to files
## ``pcLinkToFile`` yield symbolic links to files
## ``pcDir`` follow real directories
## ``pcLinkToDir`` follow symbol links to directories
## ``pcLinkToDir`` follow symbolic links to directories
## --------------------- ---------------------------------------------
##
var stack = @[dir]

View File

@@ -169,15 +169,14 @@ iterator split*(s: string, seps: set[char] = Whitespace): string =
## writeln(stdout, word)
##
## produces the same output.
var
first: int = 0
last: int = 0
var last = 0
assert(not ('\0' in seps))
while last < len(s):
while s[last] in seps: inc(last)
first = last
var first = last
while last < len(s) and s[last] not_in seps: inc(last) # BUGFIX!
yield copy(s, first, last-1)
if first <= last-1:
yield copy(s, first, last-1)
iterator split*(s: string, sep: char): string =
## Splits the string `s` into substrings.

View File

@@ -262,7 +262,8 @@ type
mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, mNSymbol,
mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol,
mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree,
mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning, mNError
mStrToIdent, mIdentToStr, mEqIdent, mEqNimrodNode, mNHint, mNWarning,
mNError
//[[[end]]]
);
@@ -521,7 +522,8 @@ const // "MagicToStr" array:
'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal', 'NSymbol',
'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol',
'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree',
'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning', 'NError'
'StrToIdent', 'IdentToStr', 'EqIdent', 'EqNimrodNode', 'NHint', 'NWarning',
'NError'
//[[[end]]]
);

View File

@@ -43,7 +43,7 @@ type
cfsProcs, // section for C procs that are not inline
cfsTypeInit1, // section 1 for declarations of type information
cfsTypeInit2, // section 2 for initialization of type information
cfsTypeInit3, // section 3 for init of type information
cfsTypeInit3, // section 3 for initialization of type information
cfsDebugInit, // section for initialization of debug information
cfsDynLibInit, // section for initialization of dynamic library binding
cfsDynLibDeinit // section for deinitialization of dynamic libraries

View File

@@ -309,11 +309,11 @@ end;
procedure processCompile(const filename: string);
var
found, trunc, ext: string;
found, trunc: string;
begin
found := findFile(filename);
if found = '' then found := filename;
splitFilename(found, trunc, ext);
trunc := changeFileExt(found, '');
extccomp.addExternalFileToCompile(trunc);
extccomp.addFileToLink(completeCFilePath(trunc, false));
end;

View File

@@ -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.
@@ -51,12 +51,12 @@ begin
case n.kind of
nkImportStmt: begin
for i := 0 to sonsLen(n)-1 do begin
imported := extractFileTrunk(getModuleFile(n.sons[i]));
imported := splitFile(getModuleFile(n.sons[i])).name;
addDependencyAux(g.module.name.s, imported);
end
end;
nkFromStmt: begin
imported := extractFileTrunk(getModuleFile(n.sons[0]));
imported := splitFile(getModuleFile(n.sons[0])).name;
addDependencyAux(g.module.name.s, imported);
end;
nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: begin

View File

@@ -994,9 +994,11 @@ begin
result := evalAux(c, n.sons[2]);
if result.kind = nkExceptBranch then exit;
k := getOrdValue(result);
if (k >= 0) and (k < sonsLen(a))
and not (a.kind in [nkEmpty..nkNilLit]) then
result := a.sons[int(k)]
if not (a.kind in [nkEmpty..nkNilLit]) and (k >= 0)
and (k < sonsLen(a)) then begin
result := a.sons[int(k)];
if result = nil then result := newNode(nkEmpty)
end
else begin
stackTrace(c, n, errIndexOutOfBounds);
result := emptyNode
@@ -1013,8 +1015,10 @@ begin
if result.kind = nkExceptBranch then exit;
k := getOrdValue(b);
if (k >= 0) and (k < sonsLen(a))
and not (a.kind in [nkEmpty..nkNilLit]) then
a.sons[int(k)] := result
and not (a.kind in [nkEmpty..nkNilLit]) then begin
if result.kind = nkEmpty then a.sons[int(k)] := nil
else a.sons[int(k)] := result
end
else
stackTrace(c, n, errIndexOutOfBounds);
result := emptyNode;
@@ -1205,6 +1209,19 @@ begin
if (a.kind = nkIdent) and (b.kind = nkIdent) then
if a.ident.id = b.ident.id then result.intVal := 1
end;
mEqNimrodNode: begin
result := evalAux(c, n.sons[1]);
if result.kind = nkExceptBranch then exit;
a := result;
result := evalAux(c, n.sons[2]);
if result.kind = nkExceptBranch then exit;
b := result;
result := newNodeIT(nkIntLit, n.info, n.typ);
if (a = b)
or (b.kind in [nkNilLit, nkEmpty])
and (a.kind in [nkNilLit, nkEmpty]) then
result.intVal := 1
end;
mNHint: begin
result := evalAux(c, n.sons[1]);
if result.kind = nkExceptBranch then exit;

View File

@@ -438,7 +438,7 @@ var
begin
c := ccompiler;
options := compileOptions;
trunk := extractFileTrunk(cfilename);
trunk := splitFile(cfilename).name;
if optCDebug in gGlobalOptions then begin
key := trunk + '.debug';
if existsConfigVar(key) then
@@ -594,15 +594,15 @@ begin
if optGenDynLib in gGlobalOptions then begin
exefile := format(platform.os[targetOS].dllFrmt,
[extractFileTrunk(projectFile)]);
[splitFile(projectFile).name]);
buildDll := cc[c].buildDll;
end
else begin
exefile := extractFileTrunk(projectFile) +{&} platform.os[targetOS].exeExt;
exefile := splitFile(projectFile).name +{&} platform.os[targetOS].exeExt;
buildDll := '';
end;
if targetOS = platform.hostOS then
exefile := joinPath(extractDir(projectFile), exefile);
exefile := joinPath(splitFile(projectFile).dir, exefile);
exefile := quoteIfContainsWhite(exefile);
it := PStrEntry(toLink.head);

View File

@@ -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.
@@ -69,7 +69,7 @@ begin
{@emit}
result.id := -1; // for better error checking
result.kind := skModule;
result.name := getIdent(extractFileTrunk(filename));
result.name := getIdent(splitFile(filename).name);
result.owner := result; // a module belongs to itself
result.info := newLineInfo(filename, 1, 1);
include(result.flags, sfUsed);
@@ -321,14 +321,11 @@ begin
end;
procedure MainCommand(const cmd, filename: string);
var
dir, f: string;
begin
appendStr(searchPaths, options.libpath);
if filename <> '' then begin
splitPath(filename, dir, f);
// current path is always looked first for modules
prependStr(searchPaths, dir);
prependStr(searchPaths, splitFile(filename).dir);
end;
setID(100);
passes.gIncludeFile := syntaxes.parseFile;

View File

@@ -467,7 +467,7 @@ const
'$1 needs a return type',
'invalid command: ''$1''',
'''$1'' is only allowed at top level',
'template instantiation too nested',
'template/macro instantiation too nested',
'instantiation from here',
'invalid index value for tuple subscript',
'command expects a filename argument',

View File

@@ -84,7 +84,7 @@ begin
command := '';
filename := '';
ProcessCmdLine(passCmd1, command, filename);
if filename <> '' then options.projectPath := extractDir(filename);
if filename <> '' then options.projectPath := splitFile(filename).dir;
nimconf.LoadConfig(filename); // load the right config file
// now process command line arguments again, because some options in the
// command line can overwite the config file's settings

View File

@@ -29,6 +29,13 @@ uses
type
EOSError = class(exception)
end;
TSplitFileResult = record
dir, name, ext: string;
end;
TSplitPathResult = record
head, tail: string;
end;
const
curdir = '.';
@@ -59,7 +66,7 @@ procedure putEnv(const name, val: string);
function JoinPath(const head, tail: string): string; overload;
function JoinPath(const parts: array of string): string; overload;
procedure SplitPath(const path: string; out head, tail: string);
procedure SplitPath(const path: string; out head, tail: string); overload;
function extractDir(const f: string): string;
function extractFilename(const f: string): string;
@@ -87,9 +94,38 @@ function sameFile(const path1, path2: string): boolean;
function extractFileTrunk(const filename: string): string;
function splitFile(const path: string): TSplitFileResult;
function splitPath(const path: string): TSplitPathResult; overload;
implementation
function splitFile(const path: string): TSplitFileResult;
var
sepPos, dotPos, i: int;
begin
if (path = '') or (path[length(path)] in [dirSep, altSep]) then begin
result.dir := path;
result.name := '';
result.ext := '';
end
else begin
sepPos := 0;
dotPos := length(path)+1;
for i := length(path) downto 1 do begin
if path[i] = ExtSep then begin
if (dotPos = length(path)+1) and (i > 1) then dotPos := i
end
else if path[i] in [dirsep, altsep] then begin
sepPos := i; break
end
end;
result.dir := ncopy(path, 1, sepPos-1);
result.name := ncopy(path, sepPos+1, dotPos-1);
result.ext := ncopy(path, dotPos)
end
end;
function extractFileTrunk(const filename: string): string;
var
f, e, dir: string;
@@ -146,7 +182,7 @@ var
i: int;
begin
result := -1;
for i := length(s) downto 1 do
for i := length(s) downto 2 do
if s[i] = extsep then begin
result := i;
break
@@ -219,6 +255,11 @@ begin
end
end;
function SplitPath(const path: string): TSplitPathResult;
begin
SplitPath(path, result.head, result.tail);
end;
function getApplicationFilename(): string;
{$ifdef darwin}
var

View File

@@ -31,10 +31,10 @@ const
//cog.outl('VersionMinor = %s;' % ver[1])
//cog.outl('VersionPatch = %s;' % ver[2])
//]]]
VersionAsString = '0.8.2';
VersionAsString = '0.8.3';
VersionMajor = 0;
VersionMinor = 8;
VersionPatch = 2;
VersionPatch = 3;
//[[[[end]]]]
implementation

View File

@@ -176,11 +176,8 @@ begin
end;
function getPrefixDir: string;
var
appdir, bin: string;
begin
appdir := getApplicationDir();
SplitPath(appdir, result, bin);
result := SplitPath(getApplicationDir()).head;
end;
function shortenDir(const dir: string): string;

View File

@@ -415,24 +415,23 @@ type
procedure processCompile(c: PContext; n: PNode);
var
s, found, trunc, ext: string;
s, found, trunc: string;
begin
s := expectStrLit(c, n);
found := findFile(s);
if found = '' then found := s;
splitFilename(found, trunc, ext);
trunc := ChangeFileExt(found, '');
extccomp.addExternalFileToCompile(trunc);
extccomp.addFileToLink(completeCFilePath(trunc, false));
end;
procedure processCommonLink(c: PContext; n: PNode; feature: TLinkFeature);
var
f, tmp, ext, found: string;
f, found: string;
begin
f := expectStrLit(c, n);
splitFilename(f, tmp, ext);
if (ext = '') then
f := toObjFile(tmp);
if splitFile(f).ext = '' then
f := toObjFile(f);
found := findFile(f);
if found = '' then
found := f; // use the default

View File

@@ -1,15 +1,15 @@
//
//
// 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 rst;
// This module implements a *reStructuredText* parser. Currently, only a
// subset is provided. Later, there will be additions.
// This module implements a *reStructuredText* parser. A larget
// subset is provided.
interface

View File

@@ -130,12 +130,17 @@ begin
end
end;
{$include 'semtempl.pas'}
function semMacroExpr(c: PContext; n: PNode; sym: PSym;
semCheck: bool = true): PNode;
var
p: PEvalContext;
s: PStackFrame;
begin
inc(evalTemplateCounter);
if evalTemplateCounter > 100 then
liMessage(n.info, errTemplateInstantiationTooNested);
markUsed(n, sym);
p := newEvalContext(c.module, '', false);
s := newStackFrame();
@@ -150,9 +155,9 @@ begin
if cyclicTree(result) then liMessage(n.info, errCyclicTree);
if semCheck then
result := semAfterMacroCall(c, result, sym);
dec(evalTemplateCounter);
end;
{$include 'semtempl.pas'}
{$include 'seminst.pas'}
{$include 'sigmatch.pas'}

View File

@@ -517,20 +517,19 @@ begin
result := nil;
prc := n.sons[0];
checkMinSonsLen(n, 1);
case n.sons[0].kind of
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!
result := n.sons[0];
result.kind := nkCall;
for i := 1 to sonsLen(n)-1 do addSon(result, n.sons[i]);
result := semExpr(c, result);
exit
end
end;
else n.sons[0] := semExpr(c, n.sons[0]);
end;
if n.sons[0].kind = nkDotExpr then 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!
result := n.sons[0];
result.kind := nkCall;
for i := 1 to sonsLen(n)-1 do addSon(result, n.sons[i]);
result := semExpr(c, result, flags);
exit
end
end
else
n.sons[0] := semExpr(c, n.sons[0]);
semOpAux(c, n);
if (n.sons[0].typ <> nil) then t := skipTypes(n.sons[0].typ, abstractInst)
else t := nil;

View File

@@ -162,9 +162,11 @@ begin
while (last <= length(s)) and (s[last] in seps) do inc(last);
first := last;
while (last <= length(s)) and not (s[last] in seps) do inc(last);
len := length(result);
setLength(result, len+1);
result[len] := ncopy(s, first, last-1);
if first >= last-1 then begin
len := length(result);
setLength(result, len+1);
result[len] := ncopy(s, first, last-1);
end
end
end;

8
tests/titer5.nim Executable file
View File

@@ -0,0 +1,8 @@
# Test method call syntax for iterators:
const lines = """abc xyz"""
for x in lines.split():
stdout.write(x)
#OUT abcxyz

View File

@@ -220,7 +220,7 @@ proc main(c: var TConfigData) =
buildAddDoc(c, "web/upload")
buildDoc(c, "web/upload")
buildDoc(c, "doc")
#buildPdfDoc(c, "doc")
buildPdfDoc(c, "doc")
var c: TConfigData
initConfigData(c)

View File

@@ -94,11 +94,6 @@ Nimrod plays nice with others
New bindings are easily generated in a semi-automatic way.
* A Pascal to Nimrod conversion utility: A large subset of Object Pascal
can be translated to Nimrod automatically!
* Nimrod's documentation syntax is a subset of the wonderfully readable plaintext
markup syntax
`reStructuredText <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_.
The documentation generator is very flexible; this website has been generated
with it!
Roadmap to 1.0