mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
idetools: 'usages' and 'def' should work now; documented js backend
This commit is contained in:
@@ -371,7 +371,7 @@ type
|
||||
skEnumField, # an identifier in an enum
|
||||
skForVar, # a for loop variable
|
||||
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
|
||||
# mean: never)
|
||||
TSymKinds* = set[TSymKind]
|
||||
@@ -380,6 +380,7 @@ const
|
||||
routineKinds* = {skProc, skMethod, skIterator, skConverter,
|
||||
skMacro, skTemplate}
|
||||
tfIncompleteStruct* = tfVarargs
|
||||
skError* = skUnknown
|
||||
|
||||
type
|
||||
TMagic* = enum # symbols that require compiler magic:
|
||||
|
||||
@@ -37,7 +37,7 @@ proc considerAcc*(n: PNode): PIdent =
|
||||
else:
|
||||
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)
|
||||
var m = n
|
||||
# ensure that 'considerAcc' can't fail:
|
||||
@@ -46,8 +46,12 @@ proc errorSym*(n: PNode): PSym =
|
||||
considerAcc(m)
|
||||
else:
|
||||
getIdent("err:" & renderTree(m))
|
||||
result = newSym(skUnknown, ident, getCurrOwner())
|
||||
result = newSym(skError, ident, getCurrOwner())
|
||||
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
|
||||
TOverloadIterMode* = enum
|
||||
@@ -106,7 +110,6 @@ proc AddInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||
# add to interface:
|
||||
if c.module != nil: StrTableAdd(c.module.tab, sym)
|
||||
else: InternalError(sym.info, "AddInterfaceDeclAux")
|
||||
#if getCurrOwner().kind == skModule: incl(sym.flags, sfGlobal)
|
||||
|
||||
proc addInterfaceDeclAt*(c: PContext, sym: PSym, at: Natural) =
|
||||
addDeclAt(c, sym, at)
|
||||
@@ -139,7 +142,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
result = SymtabGet(c.Tab, n.ident)
|
||||
if result == nil:
|
||||
LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
|
||||
result = errorSym(n)
|
||||
result = errorSym(c, n)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
of nkAccQuoted:
|
||||
@@ -147,7 +150,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
result = SymtabGet(c.Tab, ident)
|
||||
if result == nil:
|
||||
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(n)
|
||||
result = errorSym(c, n)
|
||||
else:
|
||||
InternalError(n.info, "lookUp")
|
||||
return
|
||||
@@ -166,11 +169,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
result = SymtabGet(c.Tab, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
LocalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(n)
|
||||
result = errorSym(c, n)
|
||||
elif checkAmbiguity in flags and result != nil and
|
||||
Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, ident.s)
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, n.sym.name.s)
|
||||
@@ -190,11 +193,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
result = StrTableGet(m.tab, ident)
|
||||
if result == nil and checkUndeclared in flags:
|
||||
LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||
result = errorSym(n.sons[1])
|
||||
result = errorSym(c, n.sons[1])
|
||||
elif checkUndeclared in flags:
|
||||
LocalError(n.sons[1].info, errIdentifierExpected,
|
||||
renderTree(n.sons[1]))
|
||||
result = errorSym(n.sons[1])
|
||||
result = errorSym(c, n.sons[1])
|
||||
else:
|
||||
result = nil
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
@@ -231,7 +234,7 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
else:
|
||||
LocalError(n.sons[1].info, errIdentifierExpected,
|
||||
renderTree(n.sons[1]))
|
||||
result = errorSym(n.sons[1])
|
||||
result = errorSym(c, n.sons[1])
|
||||
of nkSymChoice:
|
||||
o.mode = oimSymChoice
|
||||
result = n.sons[0].sym
|
||||
|
||||
@@ -526,7 +526,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
|
||||
# only for debugging purposes
|
||||
result = filename in info.toFilename
|
||||
|
||||
var checkPoints: seq[TLineInfo] = @[]
|
||||
var checkPoints*: seq[TLineInfo] = @[]
|
||||
|
||||
proc addCheckpoint*(info: TLineInfo) =
|
||||
checkPoints.add(info)
|
||||
@@ -541,6 +541,7 @@ proc OutWriteln*(s: string) =
|
||||
proc MsgWriteln*(s: string) =
|
||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||
if gSilence == 0:
|
||||
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
||||
else: Writeln(stdout, s)
|
||||
|
||||
@@ -587,7 +588,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||
elif eh == doRaise:
|
||||
raiseRecoverableError(s)
|
||||
|
||||
proc `==`(a, b: TLineInfo): bool =
|
||||
proc `==`*(a, b: TLineInfo): bool =
|
||||
result = a.line == b.line and a.fileIndex == b.fileIndex
|
||||
|
||||
proc writeContext(lastinfo: TLineInfo) =
|
||||
@@ -637,7 +638,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
frmt = posErrorFormat
|
||||
# we try to filter error messages so that not two error message
|
||||
# in the same file and line are produced:
|
||||
ignoreMsg = lastError == info and eh != doAbort
|
||||
#ignoreMsg = lastError == info and eh != doAbort
|
||||
lastError = info
|
||||
of warnMin..warnMax:
|
||||
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
||||
@@ -661,7 +662,6 @@ proc GlobalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doRaise)
|
||||
|
||||
proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
#if gCmd == cmdIdeTools and gErrorCounter > 10: return
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
|
||||
proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
|
||||
@@ -14,7 +14,7 @@ import
|
||||
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
||||
magicsys, parser, nversion, nimsets, semfold, importer,
|
||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||
suggest, semthreads, intsets, transf, evals, idgen, aliases
|
||||
semthreads, intsets, transf, evals, idgen, aliases
|
||||
|
||||
proc semPass*(): TPass
|
||||
# implementation
|
||||
@@ -37,9 +37,10 @@ proc addResultNode(c: PContext, n: PNode)
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||
|
||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||
LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||
typeToString(actual) & ") " &
|
||||
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||
typeToString(actual) & ") " &
|
||||
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
||||
|
||||
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
result = IndexTypesMatch(c, formal, arg.typ, arg)
|
||||
|
||||
@@ -72,7 +72,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
if c.inCompilesContext > 0:
|
||||
# quick error message for performance of 'compiles' built-in:
|
||||
GlobalError(n.Info, errAmbiguousCallXYZ, "")
|
||||
else:
|
||||
elif gErrorCounter == 0:
|
||||
# don't cascade errors
|
||||
var args = "("
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
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!
|
||||
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||
# 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.sons[0] = newSymNode(finalCallee)
|
||||
result.typ = finalCallee.typ.sons[0]
|
||||
|
||||
@@ -74,6 +74,8 @@ type
|
||||
filename*: string # the module's filename
|
||||
userPragmas*: TStrTable
|
||||
evalContext*: PEvalContext
|
||||
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
||||
# naming it multiple times
|
||||
|
||||
var
|
||||
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:
|
||||
result.generics = newGenericsCache()
|
||||
assert gGenericsCache == nil
|
||||
result.UnknownIdents = initIntSet()
|
||||
|
||||
proc addConverter(c: PContext, conv: PSym) =
|
||||
var L = len(c.converters)
|
||||
@@ -230,6 +233,10 @@ proc errorType*(c: PContext): PType =
|
||||
## creates a type representing an error state
|
||||
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) =
|
||||
dest.kind = kind
|
||||
dest.owner = getCurrOwner()
|
||||
@@ -243,22 +250,12 @@ proc makeRangeType*(c: PContext, first, last: biggestInt,
|
||||
result = newTypeS(tyRange, c)
|
||||
result.n = n
|
||||
rawAddSon(result, getSysType(tyInt)) # basetype of range
|
||||
|
||||
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)
|
||||
|
||||
proc markIndirect*(c: PContext, s: PSym) =
|
||||
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
|
||||
if s.kind in {skProc, skConverter, skMethod, skIterator}:
|
||||
incl(s.flags, sfAddrTaken)
|
||||
# XXX add to 'c' for global analysis
|
||||
|
||||
proc useSym*(sym: PSym): PNode =
|
||||
result = newSymNode(sym)
|
||||
markUsed(result, sym)
|
||||
|
||||
proc illFormedAst*(n: PNode) =
|
||||
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)
|
||||
if result.kind == nkEmpty:
|
||||
# do not produce another redundant error message:
|
||||
raiseRecoverableError("")
|
||||
#raiseRecoverableError("")
|
||||
result = errorNode(c, n)
|
||||
if result.typ != nil:
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
else:
|
||||
@@ -50,7 +51,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = semExpr(c, n, flags)
|
||||
if result.kind == nkEmpty:
|
||||
# do not produce another redundant error message:
|
||||
raiseRecoverableError("")
|
||||
result = errorNode(c, n)
|
||||
if result.typ == nil:
|
||||
LocalError(n.info, errExprXHasNoType,
|
||||
renderTree(result, {renderNoComments}))
|
||||
@@ -614,8 +615,8 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||
|
||||
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = nil
|
||||
var prc = n.sons[0]
|
||||
checkMinSonsLen(n, 1)
|
||||
var prc = n.sons[0]
|
||||
if n.sons[0].kind == nkDotExpr:
|
||||
checkSonsLen(n.sons[0], 2)
|
||||
n.sons[0] = semFieldAccess(c, n.sons[0])
|
||||
@@ -638,19 +639,25 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if m.state != csMatch:
|
||||
if c.inCompilesContext > 0:
|
||||
# speed up error generation:
|
||||
LocalError(n.Info, errTypeMismatch, "")
|
||||
GlobalError(n.Info, errTypeMismatch, "")
|
||||
return emptyNode
|
||||
else:
|
||||
var hasErrorType = false
|
||||
var msg = msgKindToString(errTypeMismatch)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if i > 1: add(msg, ", ")
|
||||
add(msg, typeToString(n.sons[i].typ))
|
||||
add(msg, ")\n" & msgKindToString(errButExpected) & "\n" &
|
||||
typeToString(n.sons[0].typ))
|
||||
LocalError(n.Info, errGenerated, msg)
|
||||
return emptyNode
|
||||
let nt = n.sons[i].typ
|
||||
add(msg, typeToString(nt))
|
||||
if nt.kind == tyError:
|
||||
hasErrorType = true
|
||||
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
|
||||
else:
|
||||
else:
|
||||
result = m.call
|
||||
# we assume that a procedure that calls something indirectly
|
||||
# has side-effects:
|
||||
@@ -663,10 +670,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
n.sons[0] = prc
|
||||
nOrig.sons[0] = prc
|
||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||
if result == nil:
|
||||
LocalError(n.info, errExprXCannotBeCalled,
|
||||
renderTree(n, {renderNoComments}))
|
||||
return emptyNode
|
||||
if result == nil:
|
||||
if c.inCompilesContext > 0 or gErrorCounter == 0:
|
||||
LocalError(n.info, errExprXCannotBeCalled,
|
||||
renderTree(n, {renderNoComments}))
|
||||
return errorNode(c, n)
|
||||
fixAbstractType(c, result)
|
||||
analyseIfAddressTakenInCall(c, result)
|
||||
if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone:
|
||||
@@ -680,9 +688,9 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||
if result == nil:
|
||||
result = overloadedCallOpr(c, n)
|
||||
if result == nil:
|
||||
LocalError(n.Info, errGenerated, getNotFoundError(c, n))
|
||||
return emptyNode
|
||||
if result == nil:
|
||||
NotFoundError(c, n)
|
||||
return errorNode(c, n)
|
||||
let callee = result.sons[0].sym
|
||||
case callee.kind
|
||||
of skMacro: result = semMacroExpr(c, nOrig, callee)
|
||||
@@ -718,7 +726,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||
addSon(result, newSymNode(e))
|
||||
else:
|
||||
LocalError(n.info, errSystemNeeds, "echo")
|
||||
addSon(result, emptyNode)
|
||||
addSon(result, errorNode(c, n))
|
||||
var arg = buildStringify(c, n)
|
||||
# problem is: implicit '$' is not checked for semantics yet. So we give up
|
||||
# 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 gCmd == cmdInteractive:
|
||||
result = buildEchoStmt(c, result)
|
||||
elif not ImplicitelyDiscardable(result):
|
||||
elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError:
|
||||
localError(n.info, errDiscardValue)
|
||||
|
||||
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, copyTree(n[0]))
|
||||
else:
|
||||
LocalError(n.Info, errUndeclaredFieldX, i.s)
|
||||
result = emptyNode
|
||||
if not ContainsOrIncl(c.UnknownIdents, i.id):
|
||||
LocalError(n.Info, errUndeclaredFieldX, i.s)
|
||||
result = errorNode(c, n)
|
||||
|
||||
proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
|
||||
result = newNodeI(nkCall, n.info)
|
||||
@@ -992,8 +1001,9 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||
fixAbstractType(c, result)
|
||||
analyseIfAddressTakenInCall(c, result)
|
||||
else:
|
||||
LocalError(n.Info, errUndeclaredFieldX, id.s)
|
||||
result = emptyNode
|
||||
if not ContainsOrIncl(c.UnknownIdents, id.id):
|
||||
LocalError(n.Info, errUndeclaredFieldX, id.s)
|
||||
result = errorNode(c, n)
|
||||
|
||||
proc takeImplicitAddr(c: PContext, n: PNode): PNode =
|
||||
case n.kind
|
||||
@@ -1116,16 +1126,16 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
|
||||
var expandedSym = qualifiedLookup(c, n[0], {checkUndeclared})
|
||||
if expandedSym == nil:
|
||||
LocalError(n.info, errUndeclaredIdentifier, n[0].renderTree)
|
||||
return errorSym(n[0])
|
||||
return errorSym(c, n[0])
|
||||
|
||||
if expandedSym.kind notin {skMacro, skTemplate}:
|
||||
LocalError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s)
|
||||
return errorSym(n[0])
|
||||
return errorSym(c, n[0])
|
||||
|
||||
result = expandedSym
|
||||
else:
|
||||
LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
||||
result = errorSym(n)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||
flags: TExprFlags): PNode =
|
||||
@@ -1395,11 +1405,11 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
result = semTemplateExpr(c, result, s, semCheck)
|
||||
else:
|
||||
LocalError(n.info, errXisNoMacroOrTemplate, s.name.s)
|
||||
result = emptyNode
|
||||
result = errorNode(c, n)
|
||||
else:
|
||||
LocalError(n.info, errInvalidExpressionX,
|
||||
renderTree(a, {renderNoComments}))
|
||||
result = emptyNode
|
||||
result = errorNode(c, n)
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = n
|
||||
|
||||
@@ -27,8 +27,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
var t = PType(IdTableGet(pt, q.typ))
|
||||
if t == nil:
|
||||
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
||||
break
|
||||
if t.kind == tyGenericParam:
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericParam:
|
||||
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
||||
elif t.kind == tyGenericInvokation:
|
||||
#t = instGenericContainer(c, a, t)
|
||||
|
||||
@@ -79,7 +79,8 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||
x.info = n.info
|
||||
incl(s.flags, sfUsed)
|
||||
n.sons[0] = x
|
||||
else:
|
||||
suggestSym(x, s)
|
||||
else:
|
||||
localError(n.info, errInvalidControlFlowX, s.name.s)
|
||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||
localError(n.info, errInvalidControlFlowX,
|
||||
@@ -94,6 +95,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||
var labl = newSymS(skLabel, n.sons[0], c)
|
||||
addDecl(c, labl)
|
||||
n.sons[0] = newSymNode(labl)
|
||||
suggestSym(n.sons[0], labl)
|
||||
n.sons[1] = semStmt(c, n.sons[1])
|
||||
closeScope(c.tab)
|
||||
Dec(c.p.nestedBlockCounter)
|
||||
@@ -132,7 +134,7 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||
case skipTypes(n.sons[0].Typ, abstractVarRange).Kind
|
||||
of tyInt..tyInt64, tyChar, tyEnum:
|
||||
chckCovered = true
|
||||
of tyFloat..tyFloat128, tyString:
|
||||
of tyFloat..tyFloat128, tyString, tyError:
|
||||
nil
|
||||
else:
|
||||
LocalError(n.info, errSelectorMustBeOfCertainTypes)
|
||||
@@ -229,8 +231,9 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||
if isTopLevel(c):
|
||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||
incl(result.flags, sfGlobal)
|
||||
else:
|
||||
else:
|
||||
result = semIdentWithPragma(c, kind, n, {})
|
||||
suggestSym(n, result)
|
||||
|
||||
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
var b: PNode
|
||||
|
||||
@@ -222,8 +222,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
amb = nextOverloadIter(ov, c, n)
|
||||
if amb != nil: result = amb
|
||||
else:
|
||||
LocalError(n.info, errTypeExpected)
|
||||
return errorSym(n)
|
||||
if result.kind != skError: LocalError(n.info, errTypeExpected)
|
||||
return errorSym(c, n)
|
||||
if result.typ.kind != tyGenericParam:
|
||||
# XXX get rid of this hack!
|
||||
reset(n[])
|
||||
@@ -231,7 +231,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
n.sym = result
|
||||
else:
|
||||
LocalError(n.info, errIdentifierExpected)
|
||||
result = errorSym(n)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
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:
|
||||
var s = semTypeIdent(c, n)
|
||||
if s.typ == nil:
|
||||
LocalError(n.info, errTypeExpected)
|
||||
if s.kind != skError: LocalError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
elif prev == nil:
|
||||
result = s.typ
|
||||
@@ -845,7 +845,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = prev
|
||||
markUsed(n, n.sym)
|
||||
else:
|
||||
LocalError(n.info, errTypeExpected)
|
||||
if n.sym.kind != skError: LocalError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||
of nkTupleTy: result = semTuple(c, n, prev)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||
magicsys, condsyms, idents
|
||||
magicsys, condsyms, idents, lexer, options
|
||||
|
||||
type
|
||||
TCandidateState* = enum
|
||||
@@ -32,6 +32,7 @@ type
|
||||
bindings*: TIdTable # maps types to types
|
||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||
# for example
|
||||
proxyMatch*: bool # to prevent instantiations
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
@@ -43,7 +44,9 @@ type
|
||||
isGeneric,
|
||||
isFromIntLit, # conversion *from* int literal; proven safe
|
||||
isEqual
|
||||
|
||||
|
||||
proc markUsed*(n: PNode, s: PSym)
|
||||
|
||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||
c.exactMatches = 0
|
||||
c.subtypeMatches = 0
|
||||
@@ -114,22 +117,26 @@ proc writeMatches*(c: TCandidate) =
|
||||
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||
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,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
if c.InCompilesContext > 0: return ""
|
||||
result = msgKindToString(errTypeMismatch)
|
||||
if c.InCompilesContext > 0:
|
||||
# fail fast:
|
||||
GlobalError(n.info, errTypeMismatch, "")
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
#debug(n.sons[i].typ)
|
||||
if n.sons[i].kind == nkExprEqExpr:
|
||||
add(result, renderTree(n.sons[i].sons[0]))
|
||||
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, ", ")
|
||||
add(result, ')')
|
||||
var candidates = ""
|
||||
var o: TOverloadIter
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, n.sons[0])
|
||||
while sym != nil:
|
||||
if sym.kind in {skProc, skMethod, skIterator, skConverter}:
|
||||
@@ -139,6 +146,7 @@ proc getNotFoundError*(c: PContext, n: PNode): string =
|
||||
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 =
|
||||
@@ -418,7 +426,7 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
result = typeRel(c, f.sons[0], x)
|
||||
if result < isGeneric: result = isNone
|
||||
of tyForward: InternalError("forward type in typeRel()")
|
||||
of tyNil:
|
||||
of tyNil:
|
||||
if a.kind == f.kind: result = isEqual
|
||||
of tyTuple:
|
||||
if a.kind == tyTuple: result = tupleRel(c, f, a)
|
||||
@@ -539,8 +547,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
if result == isGeneric: put(c.bindings, f, a)
|
||||
else:
|
||||
result = isNone
|
||||
of tyExpr, tyStmt, tyProxy:
|
||||
of tyExpr, tyStmt:
|
||||
result = isGeneric
|
||||
of tyProxy:
|
||||
result = isEqual
|
||||
else: internalError("typeRel: " & $f.kind)
|
||||
|
||||
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,
|
||||
c: PContext): PNode =
|
||||
result = newNodeI(kind, arg.info)
|
||||
if containsGenericType(f): result.typ = getInstantiatedType(c, arg, m, f)
|
||||
else: result.typ = f
|
||||
if containsGenericType(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")
|
||||
addSon(result, ast.emptyNode)
|
||||
addSon(result, arg)
|
||||
@@ -648,11 +663,12 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||
result = copyTree(arg)
|
||||
if skipTypes(f, abstractVar).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
of isNone:
|
||||
# we test for this here to not slow down ``typeRel``:
|
||||
of isNone:
|
||||
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||
if a.kind == tyProxy:
|
||||
inc(m.genericMatches)
|
||||
return copyTree(arg)
|
||||
m.proxyMatch = true
|
||||
return copyTree(arg)
|
||||
result = userConvMatch(c, m, f, a, arg)
|
||||
# check for a base type match, which supports openarray[T] without []
|
||||
# constructor in a call:
|
||||
@@ -854,3 +870,5 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||
# use default value:
|
||||
setSon(m.call, formal.position + 1, copyTree(formal.ast))
|
||||
inc(f)
|
||||
|
||||
include suggest
|
||||
|
||||
@@ -9,15 +9,14 @@
|
||||
|
||||
## This file implements features required for IDE support.
|
||||
|
||||
import
|
||||
lexer, idents, ast, astalgo, semdata, msgs, types, sigmatch, options,
|
||||
renderer
|
||||
# imported from sigmatch.nim
|
||||
|
||||
const
|
||||
sep = '\t'
|
||||
sectionSuggest = "sug"
|
||||
sectionDef = "def"
|
||||
sectionContext = "con"
|
||||
sectionUsage = "use"
|
||||
|
||||
proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string =
|
||||
result = section
|
||||
@@ -183,6 +182,16 @@ proc findClosestCall(n: PNode): PNode =
|
||||
result = findClosestCall(n.sons[i])
|
||||
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 =
|
||||
if n.kind == nkSym and msgs.inCheckpoint(n.info) == cpExact:
|
||||
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]))
|
||||
|
||||
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) =
|
||||
var cp = msgs.inCheckpoint(node.info)
|
||||
@@ -243,25 +285,6 @@ proc suggestExpr*(c: PContext, node: PNode) =
|
||||
addSon(a, x)
|
||||
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)
|
||||
if outputs > 0 and optUsages notin gGlobalOptions: quit(0)
|
||||
|
||||
|
||||
@@ -514,3 +514,40 @@ efficient:
|
||||
of "license": c.license = UnixToNativePath(k.value)
|
||||
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
|
||||
|
||||
- ``borrow`` needs to take type classes into account
|
||||
- ``=`` should be overloadable; requires specialization for ``=``
|
||||
- optimize genericAssign in the code generator
|
||||
- fix remaining closure bugs:
|
||||
- fix evals.nim with closures
|
||||
- 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
|
||||
----
|
||||
@@ -36,9 +28,15 @@ version 0.9.XX
|
||||
==============
|
||||
|
||||
- JS gen:
|
||||
- document it
|
||||
- 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
|
||||
- document destructors; don't work yet when used as expression
|
||||
- make use of ``tyIter`` to fix the implicit items/pairs issue
|
||||
|
||||
Reference in New Issue
Block a user