mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
Merge branch 'type-classes' into upstream
This commit is contained in:
@@ -178,6 +178,7 @@ type
|
||||
nkIncludeStmt, # an include statement
|
||||
nkBindStmt, # a bind statement
|
||||
nkMixinStmt, # a mixin statement
|
||||
nkUsingStmt, # an using statement
|
||||
nkCommentStmt, # a comment statement
|
||||
nkStmtListExpr, # a statement list followed by an expr; this is used
|
||||
# to allow powerful multi-line templates
|
||||
@@ -190,6 +191,7 @@ type
|
||||
nkTypeOfExpr, # type(1+2)
|
||||
nkObjectTy, # object body
|
||||
nkTupleTy, # tuple body
|
||||
nkTypeClassTy, # user-defined type class
|
||||
nkRecList, # list of object parts
|
||||
nkRecCase, # case section of object
|
||||
nkRecWhen, # when section of object
|
||||
@@ -215,7 +217,7 @@ type
|
||||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # already 30 flags!
|
||||
TSymFlag* = enum # already 32 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
sfExported, # symbol is exported from module
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
@@ -352,6 +354,8 @@ type
|
||||
# efficiency
|
||||
nfTransf, # node has been transformed
|
||||
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]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23)
|
||||
@@ -616,6 +620,7 @@ type
|
||||
TScope* = object
|
||||
depthLevel*: int
|
||||
symbols*: TStrTable
|
||||
usingSyms*: seq[PNode]
|
||||
parent*: PScope
|
||||
|
||||
PScope* = ref TScope
|
||||
@@ -688,6 +693,7 @@ type
|
||||
# for enum types a list of symbols
|
||||
# for tyInt it can be the int literal
|
||||
# for procs and tyGenericBody, it's the
|
||||
# the body of the user-defined type class
|
||||
# formal param list
|
||||
# else: unused
|
||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||
@@ -700,6 +706,7 @@ type
|
||||
# -1 means that the size is unkwown
|
||||
align*: int # the type's alignment requirements
|
||||
loc*: TLoc
|
||||
testeeName*: PIdent # the test variable in user-defined type classes
|
||||
|
||||
TPair*{.final.} = object
|
||||
key*, val*: PObject
|
||||
@@ -771,7 +778,8 @@ const
|
||||
tyProc, tyString, tyError}
|
||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||
nfAllConst, nfDelegate}
|
||||
namePos* = 0
|
||||
patternPos* = 1 # empty except for term rewriting macros
|
||||
genericParamsPos* = 2
|
||||
@@ -1074,6 +1082,7 @@ proc assignType(dest, src: PType) =
|
||||
dest.size = src.size
|
||||
dest.align = src.align
|
||||
dest.destructor = src.destructor
|
||||
dest.testeeName = src.testeeName
|
||||
# this fixes 'type TLock = TSysLock':
|
||||
if src.sym != nil:
|
||||
if dest.sym != nil:
|
||||
|
||||
@@ -430,11 +430,14 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
|
||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
|
||||
proc debug(n: PSym) =
|
||||
#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: PSym) =
|
||||
if n == nil:
|
||||
writeln(stdout, "null")
|
||||
else:
|
||||
#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) =
|
||||
writeln(stdout, ropeToStr(debugType(n)))
|
||||
|
||||
@@ -53,7 +53,8 @@ type
|
||||
features: TSandboxFlags
|
||||
globals*: TIdNodeTable # state of global vars
|
||||
getType*: proc(n: PNode): PNode {.closure.}
|
||||
|
||||
handleIsOperator*: proc(n: PNode): PNode {.closure.}
|
||||
|
||||
PEvalContext* = ref TEvalContext
|
||||
|
||||
TEvalFlag = enum
|
||||
@@ -916,33 +917,6 @@ proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
|
||||
else:
|
||||
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) =
|
||||
if n.kind notin nkStrKinds:
|
||||
GlobalError(n.info, errStringLiteralExpected)
|
||||
@@ -1038,7 +1012,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
result = evalTypeTrait(n[0], operand, c.module)
|
||||
of mIs:
|
||||
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 mStaticExec:
|
||||
let cmd = evalAux(c, n.sons[1], {})
|
||||
@@ -1466,8 +1440,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
|
||||
else:
|
||||
stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
|
||||
|
||||
proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode =
|
||||
var p = newEvalContext(module, mode)
|
||||
proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode =
|
||||
var s = newStackFrame()
|
||||
s.call = e
|
||||
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
|
||||
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 =
|
||||
result = x
|
||||
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
|
||||
|
||||
var idAnon* = getIdent":anonymous"
|
||||
let idDelegator* = getIdent":delegator"
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ type
|
||||
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
||||
tkIs, tkIsnot, tkIterator,
|
||||
tkLambda, tkLet,
|
||||
tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
|
||||
tkMacro, tkMethod, tkMixin, tkUsing, tkMod, tkNil, tkNot, tkNotin,
|
||||
tkObject, tkOf, tkOr, tkOut,
|
||||
tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic,
|
||||
tkTemplate,
|
||||
@@ -75,7 +75,7 @@ const
|
||||
"finally", "for", "from", "generic", "if",
|
||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||
"lambda", "let",
|
||||
"macro", "method", "mixin", "mod",
|
||||
"macro", "method", "mixin", "using", "mod",
|
||||
"nil", "not", "notin", "object", "of", "or",
|
||||
"out", "proc", "ptr", "raise", "ref", "return",
|
||||
"shared", "shl", "shr", "static",
|
||||
|
||||
@@ -92,6 +92,7 @@ type
|
||||
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
||||
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
|
||||
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
|
||||
|
||||
errXExpectsTwoArguments,
|
||||
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
|
||||
@@ -319,6 +320,8 @@ const
|
||||
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
|
||||
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
|
||||
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",
|
||||
errXExpectsObjectTypes: "\'$1\' expects object types",
|
||||
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
|
||||
|
||||
@@ -927,9 +927,10 @@ proc parseExpr(p: var TParser): PNode =
|
||||
of tkTry: result = parseTry(p)
|
||||
else: result = simpleExpr(p)
|
||||
|
||||
proc parseEnum(p: var TParser): PNode
|
||||
proc parseObject(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 =
|
||||
#| 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 tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
|
||||
of tkShared: result = parseTypeDescKAux(p, nkSharedTy, mode)
|
||||
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
|
||||
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
|
||||
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
|
||||
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
|
||||
@@ -983,12 +985,11 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
else:
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkDistinct:
|
||||
of tkGeneric:
|
||||
if mode == pmTypeDef:
|
||||
result = parseDistinct(p)
|
||||
result = parseTypeClass(p)
|
||||
else:
|
||||
result = newNodeP(nkDistinctTy, p)
|
||||
getTok(p)
|
||||
parMessage(p, errInvalidToken, p.tok)
|
||||
of tkAddr:
|
||||
result = newNodeP(nkAddr, p)
|
||||
getTokNoInd(p)
|
||||
@@ -1612,6 +1613,32 @@ proc parseObject(p: var TParser): PNode =
|
||||
return
|
||||
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 =
|
||||
#| distinct = 'distinct' optInd typeDesc
|
||||
result = newNodeP(nkDistinctTy, p)
|
||||
@@ -1747,6 +1774,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
|
||||
of tkBind: result = parseBind(p, nkBindStmt)
|
||||
of tkMixin: result = parseBind(p, nkMixinStmt)
|
||||
of tkUsing: result = parseBind(p, nkUsingStmt)
|
||||
else: result = simpleStmt(p)
|
||||
|
||||
proc parseStmt(p: var TParser): PNode =
|
||||
|
||||
@@ -24,13 +24,14 @@ const
|
||||
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
||||
wGenSym, wInject, wRaises, wTags, wOperator}
|
||||
wGenSym, wInject, wRaises, wTags, wOperator, wDelegator}
|
||||
converterPragmas* = procPragmas
|
||||
methodPragmas* = procPragmas
|
||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
|
||||
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty,
|
||||
wDelegator}
|
||||
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
|
||||
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
||||
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
|
||||
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wDelegator}
|
||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||
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))
|
||||
|
||||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
||||
|
||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
|
||||
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
semCheck: bool = 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,
|
||||
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 =
|
||||
var e = semExprWithType(c, n)
|
||||
@@ -148,7 +176,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
return n
|
||||
result = getConstExpr(c.module, e)
|
||||
if result == nil:
|
||||
result = evalConstExpr(c.module, e)
|
||||
result = evalConstExpr(c, c.module, e)
|
||||
if result == nil or result.kind == nkEmpty:
|
||||
if e.info != n.info:
|
||||
pushInfoContext(n.info)
|
||||
@@ -161,16 +189,6 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
|
||||
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 =
|
||||
inc(evalTemplateCounter)
|
||||
if evalTemplateCounter > 100:
|
||||
@@ -205,15 +223,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||
|
||||
if c.evalContext == nil:
|
||||
c.evalContext = newEvalContext(c.module, 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)
|
||||
c.evalContext = c.createEvalContext(emStatic)
|
||||
|
||||
result = evalMacroCall(c.evalContext, n, nOrig, 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")
|
||||
c.semConstExpr = semConstExpr
|
||||
c.semExpr = semExpr
|
||||
c.semTryExpr = tryExpr
|
||||
c.semOperand = semOperand
|
||||
c.semConstBoolExpr = semConstBoolExpr
|
||||
c.semOverloadedCall = semOverloadedCall
|
||||
|
||||
@@ -34,36 +34,35 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
||||
|
||||
proc determineType(c: PContext, s: PSym)
|
||||
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds): TCandidate =
|
||||
var initialBinding: PNode
|
||||
var f = n.sons[0]
|
||||
if f.kind == nkBracketExpr:
|
||||
# fill in the bindings:
|
||||
initialBinding = f
|
||||
f = f.sons[0]
|
||||
else:
|
||||
initialBinding = nil
|
||||
|
||||
var
|
||||
o: TOverloadIter
|
||||
alt, z: TCandidate
|
||||
|
||||
template best: expr = result
|
||||
#Message(n.info, warnUser, renderTree(n))
|
||||
var sym = initOverloadIter(o, c, f)
|
||||
proc
|
||||
pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
n, orig: PNode,
|
||||
initialBinding: PNode,
|
||||
filter: TSymKinds,
|
||||
best, alt: var TCandidate,
|
||||
errors: var seq[string]) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var symScope = o.lastOverloadScope
|
||||
|
||||
var z: TCandidate
|
||||
|
||||
if sym == nil: return
|
||||
initCandidate(best, sym, initialBinding, symScope)
|
||||
initCandidate(alt, sym, initialBinding, symScope)
|
||||
|
||||
best.state = csNoMatch
|
||||
|
||||
while sym != nil:
|
||||
if sym.kind in filter:
|
||||
determineType(c, sym)
|
||||
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
|
||||
z.calleeSym = sym
|
||||
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:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
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
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
else: nil
|
||||
sym = nextOverloadIter(o, c, f)
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
|
||||
if best.state == csEmpty:
|
||||
# no overloaded proc found
|
||||
# do not generate an error yet; the semantic checking will check for
|
||||
# an overloaded () operator
|
||||
elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
|
||||
not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
|
||||
if best.state != csMatch:
|
||||
InternalError(n.info, "x.state is not csMatch")
|
||||
#writeMatches(best)
|
||||
proc NotFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||
# 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, 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)
|
||||
if c.inCompilesContext > 0:
|
||||
# quick error message for performance of 'compiles' built-in:
|
||||
@@ -98,7 +180,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
add(args, ")")
|
||||
|
||||
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
||||
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
|
||||
args])
|
||||
|
||||
|
||||
@@ -155,6 +237,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds): PNode =
|
||||
var r = resolveOverloads(c, n, nOrig, filter)
|
||||
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
||||
# else: result = errorNode(c, n)
|
||||
|
||||
proc explicitGenericInstError(n: PNode): PNode =
|
||||
LocalError(n.info, errCannotInstantiateX, renderTree(n))
|
||||
|
||||
@@ -72,6 +72,7 @@ type
|
||||
libs*: TLinkedList # all libs used by this module
|
||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
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.}
|
||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||
@@ -204,6 +205,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||
result = newTypeS(tyTypeDesc, c)
|
||||
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 =
|
||||
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:
|
||||
# do not skip the range!
|
||||
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
|
||||
|
||||
proc semSizeof(c: PContext, n: PNode): PNode =
|
||||
@@ -295,6 +299,39 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||
n.typ = getSysType(tyBool)
|
||||
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 =
|
||||
if sonsLen(n) != 3:
|
||||
LocalError(n.info, errXExpectsTwoArguments, "is")
|
||||
@@ -303,21 +340,21 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||
n.typ = getSysType(tyBool)
|
||||
|
||||
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}:
|
||||
let t2 = semTypeNode(c, n[2], nil)
|
||||
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
|
||||
return
|
||||
else:
|
||||
let t1 = n[1].typ.sons[0]
|
||||
# BUGFIX: don't evaluate this too early: ``T is void``
|
||||
if not containsGenericType(t1): result = evalIsOp(n)
|
||||
|
||||
|
||||
let t1 = n[1].typ.sons[0]
|
||||
# BUGFIX: don't evaluate this too early: ``T is void``
|
||||
if not containsGenericType(t1): result = IsOpImpl(c, n)
|
||||
|
||||
proc semOpAux(c: PContext, n: PNode) =
|
||||
const flags = {efDetermineType}
|
||||
for i in countup(1, n.sonsLen-1):
|
||||
@@ -594,18 +631,18 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||
call.add(a)
|
||||
#echo "NOW evaluating at compile time: ", call.renderTree
|
||||
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:
|
||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(call))
|
||||
else:
|
||||
result = evalConstExpr(c.module, call)
|
||||
result = evalConstExpr(c, c.module, call)
|
||||
if result.isNil: result = n
|
||||
#if result != n:
|
||||
# echo "SUCCESS evaluated at compile time: ", call.renderTree
|
||||
|
||||
proc semStaticExpr(c: PContext, n: PNode): PNode =
|
||||
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:
|
||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||
result = emptyNode
|
||||
@@ -649,7 +686,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = n.sons[0]
|
||||
result.kind = nkCall
|
||||
for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
|
||||
return semExpr(c, result, flags)
|
||||
return semDirectOp(c, result, flags)
|
||||
else:
|
||||
n.sons[0] = semExpr(c, n.sons[0])
|
||||
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,
|
||||
# the old ``prc`` (which is likely an nkIdent) has to be restored:
|
||||
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
|
||||
nOrig.sons[0] = prc
|
||||
n.flags.incl nfExprCall
|
||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||
if result == nil:
|
||||
if c.inCompilesContext > 0 or gErrorCounter == 0:
|
||||
LocalError(n.info, errExprXCannotBeCalled,
|
||||
renderTree(n, {renderNoComments}))
|
||||
return errorNode(c, n)
|
||||
if result == nil: return errorNode(c, n)
|
||||
#result = afterCallActions(c, result, nOrig, flags)
|
||||
fixAbstractType(c, result)
|
||||
analyseIfAddressTakenInCall(c, result)
|
||||
@@ -734,12 +770,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
let nOrig = n.copyTree
|
||||
#semLazyOpAux(c, n)
|
||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||
if result == nil:
|
||||
result = overloadedCallOpr(c, n)
|
||||
if result == nil:
|
||||
NotFoundError(c, n)
|
||||
return errorNode(c, n)
|
||||
result = afterCallActions(c, result, nOrig, flags)
|
||||
if result != nil: result = afterCallActions(c, result, nOrig, flags)
|
||||
|
||||
proc buildStringify(c: PContext, arg: PNode): PNode =
|
||||
if arg.typ != nil and
|
||||
@@ -946,20 +977,11 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
|
||||
addSon(result, copyTree(n[0]))
|
||||
else:
|
||||
var i = considerAcc(n.sons[1])
|
||||
var f = searchInScopes(c, i)
|
||||
# if f != nil and f.kind == skStub: loadStub(f)
|
||||
# ``loadStub`` is not correct here as we don't care for ``f`` really
|
||||
if f != nil:
|
||||
# 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)
|
||||
|
||||
result = newNodeI(nkDotCall, n.info)
|
||||
result.flags.incl nfDelegate
|
||||
addSon(result, newIdentNode(i, n[1].info))
|
||||
addSon(result, copyTree(n[0]))
|
||||
|
||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# this is difficult, because the '.' is used in many different contexts
|
||||
# in Nimrod. We first allow types in the semantic checking.
|
||||
@@ -1307,6 +1329,22 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
|
||||
result = newSym(kind, idAnon, owner, info)
|
||||
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 =
|
||||
var macroCall = n[1]
|
||||
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:
|
||||
# check if it is an expression macro:
|
||||
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:
|
||||
case s.kind
|
||||
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
|
||||
isSymChoice(n[0][0]):
|
||||
result = semDirectOp(c, n, flags)
|
||||
elif nfDelegate in n.flags:
|
||||
result = semDirectOp(c, n, flags)
|
||||
else:
|
||||
result = semIndirectOp(c, n, flags)
|
||||
of nkWhen:
|
||||
@@ -1943,6 +1984,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkForStmt, nkParForStmt: result = semFor(c, n)
|
||||
of nkCaseStmt: result = semCase(c, n)
|
||||
of nkReturnStmt: result = semReturn(c, n)
|
||||
of nkUsingStmt: result = semUsing(c, n)
|
||||
of nkAsmStmt: result = semAsm(c, n)
|
||||
of nkYieldStmt: result = semYield(c, n)
|
||||
of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
|
||||
@@ -1974,4 +2016,4 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
else:
|
||||
LocalError(n.info, errInvalidExpressionX,
|
||||
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)
|
||||
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
||||
of mOrd: result = semOrd(c, n)
|
||||
of mHigh: result = semLowHigh(c, n, mHigh)
|
||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mNBindSym: result = semBindSym(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 key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||
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
|
||||
# let the semantic checker deal with it:
|
||||
var x = newNodeI(nkCall, n.info)
|
||||
@@ -1147,7 +1154,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||
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:
|
||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||
result = emptyNode
|
||||
|
||||
@@ -608,7 +608,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
if genericParams.sons[i].sym.name.id == finalTypId.id:
|
||||
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)
|
||||
s.linkTo(typeClass)
|
||||
s.position = genericParams.len
|
||||
@@ -871,6 +871,21 @@ proc freshType(res, prev: PType): PType {.inline.} =
|
||||
else:
|
||||
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 =
|
||||
result = nil
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
@@ -973,6 +988,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
of nkObjectTy: result = semObjectNode(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 nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||
of nkVarTy: result = semVarType(c, n, prev)
|
||||
|
||||
@@ -148,12 +148,13 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
if result != nil: return
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
var x = t.sons[i]
|
||||
if x.kind == tyGenericParam:
|
||||
if x.kind == tyGenericParam:
|
||||
x = lookupTypeVar(cl, x)
|
||||
if header == nil: header = copyType(t, t.owner, false)
|
||||
header.sons[i] = x
|
||||
propagateToOwner(header, x)
|
||||
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
||||
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
||||
|
||||
if header != nil:
|
||||
# search again after first pass:
|
||||
result = searchInstTypes(header)
|
||||
@@ -200,6 +201,9 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||
result = lookupTypeVar(cl, t)
|
||||
if result.kind == tyGenericInvokation:
|
||||
result = handleGenericInvokation(cl, result)
|
||||
of tyExpr:
|
||||
if t.sym != nil and t.sym.kind == skGenericParam:
|
||||
result = lookupTypeVar(cl, t)
|
||||
of tyGenericInvokation:
|
||||
result = handleGenericInvokation(cl, t)
|
||||
of tyGenericBody:
|
||||
|
||||
@@ -40,7 +40,9 @@ type
|
||||
# be instantiated
|
||||
typedescMatched: bool
|
||||
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!
|
||||
isNone, isConvertible,
|
||||
isIntConv,
|
||||
@@ -200,28 +202,6 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||
add(result, argTypeToString(arg))
|
||||
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 concreteType(c: TCandidate, t: PType): PType =
|
||||
case t.kind
|
||||
@@ -643,7 +623,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
else:
|
||||
result = isNone
|
||||
else:
|
||||
result = matchTypeClass(c, f, a)
|
||||
if a.kind == tyTypeClass:
|
||||
result = isGeneric
|
||||
else:
|
||||
result = matchTypeClass(c, f, a)
|
||||
|
||||
if result == isGeneric:
|
||||
var concrete = concreteType(c, a)
|
||||
@@ -754,35 +737,93 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||
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,
|
||||
arg, argOrig: PNode): PNode =
|
||||
argSemantized, argOrig: PNode): PNode =
|
||||
var arg = argSemantized
|
||||
var r: TTypeRelation
|
||||
let fMaybeExpr = f.skipTypes({tyDistinct})
|
||||
if fMaybeExpr.kind == tyExpr:
|
||||
case fMaybeExpr.kind
|
||||
of tyExpr:
|
||||
if fMaybeExpr.sonsLen == 0:
|
||||
r = isGeneric
|
||||
else:
|
||||
let match = matchTypeClass(m, fMaybeExpr, a)
|
||||
if match != isGeneric: r = isNone
|
||||
if a.kind == tyExpr:
|
||||
InternalAssert a.len > 0
|
||||
r = typeRel(m, f.lastSon, a.lastSon)
|
||||
else:
|
||||
# XXX: Ideally, this should happen much earlier somewhere near
|
||||
# semOpAux, but to do that, we need to be able to query the
|
||||
# overload set to determine whether compile-time value is expected
|
||||
# for the param before entering the full-blown sigmatch algorithm.
|
||||
# This is related to the immediate pragma since querying the
|
||||
# overload set could help there too.
|
||||
var evaluated = c.semConstExpr(c, arg)
|
||||
if evaluated != nil:
|
||||
r = isGeneric
|
||||
arg.typ = newTypeS(tyExpr, c)
|
||||
arg.typ.sons = @[evaluated.typ]
|
||||
arg.typ.n = evaluated
|
||||
let match = matchTypeClass(m, fMaybeExpr, a)
|
||||
if match != isGeneric: r = isNone
|
||||
else:
|
||||
# XXX: Ideally, this should happen much earlier somewhere near
|
||||
# semOpAux, but to do that, we need to be able to query the
|
||||
# overload set to determine whether compile-time value is expected
|
||||
# for the param before entering the full-blown sigmatch algorithm.
|
||||
# This is related to the immediate pragma since querying the
|
||||
# overload set could help there too.
|
||||
var evaluated = c.semConstExpr(c, arg)
|
||||
if evaluated != nil:
|
||||
r = isGeneric
|
||||
arg.typ = newTypeS(tyExpr, c)
|
||||
arg.typ.sons = @[evaluated.typ]
|
||||
arg.typ.n = evaluated
|
||||
|
||||
if r == isGeneric:
|
||||
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:
|
||||
r = typeRel(m, f, a)
|
||||
|
||||
|
||||
case r
|
||||
of isConvertible:
|
||||
inc(m.convMatches)
|
||||
|
||||
@@ -445,6 +445,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
if t.len == 0: result = "typedesc"
|
||||
else: result = "typedesc[" & constraintsToStr(t) & "]"
|
||||
of tyTypeClass:
|
||||
if t.n != nil: return t.sym.owner.name.s
|
||||
case t.len
|
||||
of 0: result = "typeclass[]"
|
||||
of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]"
|
||||
|
||||
@@ -28,7 +28,7 @@ type
|
||||
wElif, wElse, wEnd, wEnum, wExcept, wExport,
|
||||
wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn,
|
||||
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,
|
||||
wShared, wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wVar,
|
||||
wWhen, wWhile, wWith, wWithout, wXor, wYield,
|
||||
@@ -39,7 +39,8 @@ type
|
||||
|
||||
wDestroy,
|
||||
|
||||
wImmediate, wDestructor, wImportCpp, wImportObjC,
|
||||
wImmediate, wDestructor, wDelegator,
|
||||
wImportCpp, wImportObjC,
|
||||
wImportCompilerProc,
|
||||
wImportc, wExportc, wIncompleteStruct, wRequiresInit,
|
||||
wAlign, wNodecl, wPure, wSideeffect, wHeader,
|
||||
@@ -71,7 +72,7 @@ type
|
||||
wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
|
||||
wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
|
||||
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,
|
||||
wThread_local, wStatic_assert, wChar16_t, wChar32_t,
|
||||
@@ -94,7 +95,7 @@ const
|
||||
|
||||
cppNimSharedKeywords* = {
|
||||
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] = ["",
|
||||
|
||||
@@ -106,7 +107,7 @@ const
|
||||
"finally", "for", "from", "generic", "if",
|
||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||
"lambda", "let",
|
||||
"macro", "method", "mixin", "mod", "nil", "not", "notin",
|
||||
"macro", "method", "mixin", "using", "mod", "nil", "not", "notin",
|
||||
"object", "of", "or",
|
||||
"out", "proc", "ptr", "raise", "ref", "return",
|
||||
"shared", "shl", "shr", "static",
|
||||
@@ -120,7 +121,8 @@ const
|
||||
|
||||
"destroy",
|
||||
|
||||
"immediate", "destructor", "importcpp", "importobjc",
|
||||
"immediate", "destructor", "delegator",
|
||||
"importcpp", "importobjc",
|
||||
"importcompilerproc", "importc", "exportc", "incompletestruct",
|
||||
"requiresinit", "align", "nodecl", "pure", "sideeffect",
|
||||
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",
|
||||
@@ -152,7 +154,7 @@ const
|
||||
"private", "protected", "public", "register", "reinterpret_cast",
|
||||
"short", "signed", "sizeof", "static_cast", "struct", "switch",
|
||||
"this", "throw", "true", "typedef", "typeid",
|
||||
"typename", "union", "unsigned", "using", "virtual", "void", "volatile",
|
||||
"typename", "union", "unsigned", "virtual", "void", "volatile",
|
||||
"wchar_t",
|
||||
|
||||
"alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept",
|
||||
|
||||
@@ -7,7 +7,7 @@ finally for from
|
||||
generic
|
||||
if import in include interface is isnot iterator
|
||||
lambda let
|
||||
macro method mixin mod
|
||||
macro method mixin using mod
|
||||
nil not notin
|
||||
object of or out
|
||||
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:
|
||||
"""
|
||||
|
||||
|
||||
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
|
||||
-------------
|
||||
|
||||
@@ -3191,14 +3224,69 @@ the dot syntax:
|
||||
proc `[]`(m: TMatrix, row, col: int): TMatrix.T =
|
||||
m.data[col * high(TMatrix.Columns) + row]
|
||||
|
||||
If anonymous type classes are used, the ``type`` operator can be used to
|
||||
discover the instantiated type of each param.
|
||||
Alternatively, the `type` operator can be used over the proc params for similar
|
||||
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
|
||||
-------------------------
|
||||
|
||||
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
|
||||
@@ -3910,7 +3998,7 @@ the ordinary AST predicates:
|
||||
template ex{a = b + c}(a: int{noalias}, b, c: int) =
|
||||
# this transformation is only valid if 'b' and 'c' do not alias 'a':
|
||||
a = b
|
||||
inc a, b
|
||||
inc a, c
|
||||
|
||||
|
||||
Pattern operators
|
||||
@@ -4412,6 +4500,40 @@ be destructed at its scope exit. Later versions of the language will improve
|
||||
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
|
||||
--------------
|
||||
The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
|
||||
|
||||
@@ -56,10 +56,10 @@ type
|
||||
nnkFromStmt,
|
||||
nnkIncludeStmt,
|
||||
|
||||
nnkBindStmt, nnkMixinStmt,
|
||||
nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
|
||||
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
nnkTupleTy, nnkTypeClassTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||
nnkConstTy, nnkMutableTy,
|
||||
nnkDistinctTy,
|
||||
|
||||
@@ -1,31 +1,26 @@
|
||||
discard """
|
||||
output: '''obj has '==': false
|
||||
int has '==': true
|
||||
false
|
||||
true
|
||||
true
|
||||
no'''
|
||||
"""
|
||||
|
||||
# test the new 'compiles' feature:
|
||||
|
||||
template supports(opr, x: expr): bool {.immediate.} =
|
||||
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
|
||||
TObj = object
|
||||
|
||||
var
|
||||
myObj {.compileTime.}: TObj
|
||||
|
||||
echo "obj has '==': ", supports(`==`, myObj)
|
||||
echo "int has '==': ", supports(`==`, 45)
|
||||
ok supports(`==`, myObj)
|
||||
ok supports(`==`, 45)
|
||||
|
||||
echo supports(`++`, 34)
|
||||
echo supports(`not`, true)
|
||||
echo supports(`+`, 34)
|
||||
no supports(`++`, 34)
|
||||
ok supports(`not`, true)
|
||||
ok supports(`+`, 34)
|
||||
|
||||
no compiles(4+5.0 * "hallo")
|
||||
|
||||
when compiles(4+5.0 * "hallo"):
|
||||
echo "yes"
|
||||
else:
|
||||
echo "no"
|
||||
|
||||
@@ -3,11 +3,10 @@ discard """
|
||||
line: 11
|
||||
errormsg: "expression \'a()\' cannot be called"
|
||||
"""
|
||||
# Tests the new check in the semantic pass
|
||||
|
||||
var
|
||||
a: int
|
||||
|
||||
a() #ERROR_MSG expression 'a()' cannot be called
|
||||
# Tests the new check in the semantic pass
|
||||
|
||||
var
|
||||
a: int
|
||||
|
||||
a() #ERROR_MSG expression 'a()' cannot be called
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
discard """
|
||||
file: "topaque.nim"
|
||||
line: 16
|
||||
errormsg: "undeclared field: \'buffer\'"
|
||||
errormsg: "undeclared identifier: \'buffer\'"
|
||||
"""
|
||||
# Test the new opaque types
|
||||
|
||||
import
|
||||
mopaque
|
||||
|
||||
var
|
||||
L: TLexer
|
||||
|
||||
L.filename = "ha"
|
||||
L.line = 34
|
||||
L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'
|
||||
# Test the new opaque types
|
||||
|
||||
import
|
||||
mopaque
|
||||
|
||||
var
|
||||
L: TLexer
|
||||
|
||||
L.filename = "ha"
|
||||
L.line = 34
|
||||
L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
discard """
|
||||
file: "twrongtupleaccess.nim"
|
||||
line: 9
|
||||
errormsg: "undeclared field: \'setBLAH\'"
|
||||
errormsg: "undeclared identifier: \'setBLAH\'"
|
||||
"""
|
||||
# Bugfix
|
||||
|
||||
var v = (5.0, 10.0)
|
||||
v.setBLAH(10)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -49,6 +49,11 @@ Language Additions
|
||||
- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
|
||||
``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
|
||||
- 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!
|
||||
|
||||
Reference in New Issue
Block a user