From ad67b7106ca14a26ae7a2d5fe184134c85a80d93 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 18 May 2022 10:35:25 +0800 Subject: [PATCH 1/2] fresh start --- compiler/ast.nim | 12 ++ compiler/parser.nim | 6 +- compiler/semexprs.nim | 12 +- compiler/semmagic.nim | 108 +++++++++++ compiler/semobjconstr.nim | 70 ++++--- compiler/semstmts.nim | 12 ++ compiler/semtypes.nim | 21 ++- compiler/transf.nim | 160 +++++++++++++++- tests/objects/mobject_default_value.nim | 15 ++ tests/objects/tobject_default_value.nim | 238 ++++++++++++++++++++++++ 10 files changed, 614 insertions(+), 40 deletions(-) create mode 100644 tests/objects/mobject_default_value.nim create mode 100644 tests/objects/tobject_default_value.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index d1e5ae2bfe65..d0fcab9b5819 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -502,6 +502,7 @@ type nfLastRead # this node is a last read nfFirstWrite# this node is a first write nfHasComment # node has a comment + nfUseDefaultField TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45) @@ -1453,6 +1454,17 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = result.intVal = intVal result.typ = typ +proc newFloatTypeNode*(floatVal: BiggestFloat, typ: PType): PNode = + let kind = skipTypes(typ, abstractVarRange).kind + case kind + of tyFloat32: + result = newNode(nkFloat32Lit) + of tyFloat64, tyFloat: + result = newNode(nkFloatLit) + else: doAssert false, $kind + result.floatVal = floatVal + result.typ = typ + proc newIntTypeNode*(intVal: Int128, typ: PType): PNode = # XXX: introduce range check newIntTypeNode(castToInt64(intVal), typ) diff --git a/compiler/parser.nim b/compiler/parser.nim index 52466d9fa0f0..2f89efc560d7 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1963,11 +1963,7 @@ proc parseObjectCase(p: var Parser): PNode = #| | IND{=} objectBranches) result = newNodeP(nkRecCase, p) getTokNoInd(p) - var a = newNodeP(nkIdentDefs, p) - a.add(identWithPragma(p)) - eat(p, tkColon) - a.add(parseTypeDesc(p)) - a.add(p.emptyNode) + var a = parseIdentColonEquals(p, {withPragma}) result.add(a) if p.tok.tokType == tkColon: getTok(p) flexComment(p, result) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 702b47929c7c..fc703ea858fc 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -897,8 +897,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, rawAddSon(typ, result.typ) result.typ = typ -proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode - proc resolveIndirectCall(c: PContext; n, nOrig: PNode; t: PType): TCandidate = initCandidate(c, result, t) @@ -2380,6 +2378,16 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mSizeOf: markUsed(c, n.info, s) result = semSizeof(c, setMs(n, s)) + of mDefault: + result = semDirectOp(c, n, flags) + let typ = result[^1].typ.skipTypes({tyTypeDesc}) + if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject: + var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[^1].info, typ)) + asgnExpr.typ = typ + var hasDefault: bool + asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph, typ.skipTypes({tyGenericInst, tyAlias, tySink}).n, hasDefault) + if hasDefault: + result = semObjConstr(c, asgnExpr, flags) else: result = semDirectOp(c, n, flags) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index ed1826fd4ea9..cb630edb0009 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -10,6 +10,8 @@ # This include file implements the semantic checking for magics. # included from sem.nim +proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode + proc semAddrArg(c: PContext; n: PNode): PNode = let x = semExprWithType(c, n) if x.kind == nkSym: @@ -454,6 +456,95 @@ proc semPrivateAccess(c: PContext, n: PNode): PNode = c.currentScope.allowPrivateAccess.add t.sym result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid)) + +# import nimsets + + + +# proc caseBranchMatchesExpr2(branch, matched: PNode): bool = +# for i in 0 ..< branch.len-1: +# if branch[i].kind == nkRange: +# if overlap(branch[i], matched): return true +# elif exprStructuralEquivalent(branch[i], matched): +# return true + +# proc pickCaseBranch2(caseExpr, matched: PNode): int = +# let endsWithElse = caseExpr[^1].kind == nkElse +# for i in 1..= 4: a = newNodeI(nkRecList, n.info) else: a = newNodeI(nkEmpty, n.info) - if n[^1].kind != nkEmpty: - localError(c.config, n[^1].info, errInitHereNotAllowed) var typ: PType - if n[^2].kind == nkEmpty: + var hasDefaultField = n[^1].kind != nkEmpty + if hasDefaultField: + n[^1] = semConstExpr(c, n[^1]) + typ = n[^1].typ + propagateToOwner(rectype, typ) + elif n[^2].kind == nkEmpty: localError(c.config, n.info, errTypeExpected) typ = errorType(c) else: typ = semTypeNode(c, n[^2], nil) + if c.graph.config.isDefined("nimRangeDefault") and typ.skipTypes(abstractInst).kind in {tyRange, tyOrdinal}: + n[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ)) + n[^1].typ = typ + hasDefaultField = true propagateToOwner(rectype, typ) var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner else: rectype.sym @@ -806,8 +813,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, inc(pos) if containsOrIncl(check, f.name.id): localError(c.config, info, "attempt to redefine: '" & f.name.s & "'") - if a.kind == nkEmpty: father.add newSymNode(f) - else: a.add newSymNode(f) + let fSym = newSymNode(f) + if hasDefaultField: + fSym.sym.ast = n[^1] + fSym.sym.ast.flags.incl nfUseDefaultField + if a.kind == nkEmpty: father.add fSym + else: a.add fSym styleCheckDef(c.config, f) onDef(f.info, f) if a.kind != nkEmpty: father.add a diff --git a/compiler/transf.nim b/compiler/transf.nim index bdd7c680ccd5..b53d897c2570 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -46,7 +46,7 @@ type module: PSym transCon: PTransCon # top of a TransCon stack inlining: int # > 0 if we are in inlining context (copy vars) - nestedProcs: int # > 0 if we are in a nested proc + genResult: bool contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' deferDetected, tooEarly: bool graph: ModuleGraph @@ -927,6 +927,141 @@ proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode) else: result = n +import nimsets + +proc caseBranchMatchesExpr(branch, matched: PNode): bool = + for i in 0 ..< branch.len-1: + if branch[i].kind == nkRange: + if overlap(branch[i], matched): return true + elif exprStructuralEquivalent(branch[i], matched): + return true + +proc pickCaseBranch(caseExpr, matched: PNode): int = + let endsWithElse = caseExpr[^1].kind == nkElse + for i in 1.. resultPos and c.transCon.owner.ast[resultPos] != nil result = transform(c, n) popTransCon(c) incl(result.flags, nfTransf) diff --git a/tests/objects/mobject_default_value.nim b/tests/objects/mobject_default_value.nim new file mode 100644 index 000000000000..224549501507 --- /dev/null +++ b/tests/objects/mobject_default_value.nim @@ -0,0 +1,15 @@ +type + Clean = object + mem: int + Default* = object + poi: int = 12 + clc: Clean + se*: range[0'i32 .. high(int32)] + + NonDefault* = object + poi: int + + PrellDeque*[T] = object + pendingTasks*: range[0'i32 .. high(int32)] + head: T + tail: T diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim new file mode 100644 index 000000000000..2a71a4c19817 --- /dev/null +++ b/tests/objects/tobject_default_value.nim @@ -0,0 +1,238 @@ +discard """ + matrix: "-d:nimRangeDefault" + targets: "c js" +""" + +import times + +type + Guess = object + poi: DateTime + +block: + var x: Guess + discard x + + discard Guess() + +import mobject_default_value + +block: + let x = Default() + doAssert x.se == 0'i32 +# echo Default(poi: 12) +# echo Default(poi: 17) + +# echo NonDefault(poi: 77) + +block: + var x: Default + doAssert x.se == 0'i32 + +type + ObjectBase = object of RootObj + value = 12 + + Object = object of ObjectBase + time: float = 1.2 + date: int + scale: range[1..10] + + Object2 = object + name: Object + + Object3 = object + obj: Object2 + + ObjectTuple = tuple + base: ObjectBase + typ: int + obj: Object + + Ref = ref object of ObjectBase + + RefInt = ref object of Ref + data = 73 + +var t {.threadvar.}: Default +# var m1, m2 {.threadvar.}: Default + +block: + doAssert t.se == 0'i32 + +block: + var x: ObjectBase + doAssert x.value == 12 + let y = default(ObjectBase) + doAssert y.value == 12 + +block: + var x: Object + doAssert x.value == 12 + doAssert x.time == 1.2 + doAssert x.scale == 1 + let y = default(Object) + doAssert y.value == 12 + doAssert y.time == 1.2 + doAssert y.scale == 1 + + var x1, x2, x3: Object + doAssert x1.value == 12 + doAssert x1.time == 1.2 + doAssert x1.scale == 1 + doAssert x2.value == 12 + doAssert x2.time == 1.2 + doAssert x2.scale == 1 + doAssert x3.value == 12 + doAssert x3.time == 1.2 + doAssert x3.scale == 1 + +block: + var x: Ref + new(x) + doAssert x.value == 12, "Ref.value = " & $x.value + + var y: RefInt + new(y) + doAssert y.value == 12 + doAssert y.data == 73 + +# block: # object array +# var x: ObjectArray +# echo x + +block: + var x: Object2 + doAssert x.name.value == 12 + doAssert x.name.time == 1.2 + doAssert x.name.scale == 1 + +block: + var x: Object3 + doAssert x.obj.name.value == 12 + doAssert x.obj.name.time == 1.2 + doAssert x.obj.name.scale == 1 + +# block: #seq +# var x = newSeq[Object](10) +# echo x + +block: # array + var x: array[10, Object] + let y = x[0] + doAssert y.value == 12 + doAssert y.time == 1.2 + doAssert y.scale == 1 + +block: # array + var x {.noinit.}: array[10, Object] + discard x + +block: # tuple + var x: ObjectTuple + doAssert x.base.value == 12 + doAssert x.typ == 0 + doAssert x.obj.time == 1.2 + doAssert x.obj.date == 0 + doAssert x.obj.scale == 1 + doAssert x.obj.value == 12 + +type + ObjectArray = object + data: array[10, Object] + +block: + var x: ObjectArray + let y = x.data[0] + doAssert y.value == 12 + doAssert y.time == 1.2 + doAssert y.scale == 1 + + +block: + var x: PrellDeque[int] + doAssert x.pendingTasks == 0 + +type + Color = enum + Red, Blue, Yellow + + ObjectVarint = object + case kind: Color + of Red: + data: int = 10 + of Blue: + fill = "123" + of Yellow: + time = 1.8'f32 + + ObjectVarint1 = object + case kind: Color = Blue + of Red: + data1: int = 10 + of Blue: + fill2 = "123" + cry: float + of Yellow: + time3 = 1.8'f32 + him: int + +block: + var x = ObjectVarint(kind: Red) + doAssert x.kind == Red + doAssert x.data == 10 + +block: + var x = ObjectVarint(kind: Blue) + doAssert x.kind == Blue + doAssert x.fill == "123" + +block: + var x = ObjectVarint(kind: Yellow) + doAssert x.kind == Yellow + doAssert typeof(x.time) is float32 + +block: + var x: ObjectVarint1 + doAssert x.kind == Blue + doAssert x.fill2 == "123" + x.cry = 326 + + +type + ObjectVarint2 = object + case kind: Color + of Red: + data: int = 10 + of Blue: + fill = "123" + of Yellow: + time = 1.8'f32 + + ObjectVarint3 = object + case kind: Color = Blue + of Red: + data1: int = 10 + of Blue: + case name: Color = Blue + of Blue: + go = 12 + else: + temp = 66 + fill2 = "123" + cry: float + of Yellow: + time3 = 1.8'f32 + him: int + +block: + var x: ObjectVarint3 + doAssert x.kind == Blue + doAssert x.name == Blue + doAssert x.go == 12 + +block: + var x = ObjectVarint3(kind: Blue, name: Red, temp: 99) + doAssert x.kind == Blue + doAssert x.name == Red + doAssert x.temp == 99 From dc9c8daeeb7ea1160184f352d23c7de23f82d46a Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 18 May 2022 15:24:10 +0800 Subject: [PATCH 2/2] add cpp target --- compiler/sem.nim | 158 ++++++++++++++++++++++++ compiler/semexprs.nim | 2 +- compiler/semmagic.nim | 91 +------------- compiler/semobjconstr.nim | 9 -- compiler/semstmts.nim | 2 +- compiler/transf.nim | 155 ++--------------------- lib/system.nim | 5 + tests/objects/tobject_default_value.nim | 18 +-- 8 files changed, 185 insertions(+), 255 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 70c57864c5d0..3ecadf3fc5c6 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -535,6 +535,164 @@ proc setGenericParamsMisc(c: PContext; n: PNode) = else: n[miscPos][1] = orig +proc caseBranchMatchesExpr(branch, matched: PNode): bool = + for i in 0 ..< branch.len-1: + if branch[i].kind == nkRange: + if overlap(branch[i], matched): return true + elif exprStructuralEquivalent(branch[i], matched): + return true + +proc pickCaseBranchIndex(caseExpr, matched: PNode): int = + let endsWithElse = caseExpr[^1].kind == nkElse + for i in 1..