idetools: 'usages' and 'def' should work now; documented js backend
This commit is contained in:
parent
a7a2f464a2
commit
c7158af752
14 changed files with 215 additions and 117 deletions
|
|
@ -371,7 +371,7 @@ type
|
||||||
skEnumField, # an identifier in an enum
|
skEnumField, # an identifier in an enum
|
||||||
skForVar, # a for loop variable
|
skForVar, # a for loop variable
|
||||||
skLabel, # a label (for block statement)
|
skLabel, # a label (for block statement)
|
||||||
skStub # symbol is a stub and not yet loaded from the ROD
|
skStub, # symbol is a stub and not yet loaded from the ROD
|
||||||
# file (it is loaded on demand, which may
|
# file (it is loaded on demand, which may
|
||||||
# mean: never)
|
# mean: never)
|
||||||
TSymKinds* = set[TSymKind]
|
TSymKinds* = set[TSymKind]
|
||||||
|
|
@ -380,6 +380,7 @@ const
|
||||||
routineKinds* = {skProc, skMethod, skIterator, skConverter,
|
routineKinds* = {skProc, skMethod, skIterator, skConverter,
|
||||||
skMacro, skTemplate}
|
skMacro, skTemplate}
|
||||||
tfIncompleteStruct* = tfVarargs
|
tfIncompleteStruct* = tfVarargs
|
||||||
|
skError* = skUnknown
|
||||||
|
|
||||||
type
|
type
|
||||||
TMagic* = enum # symbols that require compiler magic:
|
TMagic* = enum # symbols that require compiler magic:
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ proc considerAcc*(n: PNode): PIdent =
|
||||||
else:
|
else:
|
||||||
GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
GlobalError(n.info, errIdentifierExpected, renderTree(n))
|
||||||
|
|
||||||
proc errorSym*(n: PNode): PSym =
|
proc errorSym*(c: PContext, n: PNode): PSym =
|
||||||
## creates an error symbol to avoid cascading errors (for IDE support)
|
## creates an error symbol to avoid cascading errors (for IDE support)
|
||||||
var m = n
|
var m = n
|
||||||
# ensure that 'considerAcc' can't fail:
|
# ensure that 'considerAcc' can't fail:
|
||||||
|
|
@ -46,8 +46,12 @@ proc errorSym*(n: PNode): PSym =
|
||||||
considerAcc(m)
|
considerAcc(m)
|
||||||
else:
|
else:
|
||||||
getIdent("err:" & renderTree(m))
|
getIdent("err:" & renderTree(m))
|
||||||
result = newSym(skUnknown, ident, getCurrOwner())
|
result = newSym(skError, ident, getCurrOwner())
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
|
result.typ = errorType(c)
|
||||||
|
incl(result.flags, sfDiscardable)
|
||||||
|
# pretend it's imported from some unknown module to prevent cascading errors:
|
||||||
|
SymTabAddAt(c.tab, result, ast.ImportTablePos)
|
||||||
|
|
||||||
type
|
type
|
||||||
TOverloadIterMode* = enum
|
TOverloadIterMode* = enum
|
||||||
|
|
@ -106,7 +110,6 @@ proc AddInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||||
# add to interface:
|
# add to interface:
|
||||||
if c.module != nil: StrTableAdd(c.module.tab, sym)
|
if c.module != nil: StrTableAdd(c.module.tab, sym)
|
||||||
else: InternalError(sym.info, "AddInterfaceDeclAux")
|
else: InternalError(sym.info, "AddInterfaceDeclAux")
|
||||||
#if getCurrOwner().kind == skModule: incl(sym.flags, sfGlobal)
|
|
||||||
|
|
||||||
proc addInterfaceDeclAt*(c: PContext, sym: PSym, at: Natural) =
|
proc addInterfaceDeclAt*(c: PContext, sym: PSym, at: Natural) =
|
||||||
addDeclAt(c, sym, at)
|
addDeclAt(c, sym, at)
|
||||||
|
|
@ -139,7 +142,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||||
result = SymtabGet(c.Tab, n.ident)
|
result = SymtabGet(c.Tab, n.ident)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
|
LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
|
||||||
result = errorSym(n)
|
result = errorSym(c, n)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
of nkAccQuoted:
|
of nkAccQuoted:
|
||||||
|
|
@ -147,7 +150,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||||
result = SymtabGet(c.Tab, ident)
|
result = SymtabGet(c.Tab, ident)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(n)
|
result = errorSym(c, n)
|
||||||
else:
|
else:
|
||||||
InternalError(n.info, "lookUp")
|
InternalError(n.info, "lookUp")
|
||||||
return
|
return
|
||||||
|
|
@ -166,7 +169,7 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||||
result = SymtabGet(c.Tab, ident)
|
result = SymtabGet(c.Tab, ident)
|
||||||
if result == nil and checkUndeclared in flags:
|
if result == nil and checkUndeclared in flags:
|
||||||
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(n)
|
result = errorSym(c, n)
|
||||||
elif checkAmbiguity in flags and result != nil and
|
elif checkAmbiguity in flags and result != nil and
|
||||||
Contains(c.AmbiguousSymbols, result.id):
|
Contains(c.AmbiguousSymbols, result.id):
|
||||||
LocalError(n.info, errUseQualifier, ident.s)
|
LocalError(n.info, errUseQualifier, ident.s)
|
||||||
|
|
@ -190,11 +193,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||||
result = StrTableGet(m.tab, ident)
|
result = StrTableGet(m.tab, ident)
|
||||||
if result == nil and checkUndeclared in flags:
|
if result == nil and checkUndeclared in flags:
|
||||||
LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(n.sons[1])
|
result = errorSym(c, n.sons[1])
|
||||||
elif checkUndeclared in flags:
|
elif checkUndeclared in flags:
|
||||||
LocalError(n.sons[1].info, errIdentifierExpected,
|
LocalError(n.sons[1].info, errIdentifierExpected,
|
||||||
renderTree(n.sons[1]))
|
renderTree(n.sons[1]))
|
||||||
result = errorSym(n.sons[1])
|
result = errorSym(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
if result != nil and result.kind == skStub: loadStub(result)
|
if result != nil and result.kind == skStub: loadStub(result)
|
||||||
|
|
@ -231,7 +234,7 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
else:
|
else:
|
||||||
LocalError(n.sons[1].info, errIdentifierExpected,
|
LocalError(n.sons[1].info, errIdentifierExpected,
|
||||||
renderTree(n.sons[1]))
|
renderTree(n.sons[1]))
|
||||||
result = errorSym(n.sons[1])
|
result = errorSym(c, n.sons[1])
|
||||||
of nkSymChoice:
|
of nkSymChoice:
|
||||||
o.mode = oimSymChoice
|
o.mode = oimSymChoice
|
||||||
result = n.sons[0].sym
|
result = n.sons[0].sym
|
||||||
|
|
|
||||||
|
|
@ -526,7 +526,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
|
||||||
# only for debugging purposes
|
# only for debugging purposes
|
||||||
result = filename in info.toFilename
|
result = filename in info.toFilename
|
||||||
|
|
||||||
var checkPoints: seq[TLineInfo] = @[]
|
var checkPoints*: seq[TLineInfo] = @[]
|
||||||
|
|
||||||
proc addCheckpoint*(info: TLineInfo) =
|
proc addCheckpoint*(info: TLineInfo) =
|
||||||
checkPoints.add(info)
|
checkPoints.add(info)
|
||||||
|
|
@ -541,6 +541,7 @@ proc OutWriteln*(s: string) =
|
||||||
proc MsgWriteln*(s: string) =
|
proc MsgWriteln*(s: string) =
|
||||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||||
if gSilence == 0:
|
if gSilence == 0:
|
||||||
|
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||||
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
||||||
else: Writeln(stdout, s)
|
else: Writeln(stdout, s)
|
||||||
|
|
||||||
|
|
@ -587,7 +588,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||||
elif eh == doRaise:
|
elif eh == doRaise:
|
||||||
raiseRecoverableError(s)
|
raiseRecoverableError(s)
|
||||||
|
|
||||||
proc `==`(a, b: TLineInfo): bool =
|
proc `==`*(a, b: TLineInfo): bool =
|
||||||
result = a.line == b.line and a.fileIndex == b.fileIndex
|
result = a.line == b.line and a.fileIndex == b.fileIndex
|
||||||
|
|
||||||
proc writeContext(lastinfo: TLineInfo) =
|
proc writeContext(lastinfo: TLineInfo) =
|
||||||
|
|
@ -637,7 +638,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
frmt = posErrorFormat
|
frmt = posErrorFormat
|
||||||
# we try to filter error messages so that not two error message
|
# we try to filter error messages so that not two error message
|
||||||
# in the same file and line are produced:
|
# in the same file and line are produced:
|
||||||
ignoreMsg = lastError == info and eh != doAbort
|
#ignoreMsg = lastError == info and eh != doAbort
|
||||||
lastError = info
|
lastError = info
|
||||||
of warnMin..warnMax:
|
of warnMin..warnMax:
|
||||||
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
||||||
|
|
@ -661,7 +662,6 @@ proc GlobalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
liMessage(info, msg, arg, doRaise)
|
liMessage(info, msg, arg, doRaise)
|
||||||
|
|
||||||
proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
#if gCmd == cmdIdeTools and gErrorCounter > 10: return
|
|
||||||
liMessage(info, msg, arg, doNothing)
|
liMessage(info, msg, arg, doNothing)
|
||||||
|
|
||||||
proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import
|
||||||
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
||||||
magicsys, parser, nversion, nimsets, semfold, importer,
|
magicsys, parser, nversion, nimsets, semfold, importer,
|
||||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||||
suggest, semthreads, intsets, transf, evals, idgen, aliases
|
semthreads, intsets, transf, evals, idgen, aliases
|
||||||
|
|
||||||
proc semPass*(): TPass
|
proc semPass*(): TPass
|
||||||
# implementation
|
# implementation
|
||||||
|
|
@ -37,9 +37,10 @@ proc addResultNode(c: PContext, n: PNode)
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||||
|
|
||||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||||
LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
|
if formal.kind != tyError and actual.kind != tyError:
|
||||||
typeToString(actual) & ") " &
|
LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||||
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
typeToString(actual) & ") " &
|
||||||
|
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
||||||
|
|
||||||
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||||
result = IndexTypesMatch(c, formal, arg.typ, arg)
|
result = IndexTypesMatch(c, formal, arg.typ, arg)
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
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:
|
||||||
GlobalError(n.Info, errAmbiguousCallXYZ, "")
|
GlobalError(n.Info, errAmbiguousCallXYZ, "")
|
||||||
else:
|
elif gErrorCounter == 0:
|
||||||
|
# don't cascade errors
|
||||||
var args = "("
|
var args = "("
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
if i > 1: add(args, ", ")
|
if i > 1: add(args, ", ")
|
||||||
|
|
@ -91,8 +92,14 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
||||||
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||||
# a generic proc!
|
# a generic proc!
|
||||||
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
if not x.proxyMatch:
|
||||||
|
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
|
||||||
|
else:
|
||||||
|
result = x.call
|
||||||
|
result.sons[0] = newSymNode(finalCallee)
|
||||||
|
result.typ = finalCallee.typ.sons[0]
|
||||||
|
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
||||||
|
return
|
||||||
result = x.call
|
result = x.call
|
||||||
result.sons[0] = newSymNode(finalCallee)
|
result.sons[0] = newSymNode(finalCallee)
|
||||||
result.typ = finalCallee.typ.sons[0]
|
result.typ = finalCallee.typ.sons[0]
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ type
|
||||||
filename*: string # the module's filename
|
filename*: string # the module's filename
|
||||||
userPragmas*: TStrTable
|
userPragmas*: TStrTable
|
||||||
evalContext*: PEvalContext
|
evalContext*: PEvalContext
|
||||||
|
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
||||||
|
# naming it multiple times
|
||||||
|
|
||||||
var
|
var
|
||||||
gGenericsCache: PGenericsCache # save for modularity
|
gGenericsCache: PGenericsCache # save for modularity
|
||||||
|
|
@ -194,6 +196,7 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
||||||
# we have to give up and use a per-module cache for generic instantiations:
|
# we have to give up and use a per-module cache for generic instantiations:
|
||||||
result.generics = newGenericsCache()
|
result.generics = newGenericsCache()
|
||||||
assert gGenericsCache == nil
|
assert gGenericsCache == nil
|
||||||
|
result.UnknownIdents = initIntSet()
|
||||||
|
|
||||||
proc addConverter(c: PContext, conv: PSym) =
|
proc addConverter(c: PContext, conv: PSym) =
|
||||||
var L = len(c.converters)
|
var L = len(c.converters)
|
||||||
|
|
@ -230,6 +233,10 @@ proc errorType*(c: PContext): PType =
|
||||||
## creates a type representing an error state
|
## creates a type representing an error state
|
||||||
result = newTypeS(tyError, c)
|
result = newTypeS(tyError, c)
|
||||||
|
|
||||||
|
proc errorNode*(c: PContext, n: PNode): PNode =
|
||||||
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
result.typ = errorType(c)
|
||||||
|
|
||||||
proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
|
proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
|
||||||
dest.kind = kind
|
dest.kind = kind
|
||||||
dest.owner = getCurrOwner()
|
dest.owner = getCurrOwner()
|
||||||
|
|
@ -244,21 +251,11 @@ proc makeRangeType*(c: PContext, first, last: biggestInt,
|
||||||
result.n = n
|
result.n = n
|
||||||
rawAddSon(result, getSysType(tyInt)) # basetype of range
|
rawAddSon(result, getSysType(tyInt)) # basetype of range
|
||||||
|
|
||||||
proc markUsed*(n: PNode, s: PSym) =
|
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
|
||||||
incl(s.flags, sfUsed)
|
|
||||||
if {sfDeprecated, sfError} * s.flags != {}:
|
|
||||||
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
|
||||||
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s)
|
|
||||||
|
|
||||||
proc markIndirect*(c: PContext, s: PSym) =
|
|
||||||
if s.kind in {skProc, skConverter, skMethod, skIterator}:
|
if s.kind in {skProc, skConverter, skMethod, skIterator}:
|
||||||
incl(s.flags, sfAddrTaken)
|
incl(s.flags, sfAddrTaken)
|
||||||
# XXX add to 'c' for global analysis
|
# XXX add to 'c' for global analysis
|
||||||
|
|
||||||
proc useSym*(sym: PSym): PNode =
|
|
||||||
result = newSymNode(sym)
|
|
||||||
markUsed(result, sym)
|
|
||||||
|
|
||||||
proc illFormedAst*(n: PNode) =
|
proc illFormedAst*(n: PNode) =
|
||||||
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = semExpr(c, n, flags)
|
result = semExpr(c, n, flags)
|
||||||
if result.kind == nkEmpty:
|
if result.kind == nkEmpty:
|
||||||
# do not produce another redundant error message:
|
# do not produce another redundant error message:
|
||||||
raiseRecoverableError("")
|
#raiseRecoverableError("")
|
||||||
|
result = errorNode(c, n)
|
||||||
if result.typ != nil:
|
if result.typ != nil:
|
||||||
if result.typ.kind == tyVar: result = newDeref(result)
|
if result.typ.kind == tyVar: result = newDeref(result)
|
||||||
else:
|
else:
|
||||||
|
|
@ -50,7 +51,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = semExpr(c, n, flags)
|
result = semExpr(c, n, flags)
|
||||||
if result.kind == nkEmpty:
|
if result.kind == nkEmpty:
|
||||||
# do not produce another redundant error message:
|
# do not produce another redundant error message:
|
||||||
raiseRecoverableError("")
|
result = errorNode(c, n)
|
||||||
if result.typ == nil:
|
if result.typ == nil:
|
||||||
LocalError(n.info, errExprXHasNoType,
|
LocalError(n.info, errExprXHasNoType,
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
|
|
@ -614,8 +615,8 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||||
|
|
||||||
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = nil
|
result = nil
|
||||||
var prc = n.sons[0]
|
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
var prc = n.sons[0]
|
||||||
if n.sons[0].kind == nkDotExpr:
|
if n.sons[0].kind == nkDotExpr:
|
||||||
checkSonsLen(n.sons[0], 2)
|
checkSonsLen(n.sons[0], 2)
|
||||||
n.sons[0] = semFieldAccess(c, n.sons[0])
|
n.sons[0] = semFieldAccess(c, n.sons[0])
|
||||||
|
|
@ -638,17 +639,23 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if m.state != csMatch:
|
if m.state != csMatch:
|
||||||
if c.inCompilesContext > 0:
|
if c.inCompilesContext > 0:
|
||||||
# speed up error generation:
|
# speed up error generation:
|
||||||
LocalError(n.Info, errTypeMismatch, "")
|
GlobalError(n.Info, errTypeMismatch, "")
|
||||||
return emptyNode
|
return emptyNode
|
||||||
else:
|
else:
|
||||||
|
var hasErrorType = false
|
||||||
var msg = msgKindToString(errTypeMismatch)
|
var msg = msgKindToString(errTypeMismatch)
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
if i > 1: add(msg, ", ")
|
if i > 1: add(msg, ", ")
|
||||||
add(msg, typeToString(n.sons[i].typ))
|
let nt = n.sons[i].typ
|
||||||
add(msg, ")\n" & msgKindToString(errButExpected) & "\n" &
|
add(msg, typeToString(nt))
|
||||||
typeToString(n.sons[0].typ))
|
if nt.kind == tyError:
|
||||||
LocalError(n.Info, errGenerated, msg)
|
hasErrorType = true
|
||||||
return emptyNode
|
break
|
||||||
|
if not hasErrorType:
|
||||||
|
add(msg, ")\n" & msgKindToString(errButExpected) & "\n" &
|
||||||
|
typeToString(n.sons[0].typ))
|
||||||
|
LocalError(n.Info, errGenerated, msg)
|
||||||
|
return errorNode(c, n)
|
||||||
result = nil
|
result = nil
|
||||||
else:
|
else:
|
||||||
result = m.call
|
result = m.call
|
||||||
|
|
@ -664,9 +671,10 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
nOrig.sons[0] = prc
|
nOrig.sons[0] = prc
|
||||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
LocalError(n.info, errExprXCannotBeCalled,
|
if c.inCompilesContext > 0 or gErrorCounter == 0:
|
||||||
renderTree(n, {renderNoComments}))
|
LocalError(n.info, errExprXCannotBeCalled,
|
||||||
return emptyNode
|
renderTree(n, {renderNoComments}))
|
||||||
|
return errorNode(c, n)
|
||||||
fixAbstractType(c, result)
|
fixAbstractType(c, result)
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone:
|
if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone:
|
||||||
|
|
@ -681,8 +689,8 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = overloadedCallOpr(c, n)
|
result = overloadedCallOpr(c, n)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
LocalError(n.Info, errGenerated, getNotFoundError(c, n))
|
NotFoundError(c, n)
|
||||||
return emptyNode
|
return errorNode(c, n)
|
||||||
let callee = result.sons[0].sym
|
let callee = result.sons[0].sym
|
||||||
case callee.kind
|
case callee.kind
|
||||||
of skMacro: result = semMacroExpr(c, nOrig, callee)
|
of skMacro: result = semMacroExpr(c, nOrig, callee)
|
||||||
|
|
@ -718,7 +726,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||||
addSon(result, newSymNode(e))
|
addSon(result, newSymNode(e))
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errSystemNeeds, "echo")
|
LocalError(n.info, errSystemNeeds, "echo")
|
||||||
addSon(result, emptyNode)
|
addSon(result, errorNode(c, n))
|
||||||
var arg = buildStringify(c, n)
|
var arg = buildStringify(c, n)
|
||||||
# problem is: implicit '$' is not checked for semantics yet. So we give up
|
# problem is: implicit '$' is not checked for semantics yet. So we give up
|
||||||
# and check 'arg' for semantics again:
|
# and check 'arg' for semantics again:
|
||||||
|
|
@ -732,7 +740,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||||
if result.typ != nil and result.typ.kind != tyStmt:
|
if result.typ != nil and result.typ.kind != tyStmt:
|
||||||
if gCmd == cmdInteractive:
|
if gCmd == cmdInteractive:
|
||||||
result = buildEchoStmt(c, result)
|
result = buildEchoStmt(c, result)
|
||||||
elif not ImplicitelyDiscardable(result):
|
elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError:
|
||||||
localError(n.info, errDiscardValue)
|
localError(n.info, errDiscardValue)
|
||||||
|
|
||||||
proc isTypeExpr(n: PNode): bool =
|
proc isTypeExpr(n: PNode): bool =
|
||||||
|
|
@ -909,8 +917,9 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
addSon(result, newIdentNode(i, n.info))
|
addSon(result, newIdentNode(i, n.info))
|
||||||
addSon(result, copyTree(n[0]))
|
addSon(result, copyTree(n[0]))
|
||||||
else:
|
else:
|
||||||
LocalError(n.Info, errUndeclaredFieldX, i.s)
|
if not ContainsOrIncl(c.UnknownIdents, i.id):
|
||||||
result = emptyNode
|
LocalError(n.Info, errUndeclaredFieldX, i.s)
|
||||||
|
result = errorNode(c, n)
|
||||||
|
|
||||||
proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
|
proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
|
||||||
result = newNodeI(nkCall, n.info)
|
result = newNodeI(nkCall, n.info)
|
||||||
|
|
@ -992,8 +1001,9 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||||
fixAbstractType(c, result)
|
fixAbstractType(c, result)
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
else:
|
else:
|
||||||
LocalError(n.Info, errUndeclaredFieldX, id.s)
|
if not ContainsOrIncl(c.UnknownIdents, id.id):
|
||||||
result = emptyNode
|
LocalError(n.Info, errUndeclaredFieldX, id.s)
|
||||||
|
result = errorNode(c, n)
|
||||||
|
|
||||||
proc takeImplicitAddr(c: PContext, n: PNode): PNode =
|
proc takeImplicitAddr(c: PContext, n: PNode): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -1116,16 +1126,16 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
|
||||||
var expandedSym = qualifiedLookup(c, n[0], {checkUndeclared})
|
var expandedSym = qualifiedLookup(c, n[0], {checkUndeclared})
|
||||||
if expandedSym == nil:
|
if expandedSym == nil:
|
||||||
LocalError(n.info, errUndeclaredIdentifier, n[0].renderTree)
|
LocalError(n.info, errUndeclaredIdentifier, n[0].renderTree)
|
||||||
return errorSym(n[0])
|
return errorSym(c, n[0])
|
||||||
|
|
||||||
if expandedSym.kind notin {skMacro, skTemplate}:
|
if expandedSym.kind notin {skMacro, skTemplate}:
|
||||||
LocalError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s)
|
LocalError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s)
|
||||||
return errorSym(n[0])
|
return errorSym(c, n[0])
|
||||||
|
|
||||||
result = expandedSym
|
result = expandedSym
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
||||||
result = errorSym(n)
|
result = errorSym(c, n)
|
||||||
|
|
||||||
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
|
|
@ -1395,11 +1405,11 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
|
||||||
result = semTemplateExpr(c, result, s, semCheck)
|
result = semTemplateExpr(c, result, s, semCheck)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errXisNoMacroOrTemplate, s.name.s)
|
LocalError(n.info, errXisNoMacroOrTemplate, s.name.s)
|
||||||
result = emptyNode
|
result = errorNode(c, n)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errInvalidExpressionX,
|
LocalError(n.info, errInvalidExpressionX,
|
||||||
renderTree(a, {renderNoComments}))
|
renderTree(a, {renderNoComments}))
|
||||||
result = emptyNode
|
result = errorNode(c, n)
|
||||||
|
|
||||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
var t = PType(IdTableGet(pt, q.typ))
|
var t = PType(IdTableGet(pt, q.typ))
|
||||||
if t == nil:
|
if t == nil:
|
||||||
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
||||||
break
|
t = errorType(c)
|
||||||
if t.kind == tyGenericParam:
|
elif t.kind == tyGenericParam:
|
||||||
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
||||||
elif t.kind == tyGenericInvokation:
|
elif t.kind == tyGenericInvokation:
|
||||||
#t = instGenericContainer(c, a, t)
|
#t = instGenericContainer(c, a, t)
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
x.info = n.info
|
x.info = n.info
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
n.sons[0] = x
|
n.sons[0] = x
|
||||||
|
suggestSym(x, s)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errInvalidControlFlowX, s.name.s)
|
localError(n.info, errInvalidControlFlowX, s.name.s)
|
||||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||||
|
|
@ -94,6 +95,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||||
var labl = newSymS(skLabel, n.sons[0], c)
|
var labl = newSymS(skLabel, n.sons[0], c)
|
||||||
addDecl(c, labl)
|
addDecl(c, labl)
|
||||||
n.sons[0] = newSymNode(labl)
|
n.sons[0] = newSymNode(labl)
|
||||||
|
suggestSym(n.sons[0], labl)
|
||||||
n.sons[1] = semStmt(c, n.sons[1])
|
n.sons[1] = semStmt(c, n.sons[1])
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
Dec(c.p.nestedBlockCounter)
|
Dec(c.p.nestedBlockCounter)
|
||||||
|
|
@ -132,7 +134,7 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
case skipTypes(n.sons[0].Typ, abstractVarRange).Kind
|
case skipTypes(n.sons[0].Typ, abstractVarRange).Kind
|
||||||
of tyInt..tyInt64, tyChar, tyEnum:
|
of tyInt..tyInt64, tyChar, tyEnum:
|
||||||
chckCovered = true
|
chckCovered = true
|
||||||
of tyFloat..tyFloat128, tyString:
|
of tyFloat..tyFloat128, tyString, tyError:
|
||||||
nil
|
nil
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errSelectorMustBeOfCertainTypes)
|
LocalError(n.info, errSelectorMustBeOfCertainTypes)
|
||||||
|
|
@ -231,6 +233,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||||
incl(result.flags, sfGlobal)
|
incl(result.flags, sfGlobal)
|
||||||
else:
|
else:
|
||||||
result = semIdentWithPragma(c, kind, n, {})
|
result = semIdentWithPragma(c, kind, n, {})
|
||||||
|
suggestSym(n, result)
|
||||||
|
|
||||||
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
var b: PNode
|
var b: PNode
|
||||||
|
|
|
||||||
|
|
@ -222,8 +222,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
amb = nextOverloadIter(ov, c, n)
|
amb = nextOverloadIter(ov, c, n)
|
||||||
if amb != nil: result = amb
|
if amb != nil: result = amb
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errTypeExpected)
|
if result.kind != skError: LocalError(n.info, errTypeExpected)
|
||||||
return errorSym(n)
|
return errorSym(c, n)
|
||||||
if result.typ.kind != tyGenericParam:
|
if result.typ.kind != tyGenericParam:
|
||||||
# XXX get rid of this hack!
|
# XXX get rid of this hack!
|
||||||
reset(n[])
|
reset(n[])
|
||||||
|
|
@ -231,7 +231,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
n.sym = result
|
n.sym = result
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errIdentifierExpected)
|
LocalError(n.info, errIdentifierExpected)
|
||||||
result = errorSym(n)
|
result = errorSym(c, n)
|
||||||
|
|
||||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
||||||
|
|
@ -827,7 +827,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkIdent, nkDotExpr, nkAccQuoted:
|
of nkIdent, nkDotExpr, nkAccQuoted:
|
||||||
var s = semTypeIdent(c, n)
|
var s = semTypeIdent(c, n)
|
||||||
if s.typ == nil:
|
if s.typ == nil:
|
||||||
LocalError(n.info, errTypeExpected)
|
if s.kind != skError: LocalError(n.info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
elif prev == nil:
|
elif prev == nil:
|
||||||
result = s.typ
|
result = s.typ
|
||||||
|
|
@ -845,7 +845,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = prev
|
result = prev
|
||||||
markUsed(n, n.sym)
|
markUsed(n, n.sym)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errTypeExpected)
|
if n.sym.kind != skError: LocalError(n.info, errTypeExpected)
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||||
magicsys, condsyms, idents
|
magicsys, condsyms, idents, lexer, options
|
||||||
|
|
||||||
type
|
type
|
||||||
TCandidateState* = enum
|
TCandidateState* = enum
|
||||||
|
|
@ -32,6 +32,7 @@ type
|
||||||
bindings*: TIdTable # maps types to types
|
bindings*: TIdTable # maps types to types
|
||||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||||
# for example
|
# for example
|
||||||
|
proxyMatch*: bool # to prevent instantiations
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
|
|
@ -44,6 +45,8 @@ type
|
||||||
isFromIntLit, # conversion *from* int literal; proven safe
|
isFromIntLit, # conversion *from* int literal; proven safe
|
||||||
isEqual
|
isEqual
|
||||||
|
|
||||||
|
proc markUsed*(n: PNode, s: PSym)
|
||||||
|
|
||||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||||
c.exactMatches = 0
|
c.exactMatches = 0
|
||||||
c.subtypeMatches = 0
|
c.subtypeMatches = 0
|
||||||
|
|
@ -114,18 +117,22 @@ proc writeMatches*(c: TCandidate) =
|
||||||
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||||
Writeln(stdout, "generic matches: " & $c.genericMatches)
|
Writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||||
|
|
||||||
proc getNotFoundError*(c: PContext, n: PNode): string =
|
proc NotFoundError*(c: PContext, n: PNode) =
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||||
# as semOverlodedCall is already pretty slow (and we need this information
|
# as semOverlodedCall is already pretty slow (and we need this information
|
||||||
# only in case of an error).
|
# only in case of an error).
|
||||||
if c.InCompilesContext > 0: return ""
|
if c.InCompilesContext > 0:
|
||||||
result = msgKindToString(errTypeMismatch)
|
# fail fast:
|
||||||
|
GlobalError(n.info, errTypeMismatch, "")
|
||||||
|
var result = msgKindToString(errTypeMismatch)
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
#debug(n.sons[i].typ)
|
#debug(n.sons[i].typ)
|
||||||
if n.sons[i].kind == nkExprEqExpr:
|
if n.sons[i].kind == nkExprEqExpr:
|
||||||
add(result, renderTree(n.sons[i].sons[0]))
|
add(result, renderTree(n.sons[i].sons[0]))
|
||||||
add(result, ": ")
|
add(result, ": ")
|
||||||
add(result, typeToString(n.sons[i].typ))
|
let nt = n.sons[i].typ
|
||||||
|
if nt.kind == tyError: return
|
||||||
|
add(result, typeToString(nt))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
add(result, ')')
|
add(result, ')')
|
||||||
var candidates = ""
|
var candidates = ""
|
||||||
|
|
@ -139,6 +146,7 @@ proc getNotFoundError*(c: PContext, n: PNode): string =
|
||||||
sym = nextOverloadIter(o, c, n.sons[0])
|
sym = nextOverloadIter(o, c, n.sons[0])
|
||||||
if candidates != "":
|
if candidates != "":
|
||||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & 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 =
|
||||||
|
|
@ -539,8 +547,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
if result == isGeneric: put(c.bindings, f, a)
|
if result == isGeneric: put(c.bindings, f, a)
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
of tyExpr, tyStmt, tyProxy:
|
of tyExpr, tyStmt:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
of tyProxy:
|
||||||
|
result = isEqual
|
||||||
else: internalError("typeRel: " & $f.kind)
|
else: internalError("typeRel: " & $f.kind)
|
||||||
|
|
||||||
proc cmpTypes*(f, a: PType): TTypeRelation =
|
proc cmpTypes*(f, a: PType): TTypeRelation =
|
||||||
|
|
@ -560,8 +570,13 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
|
||||||
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||||
c: PContext): PNode =
|
c: PContext): PNode =
|
||||||
result = newNodeI(kind, arg.info)
|
result = newNodeI(kind, arg.info)
|
||||||
if containsGenericType(f): result.typ = getInstantiatedType(c, arg, m, f)
|
if containsGenericType(f):
|
||||||
else: result.typ = f
|
if not m.proxyMatch:
|
||||||
|
result.typ = getInstantiatedType(c, arg, m, f)
|
||||||
|
else:
|
||||||
|
result.typ = errorType(c)
|
||||||
|
else:
|
||||||
|
result.typ = f
|
||||||
if result.typ == nil: InternalError(arg.info, "implicitConv")
|
if result.typ == nil: InternalError(arg.info, "implicitConv")
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
addSon(result, arg)
|
addSon(result, arg)
|
||||||
|
|
@ -649,9 +664,10 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
if skipTypes(f, abstractVar).kind in {tyTuple}:
|
if skipTypes(f, abstractVar).kind in {tyTuple}:
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
of isNone:
|
of isNone:
|
||||||
# we test for this here to not slow down ``typeRel``:
|
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||||
if a.kind == tyProxy:
|
if a.kind == tyProxy:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
|
m.proxyMatch = true
|
||||||
return copyTree(arg)
|
return copyTree(arg)
|
||||||
result = userConvMatch(c, m, f, a, arg)
|
result = userConvMatch(c, m, f, a, arg)
|
||||||
# check for a base type match, which supports openarray[T] without []
|
# check for a base type match, which supports openarray[T] without []
|
||||||
|
|
@ -854,3 +870,5 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||||
# use default value:
|
# use default value:
|
||||||
setSon(m.call, formal.position + 1, copyTree(formal.ast))
|
setSon(m.call, formal.position + 1, copyTree(formal.ast))
|
||||||
inc(f)
|
inc(f)
|
||||||
|
|
||||||
|
include suggest
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,14 @@
|
||||||
|
|
||||||
## This file implements features required for IDE support.
|
## This file implements features required for IDE support.
|
||||||
|
|
||||||
import
|
# imported from sigmatch.nim
|
||||||
lexer, idents, ast, astalgo, semdata, msgs, types, sigmatch, options,
|
|
||||||
renderer
|
|
||||||
|
|
||||||
const
|
const
|
||||||
sep = '\t'
|
sep = '\t'
|
||||||
sectionSuggest = "sug"
|
sectionSuggest = "sug"
|
||||||
sectionDef = "def"
|
sectionDef = "def"
|
||||||
sectionContext = "con"
|
sectionContext = "con"
|
||||||
|
sectionUsage = "use"
|
||||||
|
|
||||||
proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
|
proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
|
||||||
result = section
|
result = section
|
||||||
|
|
@ -183,6 +182,16 @@ proc findClosestCall(n: PNode): PNode =
|
||||||
result = findClosestCall(n.sons[i])
|
result = findClosestCall(n.sons[i])
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
|
|
||||||
|
proc isTracked(current: TLineInfo, tokenLen: int): bool =
|
||||||
|
# the column of an identifier is at its *end*, so we subtract to get the
|
||||||
|
# start of it.
|
||||||
|
for i in countup(0, high(checkPoints)):
|
||||||
|
if current.fileIndex == checkPoints[i].fileIndex:
|
||||||
|
if current.line == checkPoints[i].line:
|
||||||
|
let col = checkPoints[i].col
|
||||||
|
if col >= current.col-tokenLen and col <= current.col:
|
||||||
|
return true
|
||||||
|
|
||||||
proc findClosestSym(n: PNode): PNode =
|
proc findClosestSym(n: PNode): PNode =
|
||||||
if n.kind == nkSym and msgs.inCheckpoint(n.info) == cpExact:
|
if n.kind == nkSym and msgs.inCheckpoint(n.info) == cpExact:
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -205,7 +214,40 @@ proc fuzzySemCheck(c: PContext, n: PNode): PNode =
|
||||||
for i in 0 .. < sonsLen(n): result.addSon(fuzzySemCheck(c, n.sons[i]))
|
for i in 0 .. < sonsLen(n): result.addSon(fuzzySemCheck(c, n.sons[i]))
|
||||||
|
|
||||||
var
|
var
|
||||||
usageSym: PSym
|
usageSym*: PSym
|
||||||
|
lastLineInfo: TLineInfo
|
||||||
|
|
||||||
|
proc findUsages(node: PNode, s: PSym) =
|
||||||
|
if usageSym == nil and isTracked(node.info, s.name.s.len):
|
||||||
|
usageSym = s
|
||||||
|
OutWriteln(SymToStr(s, isLocal=false, sectionUsage))
|
||||||
|
elif s == usageSym:
|
||||||
|
if lastLineInfo != node.info:
|
||||||
|
OutWriteln(SymToStr(s, isLocal=false, sectionUsage, node.info))
|
||||||
|
lastLineInfo = node.info
|
||||||
|
|
||||||
|
proc findDefinition(node: PNode, s: PSym) =
|
||||||
|
if isTracked(node.info, s.name.s.len):
|
||||||
|
OutWriteln(SymToStr(s, isLocal=false, sectionDef))
|
||||||
|
quit(0)
|
||||||
|
|
||||||
|
proc suggestSym*(n: PNode, s: PSym) {.inline.} =
|
||||||
|
## misnamed: should be 'symDeclared'
|
||||||
|
if optUsages in gGlobalOptions:
|
||||||
|
findUsages(n, s)
|
||||||
|
if optDef in gGlobalOptions:
|
||||||
|
findDefinition(n, s)
|
||||||
|
|
||||||
|
proc markUsed(n: PNode, s: PSym) =
|
||||||
|
incl(s.flags, sfUsed)
|
||||||
|
if {sfDeprecated, sfError} * s.flags != {}:
|
||||||
|
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
||||||
|
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s)
|
||||||
|
suggestSym(n, s)
|
||||||
|
|
||||||
|
proc useSym*(sym: PSym): PNode =
|
||||||
|
result = newSymNode(sym)
|
||||||
|
markUsed(result, sym)
|
||||||
|
|
||||||
proc suggestExpr*(c: PContext, node: PNode) =
|
proc suggestExpr*(c: PContext, node: PNode) =
|
||||||
var cp = msgs.inCheckpoint(node.info)
|
var cp = msgs.inCheckpoint(node.info)
|
||||||
|
|
@ -243,25 +285,6 @@ proc suggestExpr*(c: PContext, node: PNode) =
|
||||||
addSon(a, x)
|
addSon(a, x)
|
||||||
suggestCall(c, a, n, outputs)
|
suggestCall(c, a, n, outputs)
|
||||||
|
|
||||||
if optDef in gGlobalOptions:
|
|
||||||
let n = findClosestSym(fuzzySemCheck(c, node))
|
|
||||||
if n != nil:
|
|
||||||
OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef))
|
|
||||||
inc outputs
|
|
||||||
|
|
||||||
if optUsages in gGlobalOptions:
|
|
||||||
if usageSym == nil:
|
|
||||||
let n = findClosestSym(fuzzySemCheck(c, node))
|
|
||||||
if n != nil:
|
|
||||||
usageSym = n.sym
|
|
||||||
OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef))
|
|
||||||
inc outputs
|
|
||||||
else:
|
|
||||||
let n = node
|
|
||||||
if n.kind == nkSym and n.sym == usageSym:
|
|
||||||
OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef, n.info))
|
|
||||||
inc outputs
|
|
||||||
|
|
||||||
dec(c.InCompilesContext)
|
dec(c.InCompilesContext)
|
||||||
if outputs > 0 and optUsages notin gGlobalOptions: quit(0)
|
if outputs > 0 and optUsages notin gGlobalOptions: quit(0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -514,3 +514,40 @@ efficient:
|
||||||
of "license": c.license = UnixToNativePath(k.value)
|
of "license": c.license = UnixToNativePath(k.value)
|
||||||
else: quit(errorStr(p, "unknown variable: " & k.key))
|
else: quit(errorStr(p, "unknown variable: " & k.key))
|
||||||
|
|
||||||
|
|
||||||
|
The ECMAScript target
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Nimrod can also generate `ECMAScript`:idx: (also known as `JavaScript`:idx:)
|
||||||
|
code. However, the ECMAScript code generator is experimental!
|
||||||
|
|
||||||
|
Nimrod targets ECMAScript 1.5 which is supported by any widely used browser.
|
||||||
|
Since ECMAScript does not have a portable means to include another module,
|
||||||
|
Nimrod just generates a long ``.js`` file.
|
||||||
|
|
||||||
|
Features or modules that the ECMAScript platform does not support are not
|
||||||
|
available. This includes:
|
||||||
|
|
||||||
|
* manual memory management (``alloc``, etc.)
|
||||||
|
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
||||||
|
* file management
|
||||||
|
* most modules of the Standard library
|
||||||
|
* proper 64 bit integer arithmetic
|
||||||
|
* unsigned integer arithmetic
|
||||||
|
|
||||||
|
However, the modules `strutils`:idx:, `math`:idx:, and `times`:idx: are
|
||||||
|
available! To access the DOM, use the `dom`:idx: module that is only
|
||||||
|
available for the ECMAScript platform.
|
||||||
|
|
||||||
|
To compile a Nimrod module into a ``.js`` file use the ``js`` command; the
|
||||||
|
default is a ``.js`` file that is supposed to be referenced in an ``.html``
|
||||||
|
file. However, you can also run the code with `nodejs`:idx:\:
|
||||||
|
|
||||||
|
nimrod js -d:nodejs -r examples/hallo.nim
|
||||||
|
|
||||||
|
|
||||||
|
Known bugs
|
||||||
|
----------
|
||||||
|
|
||||||
|
* exception handling does not work
|
||||||
|
|
||||||
|
|
|
||||||
16
todo.txt
16
todo.txt
|
|
@ -6,19 +6,11 @@ version 0.9.0
|
||||||
- implicit deref for parameter matching
|
- implicit deref for parameter matching
|
||||||
|
|
||||||
- ``borrow`` needs to take type classes into account
|
- ``borrow`` needs to take type classes into account
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``
|
|
||||||
- optimize genericAssign in the code generator
|
- optimize genericAssign in the code generator
|
||||||
- fix remaining closure bugs:
|
- fix remaining closure bugs:
|
||||||
- fix evals.nim with closures
|
- fix evals.nim with closures
|
||||||
- implement "closure tuple consists of a single 'ref'" optimization
|
- implement "closure tuple consists of a single 'ref'" optimization
|
||||||
|
|
||||||
- document 'do' notation
|
|
||||||
- rethink the syntax: distinction between expr and stmt is unfortunate;
|
|
||||||
indentation handling is quite complex too; problem with exception handling
|
|
||||||
is that often the scope of ``try`` is wrong and apart from that ``try`` is
|
|
||||||
a full blown statement; a ``try`` expression might be a good idea to make
|
|
||||||
error handling more light-weight
|
|
||||||
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
----
|
----
|
||||||
|
|
@ -36,9 +28,15 @@ version 0.9.XX
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- JS gen:
|
- JS gen:
|
||||||
- document it
|
|
||||||
- fix exception handling
|
- fix exception handling
|
||||||
|
|
||||||
|
- document 'do' notation
|
||||||
|
- rethink the syntax: distinction between expr and stmt is unfortunate;
|
||||||
|
indentation handling is quite complex too; problem with exception handling
|
||||||
|
is that often the scope of ``try`` is wrong and apart from that ``try`` is
|
||||||
|
a full blown statement; a ``try`` expression might be a good idea to make
|
||||||
|
error handling more light-weight
|
||||||
|
- ``=`` should be overloadable; requires specialization for ``=``
|
||||||
- ``hoist`` pragma for loop hoisting
|
- ``hoist`` pragma for loop hoisting
|
||||||
- document destructors; don't work yet when used as expression
|
- document destructors; don't work yet when used as expression
|
||||||
- make use of ``tyIter`` to fix the implicit items/pairs issue
|
- make use of ``tyIter`` to fix the implicit items/pairs issue
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue