diff options
-rwxr-xr-x | compiler/ast.nim | 6 | ||||
-rwxr-xr-x | compiler/ccgexprs.nim | 25 | ||||
-rwxr-xr-x | compiler/ccgstmts.nim | 3 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 1 | ||||
-rwxr-xr-x | compiler/evals.nim | 16 | ||||
-rwxr-xr-x | compiler/sem.nim | 23 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 44 | ||||
-rwxr-xr-x | compiler/semfold.nim | 20 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 41 | ||||
-rwxr-xr-x | compiler/transf.nim | 24 | ||||
-rwxr-xr-x | compiler/types.nim | 2 | ||||
-rwxr-xr-x | doc/manual.txt | 70 | ||||
-rwxr-xr-x | lib/nimbase.h | 2 | ||||
-rwxr-xr-x | lib/pure/pegs.nim | 10 | ||||
-rwxr-xr-x | lib/pure/strutils.nim | 25 | ||||
-rwxr-xr-x | tests/accept/compile/tconsteval.nim | 1 | ||||
-rwxr-xr-x | todo.txt | 2 | ||||
-rwxr-xr-x | web/news.txt | 2 |
18 files changed, 180 insertions, 137 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 775f679df..b33d99554 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -559,9 +559,11 @@ const tyBool, tyChar, tyEnum, tyArray, tyObject, tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyPointer, - tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128} + tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, + tyUInt..tyUInt64} - ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple} + ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, + tyTuple, tySequence} ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, skMacro, skTemplate, skConverter, skStub} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst} diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 409dd51c2..826832438 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1831,6 +1831,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) = if sym.loc.r == nil or sym.loc.t == nil: InternalError(e.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) + of nkMetaNode: expr(p, e.sons[0], d) else: InternalError(e.info, "expr(" & $e.kind & "); unknown node kind") proc genNamedConstExpr(p: BProc, n: PNode): PRope = @@ -1845,6 +1846,24 @@ proc genConstSimpleList(p: BProc, n: PNode): PRope = if length > 0: app(result, genNamedConstExpr(p, n.sons[length - 1])) appf(result, "}$n") +proc genConstSeq(p: BProc, n: PNode, t: PType): PRope = + var data = ropef("{{$1, $1}", n.len.toRope) + for i in countup(0, n.len - 1): + appf(data, ",$1$n", [genConstExpr(p, n.sons[i])]) + data.app("}") + + inc(p.labels) + result = con("CNSTSEQ", p.labels.toRope) + + appcg(p.module, cfsData, + "NIM_CONST struct {$n" & + " #TGenericSeq Sup;$n" & + " $1 data[$2];$n" & + "} $3 = $4;$n", [ + getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data]) + + result = ropef("(($1)&$2)", [getTypeDesc(p.module, t), result]) + proc genConstExpr(p: BProc, n: PNode): PRope = case n.Kind of nkHiddenStdConv, nkHiddenSubConv: @@ -1855,7 +1874,11 @@ proc genConstExpr(p: BProc, n: PNode): PRope = result = genRawSetData(cs, int(getSize(n.typ))) of nkBracket, nkPar: # XXX: tySequence! - result = genConstSimpleList(p, n) + var t = skipTypes(n.typ, abstractInst) + if t.kind == tySequence: + result = genConstSeq(p, n, t) + else: + result = genConstSimpleList(p, n) else: var d: TLoc initLocExpr(p, n, d) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index f982f2c22..bf3d6aea1 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -67,7 +67,8 @@ proc genConstStmt(p: BProc, t: PNode) = var c = it.sons[0].sym if sfFakeConst in c.flags: genSingleVar(p, it) - elif c.typ.kind in ConstantDataTypes and not (lfNoDecl in c.loc.flags): + elif c.typ.kind in ConstantDataTypes and not (lfNoDecl in c.loc.flags) and + c.ast.len != 0: # generate the data: fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown) if sfImportc in c.flags: diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 42643b39e..7ad4dbd8b 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -1426,6 +1426,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) = of nkCStringToString: convCStrToStr(p, n, r) of nkStmtListExpr: genStmtListExpr(p, n, r) of nkEmpty: nil + of nkMetaNode: gen(p, n.sons[0], r) else: InternalError(n.info, "gen: unknown node type: " & $n.kind) var globals: PGlobals diff --git a/compiler/evals.nim b/compiler/evals.nim index a61d687ef..1d443a404 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -43,7 +43,7 @@ const evalMaxIterations = 500_000 # max iterations of all loops evalMaxRecDepth = 10_000 # max recursion depth for evaluation -# Much better: use a timeout! -> Wether code compiles depends on the machine +# other idea: use a timeout! -> Wether code compiles depends on the machine # the compiler runs on then! Bad idea! proc newStackFrame*(): PStackFrame = @@ -754,17 +754,15 @@ proc evalRepr(c: PEvalContext, n: PNode): PNode = if isSpecial(result): return result = newStrNodeT(renderTree(result, {renderNoComments}), n) -proc isEmpty(n: PNode): bool = - result = (n != nil) and (n.kind == nkEmpty) +proc isEmpty(n: PNode): bool = + result = n != nil and n.kind == nkEmpty # The lexer marks multi-line strings as residing at the line where they # are closed. This function returns the line where the string begins # Maybe the lexer should mark both the beginning and the end of expressions, # then this function could be removed. proc stringStartingLine(s: PNode): int = - var totalLines = 0 - for ln in splitLines(s.strVal): inc totalLines - result = s.info.line - totalLines + result = s.info.line - countLines(s.strVal) proc evalParseExpr(c: PEvalContext, n: Pnode): Pnode = var code = evalAux(c, n.sons[1], {}) @@ -1069,9 +1067,6 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = dec(gNestedEvals) if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations) case n.kind # atoms: - of nkMetaNode: - result = copyTree(n.sons[0]) - result.typ = n.typ of nkEmpty: result = n of nkSym: result = evalSym(c, n, flags) of nkType..nkNilLit: result = copyNode(n) # end of atoms @@ -1131,6 +1126,9 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = nkTypeSection, nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef, nkIncludeStmt, nkImportStmt, nkFromStmt: nil + of nkMetaNode: + result = copyTree(n.sons[0]) + result.typ = n.typ of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, nkLambda, nkContinueStmt, nkIdent: stackTrace(c, n, errCannotInterpretNodeX, $n.kind) diff --git a/compiler/sem.nim b/compiler/sem.nim index 78a04f744..dcbdac157 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -55,25 +55,26 @@ proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} = GlobalError(typ.n.info, errXisNoType, typeToString(typ)) proc semConstExpr(c: PContext, n: PNode): PNode = - result = semExprWithType(c, n) - if result == nil: - GlobalError(n.info, errConstExprExpected) - return - result = getConstExpr(c.module, result) - if result == nil: GlobalError(n.info, errConstExprExpected) - -proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = var e = semExprWithType(c, n) if e == nil: GlobalError(n.info, errConstExprExpected) return nil result = getConstExpr(c.module, e) - if result == nil: - #writeln(output, renderTree(n)); + if result == nil: result = evalConstExpr(c.module, e) if result == nil or result.kind == nkEmpty: GlobalError(n.info, errConstExprExpected) - + when false: + result = semExprWithType(c, n) + if result == nil: + GlobalError(n.info, errConstExprExpected) + return + result = getConstExpr(c.module, result) + if result == nil: GlobalError(n.info, errConstExprExpected) + +proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = + result = semConstExpr(c, n) + include seminst, semcall proc typeMismatch(n: PNode, formal, actual: PType) = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e720cf055..356f1c196 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -9,10 +9,6 @@ # this module does the semantic checking for expressions -const - ConstAbstractTypes = {tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, - tyArrayConstr, tyTuple, tySet} - proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = markUsed(n, s) pushInfoContext(n.info) @@ -49,6 +45,11 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s) +proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = + result = copyTree(s.ast) + result.typ = s.typ + result.info = n.info + proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = case s.kind of skProc, skMethod, skIterator, skConverter: @@ -56,24 +57,25 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = getModule(s).id != c.module.id: LocalError(n.info, errXCannotBePassedToProcVar, s.name.s) result = symChoice(c, n, s) - of skConst: - # - # Consider:: - # const x = [] - # proc p(a: openarray[int]) - # proc q(a: openarray[char]) - # p(x) - # q(x) - # - # It is clear that ``[]`` means two totally different things. Thus, we - # copy `x`'s AST into each context, so that the type fixup phase can - # deal with two different ``[]``. - # + of skConst: markUsed(n, s) - if s.typ.kind in ConstAbstractTypes: - result = copyTree(s.ast) - result.typ = s.typ - result.info = n.info + case skipTypes(s.typ, abstractInst).kind + of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, + tyTuple, tySet, tyUInt..tyUInt64: + result = inlineConst(n, s) + of tyArrayConstr, tySequence: + # Consider:: + # const x = [] + # proc p(a: openarray[int]) + # proc q(a: openarray[char]) + # p(x) + # q(x) + # + # It is clear that ``[]`` means two totally different things. Thus, we + # copy `x`'s AST into each context, so that the type fixup phase can + # deal with two different ``[]``. + if s.ast.len == 0: result = inlineConst(n, s) + else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info) of skMacro: result = semMacroExpr(c, n, s) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 570656a39..77d84b6f8 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -181,10 +181,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = result.info = n.info of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n) of mInSet: result = newIntNodeT(Ord(inSet(a, b)), n) - of mRepr: - # BUGFIX: we cannot eval mRepr here. But this means that it is not - # available for interpretation. I don't know how to fix this. - #result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n); + of mRepr: + # BUGFIX: we cannot eval mRepr here for reasons that I forgot. of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n) of mBoolToStr: if getOrdValue(a) == 0: result = newStrNodeT("false", n) @@ -324,7 +322,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = var s = n.sym if s.kind == skEnumField: result = newIntNodeT(s.position, n) - elif (s.kind == skConst): + elif s.kind == skConst: case s.magic of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) of mCompileDate: result = newStrNodeT(times.getDateStr(), n) @@ -370,10 +368,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mLow: result = newIntNodeT(firstOrd(n.sons[1].typ), n) of mHigh: - if not (skipTypes(n.sons[1].typ, abstractVar).kind in - {tyOpenArray, tySequence, tyString}): - result = newIntNodeT(lastOrd(skipTypes(n.sons[1].typ, abstractVar)), - n) + if skipTypes(n.sons[1].typ, abstractVar).kind notin + {tyOpenArray, tySequence, tyString}: + result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) + else: + var a = n.sons[1] + if a.kind == nkBracket: + # we can optimize it away: + result = newIntNodeT(sonsLen(a)-1, n) of mLengthOpenArray: var a = n.sons[1] if a.kind == nkBracket: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index decc8a2d7..c00b68bb5 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -280,22 +280,33 @@ proc semConst(c: PContext, n: PNode): PNode = var typ: PType = nil if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil) - var e = semExprWithType(c, a.sons[2]) - if e == nil: GlobalError(a.sons[2].info, errConstExprExpected) - var def = getConstExpr(c.module, e) - if def == nil: - v.flags.incl(sfFakeConst) - def = evalConstExpr(c.module, e) - if def == nil or def.kind == nkEmpty: def = e - # check type compatibility between def.typ and typ: - if typ != nil: - def = fitRemoveHiddenConv(c, typ, def) - else: - typ = def.typ - if not typeAllowed(typ, skConst): - v.flags.incl(sfFakeConst) - if not typeAllowed(typ, skVar): + when true: + var def = semConstExpr(c, a.sons[2]) + if def == nil: GlobalError(a.sons[2].info, errConstExprExpected) + # check type compatibility between def.typ and typ: + if typ != nil: + def = fitRemoveHiddenConv(c, typ, def) + else: + typ = def.typ + if not typeAllowed(typ, skConst): GlobalError(a.info, errXisNoType, typeToString(typ)) + else: + var e = semExprWithType(c, a.sons[2]) + if e == nil: GlobalError(a.sons[2].info, errConstExprExpected) + var def = getConstExpr(c.module, e) + if def == nil: + v.flags.incl(sfFakeConst) + def = evalConstExpr(c.module, e) + if def == nil or def.kind == nkEmpty: def = e + # check type compatibility between def.typ and typ: + if typ != nil: + def = fitRemoveHiddenConv(c, typ, def) + else: + typ = def.typ + if not typeAllowed(typ, skConst): + v.flags.incl(sfFakeConst) + if not typeAllowed(typ, skVar): + GlobalError(a.info, errXisNoType, typeToString(typ)) v.typ = typ v.ast = def # no need to copy addInterfaceDecl(c, v) diff --git a/compiler/transf.nim b/compiler/transf.nim index 482332f38..9c67165e3 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -161,7 +161,6 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = proc transformSymAux(c: PTransf, n: PNode): PNode = var b: PNode - if (n.kind != nkSym): internalError(n.info, "transformSym") var tc = c.transCon if sfBorrow in n.sym.flags: # simply exchange the symbol: @@ -176,14 +175,15 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = if result != nil: return tc = tc.next result = b - case b.sym.kind - of skConst, skEnumField: - if sfFakeConst notin b.sym.flags: - if skipTypes(b.sym.typ, abstractInst).kind notin ConstantDataTypes: - result = getConstExpr(c.module, b) - if result == nil: InternalError(b.info, "transformSym: const") - else: - nil + when false: + case b.sym.kind + of skConst, skEnumField: + if sfFakeConst notin b.sym.flags: + if skipTypes(b.sym.typ, abstractInst).kind notin ConstantDataTypes: + result = getConstExpr(c.module, b) + if result == nil: InternalError(b.info, "transformSym: const") + else: + nil proc transformSym(c: PTransf, n: PNode): PTransNode = result = PTransNode(transformSymAux(c, n)) @@ -360,7 +360,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = var dest = skipTypes(n.typ, abstractVarRange) var source = skipTypes(n.sons[1].typ, abstractVarRange) case dest.kind - of tyInt..tyInt64, tyEnum, tyChar, tyBool: + of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt..tyUInt64: if not isOrdinalType(source): # XXX int64 -> float conversion? result = transformSons(c, n) @@ -659,7 +659,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = proc transform(c: PTransf, n: PNode): PTransNode = case n.kind of nkSym: - return transformSym(c, n) + result = transformSym(c, n) of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: # nothing to be done for leaves: result = PTransNode(n) @@ -719,7 +719,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = else: result = transformSons(c, n) var cnst = getConstExpr(c.module, PNode(result)) - if cnst != nil: + if cnst != nil and (cnst.kind != nkBracket or cnst.len == 0): result = PTransNode(cnst) # do not miss an optimization proc processTransf(context: PPassContext, n: PNode): PNode = diff --git a/compiler/types.nim b/compiler/types.nim index 144f4052e..cc1281b6e 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -762,7 +762,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = of tyOpenArray, tyVarargs: result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar) of tySequence: - result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or + result = typeAllowedAux(marker, t.sons[0], skVar) or t.sons[0].kind == tyEmpty of tyArray: result = typeAllowedAux(marker, t.sons[1], skVar) or diff --git a/doc/manual.txt b/doc/manual.txt index 77511d782..e07c7aff8 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -417,37 +417,6 @@ The grammar's start symbol is ``module``. Semantics ========= -Constants ---------- - -`Constants`:idx: are symbols which are bound to a value. The constant's value -cannot change. The compiler must be able to evaluate the expression in a -constant declaration at compile time. - -Nimrod contains a sophisticated compile-time evaluator, so procedures which -have no side-effect can be used in constant expressions too: - -.. code-block:: nimrod - import strutils - const - constEval = contains("abc", 'b') # computed at compile time! - - -The rules for compile-time computability are: - -1. Literals are compile-time computable. -2. Type conversions are compile-time computable. -3. Procedure calls of the form ``p(X)`` are compile-time computable if - ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ - for details) and if ``X`` is a (possibly empty) list of compile-time - computable arguments. - - -Constants cannot be of type ``var`` or ``object``, nor can -they contain such a type. For the types ``ptr`` and ``ref`` only the -constant literal ``nil`` is possible. - - Types ----- @@ -671,8 +640,8 @@ and ``pred`` are not available for them either. The compiler supports the built-in stringify operator ``$`` for enumerations. -The stringify's result can be controlled by specifying the string values to -use explicitely: +The stringify's result can be controlled by explicitely giving the string +values to use: .. code-block:: nimrod @@ -1521,6 +1490,7 @@ variables of the same type: If an initializer is given the type can be omitted: the variable is then of the same type as the initializing expression. Variables are always initialized + with a default value if there is no initializing expression. The default value depends on the type and is always a zero in binary. @@ -1554,17 +1524,32 @@ Syntax:: | COMMENT constSection ::= 'const' indPush constDecl (SAD constDecl)* DED indPop +`Constants`:idx: are symbols which are bound to a value. The constant's value +cannot change. The compiler must be able to evaluate the expression in a +constant declaration at compile time. -Example: +Nimrod contains a sophisticated compile-time evaluator, so procedures which +have no side-effect can be used in constant expressions too: .. code-block:: nimrod - + import strutils const - MyFilename = "/home/my/file.txt" - debugMode: bool = false + constEval = contains("abc", 'b') # computed at compile time! -The `const`:idx: section declares symbolic constants. A symbolic constant is -a name for a constant expression. Symbolic constants only allow read-access. + +The rules for compile-time computability are: + +1. Literals are compile-time computable. +2. Type conversions are compile-time computable. +3. Procedure calls of the form ``p(X)`` are compile-time computable if + ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ + for details) and if ``X`` is a (possibly empty) list of compile-time + computable arguments. + + +Constants cannot be of type ``var`` or ``object``, nor can +they contain such a type. For the types ``ptr`` and ``ref`` only the +constant literal ``nil`` is possible. If statement @@ -2398,7 +2383,6 @@ Example: add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and add(root, newNode("world")) # ``add`` for str in inorder(root): - writeln(stdout, str) `Generics`:idx: are Nimrod's means to parametrize procs, iterators or types with @@ -3338,6 +3322,12 @@ improve compile times. A thread proc is passed to ``createThread`` and invoked indirectly; so the ``thread`` pragma implies ``procvar``. +If a global variable can also be marked with the ``thread`` pragma; it is +a `thead-local`:idx: variable then: + +.. code-block:: nimrod + var checkpoints* {.thread.}: seq[string] = @[] + Actor model ----------- diff --git a/lib/nimbase.h b/lib/nimbase.h index 2af6ed8cc..cc0419f55 100755 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -362,7 +362,7 @@ static N_INLINE(NI32, float32ToInt32)(float val) { #define STRING_LITERAL(name, str, length) \ static const struct { \ TGenericSeq Sup; \ - NIM_CHAR data[length + 1]; \ + NIM_CHAR data[(length) + 1]; \ } name = {{length, length}, str} typedef struct TStringDesc* string; diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 2a680299d..25637cfee 100755 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1651,20 +1651,20 @@ proc peg*(pattern: string): TPeg = ## peg"{\ident} \s* '=' \s* {.*}" result = parsePeg(pattern, "pattern") -proc escapePeg*(s: string): string = +proc escapePeg*(s: string): string = ## escapes `s` so that it is matched verbatim when used as a peg. result = "" var inQuote = false - for c in items(s): + for c in items(s): case c - of '\0'..'\31', '\'', '"', '\\': - if inQuote: + of '\0'..'\31', '\'', '"', '\\': + if inQuote: result.add('\'') inQuote = false result.add("\\x") result.add(toHex(ord(c), 2)) else: - if not inQuote: + if not inQuote: result.add('\'') inQuote = true result.add(c) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 53aa34c83..5f91b65b5 100755 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -8,8 +8,8 @@ # ## This module contains various string utility routines. -## See the module `re` for regular expression support. -## See the module `pegs` for PEG support. +## See the module `re <re.html>`_ for regular expression support. +## See the module `pegs <pegs.html>`_ for PEG support. import parseutils @@ -369,6 +369,19 @@ proc splitLines*(s: string): seq[string] {.noSideEffect, ## sequence of substrings. accumulateResult(splitLines(s)) +proc countLines*(s: string): int {.noSideEffect, + rtl, extern: "nsuCountLines".} = + ## same as ``len(splitLines(s))``, but much more efficient. + var i = 0 + while i < s.len: + case s[i] + of '\c': + if s[i+1] == '\l': inc i + inc result + of '\l': inc result + else: nil + inc i + proc split*(s: string, seps: set[char] = Whitespace): seq[string] {. noSideEffect, rtl, extern: "nsuSplitCharSet".} = ## The same as the `split` iterator, but is a proc that returns a @@ -754,7 +767,7 @@ proc replace*(s: string, sub, by: char): string {.noSideEffect, proc delete*(s: var string, first, last: int) {.noSideEffect, rtl, extern: "nsuDelete".} = - ## Deletes in `s` the characters at position `first`..`last`. This modifies + ## Deletes in `s` the characters at position `first` .. `last`. This modifies ## `s` itself, it does not return a copy. var i = first var j = last+1 @@ -865,8 +878,8 @@ proc validIdentifier*(s: string): bool {.noSideEffect, proc editDistance*(a, b: string): int {.noSideEffect, rtl, extern: "nsuEditDistance".} = - ## returns the edit distance between `a` and `b`. This uses the - ## `Levenshtein`:idx: distance algorithm with only a linear memory overhead. + ## returns the edit distance between `a` and `b`. This uses the + ## `Levenshtein`:idx: distance algorithm with only a linear memory overhead. ## This implementation is highly optimized! var len1 = a.len var len2 = b.len @@ -958,7 +971,7 @@ proc c_sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs, noSideEffect.} type - TFloatFormat* = enum + TFloatFormat* = enum ## the different modes of floating point formating ffDefault, ## use the shorter floating point notation ffDecimal, ## use decimal floating point notation ffScientific ## use scientific notation (using ``e`` character) diff --git a/tests/accept/compile/tconsteval.nim b/tests/accept/compile/tconsteval.nim index 10af9ad35..dcc7080ea 100755 --- a/tests/accept/compile/tconsteval.nim +++ b/tests/accept/compile/tconsteval.nim @@ -1,5 +1,4 @@ discard """ - disabled: true """ import strutils diff --git a/todo.txt b/todo.txt index 59f19ab10..343ab6991 100755 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,10 @@ Version 0.8.14 ============== +- fix the 'const' issues - 'let x = y'; const ptr/ref - fix actors.nim - make threadvar efficient again on linux after testing -- fix the 'const' issues - test the sort implementation again - optional indentation for 'case' statement diff --git a/web/news.txt b/web/news.txt index 3bd68671f..2ee7c6822 100755 --- a/web/news.txt +++ b/web/news.txt @@ -76,7 +76,7 @@ Library Additions ``system.deallocShared``, ``system.reallocShared``. - Added explicit channels for thread communication. - Added ``matchers`` module for email address etc. matching. -- Added ``strutils.unindent``. +- Added ``strutils.unindent``, ``strutils.countLines``. - Added ``system.slurp`` for easy resource embedding. - Added ``system.running`` for threads. - Added ``xmltree.innerText``. |