breaking change: 'concept' is now a keyword and used instead of 'generic'

This commit is contained in:
Araq 2015-03-23 00:51:04 +01:00
commit f6ff01572e
15 changed files with 462 additions and 475 deletions

View file

@ -35,7 +35,7 @@ type
tkSymbol, # keywords: tkSymbol, # keywords:
tkAddr, tkAnd, tkAs, tkAsm, tkAtomic, tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
tkBind, tkBlock, tkBreak, tkCase, tkCast, tkBind, tkBlock, tkBreak, tkCase, tkCast,
tkConst, tkContinue, tkConverter, tkConcept, tkConst, tkContinue, tkConverter,
tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo, tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport, tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
tkFinally, tkFor, tkFrom, tkFunc, tkFinally, tkFor, tkFrom, tkFunc,
@ -72,7 +72,7 @@ const
"tkSymbol", "tkSymbol",
"addr", "and", "as", "asm", "atomic", "addr", "and", "as", "asm", "atomic",
"bind", "block", "break", "case", "cast", "bind", "block", "break", "case", "cast",
"const", "continue", "converter", "concept", "const", "continue", "converter",
"defer", "discard", "distinct", "div", "do", "defer", "discard", "distinct", "div", "do",
"elif", "else", "end", "enum", "except", "export", "elif", "else", "end", "enum", "except", "export",
"finally", "for", "from", "func", "generic", "if", "finally", "for", "from", "func", "generic", "if",

View file

@ -1073,8 +1073,10 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
else: else:
result = newNodeP(nkObjectTy, p) result = newNodeP(nkObjectTy, p)
getTok(p) getTok(p)
of tkGeneric: of tkGeneric, tkConcept:
if mode == pmTypeDef: if mode == pmTypeDef:
if p.tok.tokType == tkGeneric:
parMessage(p, warnDeprecated, "use 'concept' instead; 'generic'")
result = parseTypeClass(p) result = parseTypeClass(p)
else: else:
parMessage(p, errInvalidToken, p.tok) parMessage(p, errInvalidToken, p.tok)
@ -1107,7 +1109,7 @@ proc parseTypeDesc(p: var TParser): PNode =
proc parseTypeDefAux(p: var TParser): PNode = proc parseTypeDefAux(p: var TParser): PNode =
#| typeDefAux = simpleExpr #| typeDefAux = simpleExpr
#| | 'generic' typeClass #| | 'concept' typeClass
result = simpleExpr(p, pmTypeDef) result = simpleExpr(p, pmTypeDef)
proc makeCall(n: PNode): PNode = proc makeCall(n: PNode): PNode =

View file

@ -725,7 +725,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
proc gTypeClassTy(g: var TSrcGen, n: PNode) = proc gTypeClassTy(g: var TSrcGen, n: PNode) =
var c: TContext var c: TContext
initContext(c) initContext(c)
putWithSpace(g, tkGeneric, "generic") putWithSpace(g, tkConcept, "concept")
gsons(g, n[0], c) # arglist gsons(g, n[0], c) # arglist
gsub(g, n[1]) # pragmas gsub(g, n[1]) # pragmas
gsub(g, n[2]) # of gsub(g, n[2]) # of

View file

@ -23,7 +23,7 @@ type
wInvalid, wInvalid,
wAddr, wAnd, wAs, wAsm, wAtomic, wAddr, wAnd, wAs, wAsm, wAtomic,
wBind, wBlock, wBreak, wCase, wCast, wConst, wBind, wBlock, wBreak, wCase, wCast, wConcept, wConst,
wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo, wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo,
wElif, wElse, wEnd, wEnum, wExcept, wExport, wElif, wElse, wEnd, wEnum, wExcept, wExport,
wFinally, wFor, wFrom, wFunc, wGeneric, wIf, wImport, wIn, wFinally, wFor, wFrom, wFunc, wGeneric, wIf, wImport, wIn,
@ -103,7 +103,7 @@ const
"addr", "and", "as", "asm", "atomic", "addr", "and", "as", "asm", "atomic",
"bind", "block", "break", "case", "cast", "bind", "block", "break", "case", "cast",
"const", "continue", "converter", "concept", "const", "continue", "converter",
"defer", "discard", "distinct", "div", "do", "defer", "discard", "distinct", "div", "do",
"elif", "else", "end", "enum", "except", "export", "elif", "else", "end", "enum", "except", "export",
"finally", "for", "from", "func", "generic", "if", "finally", "for", "from", "func", "generic", "if",

View file

@ -52,11 +52,11 @@ identOrLiteral = generalizedLit | symbol | literal
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
| doBlocks | doBlocks
| '.' optInd symbol generalizedLit? | '.' optInd symbol generalizedLit?
| '[' optInd indexExprList optPar ']' | '[' optInd indexExprList optPar ']'
| '{' optInd indexExprList optPar '}' | '{' optInd indexExprList optPar '}'
| &( '`'|IDENT|literal|'cast') expr # command syntax | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
condExpr = expr colcom expr optInd condExpr = expr colcom expr optInd
('elif' expr colcom expr optInd)* ('elif' expr colcom expr optInd)*
'else' colcom expr 'else' colcom expr
@ -94,7 +94,7 @@ primary = typeKeyw typeDescK
/ 'bind' primary / 'bind' primary
typeDesc = simpleExpr typeDesc = simpleExpr
typeDefAux = simpleExpr typeDefAux = simpleExpr
| 'generic' typeClass | 'concept' typeClass
macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
| IND{=} 'elif' expr ':' stmt | IND{=} 'elif' expr ':' stmt
| IND{=} 'except' exprList ':' stmt | IND{=} 'except' exprList ':' stmt

View file

@ -1,6 +1,6 @@
addr and as asm atomic addr and as asm atomic
bind block break bind block break
case cast const continue converter case cast concept const continue converter
defer discard distinct div do defer discard distinct div do
elif else end enum except export elif else end enum except export
finally for from func finally for from func

View file

@ -203,34 +203,34 @@ be inferred to have the equivalent of the `any` type class and thus they will
match anything without discrimination. match anything without discrimination.
User defined type classes Concepts
------------------------- --------
**Note**: User defined type classes are still in development. **Note**: Concepts are still in development.
The user-defined type classes are available in two flavours - declarative and Concepts, also known as "user-defined type classes", are available in two
imperative. Both are used to specify an arbitrary set of requirements that the flavours - declarative and imperative. Both are used to specify an arbitrary
matched type must satisfy. set of requirements that the matched type must satisfy.
Declarative type classes are written in the following form: Declarative type classes are written in the following form:
.. code-block:: nim .. code-block:: nim
type type
Comparable = generic x, y Comparable = concept x, y
(x < y) is bool (x < y) is bool
Container[T] = generic c Container[T] = concept c
c.len is ordinal c.len is ordinal
items(c) is iterator items(c) is iterator
for value in c: for value in c:
type(value) is T type(value) is T
The type class will be matched if: The concept will be matched if:
a) all of the expressions within the body can be compiled for the tested type a) all of the expressions within the body can be compiled for the tested type
b) all statically evaluatable boolean expressions in the body must be true b) all statically evaluatable boolean expressions in the body must be true
The identifiers following the `generic` keyword represent instances of the The identifiers following the ``concept`` keyword represent instances of the
currently matched type. These instances can act both as variables of the type, currently matched type. These instances can act both as variables of the type,
when used in contexts where a value is expected, and as the type itself when when used in contexts where a value is expected, and as the type itself when
used in contexts where a type is expected. used in contexts where a type is expected.
@ -240,18 +240,18 @@ type signatures of the required operations, but since type inference and
default parameters are still applied in the provided block, it's also possible default parameters are still applied in the provided block, it's also possible
to encode usage protocols that do not reveal implementation details. to encode usage protocols that do not reveal implementation details.
As a special rule providing further convenience when writing type classes, any As a special rule providing further convenience when writing concepts, any
type value appearing in a callable expression will be treated as a variable of type value appearing in a callable expression will be treated as a variable of
the designated type for overload resolution purposes, unless the type value was the designated type for overload resolution purposes, unless the type value was
passed in its explicit ``typedesc[T]`` form: passed in its explicit ``typedesc[T]`` form:
.. code-block:: nim .. code-block:: nim
type type
OutputStream = generic S OutputStream = concept S
write(var S, string) write(var S, string)
Much like generics, the user defined type classes will be instantiated exactly Much like generics, concepts are instantiated exactly
once for each tested type and any static code included within them will also be once for each tested type and any static code included within them is also
executed once. executed once.

View file

@ -6,7 +6,7 @@ static[T]
**Note**: static[T] is still in development. **Note**: static[T] is still in development.
As their name suggests, static params must be known at compile-time: As their name suggests, static parameters must be known at compile-time:
.. code-block:: nim .. code-block:: nim
@ -25,22 +25,6 @@ For the purposes of code generation, all static params are treated as
generic params - the proc will be compiled separately for each unique generic params - the proc will be compiled separately for each unique
supplied value (or combination of values). supplied value (or combination of values).
Furthermore, the system module defines a `semistatic[T]` type that can be
used to declare procs accepting both static and run-time values, which can
optimize their body according to the supplied param using the `isStatic(p)`
predicate:
.. code-block:: nim
# The following proc will be compiled once for each unique static
# value and also once for the case handling all run-time values:
proc re(pattern: semistatic[string]): RegEx =
when isStatic(pattern):
result = precompiledRegex(pattern)
else:
result = compile(pattern)
Static params can also appear in the signatures of generic types: Static params can also appear in the signatures of generic types:
.. code-block:: nim .. code-block:: nim

