breaking change: 'concept' is now a keyword and used instead of 'generic'
This commit is contained in:
parent
210fab10b2
commit
f6ff01572e
15 changed files with 462 additions and 475 deletions
|
|
@ -35,7 +35,7 @@ type
|
|||
tkSymbol, # keywords:
|
||||
tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
|
||||
tkBind, tkBlock, tkBreak, tkCase, tkCast,
|
||||
tkConst, tkContinue, tkConverter,
|
||||
tkConcept, tkConst, tkContinue, tkConverter,
|
||||
tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
|
||||
tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
|
||||
tkFinally, tkFor, tkFrom, tkFunc,
|
||||
|
|
@ -72,7 +72,7 @@ const
|
|||
"tkSymbol",
|
||||
"addr", "and", "as", "asm", "atomic",
|
||||
"bind", "block", "break", "case", "cast",
|
||||
"const", "continue", "converter",
|
||||
"concept", "const", "continue", "converter",
|
||||
"defer", "discard", "distinct", "div", "do",
|
||||
"elif", "else", "end", "enum", "except", "export",
|
||||
"finally", "for", "from", "func", "generic", "if",
|
||||
|
|
|
|||
|
|
@ -1073,8 +1073,10 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
|||
else:
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkGeneric:
|
||||
of tkGeneric, tkConcept:
|
||||
if mode == pmTypeDef:
|
||||
if p.tok.tokType == tkGeneric:
|
||||
parMessage(p, warnDeprecated, "use 'concept' instead; 'generic'")
|
||||
result = parseTypeClass(p)
|
||||
else:
|
||||
parMessage(p, errInvalidToken, p.tok)
|
||||
|
|
@ -1107,7 +1109,7 @@ proc parseTypeDesc(p: var TParser): PNode =
|
|||
|
||||
proc parseTypeDefAux(p: var TParser): PNode =
|
||||
#| typeDefAux = simpleExpr
|
||||
#| | 'generic' typeClass
|
||||
#| | 'concept' typeClass
|
||||
result = simpleExpr(p, pmTypeDef)
|
||||
|
||||
proc makeCall(n: PNode): PNode =
|
||||
|
|
|
|||
|
|
@ -725,7 +725,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
|||
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
|
||||
var c: TContext
|
||||
initContext(c)
|
||||
putWithSpace(g, tkGeneric, "generic")
|
||||
putWithSpace(g, tkConcept, "concept")
|
||||
gsons(g, n[0], c) # arglist
|
||||
gsub(g, n[1]) # pragmas
|
||||
gsub(g, n[2]) # of
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ type
|
|||
wInvalid,
|
||||
|
||||
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,
|
||||
wElif, wElse, wEnd, wEnum, wExcept, wExport,
|
||||
wFinally, wFor, wFrom, wFunc, wGeneric, wIf, wImport, wIn,
|
||||
|
|
@ -103,7 +103,7 @@ const
|
|||
|
||||
"addr", "and", "as", "asm", "atomic",
|
||||
"bind", "block", "break", "case", "cast",
|
||||
"const", "continue", "converter",
|
||||
"concept", "const", "continue", "converter",
|
||||
"defer", "discard", "distinct", "div", "do",
|
||||
"elif", "else", "end", "enum", "except", "export",
|
||||
"finally", "for", "from", "func", "generic", "if",
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ identOrLiteral = generalizedLit | symbol | literal
|
|||
tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||
arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
|
||||
primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||
| doBlocks
|
||||
| '.' optInd symbol generalizedLit?
|
||||
| '[' optInd indexExprList optPar ']'
|
||||
| '{' optInd indexExprList optPar '}'
|
||||
| &( '`'|IDENT|literal|'cast') expr # command syntax
|
||||
| doBlocks
|
||||
| '.' optInd symbol generalizedLit?
|
||||
| '[' optInd indexExprList optPar ']'
|
||||
| '{' optInd indexExprList optPar '}'
|
||||
| &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
|
||||
condExpr = expr colcom expr optInd
|
||||
('elif' expr colcom expr optInd)*
|
||||
'else' colcom expr
|
||||
|
|
@ -94,7 +94,7 @@ primary = typeKeyw typeDescK
|
|||
/ 'bind' primary
|
||||
typeDesc = simpleExpr
|
||||
typeDefAux = simpleExpr
|
||||
| 'generic' typeClass
|
||||
| 'concept' typeClass
|
||||
macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
||||
| IND{=} 'elif' expr ':' stmt
|
||||
| IND{=} 'except' exprList ':' stmt
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
addr and as asm atomic
|
||||
bind block break
|
||||
case cast const continue converter
|
||||
case cast concept const continue converter
|
||||
defer discard distinct div do
|
||||
elif else end enum except export
|
||||
finally for from func
|
||||
|
|
|
|||
|
|
@ -203,34 +203,34 @@ be inferred to have the equivalent of the `any` type class and thus they will
|
|||
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
|
||||
imperative. Both are used to specify an arbitrary set of requirements that the
|
||||
matched type must satisfy.
|
||||
Concepts, also known as "user-defined type classes", are available in two
|
||||
flavours - declarative and imperative. Both are used to specify an arbitrary
|
||||
set of requirements that the matched type must satisfy.
|
||||
|
||||
Declarative type classes are written in the following form:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Comparable = generic x, y
|
||||
Comparable = concept x, y
|
||||
(x < y) is bool
|
||||
|
||||
Container[T] = generic c
|
||||
Container[T] = concept c
|
||||
c.len is ordinal
|
||||
items(c) is iterator
|
||||
for value in c:
|
||||
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
|
||||
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,
|
||||
when used in contexts where a value is expected, and as the type itself when
|
||||
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
|
||||
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
|
||||
the designated type for overload resolution purposes, unless the type value was
|
||||
passed in its explicit ``typedesc[T]`` form:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
OutputStream = generic S
|
||||
OutputStream = concept S
|
||||
write(var S, string)
|
||||
|
||||
Much like generics, the user defined type classes will be instantiated exactly
|
||||
once for each tested type and any static code included within them will also be
|
||||
Much like generics, concepts are instantiated exactly
|
||||
once for each tested type and any static code included within them is also
|
||||
executed once.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ static[T]
|
|||
|
||||
**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
|
||||
|
||||
|
|
@ -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
|
||||
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:
|
||||
|
||||
.. code-block:: nim
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ const
|
|||
# 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.
|
||||
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",
|
||||
"elif", "else", "end", "enum", "except", "export",
|
||||
"finally", "for", "from", "func",
|
||||
|
|
@ -554,10 +554,12 @@ when isMainModule:
|
|||
var keywords: seq[string]
|
||||
# Try to work running in both the subdir or at the root.
|
||||
for filename in ["doc/keywords.txt", "../../../doc/keywords.txt"]:
|
||||
except: echo filename, " not found"
|
||||
let input = string(readFile(filename))
|
||||
keywords = input.split()
|
||||
break
|
||||
try:
|
||||
let input = string(readFile(filename))
|
||||
keywords = input.split()
|
||||
break
|
||||
except:
|
||||
echo filename, " not found"
|
||||
doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!")
|
||||
doAssert keywords.len == nimKeywords.len, "No matching lengths"
|
||||
for i in 0..keywords.len-1:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ template reject(e: expr) =
|
|||
static: assert(not compiles(e))
|
||||
|
||||
type
|
||||
Container[T] = generic C
|
||||
Container[T] = concept C
|
||||
C.len is Ordinal
|
||||
items(c) is iterator
|
||||
for value in C:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ proc isSwizzle(s: string): bool {.compileTime.} =
|
|||
return false
|
||||
|
||||
type
|
||||
StringIsSwizzle = generic value
|
||||
StringIsSwizzle = concept value
|
||||
value.isSwizzle
|
||||
|
||||
SwizzleStr = static[string] and StringIsSwizzle
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ type
|
|||
TObj = object
|
||||
x: int
|
||||
|
||||
Sortable = generic x, y
|
||||
Sortable = concept x, y
|
||||
(x < y) is bool
|
||||
|
||||
ObjectContainer = generic C
|
||||
ObjectContainer = concept C
|
||||
C.len is Ordinal
|
||||
for v in items(C):
|
||||
v.type is tuple|object
|
||||
|
|
@ -38,7 +38,7 @@ proc intval(x: int): int = 10
|
|||
|
||||
# check real and virtual fields
|
||||
type
|
||||
TFoo = generic T
|
||||
TFoo = concept T
|
||||
T.x
|
||||
y(T)
|
||||
intval T.y
|
||||
|
|
@ -50,7 +50,7 @@ proc testFoo(x: TFoo) = discard
|
|||
testFoo(TObj(x: 10))
|
||||
|
||||
type
|
||||
Matrix[Rows, Cols: static[int]; T] = generic M
|
||||
Matrix[Rows, Cols: static[int]; T] = concept M
|
||||
M.M == Rows
|
||||
M.N == Cols
|
||||
M.T is T
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
type
|
||||
hasFieldX = generic z
|
||||
hasFieldX = concept z
|
||||
z.x is int
|
||||
|
||||
obj_x = object
|
||||
|
|
|
|||
3
todo.txt
3
todo.txt
|
|
@ -5,6 +5,7 @@ version 0.10.4
|
|||
- improve GC-unsafety warnings
|
||||
- make 'nil' work for 'add' and 'len'
|
||||
- add "all threads are blocked" detection to 'spawn'
|
||||
- overloading of '='
|
||||
|
||||
|
||||
version 1.0
|
||||
|
|
@ -17,8 +18,6 @@ version 1.0
|
|||
- The bitwise 'not' operator will be renamed to 'bnot' to
|
||||
prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
|
||||
- iterators always require a return type
|
||||
- overloading of '='
|
||||
|
||||
- make nimble part of the distribution
|
||||
- split docgen into separate tool
|
||||
- special rule for ``[]=``, items, pairs
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ News
|
|||
and not as ``type((x).name)``. Note that this also affects the AST
|
||||
structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
|
||||
produced instead of ``nkAddr('x')``.
|
||||
|
||||
- ``concept`` is now a keyword and is used instead of ``generic``.
|
||||
|
||||
|
||||
Language Additions
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue