Merge branch 'master' into asyncmacro
This commit is contained in:
commit
3e7ea859ec
28 changed files with 2485 additions and 19 deletions
|
|
@ -488,7 +488,7 @@ type
|
|||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
||||
mNBindSym, mLocals, mNCallSite,
|
||||
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo
|
||||
mInstantiationInfo, mGetTypeInfo, mNGenSym
|
||||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
|
|
|
|||
|
|
@ -1249,6 +1249,16 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
|||
of mNBindSym:
|
||||
# trivial implementation:
|
||||
result = n.sons[1]
|
||||
of mNGenSym:
|
||||
evalX(n.sons[1], {efLValue})
|
||||
let k = getOrdValue(result)
|
||||
evalX(n.sons[2], {efLValue})
|
||||
let b = result
|
||||
let name = if b.strVal.len == 0: ":tmp" else: b.strVal
|
||||
if k < 0 or k > ord(high(TSymKind)):
|
||||
internalError(n.info, "request to create a symbol with invalid kind")
|
||||
result = newSymNode(newSym(k.TSymKind, name.getIdent, c.module, n.info))
|
||||
incl(result.sym.flags, sfGenSym)
|
||||
of mStrToIdent:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
|
|
|
|||
33
compiler/nimeval.nim
Normal file
33
compiler/nimeval.nim
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## exposes the Nimrod VM to clients.
|
||||
|
||||
import
|
||||
ast, modules, passes, passaux, condsyms,
|
||||
options, nimconf, lists, sem, semdata, llstream, vm
|
||||
|
||||
proc execute*(program: string) =
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
initDefines()
|
||||
LoadConfigs(DefaultConfig)
|
||||
|
||||
initDefines()
|
||||
DefineSymbol("nimrodvm")
|
||||
when hasFFI: DefineSymbol("nimffi")
|
||||
registerPass(verbosePass)
|
||||
registerPass(semPass)
|
||||
registerPass(vmPass)
|
||||
|
||||
appendStr(searchPaths, options.libpath)
|
||||
compileSystemModule()
|
||||
var m = makeStdinModule()
|
||||
incl(m.flags, sfMainModule)
|
||||
processModule(m, LLStreamOpen(program), nil)
|
||||
|
|
@ -625,6 +625,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
|||
result = newIntNodeT(sonsLen(a), n)
|
||||
else:
|
||||
result = magicCall(m, n)
|
||||
of mLengthArray:
|
||||
# It doesn't matter if the argument is const or not for mLengthArray.
|
||||
# This fixes bug #544.
|
||||
result = newIntNodeT(lengthOrd(n.sons[1].typ), n)
|
||||
of mAstToStr:
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||
of mConStrStr:
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
|
||||
closeScope(c)
|
||||
of nkPragma, nkPragmaExpr: nil
|
||||
of nkExprColonExpr:
|
||||
of nkExprColonExpr, nkExprEqExpr:
|
||||
checkMinSonsLen(n, 2)
|
||||
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -841,7 +841,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
LocalError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
of nkCallKinds:
|
||||
if n[0].kind == nkIdent:
|
||||
if isRange(n):
|
||||
result = semRangeAux(c, n, prev)
|
||||
elif n[0].kind == nkIdent:
|
||||
let op = n.sons[0].ident
|
||||
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
|
||||
checkSonsLen(n, 3)
|
||||
|
|
|
|||
|
|
@ -959,8 +959,8 @@ proc skipGenericAlias*(t: PType): PType =
|
|||
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
||||
for i in countup(0, typeClass.sonsLen - 1):
|
||||
let req = typeClass.sons[i]
|
||||
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
|
||||
|
||||
var match = req.kind == skipTypes(t, {tyGenericInst, tyRange}).kind or
|
||||
req.kind == skipTypes(t, {tyGenericInst}).kind
|
||||
if not match:
|
||||
case req.kind
|
||||
of tyGenericBody:
|
||||
|
|
|
|||
584
compiler/vm.nim
Normal file
584
compiler/vm.nim
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This file implements the new evaluation engine for Nimrod code.
|
||||
## An instruction is 1-2 int32s in memory, it is a register based VM.
|
||||
|
||||
import ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned
|
||||
|
||||
type
|
||||
PStackFrame* = ref TStackFrame
|
||||
TStackFrame* = object
|
||||
prc: PSym # current prc; proc that is evaluated
|
||||
slots: TNodeSeq # parameters passed to the proc + locals;
|
||||
# parameters come first
|
||||
next: PStackFrame # for stacking
|
||||
comesFrom: int
|
||||
safePoints: seq[int] # used for exception handling
|
||||
# XXX 'break' should perform cleanup actions
|
||||
# What does the C backend do for it?
|
||||
|
||||
proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) =
|
||||
if x != nil:
|
||||
stackTraceAux(c, x.next, x.comesFrom)
|
||||
var info = c.debug[pc]
|
||||
# we now use the same format as in system/except.nim
|
||||
var s = toFilename(info)
|
||||
var line = toLineNumber(info)
|
||||
if line > 0:
|
||||
add(s, '(')
|
||||
add(s, $line)
|
||||
add(s, ')')
|
||||
if x.prc != nil:
|
||||
for k in 1..max(1, 25-s.len): add(s, ' ')
|
||||
add(s, x.prc.name.s)
|
||||
MsgWriteln(s)
|
||||
|
||||
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
|
||||
msg: TMsgKind, arg = "") =
|
||||
MsgWriteln("stack trace: (most recent call last)")
|
||||
stackTraceAux(c, tos, pc)
|
||||
LocalError(c.debug[pc], msg, arg)
|
||||
|
||||
proc bailOut(c: PCtx; tos: PStackFrame) =
|
||||
stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
|
||||
c.currentExceptionA.sons[2].strVal)
|
||||
|
||||
when not defined(nimHasInterpreterLoop):
|
||||
{.pragma: interpreterLoop.}
|
||||
|
||||
template inc(pc: ptr TInstr, diff = 1) =
|
||||
inc cast[TAddress](pc), TInstr.sizeof * diff
|
||||
|
||||
template ensureKind(k: expr) {.immediate, dirty.} =
|
||||
if regs[ra].kind != k:
|
||||
myreset(regs[ra])
|
||||
regs[ra].kind = k
|
||||
|
||||
template decodeB(k: expr) {.immediate, dirty.} =
|
||||
let rb = instr.regB
|
||||
ensureKind(k)
|
||||
|
||||
template decodeBC(k: expr) {.immediate, dirty.} =
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
ensureKind(k)
|
||||
|
||||
template decodeBImm(k: expr) {.immediate, dirty.} =
|
||||
let rb = instr.regB
|
||||
let imm = instr.regC - byteExcess
|
||||
ensureKind(k)
|
||||
|
||||
template decodeBx(k: expr) {.immediate, dirty.} =
|
||||
let rbx = instr.regBx - wordExcess
|
||||
ensureKind(k)
|
||||
|
||||
proc compile(c: PCtx, s: PSym): int = vmgen.genProc(c, s)
|
||||
|
||||
proc myreset(n: PNode) =
|
||||
when defined(system.reset):
|
||||
var oldInfo = n.info
|
||||
reset(n[])
|
||||
n.info = oldInfo
|
||||
|
||||
template move(a, b: expr) = system.shallowCopy(a, b)
|
||||
# XXX fix minor 'shallowCopy' overloading bug in compiler
|
||||
|
||||
proc asgnRef(x, y: PNode) =
|
||||
myreset(x)
|
||||
x.kind = y.kind
|
||||
x.typ = y.typ
|
||||
case x.kind
|
||||
of nkCharLit..nkInt64Lit: x.intVal = y.intVal
|
||||
of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal
|
||||
of nkStrLit..nkTripleStrLit: x.strVal = y.strVal
|
||||
of nkIdent: x.ident = y.ident
|
||||
of nkSym: x.sym = y.sym
|
||||
else:
|
||||
if x.kind notin {nkEmpty..nkNilLit}:
|
||||
move(x.sons, y.sons)
|
||||
|
||||
proc asgnComplex(x, y: PNode) =
|
||||
myreset(x)
|
||||
x.kind = y.kind
|
||||
x.typ = y.typ
|
||||
case x.kind
|
||||
of nkCharLit..nkInt64Lit: x.intVal = y.intVal
|
||||
of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal
|
||||
of nkStrLit..nkTripleStrLit: x.strVal = y.strVal
|
||||
of nkIdent: x.ident = y.ident
|
||||
of nkSym: x.sym = y.sym
|
||||
else:
|
||||
if x.kind notin {nkEmpty..nkNilLit}:
|
||||
let y = y.copyTree
|
||||
for i in countup(0, sonsLen(y) - 1): addSon(x, y.sons[i])
|
||||
|
||||
template getstr(a: expr): expr =
|
||||
(if a.kind == nkStrLit: a.strVal else: $chr(int(a.intVal)))
|
||||
|
||||
proc pushSafePoint(f: PStackFrame; pc: int) =
|
||||
if f.safePoints.isNil: f.safePoints = @[]
|
||||
f.safePoints.add(pc)
|
||||
|
||||
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
|
||||
|
||||
proc nextSafePoint(f: PStackFrame): int =
|
||||
var f = f
|
||||
while f.safePoints.isNil or f.safePoints.len == 0:
|
||||
f = f.next
|
||||
if f.isNil: return -1
|
||||
result = f.safePoints.pop
|
||||
|
||||
proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int =
|
||||
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
||||
while true:
|
||||
var pc2 = tos.nextSafePoint
|
||||
if pc2 == -1: return -1
|
||||
|
||||
var nextExceptOrFinally = -1
|
||||
if c.code[pc2].opcode == opcExcept:
|
||||
nextExceptOrFinally = pc2 + c.code[pc2].regBx - wordExcess
|
||||
inc pc2
|
||||
while c.code[pc2].opcode == opcExcept:
|
||||
let exceptType = c.types[c.code[pc2].regBx-wordExcess].skipTypes(
|
||||
abstractPtrs)
|
||||
if inheritanceDiff(exceptType, raisedType) <= 0:
|
||||
# mark exception as handled but keep it in B for
|
||||
# the getCurrentException() builtin:
|
||||
c.currentExceptionB = c.currentExceptionA
|
||||
c.currentExceptionA = nil
|
||||
# execute the corresponding handler:
|
||||
return pc2
|
||||
inc pc2
|
||||
if nextExceptOrFinally >= 0:
|
||||
pc2 = nextExceptOrFinally
|
||||
if c.code[pc2].opcode == opcFinally:
|
||||
# execute the corresponding handler, but don't quit walking the stack:
|
||||
return pc2
|
||||
|
||||
proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
||||
if f.safePoints.isNil: return -1
|
||||
for s in f.safePoints:
|
||||
var pc = s
|
||||
while c.code[pc].opcode == opcExcept:
|
||||
pc = pc + c.code[pc].regBx - wordExcess
|
||||
if c.code[pc].opcode == opcFinally:
|
||||
return pc
|
||||
return -1
|
||||
|
||||
proc execute(c: PCtx, start: int) =
|
||||
var pc = start
|
||||
var regs: TNodeSeq # alias to tos.slots for performance
|
||||
var tos: PStackFrame
|
||||
newSeq(regs, c.prc.maxSlots)
|
||||
while true:
|
||||
{.interpreterLoop.}
|
||||
let instr = c.code[pc]
|
||||
let ra = instr.regA
|
||||
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
|
||||
case instr.opcode
|
||||
of opcEof: break
|
||||
of opcRet:
|
||||
# XXX perform any cleanup actions
|
||||
tos = tos.next
|
||||
if tos.isNil: return
|
||||
let retVal = regs[0]
|
||||
move(regs, tos.slots)
|
||||
pc = tos.comesFrom
|
||||
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
||||
if c.code[pc].opcode == opcIndCallAsgn:
|
||||
regs[c.code[pc].regA] = retVal
|
||||
of opcYldYoid: assert false
|
||||
of opcYldVal: assert false
|
||||
of opcAsgnInt:
|
||||
echo ra, " ", instr.regB, " ", regs.len, tos.prc.name.s
|
||||
decodeB(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal
|
||||
of opcAsgnStr:
|
||||
decodeB(nkStrLit)
|
||||
debug regs[rb]
|
||||
echo rb
|
||||
Message(c.debug[pc], warnUser, " here")
|
||||
regs[ra].strVal = regs[rb].strVal
|
||||
of opcAsgnFloat:
|
||||
decodeB(nkFloatLit)
|
||||
regs[ra].floatVal = regs[rb].floatVal
|
||||
of opcAsgnComplex:
|
||||
asgnComplex(regs[ra], regs[instr.regB])
|
||||
of opcAsgnRef:
|
||||
asgnRef(regs[ra], regs[instr.regB])
|
||||
of opcWrGlobalRef:
|
||||
asgnRef(c.globals[instr.regBx-wordExcess-1], regs[ra])
|
||||
of opcWrGlobal:
|
||||
asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
|
||||
of opcLdArr:
|
||||
# a = b[c]
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
let idx = regs[rc].intVal
|
||||
# XXX what if the array is not 0-based? -> codegen should insert a sub
|
||||
regs[ra] = regs[rb].sons[idx.int]
|
||||
of opcWrArr:
|
||||
# a[b] = c
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
let idx = regs[rb].intVal
|
||||
asgnComplex(regs[ra].sons[idx.int], regs[rc])
|
||||
of opcWrArrRef:
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
let idx = regs[rb].intVal
|
||||
asgnRef(regs[ra].sons[idx.int], regs[rc])
|
||||
of opcLdObj:
|
||||
# a = b.c
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
# XXX this creates a wrong alias
|
||||
asgnComplex(regs[ra], regs[rb].sons[rc])
|
||||
of opcWrObj:
|
||||
# a.b = c
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
asgnComplex(regs[ra].sons[rb], regs[rc])
|
||||
of opcWrObjRef:
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
asgnRef(regs[ra].sons[rb], regs[rc])
|
||||
of opcWrStrIdx:
|
||||
decodeBC(nkStrLit)
|
||||
let idx = regs[rb].intVal.int
|
||||
regs[ra].strVal[idx] = chr(regs[rc].intVal)
|
||||
of opcAddr:
|
||||
decodeB(nkRefTy)
|
||||
if regs[ra].len == 0: regs[ra].add regs[rb]
|
||||
else: regs[ra].sons[0] = regs[rb]
|
||||
of opcDeref:
|
||||
# a = b[]
|
||||
let rb = instr.regB
|
||||
if regs[rb].kind == nkNilLit:
|
||||
stackTrace(c, tos, pc, errNilAccess)
|
||||
assert regs[rb].kind == nkRefTy
|
||||
regs[ra] = regs[rb].sons[0]
|
||||
of opcAddInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal + regs[rc].intVal
|
||||
of opcAddImmInt:
|
||||
decodeBImm(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal + imm
|
||||
of opcSubInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal - regs[rc].intVal
|
||||
of opcSubImmInt:
|
||||
decodeBImm(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal - imm
|
||||
of opcLenSeq:
|
||||
decodeBImm(nkIntLit)
|
||||
assert regs[rb].kind == nkBracket
|
||||
regs[ra].intVal = regs[rb].len - imm
|
||||
of opcLenStr:
|
||||
decodeBImm(nkIntLit)
|
||||
assert regs[rb].kind == nkStrLit
|
||||
regs[ra].intVal = regs[rb].strVal.len - imm
|
||||
of opcIncl:
|
||||
decodeB(nkCurly)
|
||||
if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb]))
|
||||
of opcExcl:
|
||||
decodeB(nkCurly)
|
||||
# XXX arg we need types here :-(
|
||||
var b = newNodeIT(nkCurly, regs[rb].info, regs[rb].typ)
|
||||
addSon(b, regs[rb])
|
||||
var r = diffSets(regs[ra], b)
|
||||
discardSons(regs[ra])
|
||||
for i in countup(0, sonsLen(r) - 1): addSon(regs[ra], r.sons[i])
|
||||
of opcCard:
|
||||
decodeB(nkIntLit)
|
||||
regs[ra].intVal = nimsets.cardSet(regs[rb])
|
||||
of opcMulInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal * regs[rc].intVal
|
||||
of opcDivInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal div regs[rc].intVal
|
||||
of opcModInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal
|
||||
of opcAddFloat:
|
||||
decodeBC(nkFloatLit)
|
||||
regs[ra].floatVal = regs[rb].floatVal + regs[rc].floatVal
|
||||
of opcSubFloat:
|
||||
decodeBC(nkFloatLit)
|
||||
regs[ra].floatVal = regs[rb].floatVal - regs[rc].floatVal
|
||||
of opcMulFloat:
|
||||
decodeBC(nkFloatLit)
|
||||
regs[ra].floatVal = regs[rb].floatVal * regs[rc].floatVal
|
||||
of opcDivFloat:
|
||||
decodeBC(nkFloatLit)
|
||||
regs[ra].floatVal = regs[rb].floatVal / regs[rc].floatVal
|
||||
of opcShrInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal shr regs[rc].intVal
|
||||
of opcShlInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal
|
||||
of opcBitandInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal and regs[rc].intVal
|
||||
of opcBitorInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal or regs[rc].intVal
|
||||
of opcBitxorInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal xor regs[rc].intVal
|
||||
of opcAddu:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal +% regs[rc].intVal
|
||||
of opcSubu:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
|
||||
of opcMulu:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
|
||||
of opcDivu:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal /% regs[rc].intVal
|
||||
of opcModu:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = regs[rb].intVal %% regs[rc].intVal
|
||||
of opcEqInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].intVal == regs[rc].intVal)
|
||||
of opcLeInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].intVal <= regs[rc].intVal)
|
||||
of opcLtInt:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].intVal < regs[rc].intVal)
|
||||
of opcEqFloat:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].floatVal == regs[rc].floatVal)
|
||||
of opcLeFloat:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].floatVal <= regs[rc].floatVal)
|
||||
of opcLtFloat:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].floatVal < regs[rc].floatVal)
|
||||
of opcLeu:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].intVal <=% regs[rc].intVal)
|
||||
of opcLtu:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
|
||||
of opcEqRef:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb] == regs[rc])
|
||||
# XXX is this correct? nope ...
|
||||
of opcXor:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
|
||||
of opcNot:
|
||||
decodeB(nkIntLit)
|
||||
assert regs[rb].kind == nkIntLit
|
||||
regs[ra].intVal = 1 - regs[rb].intVal
|
||||
of opcUnaryMinusInt:
|
||||
decodeB(nkIntLit)
|
||||
assert regs[rb].kind == nkIntLit
|
||||
regs[ra].intVal = -regs[rb].intVal
|
||||
of opcUnaryMinusFloat:
|
||||
decodeB(nkFloatLit)
|
||||
assert regs[rb].kind == nkFloatLit
|
||||
regs[ra].floatVal = -regs[rb].floatVal
|
||||
of opcBitnotInt:
|
||||
decodeB(nkIntLit)
|
||||
assert regs[rb].kind == nkIntLit
|
||||
regs[ra].intVal = not regs[rb].intVal
|
||||
of opcEqStr:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = Ord(regs[rb].strVal == regs[rc].strVal)
|
||||
of opcLeStr:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = Ord(regs[rb].strVal <= regs[rc].strVal)
|
||||
of opcLtStr:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = Ord(regs[rb].strVal < regs[rc].strVal)
|
||||
of opcLeSet:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = Ord(containsSets(regs[rb], regs[rc]))
|
||||
of opcEqSet:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = Ord(equalSets(regs[rb], regs[rc]))
|
||||
of opcLtSet:
|
||||
decodeBC(nkIntLit)
|
||||
let a = regs[rb]
|
||||
let b = regs[rc]
|
||||
regs[ra].intVal = Ord(containsSets(a, b) and not equalSets(a, b))
|
||||
of opcMulSet:
|
||||
decodeBC(nkCurly)
|
||||
move(regs[ra].sons, nimsets.intersectSets(regs[rb], regs[rc]).sons)
|
||||
of opcPlusSet:
|
||||
decodeBC(nkCurly)
|
||||
move(regs[ra].sons, nimsets.unionSets(regs[rb], regs[rc]).sons)
|
||||
of opcMinusSet:
|
||||
decodeBC(nkCurly)
|
||||
move(regs[ra].sons, nimsets.diffSets(regs[rb], regs[rc]).sons)
|
||||
of opcSymDiffSet:
|
||||
decodeBC(nkCurly)
|
||||
move(regs[ra].sons, nimsets.symdiffSets(regs[rb], regs[rc]).sons)
|
||||
of opcConcatStr:
|
||||
decodeBC(nkStrLit)
|
||||
regs[ra].strVal = getstr(regs[rb])
|
||||
for i in rb+1..rb+rc-1:
|
||||
regs[ra].strVal.add getstr(regs[i])
|
||||
of opcEcho:
|
||||
echo regs[ra].strVal
|
||||
of opcContainsSet:
|
||||
decodeBC(nkIntLit)
|
||||
regs[ra].intVal = Ord(inSet(regs[rb], regs[rc]))
|
||||
of opcSubStr:
|
||||
decodeBC(nkStrLit)
|
||||
inc pc
|
||||
assert c.code[pc].opcode == opcSubStr
|
||||
let rd = c.code[pc].regA
|
||||
regs[ra].strVal = substr(regs[rb].strVal, regs[rc].intVal.int,
|
||||
regs[rd].intVal.int)
|
||||
of opcIndCall, opcIndCallAsgn:
|
||||
# dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
let prc = regs[rb].sym
|
||||
let newPc = compile(c, prc)
|
||||
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
|
||||
newSeq(newFrame.slots, prc.position)
|
||||
if not isEmptyType(prc.typ.sons[0]):
|
||||
newFrame.slots[0] = getNullValue(prc.typ.sons[0], prc.info)
|
||||
# pass every parameter by var (the language definition allows this):
|
||||
for i in 1 .. rc-1:
|
||||
newFrame.slots[i] = regs[rb+i]
|
||||
# allocate the temporaries:
|
||||
for i in rc .. <prc.position:
|
||||
newFrame.slots[i] = newNode(nkEmpty)
|
||||
tos = newFrame
|
||||
move(regs, newFrame.slots)
|
||||
pc = newPc
|
||||
of opcTJmp:
|
||||
# jump Bx if A != 0
|
||||
let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
|
||||
if regs[ra].intVal != 0:
|
||||
inc pc, rbx
|
||||
of opcFJmp:
|
||||
# jump Bx if A == 0
|
||||
let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
|
||||
if regs[ra].intVal == 0:
|
||||
inc pc, rbx
|
||||
of opcJmp:
|
||||
# jump Bx
|
||||
let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
|
||||
inc pc, rbx
|
||||
of opcBranch:
|
||||
# we know the next instruction is a 'jmp':
|
||||
let branch = c.constants[instr.regBx-wordExcess]
|
||||
var cond = false
|
||||
for j in countup(0, sonsLen(branch) - 2):
|
||||
if overlap(regs[ra], branch.sons[j]):
|
||||
cond = true
|
||||
break
|
||||
assert c.code[pc+1].opcode == opcJmp
|
||||
inc pc
|
||||
# we skip this instruction so that the final 'inc(pc)' skips
|
||||
# the following jump
|
||||
if cond:
|
||||
let instr2 = c.code[pc]
|
||||
let rbx = instr2.regBx - wordExcess - 1 # -1 for the following 'inc pc'
|
||||
inc pc, rbx
|
||||
of opcTry:
|
||||
let rbx = instr.regBx - wordExcess
|
||||
tos.pushSafePoint(pc + rbx)
|
||||
of opcExcept:
|
||||
# just skip it; it's followed by a jump;
|
||||
# we'll execute in the 'raise' handler
|
||||
discard
|
||||
of opcFinally:
|
||||
# just skip it; it's followed by the code we need to execute anyway
|
||||
tos.popSafePoint()
|
||||
of opcFinallyEnd:
|
||||
if c.currentExceptionA != nil:
|
||||
# we are in a cleanup run:
|
||||
pc = cleanupOnException(c, tos, regs)-1
|
||||
if pc < 0:
|
||||
bailOut(c, tos)
|
||||
return
|
||||
of opcRaise:
|
||||
let raised = regs[ra]
|
||||
c.currentExceptionA = raised
|
||||
c.exceptionInstr = pc
|
||||
# -1 because of the following 'inc'
|
||||
pc = cleanupOnException(c, tos, regs) - 1
|
||||
if pc < 0:
|
||||
bailOut(c, tos)
|
||||
return
|
||||
of opcNew:
|
||||
let typ = c.types[instr.regBx - wordExcess]
|
||||
regs[ra] = getNullValue(typ, regs[ra].info)
|
||||
of opcNewSeq:
|
||||
let typ = c.types[instr.regBx - wordExcess]
|
||||
inc pc
|
||||
ensureKind(nkBracket)
|
||||
let instr2 = c.code[pc]
|
||||
let rb = instr2.regA
|
||||
regs[ra].typ = typ
|
||||
newSeq(regs[ra].sons, rb)
|
||||
for i in 0 .. <rb:
|
||||
regs[ra].sons[i] = getNullValue(typ, regs[ra].info)
|
||||
of opcNewStr:
|
||||
decodeB(nkStrLit)
|
||||
regs[ra].strVal = newString(regs[rb].intVal.int)
|
||||
of opcLdImmInt:
|
||||
# dest = immediate value
|
||||
decodeBx(nkIntLit)
|
||||
regs[ra].intVal = rbx
|
||||
of opcLdNull:
|
||||
let typ = c.types[instr.regBx - wordExcess]
|
||||
regs[ra] = getNullValue(typ, c.debug[pc])
|
||||
of opcLdConst:
|
||||
regs[ra] = c.constants.sons[instr.regBx - wordExcess]
|
||||
of opcNBindSym:
|
||||
# trivial implementation:
|
||||
let rb = instr.regB
|
||||
regs[ra] = regs[rb].sons[1]
|
||||
else:
|
||||
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
|
||||
inc pc
|
||||
|
||||
proc eval*(c: PCtx, n: PNode): PNode =
|
||||
## eval never returns nil! This simplifies the code a lot and
|
||||
## makes it faster too.
|
||||
let start = genStmt(c, n)
|
||||
# execute new instructions; this redundant opcEof check saves us lots
|
||||
# of allocations in 'execute':
|
||||
if c.code[start].opcode != opcEof:
|
||||
execute(c, start)
|
||||
result = emptyNode
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
#var c = newEvalContext(module, emRepl)
|
||||
#c.features = {allowCast, allowFFI, allowInfiniteLoops}
|
||||
#pushStackFrame(c, newStackFrame())
|
||||
result = newCtx()
|
||||
|
||||
var oldErrorCount: int
|
||||
|
||||
proc myProcess(c: PPassContext, n: PNode): PNode =
|
||||
# don't eval errornous code:
|
||||
if oldErrorCount == msgs.gErrorCounter:
|
||||
result = eval(PCtx(c), n)
|
||||
else:
|
||||
result = n
|
||||
oldErrorCount = msgs.gErrorCounter
|
||||
|
||||
const vmPass* = makePass(myOpen, nil, myProcess, myProcess)
|
||||
|
||||
149
compiler/vmdef.nim
Normal file
149
compiler/vmdef.nim
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains the type definitions for the new evaluation engine.
|
||||
## An instruction is 1-2 int32s in memory, it is a register based VM.
|
||||
|
||||
import ast, passes, msgs, intsets
|
||||
|
||||
const
|
||||
byteExcess* = 128 # we use excess-K for immediates
|
||||
wordExcess* = 32768
|
||||
|
||||
type
|
||||
TRegister* = range[0..255]
|
||||
TDest* = range[-1 .. 255]
|
||||
TInstr* = distinct uint32
|
||||
|
||||
TInstrFormat = enum
|
||||
ifABC, # three registers
|
||||
ifABx, # A + extended B
|
||||
|
||||
TOpcode* = enum
|
||||
opcEof, # end of code
|
||||
opcRet, # return
|
||||
opcYldYoid, # yield with no value
|
||||
opcYldVal, # yield with a value
|
||||
|
||||
opcAsgnInt,
|
||||
opcAsgnStr,
|
||||
opcAsgnFloat,
|
||||
opcAsgnRef,
|
||||
opcAsgnComplex,
|
||||
|
||||
opcLdArr, # a = b[c]
|
||||
opcWrArr, # a[b] = c
|
||||
opcWrArrRef,
|
||||
opcLdObj, # a = b.c
|
||||
opcWrObj, # a.b = c
|
||||
opcWrObjRef,
|
||||
opcAddr,
|
||||
opcDeref,
|
||||
opcWrStrIdx,
|
||||
|
||||
opcAddInt,
|
||||
opcAddImmInt,
|
||||
opcSubInt,
|
||||
opcSubImmInt,
|
||||
opcLenSeq,
|
||||
opcLenStr,
|
||||
|
||||
opcIncl, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
|
||||
opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
|
||||
opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
|
||||
opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
|
||||
opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcXor,
|
||||
opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
|
||||
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
|
||||
opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
|
||||
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
||||
opcSwap, opcIsNil, opcOf,
|
||||
opcSubStr, opcConv, opcCast, opcQuit, opcReset,
|
||||
|
||||
opcEcho,
|
||||
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
|
||||
opcRaise,
|
||||
opcNBindSym, # opcodes for the AST manipulation following
|
||||
|
||||
opcTJmp, # jump Bx if A != 0
|
||||
opcFJmp, # jump Bx if A == 0
|
||||
opcJmp, # jump Bx
|
||||
opcBranch, # branch for 'case'
|
||||
opcTry,
|
||||
opcExcept,
|
||||
opcFinally,
|
||||
opcFinallyEnd,
|
||||
opcNew,
|
||||
opcNewSeq,
|
||||
opcNewStr,
|
||||
opcLdNull, # dest = nullvalue(types[Bx])
|
||||
opcLdConst, # dest = constants[Bx]
|
||||
opcLdGlobal, # dest = globals[Bx]
|
||||
opcLdImmInt, # dest = immediate value
|
||||
opcWrGlobal,
|
||||
opcWrGlobalRef
|
||||
|
||||
TBlock* = object
|
||||
label*: PSym
|
||||
fixups*: seq[TPosition]
|
||||
|
||||
TSlotKind* = enum # We try to re-use slots in a smart way to
|
||||
# minimize allocations; however the VM supports arbitrary
|
||||
# temporary slot usage. This is required for the parameter
|
||||
# passing implementation.
|
||||
slotEmpty, # slot is unused
|
||||
slotFixed, # slot is used for a fixed var/param/result
|
||||
slotTempUnknown, # slot but type unknown (argument of proc call)
|
||||
slotTempInt, # some temporary int
|
||||
slotTempFloat, # some temporary float
|
||||
slotTempStr, # some temporary string
|
||||
slotTempComplex # some complex temporary (n.sons field is used)
|
||||
|
||||
PProc* = ref object
|
||||
blocks*: seq[TBlock] # blocks; temp data structure
|
||||
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
|
||||
maxSlots*: int
|
||||
|
||||
PCtx* = ref TCtx
|
||||
TCtx* = object of passes.TPassContext # code gen context
|
||||
code*: seq[TInstr]
|
||||
debug*: seq[TLineInfo] # line info for every instruction; kept separate
|
||||
# to not slow down interpretation
|
||||
jumpTargets*: TIntSet # we need to mark instructions that are
|
||||
# jump targets;
|
||||
# we must not optimize over a jump target and we
|
||||
# need to generate a label for a jump target when
|
||||
# producing a VM listing
|
||||
globals*: PNode #
|
||||
constants*: PNode # constant data
|
||||
types*: seq[PType] # some instructions reference types (e.g. 'except')
|
||||
currentExceptionA*, currentExceptionB*: PNode
|
||||
exceptionInstr*: int # index of instruction that raised the exception
|
||||
prc*: PProc
|
||||
|
||||
TPosition* = distinct int
|
||||
|
||||
proc newCtx*(): PCtx =
|
||||
PCtx(code: @[], debug: @[], jumpTargets: initIntSet(),
|
||||
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
|
||||
prc: PProc(blocks: @[]))
|
||||
|
||||
const
|
||||
firstABxInstr* = opcTJmp
|
||||
largeInstrs* = { # instructions which use 2 int32s instead of 1:
|
||||
opcSubstr, opcConv, opcCast, opcNewSeq, opcOf}
|
||||
slotSomeTemp* = slotTempUnknown
|
||||
|
||||
template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32)
|
||||
template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
|
||||
template regB*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
|
||||
template regC*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 24'u32)
|
||||
template regBx*(x: TInstr): int {.immediate.} = (x.uint32 shr 16'u32).int
|
||||
1002
compiler/vmgen.nim
Normal file
1002
compiler/vmgen.nim
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -85,11 +85,13 @@ type
|
|||
TNimTypeKinds* = set[TNimrodTypeKind]
|
||||
TNimrodSymKind* = enum
|
||||
nskUnknown, nskConditional, nskDynLib, nskParam,
|
||||
nskGenericParam, nskTemp, nskType, nskConst,
|
||||
nskVar, nskProc, nskMethod, nskIterator,
|
||||
nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet,
|
||||
nskConst, nskResult,
|
||||
nskProc, nskMethod, nskIterator,
|
||||
nskConverter, nskMacro, nskTemplate, nskField,
|
||||
nskEnumField, nskForVar, nskModule, nskLabel,
|
||||
nskEnumField, nskForVar, nskLabel,
|
||||
nskStub
|
||||
|
||||
TNimSymKinds* = set[TNimrodSymKind]
|
||||
|
||||
type
|
||||
|
|
@ -220,6 +222,11 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
|
|||
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
|
||||
## returned even if the symbol is not ambiguous.
|
||||
|
||||
proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
|
||||
magic: "NGenSym".}
|
||||
## generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||
## needs to occur in a declaration context.
|
||||
|
||||
proc callsite*(): PNimrodNode {.magic: "NCallSite".}
|
||||
## returns the AST if the invokation expression that invoked this macro.
|
||||
|
||||
|
|
|
|||
|
|
@ -956,7 +956,7 @@ type
|
|||
gain*: byte # Whether given states were gained or lost (1/0)
|
||||
state*: byte # A mask of the focus states
|
||||
|
||||
PKeyboardEvent = ptr TKeyboardEvent
|
||||
PKeyboardEvent* = ptr TKeyboardEvent
|
||||
TKeyboardEvent*{.final.} = object # SDL_KEYDOWN or SDL_KEYUP
|
||||
# Mouse motion event structure
|
||||
kind*: TEventKind
|
||||
|
|
@ -964,7 +964,7 @@ type
|
|||
state*: byte # SDL_PRESSED or SDL_RELEASED
|
||||
keysym*: TKeySym
|
||||
|
||||
PMouseMotionEvent = ptr TMouseMotionEvent
|
||||
PMouseMotionEvent* = ptr TMouseMotionEvent
|
||||
TMouseMotionEvent*{.final.} = object # SDL_MOUSEMOTION
|
||||
# Mouse button event structure
|
||||
kind*: TEventKind
|
||||
|
|
@ -974,7 +974,7 @@ type
|
|||
xrel*: int16 # The relative motion in the X direction
|
||||
yrel*: int16 # The relative motion in the Y direction
|
||||
|
||||
PMouseButtonEvent = ptr TMouseButtonEvent
|
||||
PMouseButtonEvent* = ptr TMouseButtonEvent
|
||||
TMouseButtonEvent*{.final.} = object # SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP
|
||||
# Joystick axis motion event structure
|
||||
kind*: TEventKind
|
||||
|
|
@ -984,7 +984,7 @@ type
|
|||
x*: UInt16 # The X coordinates of the mouse at press time
|
||||
y*: UInt16 # The Y coordinates of the mouse at press time
|
||||
|
||||
PJoyAxisEvent = ptr TJoyAxisEvent
|
||||
PJoyAxisEvent* = ptr TJoyAxisEvent
|
||||
TJoyAxisEvent*{.final.} = object # SDL_JOYAXISMOTION
|
||||
# Joystick trackball motion event structure
|
||||
kind*: TEventKind
|
||||
|
|
@ -992,7 +992,7 @@ type
|
|||
axis*: byte # The joystick axis index
|
||||
value*: int16 # The axis value (range: -32768 to 32767)
|
||||
|
||||
PJoyBallEvent = ptr TJoyBallEvent
|
||||
PJoyBallEvent* = ptr TJoyBallEvent
|
||||
TJoyBallEvent*{.final.} = object # SDL_JOYAVBALLMOTION
|
||||
# Joystick hat position change event structure
|
||||
kind*: TEventKind
|
||||
|
|
@ -1001,7 +1001,7 @@ type
|
|||
xrel*: int16 # The relative motion in the X direction
|
||||
yrel*: int16 # The relative motion in the Y direction
|
||||
|
||||
PJoyHatEvent = ptr TJoyHatEvent
|
||||
PJoyHatEvent* = ptr TJoyHatEvent
|
||||
TJoyHatEvent*{.final.} = object # SDL_JOYHATMOTION */
|
||||
# Joystick button event structure
|
||||
kind*: TEventKind
|
||||
|
|
@ -1013,7 +1013,7 @@ type
|
|||
# 6 5 4
|
||||
# Note that zero means the POV is centered.
|
||||
|
||||
PJoyButtonEvent = ptr TJoyButtonEvent
|
||||
PJoyButtonEvent* = ptr TJoyButtonEvent
|
||||
TJoyButtonEvent*{.final.} = object # SDL_JOYBUTTONDOWN or SDL_JOYBUTTONUP
|
||||
# The "window resized" event
|
||||
# When you get this event, you are
|
||||
|
|
@ -1024,7 +1024,7 @@ type
|
|||
button*: byte # The joystick button index
|
||||
state*: byte # SDL_PRESSED or SDL_RELEASED
|
||||
|
||||
PResizeEvent = ptr TResizeEvent
|
||||
PResizeEvent* = ptr TResizeEvent
|
||||
TResizeEvent*{.final.} = object # SDL_VIDEORESIZE
|
||||
# A user-defined event type
|
||||
kind*: TEventKind
|
||||
|
|
@ -1115,11 +1115,11 @@ type
|
|||
kind*: TEventKind
|
||||
msg*: PSysWMmsg
|
||||
|
||||
PExposeEvent = ptr TExposeEvent
|
||||
PExposeEvent* = ptr TExposeEvent
|
||||
TExposeEvent*{.final.} = object
|
||||
kind*: TEventKind
|
||||
|
||||
PQuitEvent = ptr TQuitEvent
|
||||
PQuitEvent* = ptr TQuitEvent
|
||||
TQuitEvent*{.final.} = object
|
||||
kind*: TEventKind
|
||||
|
||||
|
|
|
|||
|
|
@ -46,3 +46,15 @@ while i < s.len:
|
|||
i = i + 1
|
||||
|
||||
write(stdout, "Du heißt " & s)
|
||||
|
||||
# bug #544
|
||||
|
||||
type Bar [T; I:range] = array[I, T]
|
||||
proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
|
||||
when len(a) != 3:
|
||||
# Error: constant expression expected
|
||||
{.fatal:"Dimensions have to be 3".}
|
||||
#...
|
||||
block:
|
||||
var a, b: Bar[int, 0..2]
|
||||
discard foo(a, b)
|
||||
|
|
|
|||
44
tests/manyloc/named_argument_bug/gui.nim
Normal file
44
tests/manyloc/named_argument_bug/gui.nim
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import
|
||||
tri_engine/gfx/gl/primitive,
|
||||
tri_engine/gfx/tex,
|
||||
tri_engine/gfx/color,
|
||||
tri_engine/math/rect,
|
||||
tri_engine/math/vec
|
||||
|
||||
type
|
||||
TWidgetLayer* = enum
|
||||
wlBg = 100,
|
||||
wlOverlap = 200,
|
||||
wlMain = 300,
|
||||
wlOverlay = 400,
|
||||
wlCursor = 500
|
||||
TWidgetLayerType = TWidgetLayer|int
|
||||
TWidgetType* = enum
|
||||
wtImg
|
||||
PWidget* = ref object
|
||||
`type`* : TWidgetType
|
||||
layer* : TWidgetLayer
|
||||
rect* : TRect
|
||||
prim* : PPrimitive
|
||||
|
||||
const
|
||||
baseZ = 5000
|
||||
|
||||
proc newWidget*(`type`: TWidgetType, layer: TWidgetLayerType, rect: TRect): PWidget =
|
||||
new(result)
|
||||
result.`type` = `type`
|
||||
result.layer = layer
|
||||
result.rect = rect
|
||||
|
||||
var verts = newVert(rect)
|
||||
|
||||
# This works because z is accessible at this scope.
|
||||
#var z = baseZ + layer.int
|
||||
#result.prim = newPrimitive(verts, z=z)
|
||||
|
||||
# Doesn't work, because the compiler looks for a symbol called z in this scope,
|
||||
# but it should only check that it is the name of one of the params.
|
||||
#result.prim = newPrimitive(verts, z=baseZ + layer.int)
|
||||
|
||||
# This doesn't work either.
|
||||
result.prim = newPrimitive(verts, z=0)
|
||||
23
tests/manyloc/named_argument_bug/main.nim
Normal file
23
tests/manyloc/named_argument_bug/main.nim
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import
|
||||
tri_engine/config,
|
||||
tri_engine/math/vec,
|
||||
tri_engine/math/circle,
|
||||
tri_engine/gfx/gl/primitive,
|
||||
tri_engine/gfx/tex,
|
||||
tri_engine/gfx/color,
|
||||
tri_engine/tri_engine,
|
||||
gui
|
||||
|
||||
var isRunning = true
|
||||
|
||||
block:
|
||||
var renderer = newRenderer(w=10, h=10)
|
||||
|
||||
var primitive = newPrimitiveCircle(0.3.TR, color=white(0.5, 0.8), z=15)
|
||||
renderer.addPrimitive(primitive)
|
||||
|
||||
var verts = newVert((min: newV2xy(-0.4), size: newV2xy(0.3)))
|
||||
var primitive2 = newPrimitive(verts, color=red(0.5, 0.8), z=10)
|
||||
renderer.addPrimitive(primitive2)
|
||||
|
||||
var mainMenuWidget = newWidget(wtImg, wlBg, rect=(newV2xy(-1.0), newV2xy(2.0)))
|
||||
2
tests/manyloc/named_argument_bug/main.nimrod.cfg
Normal file
2
tests/manyloc/named_argument_bug/main.nimrod.cfg
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# this file only exists to mark 'main.nim' as the main file
|
||||
|
||||
6
tests/manyloc/named_argument_bug/tri_engine/config.nim
Normal file
6
tests/manyloc/named_argument_bug/tri_engine/config.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
when defined(doublePrecision):
|
||||
type
|
||||
TR* = float64
|
||||
else:
|
||||
type
|
||||
TR* = float32
|
||||
57
tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
Normal file
57
tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import
|
||||
tri_engine/config,
|
||||
tri_engine/math/vec
|
||||
|
||||
from strutils import
|
||||
formatFloat,
|
||||
TFloatFormat,
|
||||
`%`
|
||||
|
||||
from unsigned import
|
||||
`shr`,
|
||||
`and`
|
||||
|
||||
type
|
||||
TColor* = tuple[r, g, b, a: TR]
|
||||
|
||||
converter toColor*(o: uint32): TColor =
|
||||
## Convert an integer to a color. This is mostly useful when the integer is specified as a hex
|
||||
## literal such as 0xFF00007F, which is 100% red, with 50% alpha.
|
||||
## TODO: turn this into a template that can take either 4 or 8 characters?
|
||||
((((o and 0xff000000'u32) shr 24).TR / 255.0).TR,
|
||||
(((o and 0xff0000'u32) shr 16).TR / 255.0).TR,
|
||||
(((o and 0xff00'u32) shr 8).TR / 255.0).TR,
|
||||
(((o and 0xff'u32)).TR / 255.0).TR)
|
||||
|
||||
converter toV4*(o: TColor): TV4[TR] =
|
||||
cast[TV4[TR]](o)
|
||||
|
||||
proc newColor*(r, g, b: TR=0.0, a: TR=1.0): TColor =
|
||||
(r, g, b, a)
|
||||
|
||||
proc white*(rgb, a: TR=1.0): TColor =
|
||||
(rgb, rgb, rgb, a)
|
||||
|
||||
proc red*(r, a: TR=1.0): TColor =
|
||||
newColor(r=r, a=a)
|
||||
|
||||
proc green*(g, a: TR=1.0): TColor =
|
||||
newColor(g=g, a=a)
|
||||
|
||||
proc yellow*(rg, a: TR=1.0): TColor =
|
||||
newColor(r=rg, g=rg, a=a)
|
||||
|
||||
proc blue*(b, a: TR=1.0): TColor =
|
||||
newColor(b=b, a=a)
|
||||
|
||||
proc cyan*(gb, a: TR=1.0): TColor =
|
||||
newColor(g=gb, b=gb, a=a)
|
||||
|
||||
proc purple*(rb, a: TR=1.0): TColor =
|
||||
newColor(r=rb, b=rb, a=a)
|
||||
|
||||
proc `$`*(o: TColor): string =
|
||||
proc f(f: float): string =
|
||||
f.formatFloat(precision=2, format=ffDecimal)
|
||||
|
||||
"(r: $#, g: $#, b: $#, s: $#)" % [f(o.r), f(o.g), f(o.b), f(o.a)]
|
||||
61
tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
Normal file
61
tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import
|
||||
opengl,
|
||||
tri_engine/math/vec
|
||||
|
||||
export
|
||||
opengl
|
||||
|
||||
type
|
||||
EGL* = object of E_Base
|
||||
EGL_code* = object of EGL
|
||||
code*: EGL_err
|
||||
EGL_err {.pure.} = enum
|
||||
none = GL_NO_ERROR
|
||||
invalidEnum = GL_INVALID_ENUM
|
||||
invalidVal = GL_INVALID_VALUE
|
||||
invalidOp = GL_INVALID_OPERATION
|
||||
stackOverflow = GL_STACK_OVERFLOW
|
||||
stackUnderflow = GL_STACK_UNDERFLOW
|
||||
outOfMem = GL_OUT_OF_MEMORY
|
||||
invalidFramebufferOp = GL_INVALID_FRAMEBUFFER_OPERATION
|
||||
unknown
|
||||
|
||||
proc newGL_codeException*(msg: string, code: EGL_err): ref EGL_code =
|
||||
result = newException(EGL_code, $code)
|
||||
result.code = code
|
||||
|
||||
proc getErr*(): EGL_err =
|
||||
result = glGetError().EGL_err
|
||||
if result notin {EGL_err.none,
|
||||
EGL_err.invalidEnum,
|
||||
EGL_err.invalidVal,
|
||||
EGL_err.invalidOp,
|
||||
EGL_err.invalidFramebufferOp,
|
||||
EGL_err.outOfMem,
|
||||
EGL_err.stackUnderflow,
|
||||
EGL_err.stackOverflow}:
|
||||
return EGL_err.unknown
|
||||
|
||||
proc errCheck*() =
|
||||
let err = getErr()
|
||||
if err != EGL_err.none:
|
||||
raise newGL_codeException($err, err)
|
||||
|
||||
macro `?`*(call: expr{nkCall}): expr =
|
||||
result = call
|
||||
# Can't yet reference foreign symbols in macros.
|
||||
#errCheck()
|
||||
|
||||
when defined(doublePrecision):
|
||||
const
|
||||
glRealType* = cGLdouble
|
||||
else:
|
||||
const
|
||||
glRealType* = cGLfloat
|
||||
|
||||
proc setUniformV4*[T](loc: GLint, vecs: var openarray[TV4[T]]) =
|
||||
glUniform4fv(loc, vecs.len.GLsizei, cast[PGLfloat](vecs[0].addr))
|
||||
|
||||
proc setUniformV4*[T](loc: GLint, vec: TV4[T]) =
|
||||
var vecs = [vec]
|
||||
setUniformV4(loc, vecs)
|
||||
157
tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
Normal file
157
tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
import
|
||||
math,
|
||||
tri_engine/config,
|
||||
tri_engine/gfx/gl/gl,
|
||||
tri_engine/gfx/tex,
|
||||
tri_engine/gfx/color,
|
||||
tri_engine/math/vec,
|
||||
tri_engine/math/rect,
|
||||
tri_engine/math/circle
|
||||
|
||||
import strutils
|
||||
|
||||
type
|
||||
TVert* = tuple[pos: TV2[TR], texCoord: TV2[TR]]
|
||||
TVertAttrib* = object
|
||||
i* : GLuint
|
||||
size* : GLint
|
||||
stride* : GLsizei
|
||||
offset* : PGLvoid
|
||||
TVertMode* = enum
|
||||
vmTriStrip = GLtriangleStrip,
|
||||
vmTriFan = GLtriangleFan
|
||||
TZ_range* = range[-100_000..100_000]
|
||||
PPrimitive* = ref object
|
||||
verts* : seq[TVert]
|
||||
indices* : seq[GLushort]
|
||||
arrBufId* : GLuint
|
||||
elemArrBufId* : GLuint
|
||||
tex* : TTex
|
||||
color* : TColor
|
||||
vertMode* : TVertMode
|
||||
z* : int
|
||||
|
||||
proc newVert*(pos, texCoord: TV2): TVert =
|
||||
(pos, texCoord)
|
||||
|
||||
proc newVertQuad*(min, minRight, maxLeft, max: TV2[TR]): seq[TVert] =
|
||||
@[newVert(min, newV2()),
|
||||
newVert(minRight, newV2(x=1.0)),
|
||||
newVert(maxLeft, newV2(y=1.0)),
|
||||
newVert(max, newV2xy(1.0))
|
||||
]
|
||||
|
||||
proc newVert*(rect: rect.TRect): seq[TVert] =
|
||||
newVertQuad(rect.min, newV2(rect.max.x, rect.min.y), newV2(rect.min.x, rect.max.y), rect.max)
|
||||
|
||||
proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: PGLvoid): TVertAttrib =
|
||||
TVertAttrib(i: i, size: size, stride: stride, offset: offset)
|
||||
|
||||
proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openarray[T]): GLuint =
|
||||
result = 0.GLuint
|
||||
?glGenBuffers(1, result.addr)
|
||||
?glBindBuffer(vboTarget, result)
|
||||
|
||||
let size = (data.len * T.sizeof).GLsizeiptr
|
||||
?glBufferData(vboTarget, size, data[0].addr, objUsage)
|
||||
|
||||
proc newPrimitive*(verts: var seq[TVert],
|
||||
vertMode=vmTriStrip,
|
||||
tex=whiteTex(),
|
||||
color=white(),
|
||||
z: TZ_range=0): PPrimitive =
|
||||
var indices = newSeq[GLushort](verts.len)
|
||||
for i in 0 .. <verts.len:
|
||||
indices[i] = i.GLushort
|
||||
|
||||
new(result)
|
||||
result.verts = verts
|
||||
result.indices = indices
|
||||
|
||||
result.arrBufId = genBuf(GLarrayBuffer, GL_STATIC_DRAW, verts)
|
||||
result.elemArrBufId = genBuf(GLelementArrayBuffer, GL_STATIC_DRAW, indices)
|
||||
result.tex = tex
|
||||
result.color = color
|
||||
result.vertMode = vertMode
|
||||
result.z = z
|
||||
|
||||
proc bindBufs*(o: PPrimitive) =
|
||||
?glBindBuffer(GLarrayBuffer, o.arrBufId)
|
||||
?glBindBuffer(GLelementArrayBuffer, o.elemArrBufId)
|
||||
|
||||
proc enableVertAttribArrs*() =
|
||||
?glEnableVertexAttribArray(0)
|
||||
?glEnableVertexAttribArray(1)
|
||||
|
||||
proc disableVertAttribArrs*() =
|
||||
?glDisableVertexAttribArray(1)
|
||||
?glDisableVertexAttribArray(0)
|
||||
|
||||
proc setVertAttribPointers*() =
|
||||
let vertSize {.global.} = TVert.sizeof.GLint
|
||||
?glVertexAttribPointer(0, 2, glRealType, false, vertSize, nil)
|
||||
?glVertexAttribPointer(1, 2, glRealType, false, vertSize, cast[PGLvoid](TR.sizeof * 2))
|
||||
|
||||
proc updVerts*(o: PPrimitive, start, `end`: int, f: proc(i: int, vert: var TVert)) =
|
||||
assert start <= `end`
|
||||
assert `end` < o.verts.len
|
||||
for i in start..`end`:
|
||||
f(i, o.verts[i])
|
||||
|
||||
?glBindBuffer(GLarrayBuffer, o.arrBufId)
|
||||
|
||||
let byteLen = `end` - start + 1 * TVert.sizeof
|
||||
let byteOffset = start * TVert.sizeof
|
||||
?glBufferSubData(GLarrayBuffer,
|
||||
byteOffset.GLintptr, # Offset. Is this right?
|
||||
byteLen.GLsizeiptr, # Size.
|
||||
cast[PGLvoid](cast[int](o.verts[0].addr) + byteOffset))
|
||||
|
||||
proc updAllVerts(o: PPrimitive, f: proc(i: int, vert: var TVert)) =
|
||||
for i in 0 .. <o.verts.len:
|
||||
f(i, o.verts[i])
|
||||
|
||||
?glBindBuffer(GLarrayBuffer, o.arrBufId)
|
||||
|
||||
# Discard old buffer before creating a new one.
|
||||
let byteLen = (o.verts.len * TVert.sizeof).GLsizeiptr
|
||||
?glBufferData(GLarrayBuffer, byteLen, nil, GLstaticDraw)
|
||||
?glBufferData(GLarrayBuffer, byteLen, o.verts[0].addr, GLstaticDraw)
|
||||
|
||||
proc newVertCircle*(circle: TCircle, nSegs: Natural=0): seq[TVert] =
|
||||
let nSegs = if nSegs == 0:
|
||||
(circle.r.sqrt() * 400.0).int # TODO: Base this on the window resolution?
|
||||
else:
|
||||
max(nSegs, 3)
|
||||
|
||||
let theta: TR = (PI * 2.0) / (nSegs.TR)
|
||||
let tanFactor = theta.tan()
|
||||
let radialFactor = theta.cos()
|
||||
var x = circle.r
|
||||
var y: TR = 0.0
|
||||
|
||||
result = newSeq[TVert](nSegs)
|
||||
#result[0] = newVert(circle.p, newV2xy(0.5))
|
||||
for i in 1 .. <nSegs:
|
||||
let pos = newV2(x + circle.p.x, y + circle.p.y)
|
||||
let texCoord = pos * newV2xy(1.0 / circle.r)
|
||||
|
||||
result[i] = newVert(pos, texCoord)
|
||||
|
||||
let tx = -y
|
||||
let ty = x
|
||||
x += tx * tanFactor
|
||||
y += ty * tanFactor
|
||||
|
||||
x *= radialFactor
|
||||
y *= radialFactor
|
||||
|
||||
result.add(result[1])
|
||||
|
||||
proc newPrimitiveCircle*(circle: TCircle,
|
||||
nSegs: Natural=0,
|
||||
tex=whiteTex(),
|
||||
color=white(),
|
||||
z: TZ_range=0): PPrimitive =
|
||||
var verts = newVertCircle(circle, nSegs)
|
||||
newPrimitive(verts, vmTriFan, tex, color, z)
|
||||
103
tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
Normal file
103
tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import
|
||||
pure/os,
|
||||
tri_engine/gfx/gl/gl
|
||||
|
||||
type
|
||||
TShader* = object
|
||||
id*: GL_handle
|
||||
TShaderType* {.pure.} = enum
|
||||
frag = GL_FRAGMENT_SHADER,
|
||||
vert = GL_VERTEX_SHADER
|
||||
E_Shader* = object of E_Base
|
||||
E_UnknownShaderType* = object of E_Shader
|
||||
|
||||
converter pathToShaderType*(s: string): TShaderType =
|
||||
case s.splitFile().ext:
|
||||
of ".vs":
|
||||
return TShaderType.vert
|
||||
of ".fs":
|
||||
return TShaderType.frag
|
||||
else:
|
||||
raise newException(E_UnknownShaderType, "Can't determine shader type from file extension: " & s)
|
||||
|
||||
proc setSrc*(shader: TShader, src: string) =
|
||||
var s = src.cstring
|
||||
?glShaderSource(shader.id, 1, cast[cstringarray](s.addr), nil)
|
||||
|
||||
proc newShader*(id: GL_handle): TShader =
|
||||
if id != 0 and not (?glIsShader(id)).bool:
|
||||
raise newException(E_GL, "Invalid shader ID: " & $id)
|
||||
|
||||
result.id = id
|
||||
|
||||
proc shaderInfoLog*(o: TShader): string =
|
||||
var log {.global.}: array[0..1024, char]
|
||||
var logLen: GLsizei
|
||||
?glGetShaderInfoLog(o.id, log.len.GLsizei, logLen, cast[PGLchar](log.addr))
|
||||
cast[string](log.addr).substr(0, logLen)
|
||||
|
||||
proc compile*(shader: TShader, path="") =
|
||||
?glCompileShader(shader.id)
|
||||
var compileStatus = 0.GLint
|
||||
?glGetShaderIv(shader.id, GL_COMPILE_STATUS, compileStatus.addr)
|
||||
|
||||
if compileStatus == 0:
|
||||
raise newException(E_GL, if path.len == 0:
|
||||
shaderInfoLog(shader)
|
||||
else:
|
||||
path & ":\n" & shaderInfoLog(shader)
|
||||
)
|
||||
|
||||
proc newShaderFromSrc*(src: string, `type`: TShaderType): TShader =
|
||||
result.id = ?glCreateShader(`type`.GLenum)
|
||||
result.setSrc(src)
|
||||
result.compile()
|
||||
|
||||
proc newShaderFromFile*(path: string): TShader =
|
||||
newShaderFromSrc(readFile(path), path)
|
||||
|
||||
type
|
||||
TProgram* = object
|
||||
id*: GL_handle
|
||||
shaders: seq[TShader]
|
||||
|
||||
proc attach*(o: TProgram, shader: TShader) =
|
||||
?glAttachShader(o.id, shader.id)
|
||||
|
||||
proc infoLog*(o: TProgram): string =
|
||||
var log {.global.}: array[0..1024, char]
|
||||
var logLen: GLsizei
|
||||
?glGetProgramInfoLog(o.id, log.len.GLsizei, logLen, cast[PGLchar](log.addr))
|
||||
cast[string](log.addr).substr(0, logLen)
|
||||
|
||||
proc link*(o: TProgram) =
|
||||
?glLinkProgram(o.id)
|
||||
var linkStatus = 0.GLint
|
||||
?glGetProgramIv(o.id, GL_LINK_STATUS, linkStatus.addr)
|
||||
if linkStatus == 0:
|
||||
raise newException(E_GL, o.infoLog())
|
||||
|
||||
proc validate*(o: TProgram) =
|
||||
?glValidateProgram(o.id)
|
||||
var validateStatus = 0.GLint
|
||||
?glGetProgramIv(o.id, GL_VALIDATE_STATUS, validateStatus.addr)
|
||||
if validateStatus == 0:
|
||||
raise newException(E_GL, o.infoLog())
|
||||
|
||||
proc newProgram*(shaders: seq[TShader]): TProgram =
|
||||
result.id = ?glCreateProgram()
|
||||
if result.id == 0:
|
||||
return
|
||||
|
||||
for shader in shaders:
|
||||
if shader.id == 0:
|
||||
return
|
||||
|
||||
?result.attach(shader)
|
||||
|
||||
result.shaders = shaders
|
||||
result.link()
|
||||
result.validate()
|
||||
|
||||
proc use*(o: TProgram) =
|
||||
?glUseProgram(o.id)
|
||||
31
tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
Normal file
31
tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import
|
||||
tri_engine/gfx/gl/gl
|
||||
|
||||
type
|
||||
TTex* = object
|
||||
id*: GLuint
|
||||
|
||||
var gWhiteTex = TTex(id: 0)
|
||||
|
||||
proc setTexParams() =
|
||||
?glTexParameteri(GLtexture2D, GLtextureMinFilter, GLlinear)
|
||||
|
||||
#glTexParameteri(GLtexture2D, GLtextureMagFilter, GLlinear)
|
||||
?glTexParameteri(GLtexture2D, GLTextureMagFilter, GLnearest)
|
||||
|
||||
?glTexParameteri(GLtexture2D, GLTextureWrapS, GLClampToEdge)
|
||||
?glTexParameteri(GLtexture2D, GLTextureWrapT, GLClampToEdge)
|
||||
|
||||
proc whiteTex*(): TTex =
|
||||
if gWhiteTex.id.int != 0:
|
||||
return gWhiteTex
|
||||
|
||||
?glGenTextures(1, gWhiteTex.id.addr)
|
||||
?glBindTexture(GLtexture2D, gWhiteTex.id)
|
||||
setTexParams()
|
||||
|
||||
var pixel = [255'u8, 255'u8, 255'u8, 255'u8]
|
||||
?glTexImage2D(GLtexture2D, 0, GL_RGBA, 1, 1, 0, GL_BGRA, cGLUnsignedByte, pixel[0].addr)
|
||||
?glBindTexture(GLtexture2D, 0)
|
||||
|
||||
result = gWhiteTex
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import
|
||||
tri_engine/config,
|
||||
tri_engine/math/vec
|
||||
|
||||
type
|
||||
TCircle* = tuple[p: TV2[TR], r: TR]
|
||||
|
||||
converter toCircle*(o: TR): TCircle =
|
||||
(newV2(), o)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import
|
||||
tri_engine/config,
|
||||
tri_engine/math/vec
|
||||
|
||||
type
|
||||
TRect* = tuple[min, size: TV2[TR]]
|
||||
|
||||
proc max*(o: TRect): TV2[TR] = o.min + o.size
|
||||
55
tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
Normal file
55
tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import
|
||||
macros,
|
||||
tri_engine/config
|
||||
|
||||
type
|
||||
TV2*[T:TNumber=TR] = array[0..1, T]
|
||||
TV3*[T:TNumber=TR] = array[0..2, T]
|
||||
TV4*[T:TNumber=TR] = array[0..3, T]
|
||||
TVT*[T:TNumber=TR] = TV2|TV3|TV4
|
||||
#TV2* = array[0..1, TR]
|
||||
#TV3* = array[0..2, TR]
|
||||
#TV4* = array[0..3, TR]
|
||||
|
||||
# TODO: Change to TVT when compiler issue is resolved.
|
||||
proc `$`*[T](o: TV2[T]): string =
|
||||
result = "("
|
||||
for i in 0 .. <o.len:
|
||||
result &= $o[0]
|
||||
if i != o.len - 1:
|
||||
result &= ", "
|
||||
|
||||
result & ")"
|
||||
|
||||
proc newV2T*[T](x, y: T=0): TV2[T] =
|
||||
[x, y]
|
||||
|
||||
proc newV2*(x, y: TR=0.0): TV2[TR] =
|
||||
[x, y]
|
||||
|
||||
proc newV2xy*(xy: TR): TV2[TR] =
|
||||
[xy, xy]
|
||||
|
||||
proc x*[T](o: TV2[T]): T =
|
||||
o[0]
|
||||
|
||||
proc y*[T](o: TV2[T]): T =
|
||||
o[1]
|
||||
|
||||
proc `*`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
|
||||
[(lhs.x * rhs.x).TR, (lhs.y * rhs.y).TR]
|
||||
|
||||
proc `+`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
|
||||
[(lhs.x + rhs.x).TR, (lhs.y + rhs.y).TR]
|
||||
|
||||
#proc dotProduct[T](a: TVT[T], b: TVT[T]): T =
|
||||
# for i in 0 .. a.len - 1:
|
||||
# result += a[i] * b[i]
|
||||
|
||||
proc dot[T](a, b: TV2[T]): T =
|
||||
for i in 0 .. <a.len:
|
||||
result += a[i] * b[i]
|
||||
|
||||
assert dot(newV2(), newV2()) == 0.0
|
||||
assert dot(newV2(2, 3), newV2(6, 7)) == 33.0
|
||||
assert dot([2.0, 3.0], [6.0, 7.0]) == 33.0
|
||||
106
tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
Normal file
106
tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import
|
||||
algorithm,
|
||||
tri_engine/config,
|
||||
tri_engine/gfx/gl/gl,
|
||||
tri_engine/gfx/gl/primitive,
|
||||
tri_engine/gfx/gl/shader,
|
||||
tri_engine/gfx/color
|
||||
|
||||
const primitiveVs = """
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec2 pos;
|
||||
layout(location = 1) in vec2 texCoord;
|
||||
|
||||
out vec2 uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(pos, 0, 1);
|
||||
uv = texCoord;
|
||||
}
|
||||
|
||||
"""
|
||||
const primitiveFs = """
|
||||
#version 330 core
|
||||
|
||||
in vec2 uv;
|
||||
out vec4 color;
|
||||
uniform sampler2D tex;
|
||||
uniform vec4 inColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
color = texture(tex, uv) * inColor;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
var gW, gH: Natural = 0
|
||||
|
||||
proc w*(): int =
|
||||
gW
|
||||
|
||||
proc h*(): int =
|
||||
gH
|
||||
|
||||
type
|
||||
PRenderer = ref object
|
||||
primitiveProgram: TProgram
|
||||
primitives: seq[PPrimitive]
|
||||
|
||||
proc setupGL() =
|
||||
?glEnable(GLblend)
|
||||
?glBlendFunc(GLsrcAlpha, GLoneMinusSrcAlpha)
|
||||
?glClearColor(0.0, 0.0, 0.0, 1.0)
|
||||
?glPolygonMode(GLfrontAndBack, GLfill)
|
||||
|
||||
proc newRenderer*(w, h: Positive): PRenderer =
|
||||
gW = w
|
||||
gH = h
|
||||
|
||||
new(result)
|
||||
newSeq(result.primitives, 0)
|
||||
loadExtensions()
|
||||
setupGL()
|
||||
result.primitiveProgram = newProgram(@[
|
||||
newShaderFromSrc(primitiveVs, TShaderType.vert),
|
||||
newShaderFromSrc(primitiveFs, TShaderType.frag)])
|
||||
|
||||
proc draw(o: PRenderer, p: PPrimitive) =
|
||||
let loc = proc(x: string): Glint =
|
||||
result = glGetUniformLocation(o.primitiveProgram.id, x)
|
||||
if result == -1:
|
||||
raise newException(E_GL, "Shader error: " & x & " does not correspond to a uniform variable")
|
||||
|
||||
setUniformV4(loc("inColor"), p.color)
|
||||
?glActiveTexture(GLtexture0)
|
||||
?glBindTexture(GLtexture2D, p.tex.id.GLuint)
|
||||
?glUniform1i(loc("tex"), 0)
|
||||
|
||||
p.bindBufs()
|
||||
setVertAttribPointers()
|
||||
|
||||
?glDrawElements(p.vertMode.GLenum, p.indices.len.GLsizei, cGLunsignedShort, nil)
|
||||
|
||||
proc draw*(o: PRenderer) =
|
||||
?glClear(GLcolorBufferBit)
|
||||
o.primitiveProgram.use()
|
||||
|
||||
enableVertAttribArrs()
|
||||
var zSortedPrimitives = o.primitives
|
||||
zSortedPrimitives.sort(proc(x, y: PPrimitive): int =
|
||||
if x.z < y.z:
|
||||
-1
|
||||
elif x.z > y.z:
|
||||
1
|
||||
else:
|
||||
0)
|
||||
|
||||
for x in zSortedPrimitives:
|
||||
o.draw(x)
|
||||
|
||||
disableVertAttribArrs()
|
||||
|
||||
proc addPrimitive*(o: PRenderer, p: PPrimitive) =
|
||||
o.primitives.add(p)
|
||||
1
todo.txt
1
todo.txt
|
|
@ -8,7 +8,6 @@ version 0.9.4
|
|||
- mocking support with ``tyProxy`` that does: fallback for ``.`` operator
|
||||
- overloading of ``.``? Special case ``.=``?
|
||||
- built-in 'getImpl'
|
||||
- macros.gensym still missing?
|
||||
- optimize 'genericReset'; 'newException' leads to code bloat
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ Bugfixes
|
|||
Library Additions
|
||||
-----------------
|
||||
|
||||
- Added ``macros.genSym`` builtin for AST generation.
|
||||
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
-----------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue