fixes #287; bugfix: subrange checking is performed again
This commit is contained in:
parent
f5db2de696
commit
3cb3813eed
14 changed files with 147 additions and 32 deletions
|
|
@ -1331,8 +1331,14 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var a, b, x, y: TLoc
|
var a, b, x, y: TLoc
|
||||||
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
|
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
|
||||||
# a set constructor but not a constant set:
|
# a set constructor but not a constant set:
|
||||||
# do not emit the set, but generate a bunch of comparisons
|
# do not emit the set, but generate a bunch of comparisons; and if we do
|
||||||
initLocExpr(p, e.sons[2], a)
|
# so, we skip the unnecessary range check: This is a semantical extension
|
||||||
|
# that code now relies on. :-/ XXX
|
||||||
|
let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
|
||||||
|
e.sons[2].sons[0]
|
||||||
|
else:
|
||||||
|
e.sons[2]
|
||||||
|
initLocExpr(p, ea, a)
|
||||||
initLoc(b, locExpr, e.typ, OnUnknown)
|
initLoc(b, locExpr, e.typ, OnUnknown)
|
||||||
b.r = toRope("(")
|
b.r = toRope("(")
|
||||||
var length = sonsLen(e.sons[1])
|
var length = sonsLen(e.sons[1])
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
proc semProcBody(c: PContext, n: PNode): PNode
|
proc semProcBody(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
|
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
|
||||||
proc changeType(n: PNode, newType: PType)
|
proc changeType(n: PNode, newType: PType, check: bool)
|
||||||
|
|
||||||
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
|
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
|
||||||
|
|
|
||||||
|
|
@ -354,11 +354,11 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
|
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
|
||||||
result = semExpr(c, result)
|
result = semExpr(c, result)
|
||||||
|
|
||||||
proc changeType(n: PNode, newType: PType) =
|
proc changeType(n: PNode, newType: PType, check: bool) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCurly, nkBracket:
|
of nkCurly, nkBracket:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
changeType(n.sons[i], elemType(newType))
|
changeType(n.sons[i], elemType(newType), check)
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if newType.kind != tyTuple:
|
if newType.kind != tyTuple:
|
||||||
InternalError(n.info, "changeType: no tuple type for constructor")
|
InternalError(n.info, "changeType: no tuple type for constructor")
|
||||||
|
|
@ -373,15 +373,21 @@ proc changeType(n: PNode, newType: PType) =
|
||||||
if f == nil:
|
if f == nil:
|
||||||
internalError(m.info, "changeType(): invalid identifier")
|
internalError(m.info, "changeType(): invalid identifier")
|
||||||
return
|
return
|
||||||
changeType(n.sons[i].sons[1], f.typ)
|
changeType(n.sons[i].sons[1], f.typ, check)
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var m = n.sons[i]
|
var m = n.sons[i]
|
||||||
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
|
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
|
||||||
addSon(a, newSymNode(newType.n.sons[i].sym))
|
addSon(a, newSymNode(newType.n.sons[i].sym))
|
||||||
addSon(a, m)
|
addSon(a, m)
|
||||||
changeType(m, newType.sons[i])
|
changeType(m, newType.sons[i], check)
|
||||||
n.sons[i] = a
|
n.sons[i] = a
|
||||||
|
of nkCharLit..nkUInt64Lit:
|
||||||
|
if check:
|
||||||
|
let value = n.intVal
|
||||||
|
if value < firstOrd(newType) or value > lastOrd(newType):
|
||||||
|
LocalError(n.info, errGenerated, "cannot convert " & $value &
|
||||||
|
" to " & typeToString(newType))
|
||||||
else: nil
|
else: nil
|
||||||
n.typ = newType
|
n.typ = newType
|
||||||
|
|
||||||
|
|
@ -461,7 +467,7 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
||||||
elif skipTypes(it.sons[1].typ, abstractVar).kind in
|
elif skipTypes(it.sons[1].typ, abstractVar).kind in
|
||||||
{tyNil, tyArrayConstr, tyTuple, tySet}:
|
{tyNil, tyArrayConstr, tyTuple, tySet}:
|
||||||
var s = skipTypes(it.typ, abstractVar)
|
var s = skipTypes(it.typ, abstractVar)
|
||||||
changeType(it.sons[1], s)
|
changeType(it.sons[1], s, check=true)
|
||||||
n.sons[i] = it.sons[1]
|
n.sons[i] = it.sons[1]
|
||||||
of nkBracket:
|
of nkBracket:
|
||||||
# an implicitely constructed array (passed to an open array):
|
# an implicitely constructed array (passed to an open array):
|
||||||
|
|
@ -560,11 +566,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
call.add(n.sons[0])
|
call.add(n.sons[0])
|
||||||
var allConst = true
|
var allConst = true
|
||||||
for i in 1 .. < n.len:
|
for i in 1 .. < n.len:
|
||||||
let a = getConstExpr(c.module, n.sons[i])
|
var a = getConstExpr(c.module, n.sons[i])
|
||||||
if a != nil: call.add(a)
|
if a == nil:
|
||||||
else:
|
|
||||||
allConst = false
|
allConst = false
|
||||||
call.add(n.sons[i])
|
a = n.sons[i]
|
||||||
|
if a.kind == nkHiddenStdConv: a = a.sons[1]
|
||||||
|
call.add(a)
|
||||||
if allConst:
|
if allConst:
|
||||||
result = semfold.getConstExpr(c.module, call)
|
result = semfold.getConstExpr(c.module, call)
|
||||||
if result.isNil: result = n
|
if result.isNil: result = n
|
||||||
|
|
|
||||||
|
|
@ -458,21 +458,28 @@ proc getAppType(n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = newStrNodeT("console", n)
|
result = newStrNodeT("console", n)
|
||||||
|
|
||||||
proc foldConv*(n, a: PNode): PNode =
|
proc rangeCheck(n: PNode, value: biggestInt) =
|
||||||
|
if value < firstOrd(n.typ) or value > lastOrd(n.typ):
|
||||||
|
LocalError(n.info, errGenerated, "cannot convert " & $value &
|
||||||
|
" to " & typeToString(n.typ))
|
||||||
|
|
||||||
|
proc foldConv*(n, a: PNode; check = false): PNode =
|
||||||
# XXX range checks?
|
# XXX range checks?
|
||||||
case skipTypes(n.typ, abstractRange).kind
|
case skipTypes(n.typ, abstractRange).kind
|
||||||
of tyInt..tyInt64:
|
of tyInt..tyInt64:
|
||||||
case skipTypes(a.typ, abstractRange).kind
|
case skipTypes(a.typ, abstractRange).kind
|
||||||
of tyFloat..tyFloat64: result = newIntNodeT(system.toInt(getFloat(a)), n)
|
of tyFloat..tyFloat64:
|
||||||
|
result = newIntNodeT(system.toInt(getFloat(a)), n)
|
||||||
of tyChar: result = newIntNodeT(getOrdValue(a), n)
|
of tyChar: result = newIntNodeT(getOrdValue(a), n)
|
||||||
else:
|
else:
|
||||||
result = a
|
result = a
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
of tyFloat..tyFloat64:
|
if check: rangeCheck(n, result.intVal)
|
||||||
|
of tyFloat..tyFloat64:
|
||||||
case skipTypes(a.typ, abstractRange).kind
|
case skipTypes(a.typ, abstractRange).kind
|
||||||
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
|
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
|
||||||
result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
|
result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
|
||||||
else:
|
else:
|
||||||
result = a
|
result = a
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
of tyOpenArray, tyVarargs, tyProc:
|
of tyOpenArray, tyVarargs, tyProc:
|
||||||
|
|
@ -694,8 +701,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
|
||||||
var a = getConstExpr(m, n.sons[1])
|
var a = getConstExpr(m, n.sons[1])
|
||||||
if a == nil: return
|
if a == nil: return
|
||||||
result = foldConv(n, a)
|
result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
|
||||||
of nkBracketExpr: result = foldArrayAccess(m, n)
|
of nkBracketExpr: result = foldArrayAccess(m, n)
|
||||||
of nkDotExpr: result = foldFieldAccess(m, n)
|
of nkDotExpr: result = foldFieldAccess(m, n)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -166,10 +166,10 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
||||||
result = fitNode(c, typ, n)
|
result = fitNode(c, typ, n)
|
||||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||||
changeType(result.sons[1], typ)
|
changeType(result.sons[1], typ, check=true)
|
||||||
result = result.sons[1]
|
result = result.sons[1]
|
||||||
elif not sameType(result.typ, typ):
|
elif not sameType(result.typ, typ):
|
||||||
changeType(result, typ)
|
changeType(result, typ, check=false)
|
||||||
|
|
||||||
proc findShadowedVar(c: PContext, v: PSym): PSym =
|
proc findShadowedVar(c: PContext, v: PSym): PSym =
|
||||||
for i in countdown(c.tab.tos - 2, ModuleTablePos+1):
|
for i in countdown(c.tab.tos - 2, ModuleTablePos+1):
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,22 @@ proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
result = if matchTypeClass(c.bindings, f, a): isGeneric
|
result = if matchTypeClass(c.bindings, f, a): isGeneric
|
||||||
else: isNone
|
else: isNone
|
||||||
|
|
||||||
|
proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||||
|
let
|
||||||
|
a0 = firstOrd(a)
|
||||||
|
a1 = lastOrd(a)
|
||||||
|
f0 = firstOrd(f)
|
||||||
|
f1 = lastOrd(f)
|
||||||
|
if a0 == f0 and a1 == f1:
|
||||||
|
result = isEqual
|
||||||
|
elif a0 >= f0 and a1 <= f1:
|
||||||
|
result = isConvertible
|
||||||
|
elif a0 <= f1 and f0 <= a1:
|
||||||
|
# X..Y and C..D overlap iff (X <= D and C <= Y)
|
||||||
|
result = isConvertible
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
# is a subtype of f?
|
# is a subtype of f?
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
@ -386,6 +402,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a))
|
||||||
# bugfix: accept integer conversions here
|
# bugfix: accept integer conversions here
|
||||||
#if result < isGeneric: result = isNone
|
#if result < isGeneric: result = isNone
|
||||||
|
if result notin {isNone, isGeneric}:
|
||||||
|
result = typeRangeRel(f, a)
|
||||||
elif skipTypes(f, {tyRange}).kind == a.kind:
|
elif skipTypes(f, {tyRange}).kind == a.kind:
|
||||||
result = isIntConv
|
result = isIntConv
|
||||||
elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
|
elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
|
||||||
|
|
@ -704,7 +722,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
||||||
of isSubrange:
|
of isSubrange:
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
result = copyTree(arg)
|
#result = copyTree(arg)
|
||||||
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
||||||
|
|
|
||||||
|
|
@ -323,10 +323,10 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
||||||
# we don't include uint and uint64 here as these are no ordinal types ;-)
|
# we don't include uint and uint64 here as these are no ordinal types ;-)
|
||||||
if not isOrdinalType(source):
|
if not isOrdinalType(source):
|
||||||
# XXX int64 -> float conversion?
|
# float -> int conversions. ugh.
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
elif firstOrd(dest) <= firstOrd(source) and
|
elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
|
||||||
lastOrd(source) <= lastOrd(dest):
|
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
|
||||||
# BUGFIX: simply leave n as it is; we need a nkConv node,
|
# BUGFIX: simply leave n as it is; we need a nkConv node,
|
||||||
# but no range check:
|
# but no range check:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
|
@ -334,13 +334,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
# generate a range check:
|
# generate a range check:
|
||||||
if dest.kind == tyInt64 or source.kind == tyInt64:
|
if dest.kind == tyInt64 or source.kind == tyInt64:
|
||||||
result = newTransNode(nkChckRange64, n, 3)
|
result = newTransNode(nkChckRange64, n, 3)
|
||||||
else:
|
else:
|
||||||
result = newTransNode(nkChckRange, n, 3)
|
result = newTransNode(nkChckRange, n, 3)
|
||||||
dest = skipTypes(n.typ, abstractVar)
|
dest = skipTypes(n.typ, abstractVar)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
|
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
|
||||||
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
||||||
of tyFloat..tyFloat128:
|
of tyFloat..tyFloat128:
|
||||||
|
# XXX int64 -> float conversion?
|
||||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||||
result = newTransNode(nkChckRangeF, n, 3)
|
result = newTransNode(nkChckRangeF, n, 3)
|
||||||
dest = skipTypes(n.typ, abstractVar)
|
dest = skipTypes(n.typ, abstractVar)
|
||||||
|
|
|
||||||
|
|
@ -485,8 +485,8 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
add(result, ']')
|
add(result, ']')
|
||||||
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
||||||
result = typeToStr[t.kind] & typeToString(t.sons[0])
|
result = typeToStr[t.kind] & typeToString(t.sons[0])
|
||||||
of tyRange:
|
of tyRange:
|
||||||
result = "range " & rangeToStr(t.n)
|
result = "range " & rangeToStr(t.n) & "(" & typeToString(t.sons[0]) & ")"
|
||||||
of tyProc:
|
of tyProc:
|
||||||
result = if tfIterator in t.flags: "iterator (" else: "proc ("
|
result = if tfIterator in t.flags: "iterator (" else: "proc ("
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
|
|
|
||||||
|
|
@ -103,5 +103,5 @@ On UNIX
|
||||||
* ``bin/nimrod c koch``
|
* ``bin/nimrod c koch``
|
||||||
* ``./koch boot -d:release``
|
* ``./koch boot -d:release``
|
||||||
|
|
||||||
Installation on UNIX can then be done with ``koch install``.
|
Installation on UNIX can then be done with ``koch install [dir]``.
|
||||||
|
|
||||||
|
|
|
||||||
19
tests/compile/tmatrix1.nim
Normal file
19
tests/compile/tmatrix1.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
discard """
|
||||||
|
output: "right proc called"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TMatrixNM*[M, N, T] = object
|
||||||
|
aij*: array[M, array[N, T]]
|
||||||
|
TMatrix2x2*[T] = TMatrixNM[range[0..1], range[0..1], T]
|
||||||
|
TMatrix3x3*[T] = TMatrixNM[range[0..2], range[0..2], T]
|
||||||
|
|
||||||
|
proc test*[T] (matrix: TMatrix2x2[T]) =
|
||||||
|
echo "wrong proc called"
|
||||||
|
|
||||||
|
proc test*[T] (matrix: TMatrix3x3[T]) =
|
||||||
|
echo "right proc called"
|
||||||
|
|
||||||
|
var matrix: TMatrix3x3[float]
|
||||||
|
|
||||||
|
matrix.test
|
||||||
21
tests/reject/tsubrange.nim
Normal file
21
tests/reject/tsubrange.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
discard """
|
||||||
|
line: 20
|
||||||
|
errormsg: "cannot convert 60 to TRange"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TRange = range[0..40]
|
||||||
|
|
||||||
|
proc p(r: TRange) =
|
||||||
|
nil
|
||||||
|
|
||||||
|
var
|
||||||
|
r: TRange
|
||||||
|
y = 50
|
||||||
|
r = y
|
||||||
|
|
||||||
|
p y
|
||||||
|
|
||||||
|
const
|
||||||
|
myConst: TRange = 60
|
||||||
|
|
||||||
19
tests/run/tsubrange.nim
Normal file
19
tests/run/tsubrange.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
discard """
|
||||||
|
file: "tsubrange.nim"
|
||||||
|
outputsub: "value 50 out of range [EOutOfRange]"
|
||||||
|
exitcode: "1"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TRange = range[0..40]
|
||||||
|
|
||||||
|
proc p(r: TRange) =
|
||||||
|
nil
|
||||||
|
|
||||||
|
var
|
||||||
|
r: TRange
|
||||||
|
y = 50
|
||||||
|
r = y
|
||||||
|
|
||||||
|
#p y
|
||||||
|
|
||||||
17
tests/run/tsubrange2.nim
Normal file
17
tests/run/tsubrange2.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
file: "tsubrange2.nim"
|
||||||
|
outputsub: "value 50 out of range [EOutOfRange]"
|
||||||
|
exitcode: "1"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TRange = range[0..40]
|
||||||
|
|
||||||
|
proc p(r: TRange) =
|
||||||
|
nil
|
||||||
|
|
||||||
|
var
|
||||||
|
r: TRange
|
||||||
|
y = 50
|
||||||
|
p y
|
||||||
|
|
||||||
3
todo.txt
3
todo.txt
|
|
@ -13,7 +13,6 @@ Bugs
|
||||||
====
|
====
|
||||||
|
|
||||||
- docgen: sometimes effects are listed twice
|
- docgen: sometimes effects are listed twice
|
||||||
- even the easiest range checking is not performed anymore
|
|
||||||
- 'result' is not properly cleaned for NRVO
|
- 'result' is not properly cleaned for NRVO
|
||||||
- instantiated generics are listed in error messages
|
- instantiated generics are listed in error messages
|
||||||
- sneaking with qualifiedLookup() is really broken!
|
- sneaking with qualifiedLookup() is really broken!
|
||||||
|
|
@ -23,6 +22,7 @@ Bugs
|
||||||
- osproc execProcesses can deadlock if all processes fail (as experienced
|
- osproc execProcesses can deadlock if all processes fail (as experienced
|
||||||
in c++ mode)
|
in c++ mode)
|
||||||
- bootstrapping does not work in C++ mode
|
- bootstrapping does not work in C++ mode
|
||||||
|
- result = result shr 8 for the "system()" wrapper
|
||||||
|
|
||||||
|
|
||||||
version 0.9.4
|
version 0.9.4
|
||||||
|
|
@ -54,7 +54,6 @@ version 0.9.X
|
||||||
- improve the compiler as a service
|
- improve the compiler as a service
|
||||||
- better support for macros that rewrite procs
|
- better support for macros that rewrite procs
|
||||||
- macros need access to types and symbols (partially implemented)
|
- macros need access to types and symbols (partially implemented)
|
||||||
- result = result shr 8 for the "system()" wrapper
|
|
||||||
- rethink the syntax/grammar:
|
- rethink the syntax/grammar:
|
||||||
* parser is not strict enough with newlines
|
* parser is not strict enough with newlines
|
||||||
* change comment handling in the AST
|
* change comment handling in the AST
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue