resolved conflict for news.txt

This commit is contained in:
Araq 2012-04-21 03:22:53 +02:00
commit 7511a05b27
9 changed files with 244 additions and 204 deletions

View file

@ -477,42 +477,8 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi) result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
else: break else: break
proc primary(p: var TParser, skipSuffix = false): PNode = proc primary(p: var TParser, skipSuffix = false): PNode
# prefix operator?
if isOperator(p.tok):
let isSigil = IsSigilLike(p.tok)
result = newNodeP(nkPrefix, p)
var a = newIdentNodeP(p.tok.ident, p)
addSon(result, a)
getTok(p)
optInd(p, a)
if isSigil:
#XXX prefix operators
addSon(result, primary(p, true))
result = primarySuffix(p, result)
else:
addSon(result, primary(p))
return
elif p.tok.tokType == tkAddr:
result = newNodeP(nkAddr, p)
getTok(p)
addSon(result, primary(p))
return
elif p.tok.tokType == tkStatic:
result = newNodeP(nkStaticExpr, p)
getTok(p)
addSon(result, primary(p))
return
elif p.tok.tokType == tkBind:
result = newNodeP(nkBind, p)
getTok(p)
optInd(p, result)
addSon(result, primary(p))
return
result = identOrLiteral(p)
if not skipSuffix:
result = primarySuffix(p, result)
proc lowestExprAux(p: var TParser, limit: int): PNode = proc lowestExprAux(p: var TParser, limit: int): PNode =
result = primary(p) result = primary(p)
# expand while operators have priorities higher than 'limit' # expand while operators have priorities higher than 'limit'
@ -642,7 +608,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
var a: PNode var a: PNode
result = newNodeP(nkFormalParams, p) result = newNodeP(nkFormalParams, p)
addSon(result, ast.emptyNode) # return type addSon(result, ast.emptyNode) # return type
if p.tok.tokType == tkParLe: if p.tok.tokType == tkParLe:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while true: while true:
@ -660,9 +626,9 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
optInd(p, a) optInd(p, a)
optPar(p) optPar(p)
eat(p, tkParRi) eat(p, tkParRi)
let b = if retColon: p.tok.tokType == tkColon let hasRet = if retColon: p.tok.tokType == tkColon
else: p.tok.tokType == tkOpr and IdentEq(p.tok.ident, "->") else: p.tok.tokType == tkOpr and IdentEq(p.tok.ident, "->")
if b: if hasRet:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
result.sons[0] = parseTypeDesc(p) result.sons[0] = parseTypeDesc(p)
@ -696,6 +662,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
info: TLineInfo info: TLineInfo
info = parLineInfo(p) info = parLineInfo(p)
getTok(p) getTok(p)
let hasSignature = p.tok.tokType in {tkParLe, tkColon}
params = parseParamList(p) params = parseParamList(p)
pragmas = optPragmas(p) pragmas = optPragmas(p)
if (p.tok.tokType == tkEquals) and isExpr: if (p.tok.tokType == tkEquals) and isExpr:
@ -709,8 +676,9 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
else: else:
result = newNodeI(nkProcTy, info) result = newNodeI(nkProcTy, info)
addSon(result, params) if hasSignature:
addSon(result, pragmas) addSon(result, params)
addSon(result, pragmas)
proc isExprStart(p: TParser): bool = proc isExprStart(p: TParser): bool =
case p.tok.tokType case p.tok.tokType
@ -724,39 +692,70 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
if isExprStart(p): if not isOperator(p.tok) and isExprStart(p):
addSon(result, parseTypeDesc(p)) addSon(result, parseTypeDesc(p))
proc parseExpr(p: var TParser): PNode = proc parseExpr(p: var TParser): PNode =
# #
#expr ::= lowestExpr #expr ::= lowestExpr
# | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr # | 'if' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
# | 'var' [expr] # | 'when' expr ':' expr ('elif' expr ':' expr)* 'else' ':' expr
# | 'ref' [expr]
# | 'ptr' [expr]
# | 'type' expr
# | 'tuple' [tupleDesc]
# | 'enum'
# | 'object'
# |
# | 'proc' paramList [pragma] ['=' stmt]
# #
case p.tok.toktype case p.tok.tokType:
of tkIf: result = parseIfExpr(p, nkIfExpr)
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
else: result = lowestExpr(p)
proc primary(p: var TParser, skipSuffix = false): PNode =
# prefix operator?
if isOperator(p.tok):
let isSigil = IsSigilLike(p.tok)
result = newNodeP(nkPrefix, p)
var a = newIdentNodeP(p.tok.ident, p)
addSon(result, a)
getTok(p)
optInd(p, a)
if isSigil:
#XXX prefix operators
addSon(result, primary(p, true))
result = primarySuffix(p, result)
else:
addSon(result, primary(p))
return
case p.tok.tokType:
of tkVar: result = parseTypeDescKAux(p, nkVarTy) of tkVar: result = parseTypeDescKAux(p, nkVarTy)
of tkRef: result = parseTypeDescKAux(p, nkRefTy) of tkRef: result = parseTypeDescKAux(p, nkRefTy)
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy) of tkPtr: result = parseTypeDescKAux(p, nkPtrTy)
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr) of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr)
of tkTuple: result = parseTuple(p) of tkTuple: result = parseTuple(p)
of tkProc: result = parseProcExpr(p, true) of tkProc: result = parseProcExpr(p, true)
of tkIf: result = parseIfExpr(p, nkIfExpr)
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
of tkEnum: of tkEnum:
result = newNodeP(nkEnumTy, p) result = newNodeP(nkEnumTy, p)
getTok(p) getTok(p)
of tkObject: of tkObject:
result = newNodeP(nkObjectTy, p) result = newNodeP(nkObjectTy, p)
getTok(p) getTok(p)
else: result = lowestExpr(p) of tkDistinct:
result = newNodeP(nkDistinctTy, p)
getTok(p)
of tkAddr:
result = newNodeP(nkAddr, p)
getTok(p)
addSon(result, primary(p))
of tkStatic:
result = newNodeP(nkStaticExpr, p)
getTok(p)
addSon(result, primary(p))
of tkBind:
result = newNodeP(nkBind, p)
getTok(p)
optInd(p, result)
addSon(result, primary(p))
else:
result = identOrLiteral(p)
if not skipSuffix:
result = primarySuffix(p, result)
proc parseTypeDesc(p: var TParser): PNode = proc parseTypeDesc(p: var TParser): PNode =
if p.tok.toktype == tkProc: result = parseProcExpr(p, false) if p.tok.toktype == tkProc: result = parseProcExpr(p, false)

View file

@ -16,8 +16,13 @@ proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
else: else:
result = prev result = prev
if result.kind == tyForward: result.kind = kind if result.kind == tyForward: result.kind = kind
proc semEnum(c: PContext, n: PNode, prev: PType): PType = proc newConstraint(c: PContext, k: TTypeKind): PType =
result = newTypeS(tyTypeClass, c)
result.addSon(newTypeS(k, c))
proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if n.sonsLen == 0: return newConstraint(c, tyEnum)
var var
counter, x: BiggestInt counter, x: BiggestInt
e: PSym e: PSym
@ -92,29 +97,30 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
addSon(result, base) addSon(result, base)
else: else:
GlobalError(n.info, errXExpectsOneTypeParam, kindStr) GlobalError(n.info, errXExpectsOneTypeParam, kindStr)
proc semAnyRef(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, proc semAnyRef(c: PContext, n: PNode, kind: TTypeKind, prev: PType): PType =
prev: PType): PType = if sonsLen(n) == 1:
result = newOrPrevType(kind, prev, c) result = newOrPrevType(kind, prev, c)
if sonsLen(n) == 1:
var base = semTypeNode(c, n.sons[0], nil) var base = semTypeNode(c, n.sons[0], nil)
addSon(result, base) addSon(result, base)
else: else:
GlobalError(n.info, errXExpectsOneTypeParam, kindStr) result = newConstraint(c, kind)
proc semVarType(c: PContext, n: PNode, prev: PType): PType = proc semVarType(c: PContext, n: PNode, prev: PType): PType =
result = newOrPrevType(tyVar, prev, c)
if sonsLen(n) == 1: if sonsLen(n) == 1:
result = newOrPrevType(tyVar, prev, c)
var base = semTypeNode(c, n.sons[0], nil) var base = semTypeNode(c, n.sons[0], nil)
if base.kind == tyVar: GlobalError(n.info, errVarVarTypeNotAllowed) if base.kind == tyVar: GlobalError(n.info, errVarVarTypeNotAllowed)
addSon(result, base) addSon(result, base)
else: else:
GlobalError(n.info, errXExpectsOneTypeParam, "var") result = newConstraint(c, tyVar)
proc semDistinct(c: PContext, n: PNode, prev: PType): PType = proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
result = newOrPrevType(tyDistinct, prev, c) if sonsLen(n) == 1:
if sonsLen(n) == 1: addSon(result, semTypeNode(c, n.sons[0], nil)) result = newOrPrevType(tyDistinct, prev, c)
else: GlobalError(n.info, errXExpectsOneTypeParam, "distinct") addSon(result, semTypeNode(c, n.sons[0], nil))
else:
result = newConstraint(c, tyDistinct)
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
assert IsRange(n) assert IsRange(n)
@ -184,7 +190,11 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
# This is a typedesc param. is it already bound? # This is a typedesc param. is it already bound?
# it's not bound when it's also used as return type for example # it's not bound when it's also used as return type for example
if result.typ.sonsLen > 0: if result.typ.sonsLen > 0:
return result.typ.sons[0].sym let bound = result.typ.sons[0].sym
if bound != nil:
return bound
else:
return result.typ.sym
else: else:
return result.typ.sym return result.typ.sym
if result.kind != skType: GlobalError(n.info, errTypeExpected) if result.kind != skType: GlobalError(n.info, errTypeExpected)
@ -197,8 +207,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
GlobalError(n.info, errIdentifierExpected) GlobalError(n.info, errIdentifierExpected)
proc semTuple(c: PContext, n: PNode, prev: PType): PType = proc semTuple(c: PContext, n: PNode, prev: PType): PType =
var if n.sonsLen == 0: return newConstraint(c, tyTuple)
typ: PType var typ: PType
result = newOrPrevType(tyTuple, prev, c) result = newOrPrevType(tyTuple, prev, c)
result.n = newNodeI(nkRecList, n.info) result.n = newNodeI(nkRecList, n.info)
var check = initIntSet() var check = initIntSet()
@ -458,7 +468,8 @@ proc skipGenericInvokation(t: PType): PType {.inline.} =
if result.kind == tyGenericBody: if result.kind == tyGenericBody:
result = lastSon(result) result = lastSon(result)
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
if n.sonsLen == 0: return newConstraint(c, tyObject)
var check = initIntSet() var check = initIntSet()
var pos = 0 var pos = 0
var base: PType = nil var base: PType = nil
@ -529,6 +540,36 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
result.typ = copyType(paramType, getCurrOwner(), false) result.typ = copyType(paramType, getCurrOwner(), false)
else: nil else: nil
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramType: PType, paramName: string): PType =
## Params having implicit generic types or pseudo types such as 'expr'
## need to be added to the generic params lists.
## 'expr' is different from 'expr{string}' so we must first call
## paramTypeClass to get the actual type we are going to use.
result = paramType
var (typeClass, paramTypId) = paramTypeClass(c, paramType, procKind)
let isAnon = paramTypId == nil
if typeClass != nil:
if isAnon: paramTypId = getIdent(paramName & ":type")
if genericParams == nil:
# genericParams is nil when the proc is being instantiated
# the resolved type will be in scope then
result = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
else:
block addImplicitGeneric:
# is this a bindOnce type class already present in the param list?
for i in countup(0, genericParams.len - 1):
if genericParams.sons[i].sym.name == paramTypId:
result = genericParams.sons[i].typ
break addImplicitGeneric
var s = newSym(skType, paramTypId, getCurrOwner())
if isAnon: s.flags.incl(sfAnon)
s.linkTo(typeClass)
s.position = genericParams.len
genericParams.addSon(newSymNode(s))
result = typeClass
proc semProcTypeNode(c: PContext, n, genericParams: PNode, proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType, kind: TSymKind): PType = prev: PType, kind: TSymKind): PType =
var var
@ -576,37 +617,15 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
for j in countup(0, length-3): for j in countup(0, length-3):
var arg = newSymS(skParam, a.sons[j], c) var arg = newSymS(skParam, a.sons[j], c)
var endingType = typ var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s)
var (typeClass, paramTypId) = paramTypeClass(c, typ, kind) arg.typ = finalType
if typeClass != nil:
if paramTypId == nil: paramTypId = getIdent(arg.name.s & ":type")
if genericParams == nil:
# genericParams is nil when the proc is being instantiated
# the resolved type will be in scope then
endingType = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
else:
block addImplicitGeneric:
# is this a bindOnce type class already present in the param list?
for i in countup(0, genericParams.len - 1):
if genericParams.sons[i].sym.name == paramTypId:
endingType = genericParams.sons[i].typ
break addImplicitGeneric
var s = newSym(skType, paramTypId, getCurrOwner())
s.flags.incl(sfAnon)
s.linkTo(typeClass)
s.position = genericParams.len
genericParams.addSon(newSymNode(s))
endingType = typeClass
arg.typ = endingType
arg.position = counter arg.position = counter
inc(counter) inc(counter)
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
if ContainsOrIncl(check, arg.name.id): if ContainsOrIncl(check, arg.name.id):
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s) LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
addSon(result.n, newSymNode(arg)) addSon(result.n, newSymNode(arg))
addSon(result, endingType) addSon(result, finalType)
addParamOrResult(c, arg, kind) addParamOrResult(c, arg, kind)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
@ -614,6 +633,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# turn explicit 'void' return type into 'nil' because the rest of the # turn explicit 'void' return type into 'nil' because the rest of the
# compiler only checks for 'nil': # compiler only checks for 'nil':
if skipTypes(r, {tyGenericInst}).kind != tyEmpty: if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
if r.sym == nil or sfAnon notin r.sym.flags:
r = liftParamType(c, kind, genericParams, r, "result")
result.sons[0] = r result.sons[0] = r
res.typ = result.sons[0] res.typ = result.sons[0]
@ -708,8 +729,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else: GlobalError(n.info, errTypeExpected) else: GlobalError(n.info, errTypeExpected)
of nkCallKinds: of nkCallKinds:
let op = n.sons[0].ident.id let op = n.sons[0].ident
if op in {ord(wAnd), ord(wOr)}: if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
var var
t1 = semTypeNode(c, n.sons[1], nil) t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil) t2 = semTypeNode(c, n.sons[2], nil)
@ -720,7 +741,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = newTypeS(tyTypeClass, c) result = newTypeS(tyTypeClass, c)
result.addSon(t1) result.addSon(t1)
result.addSon(t2) result.addSon(t2)
result.flags.incl(if op == ord(wAnd): tfAll else: tfAny) result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
else: else:
result = semTypeFromMacro(c, n) result = semTypeFromMacro(c, n)
of nkCurlyExpr: of nkCurlyExpr:
@ -766,11 +787,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
GlobalError(n.info, errTypeExpected) GlobalError(n.info, errTypeExpected)
of nkObjectTy: result = semObjectNode(c, n, prev) of nkObjectTy: result = semObjectNode(c, n, prev)
of nkTupleTy: result = semTuple(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev)
of nkRefTy: result = semAnyRef(c, n, tyRef, "ref", prev) of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
of nkPtrTy: result = semAnyRef(c, n, tyPtr, "ptr", prev) of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
of nkVarTy: result = semVarType(c, n, prev) of nkVarTy: result = semVarType(c, n, prev)
of nkDistinctTy: result = semDistinct(c, n, prev) of nkDistinctTy: result = semDistinct(c, n, prev)
of nkProcTy: of nkProcTy:
if n.sonsLen == 0: return newConstraint(c, tyProc)
checkSonsLen(n, 2) checkSonsLen(n, 2)
openScope(c.tab) openScope(c.tab)
result = semProcTypeNode(c, n.sons[0], nil, prev, skProc) result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
@ -778,7 +800,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c) var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
s.typ = result s.typ = result
pragma(c, s, n.sons[1], procTypePragmas) pragma(c, s, n.sons[1], procTypePragmas)
closeScope(c.tab) closeScope(c.tab)
of nkEnumTy: result = semEnum(c, n, prev) of nkEnumTy: result = semEnum(c, n, prev)
of nkType: result = n.typ of nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev) of nkStmtListType: result = semStmtListType(c, n, prev)
@ -828,29 +850,12 @@ proc processMagicType(c: PContext, m: PSym) =
of mPNimrodNode: nil of mPNimrodNode: nil
else: GlobalError(m.info, errTypeExpected) else: GlobalError(m.info, errTypeExpected)
proc newConstraint(c: PContext, k: TTypeKind): PType =
result = newTypeS(tyTypeClass, c)
result.addSon(newTypeS(k, c))
proc semGenericConstraints(c: PContext, n: PNode, result: PType) = proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
case n.kind var x = semTypeNode(c, n, nil)
of nkProcTy: result.addSon(newConstraint(c, tyProc)) if x.kind in StructuralEquivTypes and (
of nkEnumTy: result.addSon(newConstraint(c, tyEnum)) sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
of nkObjectTy: result.addSon(newConstraint(c, tyObject)) x = newConstraint(c, x.kind)
of nkTupleTy: result.addSon(newConstraint(c, tyTuple)) result.addSon(x)
of nkDistinctTy: result.addSon(newConstraint(c, tyDistinct))
of nkVarTy: result.addSon(newConstraint(c, tyVar))
of nkPtrTy: result.addSon(newConstraint(c, tyPtr))
of nkRefTy: result.addSon(newConstraint(c, tyRef))
of nkInfix:
semGenericConstraints(c, n.sons[1], result)
semGenericConstraints(c, n.sons[2], result)
else:
var x = semTypeNode(c, n, nil)
if x.kind in StructuralEquivTypes and (
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
x = newConstraint(c, x.kind)
result.addSon(x)
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
result = copyNode(n) result = copyNode(n)

View file

@ -17,8 +17,10 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) =
elif t.kind == tyVar and t.sons[0].kind == tyVar: elif t.kind == tyVar and t.sons[0].kind == tyVar:
LocalError(info, errVarVarTypeNotAllowed) LocalError(info, errVarVarTypeNotAllowed)
proc checkConstructedType*(info: TLineInfo, t: PType) = proc checkConstructedType*(info: TLineInfo, typ: PType) =
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: var t = typ.skipTypes({tyDistinct})
if t.kind in {tyTypeClass}: nil
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
LocalError(info, errInvalidPragmaX, "acyclic") LocalError(info, errInvalidPragmaX, "acyclic")
elif t.kind == tyVar and t.sons[0].kind == tyVar: elif t.kind == tyVar and t.sons[0].kind == tyVar:
LocalError(info, errVarVarTypeNotAllowed) LocalError(info, errVarVarTypeNotAllowed)

View file

@ -459,33 +459,22 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}: if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
InternalError("wrong instantiated type!") InternalError("wrong instantiated type!")
put(mapping, f.sons[i], x) put(mapping, f.sons[i], x)
of tyGenericParam: of tyGenericParam, tyTypeClass:
var x = PType(idTableGet(mapping, f)) var x = PType(idTableGet(mapping, f))
if x == nil: if x == nil:
if sonsLen(f) == 0: result = matchTypeClass(mapping, f, a)
# no constraints if result == isGeneric:
var concrete = concreteType(mapping, a) var concrete = concreteType(mapping, a)
if concrete != nil: if concrete == nil:
result = isNone
else:
put(mapping, f, concrete) put(mapping, f, concrete)
result = isGeneric elif a.kind == tyEmpty:
else:
# check constraints:
for i in countup(0, sonsLen(f) - 1):
if typeRel(mapping, f.sons[i], a) >= isSubtype:
var concrete = concreteType(mapping, a)
if concrete != nil:
put(mapping, f, concrete)
result = isGeneric
break
elif a.kind == tyEmpty:
result = isGeneric result = isGeneric
elif x.kind == tyGenericParam: elif x.kind == tyGenericParam:
result = isGeneric result = isGeneric
else: else:
result = typeRel(mapping, x, a) # check if it fits result = typeRel(mapping, x, a) # check if it fits
of tyTypeClass:
result = matchTypeClass(mapping, f, a)
if result == isGeneric: put(mapping, f, a)
of tyTypeDesc: of tyTypeDesc:
if a.kind == tyTypeDesc: if a.kind == tyTypeDesc:
if f.sonsLen == 0: if f.sonsLen == 0:

View file

@ -406,20 +406,22 @@ proc drawEllipse*(sur: PSurface, CX, CY, XRadius, YRadius: Natural,
inc(YChange,TwoASquare) inc(YChange,TwoASquare)
proc plotAA(sur: PSurface, x, y, c: float, color: TColor) = proc plotAA(sur: PSurface, x, y: int, c: float, color: TColor) =
if (x.toInt() > 0 and x.toInt() < sur.s.w) and (y.toInt() > 0 and if (x > 0 and x < sur.s.w) and (y > 0 and
y.toInt() < sur.s.h): y < sur.s.h):
var video = cast[PPixels](sur.s.pixels) var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch div ColSize var pitch = sur.s.pitch div ColSize
var pixColor = getPix(video, pitch, x.toInt, y.toInt) var pixColor = getPix(video, pitch, x, y)
setPix(video, pitch, x.toInt(), y.toInt(), setPix(video, pitch, x, y,
pixColor.intensity(1.0 - c) + color.intensity(c)) pixColor.intensity(1.0 - c) + color.intensity(c))
proc ipart(x: float): float = return x.trunc()
proc fpart(x: float): float = return x - ipart(x) template ipart(x: expr): expr = floor(x)
proc rfpart(x: float): float = return 1.0 - fpart(x) template cround(x: expr): expr = ipart(x + 0.5)
template fpart(x: expr): expr = x - ipart(x)
template rfpart(x: expr): expr = 1.0 - fpart(x)
proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: TColor) = proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: TColor) =
## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's ## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's
@ -428,36 +430,56 @@ proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: TColor) =
p1.y.toFloat(), p2.y.toFloat()) p1.y.toFloat(), p2.y.toFloat())
var dx = x2 - x1 var dx = x2 - x1
var dy = y2 - y1 var dy = y2 - y1
if abs(dx) < abs(dy):
var ax = dx
if ax < 0'f64:
ax = 0'f64 - ax
var ay = dy
if ay < 0'f64:
ay = 0'f64 - ay
if ax < ay:
swap(x1, y1) swap(x1, y1)
swap(x2, y2) swap(x2, y2)
swap(dx, dy)
template doPlot(x, y: int, c: float, color: TColor): stmt =
if ax < ay:
sur.PlotAA(y, x, c, color)
else:
sur.PlotAA(x, y, c, color)
if x2 < x1: if x2 < x1:
swap(x1, x2) swap(x1, x2)
swap(y1, y2) swap(y1, y2)
var gradient = dy / dx var gradient = dy / dx
# handle first endpoint # handle first endpoint
var xend = x1 # Should be round(x1), but since this is an int anyway.. var xend = cround(x1)
var yend = y1 + gradient * (xend - x1) var yend = y1 + gradient * (xend - x1)
var xgap = rfpart(x1 + 0.5) var xgap = rfpart(x1 + 0.5)
var xpxl1 = xend # this will be used in the main loop var xpxl1 = int(xend) # this will be used in the main loop
var ypxl1 = ipart(yend) var ypxl1 = int(ipart(yend))
sur.plotAA(xpxl1, ypxl1, rfpart(yend) * xgap, color) doPlot(xpxl1, ypxl1, rfpart(yend)*xgap, color)
sur.plotAA(xpxl1, ypxl1 + 1.0, fpart(yend) * xgap, color) doPlot(xpxl1, ypxl1 + 1, fpart(yend)*xgap, color)
var intery = yend + gradient # first y-intersection for the main loop var intery = yend + gradient # first y-intersection for the main loop
# handle second endpoint # handle second endpoint
xend = x2 # Should be round(x1), but since this is an int anyway.. xend = cround(x2)
yend = y2 + gradient * (xend - x2) yend = y2 + gradient * (xend - x2)
xgap = fpart(x2 + 0.5) xgap = fpart(x2 + 0.5)
var xpxl2 = xend # this will be used in the main loop var xpxl2 = int(xend) # this will be used in the main loop
var ypxl2 = ipart(yend) var ypxl2 = int(ipart(yend))
sur.plotAA(xpxl2, ypxl2, rfpart(yend) * xgap, color) doPlot(xpxl2, ypxl2, rfpart(yend) * xgap, color)
sur.plotAA(xpxl2, ypxl2 + 1.0, fpart(yend) * xgap, color) doPlot(xpxl2, ypxl2 + 1, fpart(yend) * xgap, color)
# main loop # main loop
for x in xpxl1.toInt + 1..xpxl2.toInt - 1: var x = xpxl1 + 1
sur.plotAA(x.toFloat(), ipart(intery), rfpart(intery), color) while x <= xpxl2-1:
sur.plotAA(x.toFloat(), ipart(intery) + 1.0, fpart(intery), color) doPlot(x, int(ipart(intery)), rfpart(intery), color)
doPlot(x, int(ipart(intery)) + 1, fpart(intery), color)
intery = intery + gradient intery = intery + gradient
inc(x)
proc fillSurface*(sur: PSurface, color: TColor) = proc fillSurface*(sur: PSurface, color: TColor) =
## Fills the entire surface with ``color``. ## Fills the entire surface with ``color``.
@ -469,7 +491,7 @@ template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt =
## variable containing the TEvent object. ## variable containing the TEvent object.
while True: while True:
var event: SDL.TEvent var event: SDL.TEvent
if SDL.PollEvent(addr(event)) == 1: if SDL.WaitEvent(addr(event)) == 1:
actions actions
if sdl.Init(sdl.INIT_VIDEO) < 0: raiseEGraphics() if sdl.Init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
@ -478,9 +500,9 @@ if sdl_ttf.Init() < 0: raiseEGraphics()
when isMainModule: when isMainModule:
var surf = newScreenSurface(800, 600) var surf = newScreenSurface(800, 600)
surf.fillSurface(colWhite) surf.fillSurface(colWhite)
# Draw the shapes # Draw the shapes
surf.drawLineAA((100, 170), (400, 471), colTan) surf.drawLineAA((150, 170), (400, 471), colTan)
surf.drawLine((100, 170), (400, 471), colRed) surf.drawLine((100, 170), (400, 471), colRed)
surf.drawEllipse(200, 300, 200, 30, colSeaGreen) surf.drawEllipse(200, 300, 200, 30, colSeaGreen)
@ -496,14 +518,16 @@ when isMainModule:
surf.drawCircle((600, 500), 60, colRed) surf.drawCircle((600, 500), 60, colRed)
surf.fillRect((50, 50, 100, 100), colFuchsia) surf.fillRect((50, 50, 100, 100), colFuchsia)
surf.drawLineAA((592, 160), (592, 280), colPurple)
#surf.drawText((300, 300), "TEST", colMidnightBlue) #surf.drawText((300, 300), "TEST", colMidnightBlue)
#var textSize = textBounds("TEST") #var textSize = textBounds("TEST")
#surf.drawText((300, 300 + textSize.height), $textSize.width & ", " & #surf.drawText((300, 300 + textSize.height), $textSize.width & ", " &
# $textSize.height, colDarkGreen) # $textSize.height, colDarkGreen)
var mouseStartX = 0 var mouseStartX = -1
var mouseStartY = 0 var mouseStartY = -1
withEvents(surf, event): withEvents(surf, event):
var eventp = addr(event) var eventp = addr(event)
case event.kind: case event.kind:
@ -518,22 +542,19 @@ when isMainModule:
echo(evk.keysym.sym) echo(evk.keysym.sym)
of SDL.MOUSEBUTTONDOWN: of SDL.MOUSEBUTTONDOWN:
var mbd = sdl.EvMouseButton(eventp) var mbd = sdl.EvMouseButton(eventp)
mouseStartX = mbd.x if mouseStartX == -1 or mouseStartY == -1:
mouseStartY = mbd.y mouseStartX = int(mbd.x)
mouseStartY = int(mbd.y)
of SDL.MOUSEBUTTONUP: else:
var mbu = sdl.EvMouseButton(eventp) surf.drawLineAA((mouseStartX, mouseStartY), (int(mbd.x), int(mbd.y)), colPurple)
if mouseStartX != 0 and mouseStartY != 0: mouseStartX = -1
echo(mouseStartX, "x->", mbu.x) mouseStartY = -1
echo(mouseStartY, "y->", mbu.y)
surf.drawLineAA((mouseStartX, MouseStartY),
(int(mbu.x), int(mbu.y)), colRed)
mouseStartX = 0
mouseStartY = 0
of SDL.MouseMotion: of SDL.MouseMotion:
var mm = sdl.EvMouseMotion(eventp) var mm = sdl.EvMouseMotion(eventp)
echo(mm.x, " ", mm.y, " ", mm.yrel) if mouseStartX != -1 and mouseStartY != -1:
surf.drawLineAA((mouseStartX, mouseStartY), (int(mm.x), int(mm.y)), colPurple)
#echo(mm.x, " ", mm.y, " ", mm.yrel)
else: else:
#echo(event.kind) #echo(event.kind)

View file

@ -1889,7 +1889,7 @@ proc setpwent*() {.importc, header: "<pwd.h>".}
proc uname*(a1: var Tutsname): cint {.importc, header: "<sys/utsname.h>".} proc uname*(a1: var Tutsname): cint {.importc, header: "<sys/utsname.h>".}
proc pthread_atfork*(a1, a2, a3: proc {.noconv.}): cint {. proc pthread_atfork*(a1, a2, a3: proc () {.noconv.}): cint {.
importc, header: "<pthread.h>".} importc, header: "<pthread.h>".}
proc pthread_attr_destroy*(a1: ptr Tpthread_attr): cint {. proc pthread_attr_destroy*(a1: ptr Tpthread_attr): cint {.
importc, header: "<pthread.h>".} importc, header: "<pthread.h>".}
@ -2015,7 +2015,7 @@ proc pthread_mutexattr_setprotocol*(a1: ptr Tpthread_mutexattr, a2: cint): cint
proc pthread_mutexattr_setpshared*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".} proc pthread_mutexattr_setpshared*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_mutexattr_settype*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".} proc pthread_mutexattr_settype*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_once*(a1: ptr Tpthread_once, a2: proc {.noconv.}): cint {.importc, header: "<pthread.h>".} proc pthread_once*(a1: ptr Tpthread_once, a2: proc () {.noconv.}): cint {.importc, header: "<pthread.h>".}
proc pthread_rwlock_destroy*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".} proc pthread_rwlock_destroy*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".}
proc pthread_rwlock_init*(a1: ptr Tpthread_rwlock, proc pthread_rwlock_init*(a1: ptr Tpthread_rwlock,

View file

@ -48,8 +48,14 @@ type
typeDesc* {.magic: TypeDesc.} ## meta type to denote typeDesc* {.magic: TypeDesc.} ## meta type to denote
## a type description (for templates) ## a type description (for templates)
void* {.magic: "VoidType".} ## meta type to denote the absense of any type void* {.magic: "VoidType".} ## meta type to denote the absense of any type
TInteger* = int|char|int8|int16|int32|int64|bool|enum
## type class matching all integer types
proc defined*[T](x: T): bool {.magic: "Defined", noSideEffect.} TNumber* = TInteger|float|float32|float64
## type class matching all number types
proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
## Special compile-time procedure that checks whether `x` is ## Special compile-time procedure that checks whether `x` is
## defined. `x` has to be an identifier or a qualified identifier. ## defined. `x` has to be an identifier or a qualified identifier.
## This can be used to check whether a library provides a certain ## This can be used to check whether a library provides a certain
@ -60,7 +66,7 @@ proc defined*[T](x: T): bool {.magic: "Defined", noSideEffect.}
## # provide our own toUpper proc here, because strutils is ## # provide our own toUpper proc here, because strutils is
## # missing it. ## # missing it.
proc definedInScope*[T](x: T): bool {. proc definedInScope*(x: expr): bool {.
magic: "DefinedInScope", noSideEffect.} magic: "DefinedInScope", noSideEffect.}
## Special compile-time procedure that checks whether `x` is ## Special compile-time procedure that checks whether `x` is
## defined in the current scope. `x` has to be an identifier. ## defined in the current scope. `x` has to be an identifier.
@ -971,7 +977,7 @@ proc toBiggestInt*(f: biggestfloat): biggestint {.
## rounds `f` if it does not contain an integer value. If the conversion ## rounds `f` if it does not contain an integer value. If the conversion
## fails (because `f` is infinite for example), `EInvalidValue` is raised. ## fails (because `f` is infinite for example), `EInvalidValue` is raised.
proc addQuitProc*(QuitProc: proc {.noconv.}) {.importc: "atexit", nodecl.} proc addQuitProc*(QuitProc: proc() {.noconv.}) {.importc: "atexit", nodecl.}
## adds/registers a quit procedure. Each call to ``addQuitProc`` ## adds/registers a quit procedure. Each call to ``addQuitProc``
## registers another quit procedure. Up to 30 procedures can be ## registers another quit procedure. Up to 30 procedures can be
## registered. They are executed on a last-in, first-out basis ## registered. They are executed on a last-in, first-out basis
@ -1214,6 +1220,11 @@ proc max*[T](x: openarray[T]): T =
result = x[0] result = x[0]
for i in 1..high(x): result = max(result, x[i]) for i in 1..high(x): result = max(result, x[i])
proc clamp*[T](x, a, b: T): T =
## limits the value ``x`` within the interval [a, b]
if x > a: return a
if x < b: return b
return x
iterator items*[T](a: openarray[T]): T {.inline.} = iterator items*[T](a: openarray[T]): T {.inline.} =
## iterates over each item of `a`. ## iterates over each item of `a`.
@ -1263,6 +1274,10 @@ iterator items*(a: cstring): char {.inline.} =
yield a[i] yield a[i]
inc(i) inc(i)
iterator items*(E: typedesc{enum}): E =
## iterates over the values of the enum ``E``.
for v in low(E)..high(E):
yield v
iterator pairs*[T](a: openarray[T]): tuple[key: int, val: T] {.inline.} = iterator pairs*[T](a: openarray[T]): tuple[key: int, val: T] {.inline.} =
## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
@ -1374,7 +1389,8 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
## `op` to every item in `data`. ## `op` to every item in `data`.
for i in 0..data.len-1: op(data[i]) for i in 0..data.len-1: op(data[i])
iterator fields*[T: tuple](x: T): expr {.magic: "Fields", noSideEffect.} iterator fields*[T: tuple](x: T): TObject {.
magic: "Fields", noSideEffect.}
## iterates over every field of `x`. Warning: This really transforms ## iterates over every field of `x`. Warning: This really transforms
## the 'for' and unrolls the loop. The current implementation also has a bug ## the 'for' and unrolls the loop. The current implementation also has a bug
## that affects symbol binding in the loop body. ## that affects symbol binding in the loop body.
@ -1384,7 +1400,8 @@ iterator fields*[S: tuple, T: tuple](x: S, y: T): tuple[a, b: expr] {.
## Warning: This is really transforms the 'for' and unrolls the loop. ## Warning: This is really transforms the 'for' and unrolls the loop.
## The current implementation also has a bug that affects symbol binding ## The current implementation also has a bug that affects symbol binding
## in the loop body. ## in the loop body.
iterator fieldPairs*[T: tuple](x: T): expr {.magic: "FieldPairs", noSideEffect.} iterator fieldPairs*[T: tuple](x: T): TObject {.
magic: "FieldPairs", noSideEffect.}
## iterates over every field of `x`. Warning: This really transforms ## iterates over every field of `x`. Warning: This really transforms
## the 'for' and unrolls the loop. The current implementation also has a bug ## the 'for' and unrolls the loop. The current implementation also has a bug
## that affects symbol binding in the loop body. ## that affects symbol binding in the loop body.
@ -1511,7 +1528,7 @@ const nimrodStackTrace = compileOption("stacktrace")
# of the code # of the code
var var
dbgLineHook*: proc dbgLineHook*: proc ()
## set this variable to provide a procedure that should be called before ## set this variable to provide a procedure that should be called before
## each executed instruction. This should only be used by debuggers! ## each executed instruction. This should only be used by debuggers!
## Only code compiled with the ``debugger:on`` switch calls this hook. ## Only code compiled with the ``debugger:on`` switch calls this hook.
@ -1531,7 +1548,7 @@ var
## do when setting this. If ``localRaiseHook`` returns false, the exception ## do when setting this. If ``localRaiseHook`` returns false, the exception
## is caught and does not propagate further through the call stack. ## is caught and does not propagate further through the call stack.
outOfMemHook*: proc outOfMemHook*: proc ()
## set this variable to provide a procedure that should be called ## set this variable to provide a procedure that should be called
## in case of an `out of memory`:idx: event. The standard handler ## in case of an `out of memory`:idx: event. The standard handler
## writes an error message and terminates the program. `outOfMemHook` can ## writes an error message and terminates the program. `outOfMemHook` can

View file

@ -5,7 +5,7 @@ discard """
type TAlphabet = enum type TAlphabet = enum
A, B, C A, B, C
iterator items(E: typedesc): E = iterator items(E: typedesc{enum}): E =
for v in low(E)..high(E): for v in low(E)..high(E):
yield v yield v

View file

@ -35,6 +35,10 @@ Library Additions
- Added a wrapper for ``libsvm``. - Added a wrapper for ``libsvm``.
- Added a wrapper for ``mongodb``. - Added a wrapper for ``mongodb``.
- Added ``terminal.isatty``. - Added ``terminal.isatty``.
- Added overload for ``system.items`` that can be used to iterate over the
values of an enum.
- Added ``system.TInteger`` and ``system.TNumber`` type classes matching
any of the corresponding type available in nimrod.
- The GC supports (soft) realtime systems via ``GC_setMaxPause`` - The GC supports (soft) realtime systems via ``GC_setMaxPause``
and ``GC_step`` procs. and ``GC_step`` procs.
@ -54,6 +58,9 @@ Changes affecting backwards compatibility
``PNimrodNode`` which unfortunately breaks the old macro system. ``PNimrodNode`` which unfortunately breaks the old macro system.
- ``pegs.@`` has been renamed to ``pegs.!*`` and ``pegs.@@`` has been renamed - ``pegs.@`` has been renamed to ``pegs.!*`` and ``pegs.@@`` has been renamed
to ``pegs.!*\`` as ``@`` operators now have different precedence. to ``pegs.!*\`` as ``@`` operators now have different precedence.
- the type ``proc`` (without any params or return type) is now considered a
type class matching all proc types. Use ``proc ()`` to get the old meaning
denoting a proc expecing no arguments and returing no value.
Compiler Additions Compiler Additions