idetools: 'usages' and 'def' should work now; documented js backend

This commit is contained in:
Araq 2012-08-05 12:33:23 +02:00
commit c7158af752
14 changed files with 215 additions and 117 deletions

View file

@ -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:

View file

@ -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

View file

@ -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 = "") =

View file

@ -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)

View file

@ -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]

View file

@ -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}))

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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