View file

@ -47,7 +47,7 @@ const
# The following list comes from doc/keywords.txt, make sure it is # The following list comes from doc/keywords.txt, make sure it is
# synchronized with this array by running the module itself as a test case. # synchronized with this array by running the module itself as a test case.
nimKeywords = ["addr", "and", "as", "asm", "atomic", "bind", "block", nimKeywords = ["addr", "and", "as", "asm", "atomic", "bind", "block",
"break", "case", "cast", "const", "continue", "converter", "break", "case", "cast", "concept", "const", "continue", "converter",
"defer", "discard", "distinct", "div", "do", "defer", "discard", "distinct", "div", "do",
"elif", "else", "end", "enum", "except", "export", "elif", "else", "end", "enum", "except", "export",
"finally", "for", "from", "func", "finally", "for", "from", "func",
@ -554,10 +554,12 @@ when isMainModule:
var keywords: seq[string] var keywords: seq[string]
# Try to work running in both the subdir or at the root. # Try to work running in both the subdir or at the root.
for filename in ["doc/keywords.txt", "../../../doc/keywords.txt"]: for filename in ["doc/keywords.txt", "../../../doc/keywords.txt"]:
except: echo filename, " not found" try:
let input = string(readFile(filename)) let input = string(readFile(filename))
keywords = input.split() keywords = input.split()
break break
except:
echo filename, " not found"
doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!") doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!")
doAssert keywords.len == nimKeywords.len, "No matching lengths" doAssert keywords.len == nimKeywords.len, "No matching lengths"
for i in 0..keywords.len-1: for i in 0..keywords.len-1:

View file

@ -22,7 +22,7 @@ template reject(e: expr) =
static: assert(not compiles(e)) static: assert(not compiles(e))
type type
Container[T] = generic C Container[T] = concept C
C.len is Ordinal C.len is Ordinal
items(c) is iterator items(c) is iterator
for value in C: for value in C:

View file

@ -40,7 +40,7 @@ proc isSwizzle(s: string): bool {.compileTime.} =
return false return false
type type
StringIsSwizzle = generic value StringIsSwizzle = concept value
value.isSwizzle value.isSwizzle
SwizzleStr = static[string] and StringIsSwizzle SwizzleStr = static[string] and StringIsSwizzle

View file

@ -16,10 +16,10 @@ type
TObj = object TObj = object
x: int x: int
Sortable = generic x, y Sortable = concept x, y
(x < y) is bool (x < y) is bool
ObjectContainer = generic C ObjectContainer = concept C
C.len is Ordinal C.len is Ordinal
for v in items(C): for v in items(C):
v.type is tuple|object v.type is tuple|object
@ -38,7 +38,7 @@ proc intval(x: int): int = 10
# check real and virtual fields # check real and virtual fields
type type
TFoo = generic T TFoo = concept T
T.x T.x
y(T) y(T)
intval T.y intval T.y
@ -50,7 +50,7 @@ proc testFoo(x: TFoo) = discard
testFoo(TObj(x: 10)) testFoo(TObj(x: 10))
type type
Matrix[Rows, Cols: static[int]; T] = generic M Matrix[Rows, Cols: static[int]; T] = concept M
M.M == Rows M.M == Rows
M.N == Cols M.N == Cols
M.T is T M.T is T

View file

@ -1,5 +1,5 @@
type type
hasFieldX = generic z hasFieldX = concept z
z.x is int z.x is int
obj_x = object obj_x = object

View file

@ -5,6 +5,7 @@ version 0.10.4
- improve GC-unsafety warnings - improve GC-unsafety warnings
- make 'nil' work for 'add' and 'len' - make 'nil' work for 'add' and 'len'
- add "all threads are blocked" detection to 'spawn' - add "all threads are blocked" detection to 'spawn'
- overloading of '='
version 1.0 version 1.0
@ -17,8 +18,6 @@ version 1.0
- The bitwise 'not' operator will be renamed to 'bnot' to - The bitwise 'not' operator will be renamed to 'bnot' to
prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs! prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
- iterators always require a return type - iterators always require a return type
- overloading of '='
- make nimble part of the distribution - make nimble part of the distribution
- split docgen into separate tool - split docgen into separate tool
- special rule for ``[]=``, items, pairs - special rule for ``[]=``, items, pairs

View file

@ -41,7 +41,7 @@ News
and not as ``type((x).name)``. Note that this also affects the AST and not as ``type((x).name)``. Note that this also affects the AST
structure; for immediate macro parameters ``nkCall('addr', 'x')`` is structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
produced instead of ``nkAddr('x')``. produced instead of ``nkAddr('x')``.
- ``concept`` is now a keyword and is used instead of ``generic``.
Language Additions Language Additions