Merge branch 'type-classes' into upstream
This commit is contained in:
commit
6082595e96
27 changed files with 594 additions and 249 deletions
|
|
@ -178,6 +178,7 @@ type
|
||||||
nkIncludeStmt, # an include statement
|
nkIncludeStmt, # an include statement
|
||||||
nkBindStmt, # a bind statement
|
nkBindStmt, # a bind statement
|
||||||
nkMixinStmt, # a mixin statement
|
nkMixinStmt, # a mixin statement
|
||||||
|
nkUsingStmt, # an using statement
|
||||||
nkCommentStmt, # a comment statement
|
nkCommentStmt, # a comment statement
|
||||||
nkStmtListExpr, # a statement list followed by an expr; this is used
|
nkStmtListExpr, # a statement list followed by an expr; this is used
|
||||||
# to allow powerful multi-line templates
|
# to allow powerful multi-line templates
|
||||||
|
|
@ -190,6 +191,7 @@ type
|
||||||
nkTypeOfExpr, # type(1+2)
|
nkTypeOfExpr, # type(1+2)
|
||||||
nkObjectTy, # object body
|
nkObjectTy, # object body
|
||||||
nkTupleTy, # tuple body
|
nkTupleTy, # tuple body
|
||||||
|
nkTypeClassTy, # user-defined type class
|
||||||
nkRecList, # list of object parts
|
nkRecList, # list of object parts
|
||||||
nkRecCase, # case section of object
|
nkRecCase, # case section of object
|
||||||
nkRecWhen, # when section of object
|
nkRecWhen, # when section of object
|
||||||
|
|
@ -215,7 +217,7 @@ type
|
||||||
TNodeKinds* = set[TNodeKind]
|
TNodeKinds* = set[TNodeKind]
|
||||||
|
|
||||||
type
|
type
|
||||||
TSymFlag* = enum # already 30 flags!
|
TSymFlag* = enum # already 32 flags!
|
||||||
sfUsed, # read access of sym (for warnings) or simply used
|
sfUsed, # read access of sym (for warnings) or simply used
|
||||||
sfExported, # symbol is exported from module
|
sfExported, # symbol is exported from module
|
||||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||||
|
|
@ -352,6 +354,8 @@ type
|
||||||
# efficiency
|
# efficiency
|
||||||
nfTransf, # node has been transformed
|
nfTransf, # node has been transformed
|
||||||
nfSem # node has been checked for semantics
|
nfSem # node has been checked for semantics
|
||||||
|
nfDelegate # the call can use a delegator
|
||||||
|
nfExprCall # this is an attempt to call a regular expression
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23)
|
||||||
|
|
@ -616,6 +620,7 @@ type
|
||||||
TScope* = object
|
TScope* = object
|
||||||
depthLevel*: int
|
depthLevel*: int
|
||||||
symbols*: TStrTable
|
symbols*: TStrTable
|
||||||
|
usingSyms*: seq[PNode]
|
||||||
parent*: PScope
|
parent*: PScope
|
||||||
|
|
||||||
PScope* = ref TScope
|
PScope* = ref TScope
|
||||||
|
|
@ -688,6 +693,7 @@ type
|
||||||
# for enum types a list of symbols
|
# for enum types a list of symbols
|
||||||
# for tyInt it can be the int literal
|
# for tyInt it can be the int literal
|
||||||
# for procs and tyGenericBody, it's the
|
# for procs and tyGenericBody, it's the
|
||||||
|
# the body of the user-defined type class
|
||||||
# formal param list
|
# formal param list
|
||||||
# else: unused
|
# else: unused
|
||||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||||
|
|
@ -700,6 +706,7 @@ type
|
||||||
# -1 means that the size is unkwown
|
# -1 means that the size is unkwown
|
||||||
align*: int # the type's alignment requirements
|
align*: int # the type's alignment requirements
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
|
testeeName*: PIdent # the test variable in user-defined type classes
|
||||||
|
|
||||||
TPair*{.final.} = object
|
TPair*{.final.} = object
|
||||||
key*, val*: PObject
|
key*, val*: PObject
|
||||||
|
|
@ -771,7 +778,8 @@ const
|
||||||
tyProc, tyString, tyError}
|
tyProc, tyString, tyError}
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||||
|
nfAllConst, nfDelegate}
|
||||||
namePos* = 0
|
namePos* = 0
|
||||||
patternPos* = 1 # empty except for term rewriting macros
|
patternPos* = 1 # empty except for term rewriting macros
|
||||||
genericParamsPos* = 2
|
genericParamsPos* = 2
|
||||||
|
|
@ -1074,6 +1082,7 @@ proc assignType(dest, src: PType) =
|
||||||
dest.size = src.size
|
dest.size = src.size
|
||||||
dest.align = src.align
|
dest.align = src.align
|
||||||
dest.destructor = src.destructor
|
dest.destructor = src.destructor
|
||||||
|
dest.testeeName = src.testeeName
|
||||||
# this fixes 'type TLock = TSysLock':
|
# this fixes 'type TLock = TSysLock':
|
||||||
if src.sym != nil:
|
if src.sym != nil:
|
||||||
if dest.sym != nil:
|
if dest.sym != nil:
|
||||||
|
|
|
||||||
|
|
@ -431,10 +431,13 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
||||||
appf(result, "$N$1}", [spaces(indent)])
|
appf(result, "$N$1}", [spaces(indent)])
|
||||||
|
|
||||||
proc debug(n: PSym) =
|
proc debug(n: PSym) =
|
||||||
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
if n == nil:
|
||||||
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
|
writeln(stdout, "null")
|
||||||
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
|
else:
|
||||||
flagsToStr(n.loc.flags)])))
|
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
||||||
|
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [
|
||||||
|
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
|
||||||
|
flagsToStr(n.loc.flags)])))
|
||||||
|
|
||||||
proc debug(n: PType) =
|
proc debug(n: PType) =
|
||||||
writeln(stdout, ropeToStr(debugType(n)))
|
writeln(stdout, ropeToStr(debugType(n)))
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ type
|
||||||
features: TSandboxFlags
|
features: TSandboxFlags
|
||||||
globals*: TIdNodeTable # state of global vars
|
globals*: TIdNodeTable # state of global vars
|
||||||
getType*: proc(n: PNode): PNode {.closure.}
|
getType*: proc(n: PNode): PNode {.closure.}
|
||||||
|
handleIsOperator*: proc(n: PNode): PNode {.closure.}
|
||||||
|
|
||||||
PEvalContext* = ref TEvalContext
|
PEvalContext* = ref TEvalContext
|
||||||
|
|
||||||
|
|
@ -916,33 +917,6 @@ proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
proc evalIsOp*(n: PNode): PNode =
|
|
||||||
InternalAssert n.sonsLen == 3 and
|
|
||||||
n[1].kind == nkSym and n[1].sym.kind == skType and
|
|
||||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
|
||||||
|
|
||||||
let t1 = n[1].sym.typ
|
|
||||||
|
|
||||||
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
|
||||||
case n[2].strVal.normalize
|
|
||||||
of "closure":
|
|
||||||
let t = skipTypes(t1, abstractRange)
|
|
||||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
|
||||||
t.callConv == ccClosure and
|
|
||||||
tfIterator notin t.flags))
|
|
||||||
of "iterator":
|
|
||||||
let t = skipTypes(t1, abstractRange)
|
|
||||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
|
||||||
t.callConv == ccClosure and
|
|
||||||
tfIterator in t.flags))
|
|
||||||
else:
|
|
||||||
let t2 = n[2].typ
|
|
||||||
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
|
|
||||||
else: sameType(t1, t2)
|
|
||||||
result = newIntNode(nkIntLit, ord(match))
|
|
||||||
|
|
||||||
result.typ = n.typ
|
|
||||||
|
|
||||||
proc expectString(n: PNode) =
|
proc expectString(n: PNode) =
|
||||||
if n.kind notin nkStrKinds:
|
if n.kind notin nkStrKinds:
|
||||||
GlobalError(n.info, errStringLiteralExpected)
|
GlobalError(n.info, errStringLiteralExpected)
|
||||||
|
|
@ -1038,7 +1012,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
result = evalTypeTrait(n[0], operand, c.module)
|
result = evalTypeTrait(n[0], operand, c.module)
|
||||||
of mIs:
|
of mIs:
|
||||||
n.sons[1] = evalAux(c, n.sons[1], {})
|
n.sons[1] = evalAux(c, n.sons[1], {})
|
||||||
result = evalIsOp(n)
|
result = c.handleIsOperator(n)
|
||||||
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
|
||||||
of mStaticExec:
|
of mStaticExec:
|
||||||
let cmd = evalAux(c, n.sons[1], {})
|
let cmd = evalAux(c, n.sons[1], {})
|
||||||
|
|
@ -1466,8 +1440,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
|
stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
|
||||||
|
|
||||||
proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode =
|
proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode =
|
||||||
var p = newEvalContext(module, mode)
|
|
||||||
var s = newStackFrame()
|
var s = newStackFrame()
|
||||||
s.call = e
|
s.call = e
|
||||||
s.prc = prc
|
s.prc = prc
|
||||||
|
|
@ -1476,12 +1449,6 @@ proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode =
|
||||||
if result != nil and result.kind == nkExceptBranch: result = nil
|
if result != nil and result.kind == nkExceptBranch: result = nil
|
||||||
popStackFrame(p)
|
popStackFrame(p)
|
||||||
|
|
||||||
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
|
||||||
result = evalConstExprAux(module, nil, e, emConst)
|
|
||||||
|
|
||||||
proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
|
|
||||||
result = evalConstExprAux(module, prc, e, emStatic)
|
|
||||||
|
|
||||||
proc setupMacroParam(x: PNode): PNode =
|
proc setupMacroParam(x: PNode): PNode =
|
||||||
result = x
|
result = x
|
||||||
if result.kind == nkHiddenStdConv: result = result.sons[1]
|
if result.kind == nkHiddenStdConv: result = result.sons[1]
|
||||||
|
|
|
||||||
|
|
@ -103,4 +103,5 @@ proc IdentEq*(id: PIdent, name: string): bool =
|
||||||
result = id.id == getIdent(name).id
|
result = id.id == getIdent(name).id
|
||||||
|
|
||||||
var idAnon* = getIdent":anonymous"
|
var idAnon* = getIdent":anonymous"
|
||||||
|
let idDelegator* = getIdent":delegator"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ type
|
||||||
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
||||||
tkIs, tkIsnot, tkIterator,
|
tkIs, tkIsnot, tkIterator,
|
||||||
tkLambda, tkLet,
|
tkLambda, tkLet,
|
||||||
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
|
tkMacro, tkMethod, tkMixin, tkUsing, tkMod, tkNil, tkNot, tkNotin,
|
||||||
tkObject, tkOf, tkOr, tkOut,
|
tkObject, tkOf, tkOr, tkOut,
|
||||||
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic,
|
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic,
|
||||||
tkTemplate,
|
tkTemplate,
|
||||||
|
|
@ -75,7 +75,7 @@ const
|
||||||
"finally", "for", "from", "generic", "if",
|
"finally", "for", "from", "generic", "if",
|
||||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||||
"lambda", "let",
|
"lambda", "let",
|
||||||
"macro", "method", "mixin", "mod",
|
"macro", "method", "mixin", "using", "mod",
|
||||||
"nil", "not", "notin", "object", "of", "or",
|
"nil", "not", "notin", "object", "of", "or",
|
||||||
"out", "proc", "ptr", "raise", "ref", "return",
|
"out", "proc", "ptr", "raise", "ref", "return",
|
||||||
"shared", "shl", "shr", "static",
|
"shared", "shl", "shr", "static",
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ type
|
||||||
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
||||||
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
||||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
|
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
|
||||||
|
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
|
||||||
|
|
||||||
errXExpectsTwoArguments,
|
errXExpectsTwoArguments,
|
||||||
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
|
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
|
||||||
|
|
@ -319,6 +320,8 @@ const
|
||||||
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
|
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
|
||||||
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
|
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
|
||||||
errInstantiateXExplicitely: "instantiate '$1' explicitely",
|
errInstantiateXExplicitely: "instantiate '$1' explicitely",
|
||||||
|
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
|
||||||
|
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
|
||||||
errXExpectsTwoArguments: "\'$1\' expects two arguments",
|
errXExpectsTwoArguments: "\'$1\' expects two arguments",
|
||||||
errXExpectsObjectTypes: "\'$1\' expects object types",
|
errXExpectsObjectTypes: "\'$1\' expects object types",
|
||||||
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
|
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
|
||||||
|
|
|
||||||
|
|
@ -927,9 +927,10 @@ proc parseExpr(p: var TParser): PNode =
|
||||||
of tkTry: result = parseTry(p)
|
of tkTry: result = parseTry(p)
|
||||||
else: result = simpleExpr(p)
|
else: result = simpleExpr(p)
|
||||||
|
|
||||||
|
proc parseEnum(p: var TParser): PNode
|
||||||
proc parseObject(p: var TParser): PNode
|
proc parseObject(p: var TParser): PNode
|
||||||
proc parseDistinct(p: var TParser): PNode
|
proc parseDistinct(p: var TParser): PNode
|
||||||
proc parseEnum(p: var TParser): PNode
|
proc parseTypeClass(p: var TParser): PNode
|
||||||
|
|
||||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
#| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
|
#| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
|
||||||
|
|
@ -959,6 +960,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
|
of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
|
||||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
|
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
|
||||||
of tkShared: result = parseTypeDescKAux(p, nkSharedTy, mode)
|
of tkShared: result = parseTypeDescKAux(p, nkSharedTy, mode)
|
||||||
|
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
|
||||||
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
|
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
|
||||||
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
||||||
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||||
|
|
@ -983,12 +985,11 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
else:
|
else:
|
||||||
result = newNodeP(nkObjectTy, p)
|
result = newNodeP(nkObjectTy, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
of tkDistinct:
|
of tkGeneric:
|
||||||
if mode == pmTypeDef:
|
if mode == pmTypeDef:
|
||||||
result = parseDistinct(p)
|
result = parseTypeClass(p)
|
||||||
else:
|
else:
|
||||||
result = newNodeP(nkDistinctTy, p)
|
parMessage(p, errInvalidToken, p.tok)
|
||||||
getTok(p)
|
|
||||||
of tkAddr:
|
of tkAddr:
|
||||||
result = newNodeP(nkAddr, p)
|
result = newNodeP(nkAddr, p)
|
||||||
getTokNoInd(p)
|
getTokNoInd(p)
|
||||||
|
|
@ -1612,6 +1613,32 @@ proc parseObject(p: var TParser): PNode =
|
||||||
return
|
return
|
||||||
addSon(result, parseObjectPart(p))
|
addSon(result, parseObjectPart(p))
|
||||||
|
|
||||||
|
proc parseTypeClass(p: var TParser): PNode =
|
||||||
|
result = newNodeP(nkTypeClassTy, p)
|
||||||
|
getTok(p)
|
||||||
|
addSon(result, p.parseSymbol)
|
||||||
|
if p.tok.tokType == tkCurlyDotLe and p.validInd:
|
||||||
|
addSon(result, parsePragma(p))
|
||||||
|
else:
|
||||||
|
addSon(result, ast.emptyNode)
|
||||||
|
if p.tok.tokType == tkOf and p.tok.indent < 0:
|
||||||
|
var a = newNodeP(nkOfInherit, p)
|
||||||
|
getTok(p)
|
||||||
|
while true:
|
||||||
|
addSon(a, parseTypeDesc(p))
|
||||||
|
if p.tok.tokType != tkComma: break
|
||||||
|
getTok(p)
|
||||||
|
addSon(result, a)
|
||||||
|
else:
|
||||||
|
addSon(result, ast.emptyNode)
|
||||||
|
if p.tok.tokType == tkComment:
|
||||||
|
skipComment(p, result)
|
||||||
|
# an initial IND{>} HAS to follow:
|
||||||
|
if not realInd(p):
|
||||||
|
addSon(result, emptyNode)
|
||||||
|
else:
|
||||||
|
addSon(result, parseStmt(p))
|
||||||
|
|
||||||
proc parseDistinct(p: var TParser): PNode =
|
proc parseDistinct(p: var TParser): PNode =
|
||||||
#| distinct = 'distinct' optInd typeDesc
|
#| distinct = 'distinct' optInd typeDesc
|
||||||
result = newNodeP(nkDistinctTy, p)
|
result = newNodeP(nkDistinctTy, p)
|
||||||
|
|
@ -1747,6 +1774,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||||
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
|
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
|
||||||
of tkBind: result = parseBind(p, nkBindStmt)
|
of tkBind: result = parseBind(p, nkBindStmt)
|
||||||
of tkMixin: result = parseBind(p, nkMixinStmt)
|
of tkMixin: result = parseBind(p, nkMixinStmt)
|
||||||
|
of tkUsing: result = parseBind(p, nkUsingStmt)
|
||||||
else: result = simpleStmt(p)
|
else: result = simpleStmt(p)
|
||||||
|
|
||||||
proc parseStmt(p: var TParser): PNode =
|
proc parseStmt(p: var TParser): PNode =
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,14 @@ const
|
||||||
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||||
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
||||||
wGenSym, wInject, wRaises, wTags, wOperator}
|
wGenSym, wInject, wRaises, wTags, wOperator, wDelegator}
|
||||||
converterPragmas* = procPragmas
|
converterPragmas* = procPragmas
|
||||||
methodPragmas* = procPragmas
|
methodPragmas* = procPragmas
|
||||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
|
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty,
|
||||||
|
wDelegator}
|
||||||
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
|
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
|
||||||
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
||||||
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
|
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wDelegator}
|
||||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
||||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||||
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
|
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
|
||||||
|
|
|
||||||
|
|
@ -132,14 +132,42 @@ proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||||
LocalError(typ.n.info, errXisNoType, typeToString(typ))
|
LocalError(typ.n.info, errXisNoType, typeToString(typ))
|
||||||
|
|
||||||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
||||||
|
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
|
||||||
|
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||||
|
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
|
||||||
|
proc IsOpImpl(c: PContext, n: PNode): PNode
|
||||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
semCheck: bool = true): PNode
|
semCheck: bool = true): PNode
|
||||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
|
||||||
|
|
||||||
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
|
proc symFromType(t: PType, info: TLineInfo): PSym =
|
||||||
|
if t.sym != nil: return t.sym
|
||||||
|
result = newSym(skType, getIdent"AnonType", t.owner, info)
|
||||||
|
result.flags.incl sfAnon
|
||||||
|
result.typ = t
|
||||||
|
|
||||||
|
proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
|
||||||
|
result = newSymNode(symFromType(t, info), info)
|
||||||
|
result.typ = makeTypeDesc(c, t)
|
||||||
|
|
||||||
|
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
|
||||||
|
result = newEvalContext(c.module, mode)
|
||||||
|
result.getType = proc (n: PNode): PNode =
|
||||||
|
var e = tryExpr(c, n)
|
||||||
|
if e == nil:
|
||||||
|
result = symNodeFromType(c, errorType(c), n.info)
|
||||||
|
elif e.typ == nil:
|
||||||
|
result = newSymNode(getSysSym"void")
|
||||||
|
else:
|
||||||
|
result = symNodeFromType(c, e.typ, n.info)
|
||||||
|
|
||||||
|
result.handleIsOperator = proc (n: PNode): PNode =
|
||||||
|
result = IsOpImpl(c, n)
|
||||||
|
|
||||||
|
proc evalConstExpr(c: PContext, module: PSym, e: PNode): PNode =
|
||||||
|
result = evalConstExprAux(c.createEvalContext(emConst), module, nil, e)
|
||||||
|
|
||||||
|
proc evalStaticExpr(c: PContext, module: PSym, e: PNode, prc: PSym): PNode =
|
||||||
|
result = evalConstExprAux(c.createEvalContext(emStatic), module, prc, e)
|
||||||
|
|
||||||
proc semConstExpr(c: PContext, n: PNode): PNode =
|
proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
var e = semExprWithType(c, n)
|
var e = semExprWithType(c, n)
|
||||||
|
|
@ -148,7 +176,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
return n
|
return n
|
||||||
result = getConstExpr(c.module, e)
|
result = getConstExpr(c.module, e)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = evalConstExpr(c.module, e)
|
result = evalConstExpr(c, c.module, e)
|
||||||
if result == nil or result.kind == nkEmpty:
|
if result == nil or result.kind == nkEmpty:
|
||||||
if e.info != n.info:
|
if e.info != n.info:
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
|
|
@ -161,16 +189,6 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
include hlo, seminst, semcall
|
include hlo, seminst, semcall
|
||||||
|
|
||||||
proc symFromType(t: PType, info: TLineInfo): PSym =
|
|
||||||
if t.sym != nil: return t.sym
|
|
||||||
result = newSym(skType, getIdent"AnonType", t.owner, info)
|
|
||||||
result.flags.incl sfAnon
|
|
||||||
result.typ = t
|
|
||||||
|
|
||||||
proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
|
|
||||||
result = newSymNode(symFromType(t, info), info)
|
|
||||||
result.typ = makeTypeDesc(c, t)
|
|
||||||
|
|
||||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
inc(evalTemplateCounter)
|
inc(evalTemplateCounter)
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > 100:
|
||||||
|
|
@ -205,15 +223,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||||
|
|
||||||
if c.evalContext == nil:
|
if c.evalContext == nil:
|
||||||
c.evalContext = newEvalContext(c.module, emStatic)
|
c.evalContext = c.createEvalContext(emStatic)
|
||||||
c.evalContext.getType = proc (n: PNode): PNode =
|
|
||||||
var e = tryExpr(c, n)
|
|
||||||
if e == nil:
|
|
||||||
result = symNodeFromType(c, errorType(c), n.info)
|
|
||||||
elif e.typ == nil:
|
|
||||||
result = newSymNode(getSysSym"void")
|
|
||||||
else:
|
|
||||||
result = symNodeFromType(c, e.typ, n.info)
|
|
||||||
|
|
||||||
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
||||||
if semCheck: result = semAfterMacroCall(c, result, sym)
|
if semCheck: result = semAfterMacroCall(c, result, sym)
|
||||||
|
|
@ -250,6 +260,7 @@ proc myOpen(module: PSym): PPassContext =
|
||||||
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
||||||
c.semConstExpr = semConstExpr
|
c.semConstExpr = semConstExpr
|
||||||
c.semExpr = semExpr
|
c.semExpr = semExpr
|
||||||
|
c.semTryExpr = tryExpr
|
||||||
c.semOperand = semOperand
|
c.semOperand = semOperand
|
||||||
c.semConstBoolExpr = semConstBoolExpr
|
c.semConstBoolExpr = semConstBoolExpr
|
||||||
c.semOverloadedCall = semOverloadedCall
|
c.semOverloadedCall = semOverloadedCall
|
||||||
|
|
|
||||||
|
|
@ -34,29 +34,23 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
||||||
|
|
||||||
proc determineType(c: PContext, s: PSym)
|
proc determineType(c: PContext, s: PSym)
|
||||||
|
|
||||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
proc
|
||||||
filter: TSymKinds): TCandidate =
|
pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
var initialBinding: PNode
|
n, orig: PNode,
|
||||||
var f = n.sons[0]
|
initialBinding: PNode,
|
||||||
if f.kind == nkBracketExpr:
|
filter: TSymKinds,
|
||||||
# fill in the bindings:
|
best, alt: var TCandidate,
|
||||||
initialBinding = f
|
errors: var seq[string]) =
|
||||||
f = f.sons[0]
|
var o: TOverloadIter
|
||||||
else:
|
var sym = initOverloadIter(o, c, headSymbol)
|
||||||
initialBinding = nil
|
|
||||||
|
|
||||||
var
|
|
||||||
o: TOverloadIter
|
|
||||||
alt, z: TCandidate
|
|
||||||
|
|
||||||
template best: expr = result
|
|
||||||
#Message(n.info, warnUser, renderTree(n))
|
|
||||||
var sym = initOverloadIter(o, c, f)
|
|
||||||
var symScope = o.lastOverloadScope
|
var symScope = o.lastOverloadScope
|
||||||
|
|
||||||
|
var z: TCandidate
|
||||||
|
|
||||||
if sym == nil: return
|
if sym == nil: return
|
||||||
initCandidate(best, sym, initialBinding, symScope)
|
initCandidate(best, sym, initialBinding, symScope)
|
||||||
initCandidate(alt, sym, initialBinding, symScope)
|
initCandidate(alt, sym, initialBinding, symScope)
|
||||||
|
best.state = csNoMatch
|
||||||
|
|
||||||
while sym != nil:
|
while sym != nil:
|
||||||
if sym.kind in filter:
|
if sym.kind in filter:
|
||||||
|
|
@ -64,6 +58,11 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
|
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
|
||||||
z.calleeSym = sym
|
z.calleeSym = sym
|
||||||
matches(c, n, orig, z)
|
matches(c, n, orig, z)
|
||||||
|
if errors != nil:
|
||||||
|
errors.safeAdd(getProcHeader(sym))
|
||||||
|
if z.errors != nil:
|
||||||
|
for err in z.errors:
|
||||||
|
errors[errors.len - 1].add("\n " & err)
|
||||||
if z.state == csMatch:
|
if z.state == csMatch:
|
||||||
# little hack so that iterators are preferred over everything else:
|
# little hack so that iterators are preferred over everything else:
|
||||||
if sym.kind == skIterator: inc(z.exactMatches, 200)
|
if sym.kind == skIterator: inc(z.exactMatches, 200)
|
||||||
|
|
@ -74,17 +73,100 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
if cmp < 0: best = z # x is better than the best so far
|
if cmp < 0: best = z # x is better than the best so far
|
||||||
elif cmp == 0: alt = z # x is as good as the best so far
|
elif cmp == 0: alt = z # x is as good as the best so far
|
||||||
else: nil
|
else: nil
|
||||||
sym = nextOverloadIter(o, c, f)
|
sym = nextOverloadIter(o, c, headSymbol)
|
||||||
|
|
||||||
if best.state == csEmpty:
|
proc NotFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||||
# no overloaded proc found
|
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||||
# do not generate an error yet; the semantic checking will check for
|
# as semOverlodedCall is already pretty slow (and we need this information
|
||||||
# an overloaded () operator
|
# only in case of an error).
|
||||||
elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
|
if c.InCompilesContext > 0:
|
||||||
not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
|
# fail fast:
|
||||||
if best.state != csMatch:
|
GlobalError(n.info, errTypeMismatch, "")
|
||||||
InternalError(n.info, "x.state is not csMatch")
|
var result = msgKindToString(errTypeMismatch)
|
||||||
#writeMatches(best)
|
add(result, describeArgs(c, n, 1 + ord(nfDelegate in n.flags)))
|
||||||
|
add(result, ')')
|
||||||
|
|
||||||
|
var candidates = ""
|
||||||
|
for err in errors:
|
||||||
|
add(candidates, err)
|
||||||
|
add(candidates, "\n")
|
||||||
|
|
||||||
|
if candidates != "":
|
||||||
|
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||||
|
|
||||||
|
LocalError(n.Info, errGenerated, result)
|
||||||
|
|
||||||
|
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
|
||||||
|
for scope in walkScopes(c.currentScope):
|
||||||
|
if scope.usingSyms != nil:
|
||||||
|
for s in scope.usingSyms: usedSyms.safeAdd(s)
|
||||||
|
|
||||||
|
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
|
filter: TSymKinds): TCandidate =
|
||||||
|
var initialBinding: PNode
|
||||||
|
var alt: TCandidate
|
||||||
|
var f = n.sons[0]
|
||||||
|
if f.kind == nkBracketExpr:
|
||||||
|
# fill in the bindings:
|
||||||
|
initialBinding = f
|
||||||
|
f = f.sons[0]
|
||||||
|
else:
|
||||||
|
initialBinding = nil
|
||||||
|
|
||||||
|
var errors: seq[string]
|
||||||
|
var usedSyms: seq[PNode]
|
||||||
|
|
||||||
|
template pickBest(headSymbol: expr) =
|
||||||
|
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||||
|
filter, result, alt, errors)
|
||||||
|
|
||||||
|
gatherUsedSyms(c, usedSyms)
|
||||||
|
if usedSyms != nil:
|
||||||
|
var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
|
||||||
|
else: usedSyms[0]
|
||||||
|
|
||||||
|
n.sons.insert(hiddenArg, 1)
|
||||||
|
orig.sons.insert(hiddenArg, 1)
|
||||||
|
|
||||||
|
pickBest(f)
|
||||||
|
|
||||||
|
if result.state != csMatch:
|
||||||
|
n.sons.delete(1)
|
||||||
|
orig.sons.delete(1)
|
||||||
|
else: return
|
||||||
|
|
||||||
|
pickBest(f)
|
||||||
|
|
||||||
|
let overloadsState = result.state
|
||||||
|
if overloadsState != csMatch:
|
||||||
|
if nfDelegate in n.flags:
|
||||||
|
InternalAssert f.kind == nkIdent
|
||||||
|
let calleeName = newStrNode(nkStrLit, f.ident.s)
|
||||||
|
calleeName.info = n.info
|
||||||
|
|
||||||
|
let callOp = newIdentNode(idDelegator, n.info)
|
||||||
|
n.sons[0..0] = [callOp, calleeName]
|
||||||
|
orig.sons[0..0] = [callOp, calleeName]
|
||||||
|
|
||||||
|
pickBest(callOp)
|
||||||
|
|
||||||
|
if overloadsState == csEmpty and result.state == csEmpty:
|
||||||
|
LocalError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
|
||||||
|
return
|
||||||
|
elif result.state != csMatch:
|
||||||
|
if nfExprCall in n.flags:
|
||||||
|
LocalError(n.info, errExprXCannotBeCalled,
|
||||||
|
renderTree(n, {renderNoComments}))
|
||||||
|
else:
|
||||||
|
errors = @[]
|
||||||
|
pickBest(f)
|
||||||
|
NotFoundError(c, n, errors)
|
||||||
|
return
|
||||||
|
|
||||||
|
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
|
||||||
|
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
|
||||||
|
InternalAssert result.state == csMatch
|
||||||
|
#writeMatches(result)
|
||||||
#writeMatches(alt)
|
#writeMatches(alt)
|
||||||
if c.inCompilesContext > 0:
|
if c.inCompilesContext > 0:
|
||||||
# quick error message for performance of 'compiles' built-in:
|
# quick error message for performance of 'compiles' built-in:
|
||||||
|
|
@ -98,7 +180,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
add(args, ")")
|
add(args, ")")
|
||||||
|
|
||||||
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
|
||||||
args])
|
args])
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -155,6 +237,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||||
filter: TSymKinds): PNode =
|
filter: TSymKinds): PNode =
|
||||||
var r = resolveOverloads(c, n, nOrig, filter)
|
var r = resolveOverloads(c, n, nOrig, filter)
|
||||||
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
||||||
|
# else: result = errorNode(c, n)
|
||||||
|
|
||||||
proc explicitGenericInstError(n: PNode): PNode =
|
proc explicitGenericInstError(n: PNode): PNode =
|
||||||
LocalError(n.info, errCannotInstantiateX, renderTree(n))
|
LocalError(n.info, errCannotInstantiateX, renderTree(n))
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ type
|
||||||
libs*: TLinkedList # all libs used by this module
|
libs*: TLinkedList # all libs used by this module
|
||||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
|
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||||
|
|
@ -204,6 +205,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||||
result = newTypeS(tyTypeDesc, c)
|
result = newTypeS(tyTypeDesc, c)
|
||||||
result.addSonSkipIntLit(typ.AssertNotNil)
|
result.addSonSkipIntLit(typ.AssertNotNil)
|
||||||
|
|
||||||
|
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||||
|
let typedesc = makeTypeDesc(c, typ)
|
||||||
|
let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
|
||||||
|
return newSymNode(sym, info)
|
||||||
|
|
||||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||||
result = newType(kind, getCurrOwner())
|
result = newType(kind, getCurrOwner())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,11 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
|
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
|
||||||
# do not skip the range!
|
# do not skip the range!
|
||||||
n.typ = n.sons[1].typ.skipTypes(abstractVar)
|
n.typ = n.sons[1].typ.skipTypes(abstractVar)
|
||||||
else: LocalError(n.info, errInvalidArgForX, opToStr[m])
|
of tyGenericParam:
|
||||||
|
# leave it for now, it will be resolved in semtypinst
|
||||||
|
n.typ = getSysType(tyInt)
|
||||||
|
else:
|
||||||
|
LocalError(n.info, errInvalidArgForX, opToStr[m])
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc semSizeof(c: PContext, n: PNode): PNode =
|
proc semSizeof(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -295,6 +299,39 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||||
n.typ = getSysType(tyBool)
|
n.typ = getSysType(tyBool)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
proc IsOpImpl(c: PContext, n: PNode): PNode =
|
||||||
|
InternalAssert n.sonsLen == 3 and
|
||||||
|
n[1].kind == nkSym and n[1].sym.kind == skType and
|
||||||
|
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||||
|
|
||||||
|
let t1 = n[1].sym.typ.skipTypes({tyTypeDesc})
|
||||||
|
|
||||||
|
if n[2].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
|
case n[2].strVal.normalize
|
||||||
|
of "closure":
|
||||||
|
let t = skipTypes(t1, abstractRange)
|
||||||
|
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||||
|
t.callConv == ccClosure and
|
||||||
|
tfIterator notin t.flags))
|
||||||
|
of "iterator":
|
||||||
|
let t = skipTypes(t1, abstractRange)
|
||||||
|
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||||
|
t.callConv == ccClosure and
|
||||||
|
tfIterator in t.flags))
|
||||||
|
else:
|
||||||
|
var match: bool
|
||||||
|
let t2 = n[2].typ
|
||||||
|
if t2.kind == tyTypeClass:
|
||||||
|
var m: TCandidate
|
||||||
|
InitCandidate(m, t2)
|
||||||
|
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
||||||
|
else:
|
||||||
|
match = sameType(t1, t2)
|
||||||
|
|
||||||
|
result = newIntNode(nkIntLit, ord(match))
|
||||||
|
|
||||||
|
result.typ = n.typ
|
||||||
|
|
||||||
proc semIs(c: PContext, n: PNode): PNode =
|
proc semIs(c: PContext, n: PNode): PNode =
|
||||||
if sonsLen(n) != 3:
|
if sonsLen(n) != 3:
|
||||||
LocalError(n.info, errXExpectsTwoArguments, "is")
|
LocalError(n.info, errXExpectsTwoArguments, "is")
|
||||||
|
|
@ -303,20 +340,20 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||||
n.typ = getSysType(tyBool)
|
n.typ = getSysType(tyBool)
|
||||||
|
|
||||||
n.sons[1] = semExprWithType(c, n[1], {efDetermineType})
|
n.sons[1] = semExprWithType(c, n[1], {efDetermineType})
|
||||||
if n[1].typ.kind != tyTypeDesc:
|
|
||||||
LocalError(n[0].info, errTypeExpected)
|
|
||||||
|
|
||||||
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
|
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
|
||||||
let t2 = semTypeNode(c, n[2], nil)
|
let t2 = semTypeNode(c, n[2], nil)
|
||||||
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
|
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
|
||||||
|
|
||||||
if n[1].typ.sonsLen == 0:
|
if n[1].typ.kind != tyTypeDesc:
|
||||||
|
n.sons[1] = makeTypeSymNode(c, n[1].typ, n[1].info)
|
||||||
|
elif n[1].typ.sonsLen == 0:
|
||||||
# this is a typedesc variable, leave for evals
|
# this is a typedesc variable, leave for evals
|
||||||
return
|
return
|
||||||
else:
|
|
||||||
let t1 = n[1].typ.sons[0]
|
let t1 = n[1].typ.sons[0]
|
||||||
# BUGFIX: don't evaluate this too early: ``T is void``
|
# BUGFIX: don't evaluate this too early: ``T is void``
|
||||||
if not containsGenericType(t1): result = evalIsOp(n)
|
if not containsGenericType(t1): result = IsOpImpl(c, n)
|
||||||
|
|
||||||
proc semOpAux(c: PContext, n: PNode) =
|
proc semOpAux(c: PContext, n: PNode) =
|
||||||
const flags = {efDetermineType}
|
const flags = {efDetermineType}
|
||||||
|
|
@ -594,18 +631,18 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
call.add(a)
|
call.add(a)
|
||||||
#echo "NOW evaluating at compile time: ", call.renderTree
|
#echo "NOW evaluating at compile time: ", call.renderTree
|
||||||
if sfCompileTime in callee.flags:
|
if sfCompileTime in callee.flags:
|
||||||
result = evalStaticExpr(c.module, call, c.p.owner)
|
result = evalStaticExpr(c, c.module, call, c.p.owner)
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(call))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(call))
|
||||||
else:
|
else:
|
||||||
result = evalConstExpr(c.module, call)
|
result = evalConstExpr(c, c.module, call)
|
||||||
if result.isNil: result = n
|
if result.isNil: result = n
|
||||||
#if result != n:
|
#if result != n:
|
||||||
# echo "SUCCESS evaluated at compile time: ", call.renderTree
|
# echo "SUCCESS evaluated at compile time: ", call.renderTree
|
||||||
|
|
||||||
proc semStaticExpr(c: PContext, n: PNode): PNode =
|
proc semStaticExpr(c: PContext, n: PNode): PNode =
|
||||||
let a = semExpr(c, n.sons[0])
|
let a = semExpr(c, n.sons[0])
|
||||||
result = evalStaticExpr(c.module, a, c.p.owner)
|
result = evalStaticExpr(c, c.module, a, c.p.owner)
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
|
|
@ -649,7 +686,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = n.sons[0]
|
result = n.sons[0]
|
||||||
result.kind = nkCall
|
result.kind = nkCall
|
||||||
for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
|
for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
|
||||||
return semExpr(c, result, flags)
|
return semDirectOp(c, result, flags)
|
||||||
else:
|
else:
|
||||||
n.sons[0] = semExpr(c, n.sons[0])
|
n.sons[0] = semExpr(c, n.sons[0])
|
||||||
let nOrig = n.copyTree
|
let nOrig = n.copyTree
|
||||||
|
|
@ -699,14 +736,13 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# Now that nkSym does not imply an iteration over the proc/iterator space,
|
# Now that nkSym does not imply an iteration over the proc/iterator space,
|
||||||
# the old ``prc`` (which is likely an nkIdent) has to be restored:
|
# the old ``prc`` (which is likely an nkIdent) has to be restored:
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
# XXX: hmm, what kind of symbols will end up here?
|
||||||
|
# do we really need to try the overload resolution?
|
||||||
n.sons[0] = prc
|
n.sons[0] = prc
|
||||||
nOrig.sons[0] = prc
|
nOrig.sons[0] = prc
|
||||||
|
n.flags.incl nfExprCall
|
||||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||||
if result == nil:
|
if result == nil: return errorNode(c, n)
|
||||||
if c.inCompilesContext > 0 or gErrorCounter == 0:
|
|
||||||
LocalError(n.info, errExprXCannotBeCalled,
|
|
||||||
renderTree(n, {renderNoComments}))
|
|
||||||
return errorNode(c, n)
|
|
||||||
#result = afterCallActions(c, result, nOrig, flags)
|
#result = afterCallActions(c, result, nOrig, flags)
|
||||||
fixAbstractType(c, result)
|
fixAbstractType(c, result)
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
|
|
@ -734,12 +770,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
let nOrig = n.copyTree
|
let nOrig = n.copyTree
|
||||||
#semLazyOpAux(c, n)
|
#semLazyOpAux(c, n)
|
||||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||||
if result == nil:
|
if result != nil: result = afterCallActions(c, result, nOrig, flags)
|
||||||
result = overloadedCallOpr(c, n)
|
|
||||||
if result == nil:
|
|
||||||
NotFoundError(c, n)
|
|
||||||
return errorNode(c, n)
|
|
||||||
result = afterCallActions(c, result, nOrig, flags)
|
|
||||||
|
|
||||||
proc buildStringify(c: PContext, arg: PNode): PNode =
|
proc buildStringify(c: PContext, arg: PNode): PNode =
|
||||||
if arg.typ != nil and
|
if arg.typ != nil and
|
||||||
|
|
@ -946,19 +977,10 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
|
||||||
addSon(result, copyTree(n[0]))
|
addSon(result, copyTree(n[0]))
|
||||||
else:
|
else:
|
||||||
var i = considerAcc(n.sons[1])
|
var i = considerAcc(n.sons[1])
|
||||||
var f = searchInScopes(c, i)
|
result = newNodeI(nkDotCall, n.info)
|
||||||
# if f != nil and f.kind == skStub: loadStub(f)
|
result.flags.incl nfDelegate
|
||||||
# ``loadStub`` is not correct here as we don't care for ``f`` really
|
addSon(result, newIdentNode(i, n[1].info))
|
||||||
if f != nil:
|
addSon(result, copyTree(n[0]))
|
||||||
# BUGFIX: do not check for (f.kind in {skProc, skMethod, skIterator}) here
|
|
||||||
# This special node kind is to merge with the call handler in `semExpr`.
|
|
||||||
result = newNodeI(nkDotCall, n.info)
|
|
||||||
addSon(result, newIdentNode(i, n[1].info))
|
|
||||||
addSon(result, copyTree(n[0]))
|
|
||||||
else:
|
|
||||||
if not ContainsOrIncl(c.UnknownIdents, i.id):
|
|
||||||
LocalError(n.Info, errUndeclaredFieldX, i.s)
|
|
||||||
result = errorNode(c, n)
|
|
||||||
|
|
||||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# this is difficult, because the '.' is used in many different contexts
|
# this is difficult, because the '.' is used in many different contexts
|
||||||
|
|
@ -1307,6 +1329,22 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
|
||||||
result = newSym(kind, idAnon, owner, info)
|
result = newSym(kind, idAnon, owner, info)
|
||||||
result.flags = {sfGenSym}
|
result.flags = {sfGenSym}
|
||||||
|
|
||||||
|
proc semUsing(c: PContext, n: PNode): PNode =
|
||||||
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
for e in n.sons:
|
||||||
|
let usedSym = semExpr(c, e)
|
||||||
|
if usedSym.kind == nkSym:
|
||||||
|
case usedSym.sym.kind
|
||||||
|
of skLocalVars + {skConst}:
|
||||||
|
c.currentScope.usingSyms.safeAdd(usedSym)
|
||||||
|
continue
|
||||||
|
of skProcKinds:
|
||||||
|
addDeclAt(c.currentScope, usedSym.sym)
|
||||||
|
continue
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
LocalError(e.info, errUsingNoSymbol, e.renderTree)
|
||||||
|
|
||||||
proc semExpandToAst(c: PContext, n: PNode): PNode =
|
proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||||
var macroCall = n[1]
|
var macroCall = n[1]
|
||||||
var expandedSym = expectMacroOrTemplateCall(c, macroCall)
|
var expandedSym = expectMacroOrTemplateCall(c, macroCall)
|
||||||
|
|
@ -1834,7 +1872,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||||
# check if it is an expression macro:
|
# check if it is an expression macro:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
|
let mode = if nfDelegate in n.flags: {} else: {checkUndeclared}
|
||||||
|
var s = qualifiedLookup(c, n.sons[0], mode)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
case s.kind
|
case s.kind
|
||||||
of skMacro:
|
of skMacro:
|
||||||
|
|
@ -1868,6 +1907,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and
|
elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and
|
||||||
isSymChoice(n[0][0]):
|
isSymChoice(n[0][0]):
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
|
elif nfDelegate in n.flags:
|
||||||
|
result = semDirectOp(c, n, flags)
|
||||||
else:
|
else:
|
||||||
result = semIndirectOp(c, n, flags)
|
result = semIndirectOp(c, n, flags)
|
||||||
of nkWhen:
|
of nkWhen:
|
||||||
|
|
@ -1943,6 +1984,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkForStmt, nkParForStmt: result = semFor(c, n)
|
of nkForStmt, nkParForStmt: result = semFor(c, n)
|
||||||
of nkCaseStmt: result = semCase(c, n)
|
of nkCaseStmt: result = semCase(c, n)
|
||||||
of nkReturnStmt: result = semReturn(c, n)
|
of nkReturnStmt: result = semReturn(c, n)
|
||||||
|
of nkUsingStmt: result = semUsing(c, n)
|
||||||
of nkAsmStmt: result = semAsm(c, n)
|
of nkAsmStmt: result = semAsm(c, n)
|
||||||
of nkYieldStmt: result = semYield(c, n)
|
of nkYieldStmt: result = semYield(c, n)
|
||||||
of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
|
of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
|
||||||
|
|
@ -1974,4 +2016,4 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errInvalidExpressionX,
|
LocalError(n.info, errInvalidExpressionX,
|
||||||
renderTree(n, {renderNoComments}))
|
renderTree(n, {renderNoComments}))
|
||||||
incl(result.flags, nfSem)
|
if result != nil: incl(result.flags, nfSem)
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
result.typ = getSysType(tyString)
|
result.typ = getSysType(tyString)
|
||||||
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
||||||
of mOrd: result = semOrd(c, n)
|
of mOrd: result = semOrd(c, n)
|
||||||
|
of mHigh: result = semLowHigh(c, n, mHigh)
|
||||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||||
of mNBindSym: result = semBindSym(c, n)
|
of mNBindSym: result = semBindSym(c, n)
|
||||||
of mLocals: result = semLocals(c, n)
|
of mLocals: result = semLocals(c, n)
|
||||||
|
|
|
||||||
|
|
@ -838,7 +838,14 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||||
let m = lookupMacro(c, key)
|
let m = lookupMacro(c, key)
|
||||||
if m == nil: continue
|
if m == nil:
|
||||||
|
if key.kind == nkIdent and key.ident.id == ord(wDelegator):
|
||||||
|
if considerAcc(prc.sons[namePos]).s == "()":
|
||||||
|
prc.sons[namePos] = newIdentNode(idDelegator, prc.info)
|
||||||
|
prc.sons[pragmasPos] = copyExcept(n, i)
|
||||||
|
else:
|
||||||
|
LocalError(prc.info, errOnlyACallOpCanBeDelegator)
|
||||||
|
continue
|
||||||
# we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and
|
# we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and
|
||||||
# let the semantic checker deal with it:
|
# let the semantic checker deal with it:
|
||||||
var x = newNodeI(nkCall, n.info)
|
var x = newNodeI(nkCall, n.info)
|
||||||
|
|
@ -1147,7 +1154,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
let a = semStmt(c, n.sons[0])
|
let a = semStmt(c, n.sons[0])
|
||||||
result = evalStaticExpr(c.module, a, c.p.owner)
|
result = evalStaticExpr(c, c.module, a, c.p.owner)
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
|
|
|
||||||
|
|
@ -608,7 +608,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
if genericParams.sons[i].sym.name.id == finalTypId.id:
|
if genericParams.sons[i].sym.name.id == finalTypId.id:
|
||||||
return genericParams.sons[i].typ
|
return genericParams.sons[i].typ
|
||||||
|
|
||||||
var s = newSym(skType, finalTypId, getCurrOwner(), info)
|
var s = newSym(skType, finalTypId, typeClass.sym, info)
|
||||||
if typId == nil: s.flags.incl(sfAnon)
|
if typId == nil: s.flags.incl(sfAnon)
|
||||||
s.linkTo(typeClass)
|
s.linkTo(typeClass)
|
||||||
s.position = genericParams.len
|
s.position = genericParams.len
|
||||||
|
|
@ -871,6 +871,21 @@ proc freshType(res, prev: PType): PType {.inline.} =
|
||||||
else:
|
else:
|
||||||
result = res
|
result = res
|
||||||
|
|
||||||
|
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
||||||
|
result = newOrPrevType(tyTypeClass, prev, c)
|
||||||
|
result.testeeName = considerAcc(n[0])
|
||||||
|
result.n = n[3]
|
||||||
|
|
||||||
|
let
|
||||||
|
pragmas = n[1]
|
||||||
|
inherited = n[2]
|
||||||
|
|
||||||
|
if inherited.kind != nkEmpty:
|
||||||
|
for n in inherited.sons:
|
||||||
|
let typ = semTypeNode(c, n, nil)
|
||||||
|
result.sons.safeAdd(typ)
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
|
|
@ -973,6 +988,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||||
of nkTupleTy: result = semTuple(c, n, prev)
|
of nkTupleTy: result = semTuple(c, n, prev)
|
||||||
|
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||||
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
||||||
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||||
of nkVarTy: result = semVarType(c, n, prev)
|
of nkVarTy: result = semVarType(c, n, prev)
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
header.sons[i] = x
|
header.sons[i] = x
|
||||||
propagateToOwner(header, x)
|
propagateToOwner(header, x)
|
||||||
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
||||||
|
|
||||||
if header != nil:
|
if header != nil:
|
||||||
# search again after first pass:
|
# search again after first pass:
|
||||||
result = searchInstTypes(header)
|
result = searchInstTypes(header)
|
||||||
|
|
@ -200,6 +201,9 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = lookupTypeVar(cl, t)
|
result = lookupTypeVar(cl, t)
|
||||||
if result.kind == tyGenericInvokation:
|
if result.kind == tyGenericInvokation:
|
||||||
result = handleGenericInvokation(cl, result)
|
result = handleGenericInvokation(cl, result)
|
||||||
|
of tyExpr:
|
||||||
|
if t.sym != nil and t.sym.kind == skGenericParam:
|
||||||
|
result = lookupTypeVar(cl, t)
|
||||||
of tyGenericInvokation:
|
of tyGenericInvokation:
|
||||||
result = handleGenericInvokation(cl, t)
|
result = handleGenericInvokation(cl, t)
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ type
|
||||||
# be instantiated
|
# be instantiated
|
||||||
typedescMatched: bool
|
typedescMatched: bool
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
errors*: seq[string] # additional clarifications to be displayed to the
|
||||||
|
# user if overload resolution fails
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible,
|
isNone, isConvertible,
|
||||||
|
|
@ -200,28 +202,6 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||||
add(result, argTypeToString(arg))
|
add(result, argTypeToString(arg))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
proc NotFoundError*(c: PContext, n: PNode) =
|
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
|
||||||
# as semOverlodedCall is already pretty slow (and we need this information
|
|
||||||
# only in case of an error).
|
|
||||||
if c.InCompilesContext > 0:
|
|
||||||
# fail fast:
|
|
||||||
GlobalError(n.info, errTypeMismatch, "")
|
|
||||||
var result = msgKindToString(errTypeMismatch)
|
|
||||||
add(result, describeArgs(c, n))
|
|
||||||
add(result, ')')
|
|
||||||
var candidates = ""
|
|
||||||
var o: TOverloadIter
|
|
||||||
var sym = initOverloadIter(o, c, n.sons[0])
|
|
||||||
while sym != nil:
|
|
||||||
if sym.kind in RoutineKinds:
|
|
||||||
add(candidates, getProcHeader(sym))
|
|
||||||
add(candidates, "\n")
|
|
||||||
sym = nextOverloadIter(o, c, n.sons[0])
|
|
||||||
if candidates != "":
|
|
||||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
|
||||||
LocalError(n.Info, errGenerated, result)
|
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
|
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
|
|
@ -643,7 +623,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
result = matchTypeClass(c, f, a)
|
if a.kind == tyTypeClass:
|
||||||
|
result = isGeneric
|
||||||
|
else:
|
||||||
|
result = matchTypeClass(c, f, a)
|
||||||
|
|
||||||
if result == isGeneric:
|
if result == isGeneric:
|
||||||
var concrete = concreteType(c, a)
|
var concrete = concreteType(c, a)
|
||||||
|
|
@ -754,32 +737,90 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||||
m.baseTypeMatch = true
|
m.baseTypeMatch = true
|
||||||
|
|
||||||
|
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
|
arg: PNode, f, a: PType): PNode =
|
||||||
|
if f.n == nil:
|
||||||
|
let r = typeRel(m, f, a)
|
||||||
|
return if r == isGeneric: arg else: nil
|
||||||
|
|
||||||
|
var prev = PType(idTableGet(m.bindings, f))
|
||||||
|
if prev != nil:
|
||||||
|
if sameType(prev, a): return arg
|
||||||
|
else: return nil
|
||||||
|
|
||||||
|
# pushInfoContext(arg.info)
|
||||||
|
openScope(c)
|
||||||
|
|
||||||
|
var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info)
|
||||||
|
testee.typ = a
|
||||||
|
addDecl(c, testee)
|
||||||
|
|
||||||
|
for stmt in f.n:
|
||||||
|
var e = c.semTryExpr(c, copyTree(stmt))
|
||||||
|
if e == nil:
|
||||||
|
let expStr = renderTree(stmt, {renderNoComments})
|
||||||
|
m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString)
|
||||||
|
return nil
|
||||||
|
case e.kind
|
||||||
|
of nkReturnStmt:
|
||||||
|
nil
|
||||||
|
of nkTypeSection: nil
|
||||||
|
of nkConstDef: nil
|
||||||
|
else:
|
||||||
|
if e.typ.kind == tyBool:
|
||||||
|
let verdict = c.semConstExpr(c, e)
|
||||||
|
if verdict.intVal == 0:
|
||||||
|
let expStr = renderTree(stmt, {renderNoComments})
|
||||||
|
m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
closeScope(c)
|
||||||
|
|
||||||
|
result = arg
|
||||||
|
put(m.bindings, f, a)
|
||||||
|
|
||||||
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
arg, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
|
var arg = argSemantized
|
||||||
var r: TTypeRelation
|
var r: TTypeRelation
|
||||||
let fMaybeExpr = f.skipTypes({tyDistinct})
|
let fMaybeExpr = f.skipTypes({tyDistinct})
|
||||||
if fMaybeExpr.kind == tyExpr:
|
case fMaybeExpr.kind
|
||||||
|
of tyExpr:
|
||||||
if fMaybeExpr.sonsLen == 0:
|
if fMaybeExpr.sonsLen == 0:
|
||||||
r = isGeneric
|
r = isGeneric
|
||||||
else:
|
else:
|
||||||
let match = matchTypeClass(m, fMaybeExpr, a)
|
if a.kind == tyExpr:
|
||||||
if match != isGeneric: r = isNone
|
InternalAssert a.len > 0
|
||||||
|
r = typeRel(m, f.lastSon, a.lastSon)
|
||||||
else:
|
else:
|
||||||
# XXX: Ideally, this should happen much earlier somewhere near
|
let match = matchTypeClass(m, fMaybeExpr, a)
|
||||||
# semOpAux, but to do that, we need to be able to query the
|
if match != isGeneric: r = isNone
|
||||||
# overload set to determine whether compile-time value is expected
|
else:
|
||||||
# for the param before entering the full-blown sigmatch algorithm.
|
# XXX: Ideally, this should happen much earlier somewhere near
|
||||||
# This is related to the immediate pragma since querying the
|
# semOpAux, but to do that, we need to be able to query the
|
||||||
# overload set could help there too.
|
# overload set to determine whether compile-time value is expected
|
||||||
var evaluated = c.semConstExpr(c, arg)
|
# for the param before entering the full-blown sigmatch algorithm.
|
||||||
if evaluated != nil:
|
# This is related to the immediate pragma since querying the
|
||||||
r = isGeneric
|
# overload set could help there too.
|
||||||
arg.typ = newTypeS(tyExpr, c)
|
var evaluated = c.semConstExpr(c, arg)
|
||||||
arg.typ.sons = @[evaluated.typ]
|
if evaluated != nil:
|
||||||
arg.typ.n = evaluated
|
r = isGeneric
|
||||||
|
arg.typ = newTypeS(tyExpr, c)
|
||||||
|
arg.typ.sons = @[evaluated.typ]
|
||||||
|
arg.typ.n = evaluated
|
||||||
|
|
||||||
if r == isGeneric:
|
if r == isGeneric:
|
||||||
put(m.bindings, f, arg.typ)
|
put(m.bindings, f, arg.typ)
|
||||||
|
of tyTypeClass:
|
||||||
|
if fMaybeExpr.n != nil:
|
||||||
|
let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a)
|
||||||
|
if match != nil:
|
||||||
|
r = isGeneric
|
||||||
|
arg = match
|
||||||
|
else:
|
||||||
|
r = isNone
|
||||||
|
else:
|
||||||
|
r = typeRel(m, f, a)
|
||||||
else:
|
else:
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -445,6 +445,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
if t.len == 0: result = "typedesc"
|
if t.len == 0: result = "typedesc"
|
||||||
else: result = "typedesc[" & constraintsToStr(t) & "]"
|
else: result = "typedesc[" & constraintsToStr(t) & "]"
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
|
if t.n != nil: return t.sym.owner.name.s
|
||||||
case t.len
|
case t.len
|
||||||
of 0: result = "typeclass[]"
|
of 0: result = "typeclass[]"
|
||||||
of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]"
|
of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ type
|
||||||
wElif, wElse, wEnd, wEnum, wExcept, wExport,
|
wElif, wElse, wEnd, wEnum, wExcept, wExport,
|
||||||
wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn,
|
wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn,
|
||||||
wInclude, wInterface, wIs, wIsnot, wIterator, wLambda, wLet,
|
wInclude, wInterface, wIs, wIsnot, wIterator, wLambda, wLet,
|
||||||
wMacro, wMethod, wMixin, wMod, wNil,
|
wMacro, wMethod, wMixin, wUsing, wMod, wNil,
|
||||||
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
|
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
|
||||||
wShared, wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wVar,
|
wShared, wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wVar,
|
||||||
wWhen, wWhile, wWith, wWithout, wXor, wYield,
|
wWhen, wWhile, wWith, wWithout, wXor, wYield,
|
||||||
|
|
@ -39,7 +39,8 @@ type
|
||||||
|
|
||||||
wDestroy,
|
wDestroy,
|
||||||
|
|
||||||
wImmediate, wDestructor, wImportCpp, wImportObjC,
|
wImmediate, wDestructor, wDelegator,
|
||||||
|
wImportCpp, wImportObjC,
|
||||||
wImportCompilerProc,
|
wImportCompilerProc,
|
||||||
wImportc, wExportc, wIncompleteStruct, wRequiresInit,
|
wImportc, wExportc, wIncompleteStruct, wRequiresInit,
|
||||||
wAlign, wNodecl, wPure, wSideeffect, wHeader,
|
wAlign, wNodecl, wPure, wSideeffect, wHeader,
|
||||||
|
|
@ -71,7 +72,7 @@ type
|
||||||
wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
|
wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
|
||||||
wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
|
wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
|
||||||
wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
|
wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
|
||||||
wUnion, wUnsigned, wUsing, wVirtual, wVoid, wVolatile, wWchar_t,
|
wUnion, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t,
|
||||||
|
|
||||||
wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
|
wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
|
||||||
wThread_local, wStatic_assert, wChar16_t, wChar32_t,
|
wThread_local, wStatic_assert, wChar16_t, wChar32_t,
|
||||||
|
|
@ -94,7 +95,7 @@ const
|
||||||
|
|
||||||
cppNimSharedKeywords* = {
|
cppNimSharedKeywords* = {
|
||||||
wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
|
wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
|
||||||
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile}
|
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing }
|
||||||
|
|
||||||
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
|
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
|
||||||
|
|
||||||
|
|
@ -106,7 +107,7 @@ const
|
||||||
"finally", "for", "from", "generic", "if",
|
"finally", "for", "from", "generic", "if",
|
||||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||||
"lambda", "let",
|
"lambda", "let",
|
||||||
"macro", "method", "mixin", "mod", "nil", "not", "notin",
|
"macro", "method", "mixin", "using", "mod", "nil", "not", "notin",
|
||||||
"object", "of", "or",
|
"object", "of", "or",
|
||||||
"out", "proc", "ptr", "raise", "ref", "return",
|
"out", "proc", "ptr", "raise", "ref", "return",
|
||||||
"shared", "shl", "shr", "static",
|
"shared", "shl", "shr", "static",
|
||||||
|
|
@ -120,7 +121,8 @@ const
|
||||||
|
|
||||||
"destroy",
|
"destroy",
|
||||||
|
|
||||||
"immediate", "destructor", "importcpp", "importobjc",
|
"immediate", "destructor", "delegator",
|
||||||
|
"importcpp", "importobjc",
|
||||||
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
||||||
"requiresinit", "align", "nodecl", "pure", "sideeffect",
|
"requiresinit", "align", "nodecl", "pure", "sideeffect",
|
||||||
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
|
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
|
||||||
|
|
@ -152,7 +154,7 @@ const
|
||||||
"private", "protected", "public", "register", "reinterpret_cast",
|
"private", "protected", "public", "register", "reinterpret_cast",
|
||||||
"short", "signed", "sizeof", "static_cast", "struct", "switch",
|
"short", "signed", "sizeof", "static_cast", "struct", "switch",
|
||||||
"this", "throw", "true", "typedef", "typeid",
|
"this", "throw", "true", "typedef", "typeid",
|
||||||
"typename", "union", "unsigned", "using", "virtual", "void", "volatile",
|
"typename", "union", "unsigned", "virtual", "void", "volatile",
|
||||||
"wchar_t",
|
"wchar_t",
|
||||||
|
|
||||||
"alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept",
|
"alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ finally for from
|
||||||
generic
|
generic
|
||||||
if import in include interface is isnot iterator
|
if import in include interface is isnot iterator
|
||||||
lambda let
|
lambda let
|
||||||
macro method mixin mod
|
macro method mixin using mod
|
||||||
nil not notin
|
nil not notin
|
||||||
object of or out
|
object of or out
|
||||||
proc ptr
|
proc ptr
|
||||||
|
|
|
||||||
130
doc/manual.txt
130
doc/manual.txt
|
|
@ -2166,6 +2166,39 @@ specified in the statement's pragmas. The default special character is ``'`'``:
|
||||||
theEnd:
|
theEnd:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
Using statement
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The using statement provides syntactic convenience for procs that heavily use a
|
||||||
|
single contextual parameter. When applied to a variable or a constant, it will
|
||||||
|
instruct Nimrod to automatically consider the used symbol as a hidden leading
|
||||||
|
parameter for any procedure calls, following the using statement in the current
|
||||||
|
scope. Thus, it behaves much like the hidden `this` parameter available in some
|
||||||
|
object-oriented programming languages.
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
var s = socket()
|
||||||
|
using s
|
||||||
|
|
||||||
|
connect(host, port)
|
||||||
|
send(data)
|
||||||
|
|
||||||
|
while true:
|
||||||
|
let line = readLine(timeout)
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
When applied to a callable symbol, it brings the designated symbol in the
|
||||||
|
current scope. Thus, it can be used to disambiguate between imported symbols
|
||||||
|
from different modules having the same name.
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
import windows, sdl
|
||||||
|
using sdl.SetTimer
|
||||||
|
|
||||||
|
|
||||||
If expression
|
If expression
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
@ -3191,14 +3224,69 @@ the dot syntax:
|
||||||
proc `[]`(m: TMatrix, row, col: int): TMatrix.T =
|
proc `[]`(m: TMatrix, row, col: int): TMatrix.T =
|
||||||
m.data[col * high(TMatrix.Columns) + row]
|
m.data[col * high(TMatrix.Columns) + row]
|
||||||
|
|
||||||
If anonymous type classes are used, the ``type`` operator can be used to
|
Alternatively, the `type` operator can be used over the proc params for similar
|
||||||
discover the instantiated type of each param.
|
effect when anonymous or distinct type classes are used.
|
||||||
|
|
||||||
|
When a generic type is instantiated with a type class instead of a concrete
|
||||||
|
type, this results in another more specific type class:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
seq[ref object] # Any sequence storing references to any object type
|
||||||
|
|
||||||
|
type T1 = auto
|
||||||
|
proc foo(s: seq[T1], e: T1)
|
||||||
|
# seq[T1] is the same as just `seq`, but T1 will be allowed to bind
|
||||||
|
# to a single type, while the signature is being matched
|
||||||
|
|
||||||
|
TMatrix[Ordinal] # Any TMatrix instantiation using integer values
|
||||||
|
|
||||||
|
As seen in the previous example, in such instantiations, it's not necessary to
|
||||||
|
supply all type parameters of the generic type, because any missing ones will
|
||||||
|
be inferred to have the equivalent of the `any` type class and thus they will
|
||||||
|
match anything without discrimination.
|
||||||
|
|
||||||
|
|
||||||
User defined type classes
|
User defined type classes
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
To be written.
|
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.
|
||||||
|
|
||||||
|
Declarative type classes are written in the following form:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type
|
||||||
|
Comparable = generic x, y
|
||||||
|
(x < y) is bool
|
||||||
|
|
||||||
|
Container[T] = generic c
|
||||||
|
c.len is ordinal
|
||||||
|
items(c) is iterator
|
||||||
|
for value in c:
|
||||||
|
type(value) is T
|
||||||
|
|
||||||
|
|
||||||
|
The identifiers following the `generic` keyword are treated as variables of
|
||||||
|
the matched type and the body of the type class consists of arbitrary code that
|
||||||
|
must be valid under these circumstances.
|
||||||
|
|
||||||
|
Specifically, the type class 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
|
||||||
|
|
||||||
|
Please note that the `is` operator allows you to easily verify the precise 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 doesn't reveal implementation details.
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
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
|
||||||
|
executed once.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Return Type Inference
|
Return Type Inference
|
||||||
|
|
@ -3910,7 +3998,7 @@ the ordinary AST predicates:
|
||||||
template ex{a = b + c}(a: int{noalias}, b, c: int) =
|
template ex{a = b + c}(a: int{noalias}, b, c: int) =
|
||||||
# this transformation is only valid if 'b' and 'c' do not alias 'a':
|
# this transformation is only valid if 'b' and 'c' do not alias 'a':
|
||||||
a = b
|
a = b
|
||||||
inc a, b
|
inc a, c
|
||||||
|
|
||||||
|
|
||||||
Pattern operators
|
Pattern operators
|
||||||
|
|
@ -4412,6 +4500,40 @@ be destructed at its scope exit. Later versions of the language will improve
|
||||||
the support of destructors.
|
the support of destructors.
|
||||||
|
|
||||||
|
|
||||||
|
delegator pragma
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The delegator pragma can be used to intercept and rewrite proc call and field
|
||||||
|
access attempts referring to previously undeclared symbol names. It can be used
|
||||||
|
to provide a fluent interface to objects lying outside the static confines of
|
||||||
|
the Nimrod's type system such as values from dynamic scripting languages or
|
||||||
|
dynamic file formats such as JSON or XML.
|
||||||
|
|
||||||
|
A delegator is a special form of the `()` operator marked with the delagator
|
||||||
|
pragma. When Nimrod encounters an expression that cannot be resolved by the
|
||||||
|
standard overload resolution, any delegators in the current scope will be
|
||||||
|
matched against a rewritten form of the expression following the standard
|
||||||
|
signature matching rules. In the rewritten expression, the name of the unknown
|
||||||
|
proc or field name is inserted as an additional static string parameter always
|
||||||
|
appearing in the leading position:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
a.b => delegator("b", a)
|
||||||
|
a.b(c, d) => delegator("b", a, c)
|
||||||
|
a b, c, d => delegator("a", b, c, d)
|
||||||
|
|
||||||
|
|
||||||
|
The delegators can be any callable symbol type (procs, templates, macros)
|
||||||
|
depending on the desired effect:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc `()` (field: string, js: PJsonNode): JSON {.delegator.} = js[field]
|
||||||
|
|
||||||
|
var js = parseJson("{ x: 1, y: 2}")
|
||||||
|
echo js.x # outputs 1
|
||||||
|
echo js.y # outputs 2
|
||||||
|
|
||||||
|
|
||||||
procvar pragma
|
procvar pragma
|
||||||
--------------
|
--------------
|
||||||
The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
|
The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,10 @@ type
|
||||||
nnkFromStmt,
|
nnkFromStmt,
|
||||||
nnkIncludeStmt,
|
nnkIncludeStmt,
|
||||||
|
|
||||||
nnkBindStmt, nnkMixinStmt,
|
nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
|
||||||
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
nnkTupleTy, nnkTypeClassTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||||
nnkConstTy, nnkMutableTy,
|
nnkConstTy, nnkMutableTy,
|
||||||
nnkDistinctTy,
|
nnkDistinctTy,
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,26 @@
|
||||||
discard """
|
|
||||||
output: '''obj has '==': false
|
|
||||||
int has '==': true
|
|
||||||
false
|
|
||||||
true
|
|
||||||
true
|
|
||||||
no'''
|
|
||||||
"""
|
|
||||||
|
|
||||||
# test the new 'compiles' feature:
|
# test the new 'compiles' feature:
|
||||||
|
|
||||||
template supports(opr, x: expr): bool {.immediate.} =
|
template supports(opr, x: expr): bool {.immediate.} =
|
||||||
compiles(opr(x)) or compiles(opr(x, x))
|
compiles(opr(x)) or compiles(opr(x, x))
|
||||||
|
|
||||||
|
template ok(x: expr): stmt =
|
||||||
|
static: assert(x)
|
||||||
|
|
||||||
|
template no(x: expr): stmt =
|
||||||
|
static: assert(not x)
|
||||||
|
|
||||||
type
|
type
|
||||||
TObj = object
|
TObj = object
|
||||||
|
|
||||||
var
|
var
|
||||||
myObj {.compileTime.}: TObj
|
myObj {.compileTime.}: TObj
|
||||||
|
|
||||||
echo "obj has '==': ", supports(`==`, myObj)
|
ok supports(`==`, myObj)
|
||||||
echo "int has '==': ", supports(`==`, 45)
|
ok supports(`==`, 45)
|
||||||
|
|
||||||
echo supports(`++`, 34)
|
no supports(`++`, 34)
|
||||||
echo supports(`not`, true)
|
ok supports(`not`, true)
|
||||||
echo supports(`+`, 34)
|
ok supports(`+`, 34)
|
||||||
|
|
||||||
|
no compiles(4+5.0 * "hallo")
|
||||||
|
|
||||||
when compiles(4+5.0 * "hallo"):
|
|
||||||
echo "yes"
|
|
||||||
else:
|
|
||||||
echo "no"
|
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,3 @@ var
|
||||||
|
|
||||||
a() #ERROR_MSG expression 'a()' cannot be called
|
a() #ERROR_MSG expression 'a()' cannot be called
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
file: "topaque.nim"
|
file: "topaque.nim"
|
||||||
line: 16
|
line: 16
|
||||||
errormsg: "undeclared field: \'buffer\'"
|
errormsg: "undeclared identifier: \'buffer\'"
|
||||||
"""
|
"""
|
||||||
# Test the new opaque types
|
# Test the new opaque types
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
discard """
|
discard """
|
||||||
file: "twrongtupleaccess.nim"
|
file: "twrongtupleaccess.nim"
|
||||||
line: 9
|
line: 9
|
||||||
errormsg: "undeclared field: \'setBLAH\'"
|
errormsg: "undeclared identifier: \'setBLAH\'"
|
||||||
"""
|
"""
|
||||||
# Bugfix
|
# Bugfix
|
||||||
|
|
||||||
var v = (5.0, 10.0)
|
var v = (5.0, 10.0)
|
||||||
v.setBLAH(10)
|
v.setBLAH(10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,11 @@ Language Additions
|
||||||
- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
|
- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
|
||||||
``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
|
``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
|
||||||
- Added ``requiresInit`` pragma to enforce explicit initialization.
|
- Added ``requiresInit`` pragma to enforce explicit initialization.
|
||||||
|
- Added ``using statement`` for better authoring domain-specific languages and
|
||||||
|
OOP-like syntactic sugar.
|
||||||
|
- Added ``delegator pragma`` for handling calls to missing procs and fields at
|
||||||
|
compile-time.
|
||||||
|
- Support for user-defined type classes have been added.
|
||||||
|
|
||||||
|
|
||||||
2013-05-20 New website design!
|
2013-05-20 New website design!
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue