diff --git a/compiler/cbuilderdecls.nim b/compiler/cbuilderdecls.nim index 4185c71826..e3c1c31075 100644 --- a/compiler/cbuilderdecls.nim +++ b/compiler/cbuilderdecls.nim @@ -63,41 +63,55 @@ template addTypedef(builder: var Builder, name: string, typeBody: typed) = builder.add(name) builder.add(";\n") -type StructInitializer = object - ## context for building struct initializers, i.e. `{ field1, field2 }` - # XXX use in genBracedInit - orderCompliant: bool - ## if true, fields will not be named, instead values are placed in order - needsComma: bool +type + StructInitializerKind = enum + siOrderedStruct ## struct constructor, but without named fields on C + siNamedStruct ## struct constructor, with named fields i.e. C99 designated initializer + siArray ## array constructor + siWrapper ## wrapper for a single field, generates it verbatim -proc initStructInitializer(builder: var Builder, orderCompliant: bool): StructInitializer = + StructInitializer = object + ## context for building struct initializers, i.e. `{ field1, field2 }` + kind: StructInitializerKind + ## if true, fields will not be named, instead values are placed in order + needsComma: bool + +proc initStructInitializer(builder: var Builder, kind: StructInitializerKind): StructInitializer = ## starts building a struct initializer, `orderCompliant = true` means ## built fields must be ordered correctly - doAssert orderCompliant, "named struct constructors unimplemented" - result = StructInitializer(orderCompliant: true, needsComma: false) - builder.add("{ ") + assert kind != siNamedStruct, "named struct constructors unimplemented" + result = StructInitializer(kind: kind, needsComma: false) + if kind != siWrapper: + builder.add("{") template addField(builder: var Builder, constr: var StructInitializer, name: string, valueBody: typed) = ## adds a field to a struct initializer, with the value built in `valueBody` if constr.needsComma: + assert constr.kind != siWrapper, "wrapper constructor cannot have multiple fields" builder.add(", ") else: constr.needsComma = true - if constr.orderCompliant: + case constr.kind + of siArray, siWrapper: # no name, can just add value valueBody - else: - doAssert false, "named struct constructors unimplemented" + of siOrderedStruct: + # no name, can just add value on C + assert name.len != 0, "name has to be given for struct initializer field" + valueBody + of siNamedStruct: + assert false, "named struct constructors unimplemented" proc finishStructInitializer(builder: var Builder, constr: StructInitializer) = ## finishes building a struct initializer - builder.add(" }") + if constr.kind != siWrapper: + builder.add("}") -template addStructInitializer(builder: var Builder, constr: out StructInitializer, orderCompliant: bool, body: typed) = +template addStructInitializer(builder: var Builder, constr: out StructInitializer, kind: StructInitializerKind, body: typed) = ## builds a struct initializer, i.e. `{ field1, field2 }` ## a `var StructInitializer` must be declared and passed as a parameter so ## that it can be used with `addField` - constr = builder.initStructInitializer(orderCompliant) + constr = builder.initStructInitializer(kind) body builder.finishStructInitializer(constr) diff --git a/compiler/cbuilderexprs.nim b/compiler/cbuilderexprs.nim index 16caaa0215..f70405be7a 100644 --- a/compiler/cbuilderexprs.nim +++ b/compiler/cbuilderexprs.nim @@ -15,5 +15,11 @@ const proc procPtrType(conv: TCallingConvention, rettype: Snippet, name: string): Snippet = CallingConvToStr[conv] & "_PTR(" & rettype & ", " & name & ")" +proc cCast(typ, value: Snippet): Snippet = + "((" & typ & ") " & value & ")" + +proc cAddr(value: Snippet): Snippet = + "&" & value + proc bitOr(a, b: Snippet): Snippet = a & " | " & b diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a344816ba8..21ecc9688b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -13,7 +13,7 @@ when defined(nimCompilerStacktraceHints): import std/stackframes proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, - result: var Rope; count: var int; + result: var Builder; init: var StructInitializer; isConst: bool, info: TLineInfo) # -------------------------- constant expressions ------------------------ @@ -3193,7 +3193,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkMixinStmt, nkBindStmt: discard else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind") -proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) = +proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Builder) = var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc}) case t.kind of tyBool: result.add rope"NIM_FALSE" @@ -3204,38 +3204,56 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) = result.add rope"NIM_NIL" of tyString, tySequence: if optSeqDestructors in p.config.globalOptions: - result.add "{0, NIM_NIL}" + var seqInit: StructInitializer + result.addStructInitializer(seqInit, kind = siOrderedStruct): + result.addField(seqInit, name = "len"): + result.add("0") + result.addField(seqInit, name = "p"): + result.add("NIM_NIL") else: result.add "NIM_NIL" of tyProc: if t.callConv != ccClosure: result.add "NIM_NIL" else: - result.add "{NIM_NIL, NIM_NIL}" + var closureInit: StructInitializer + result.addStructInitializer(closureInit, kind = siOrderedStruct): + result.addField(closureInit, name = "ClP_0"): + result.add("NIM_NIL") + result.addField(closureInit, name = "ClE_0"): + result.add("NIM_NIL") of tyObject: - var count = 0 - result.add "{" - getNullValueAuxT(p, t, t, t.n, nil, result, count, true, info) - result.add "}" + var objInit: StructInitializer + result.addStructInitializer(objInit, kind = siOrderedStruct): + getNullValueAuxT(p, t, t, t.n, nil, result, objInit, true, info) of tyTuple: - result.add "{" - if p.vccAndC and t.isEmptyTupleType: - result.add "0" - for i, a in t.ikids: - if i > 0: result.add ", " - getDefaultValue(p, a, info, result) - result.add "}" + var tupleInit: StructInitializer + result.addStructInitializer(tupleInit, kind = siOrderedStruct): + if p.vccAndC and t.isEmptyTupleType: + result.addField(tupleInit, name = "dummy"): + result.add "0" + for i, a in t.ikids: + result.addField(tupleInit, name = "Field" & $i): + getDefaultValue(p, a, info, result) of tyArray: - result.add "{" - for i in 0.. 0: result.add ", " - getDefaultValue(p, t.elementType, info, result) - result.add "}" + var arrInit: StructInitializer + result.addStructInitializer(arrInit, kind = siArray): + for i in 0.. 0: res.add ", " + getNullValueAux(p, t, obj[0], constOrNil, result, init, isConst, info) var branch = Zero if constOrNil != nil: ## find kind value, default is zero if not specified @@ -3269,140 +3285,177 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, break let selectedBranch = caseObjDefaultBranch(obj, branch) - res.add "{" - var countB = 0 + # XXX siNamedStruct needs to be implemented to replace `res` here + var res = "{" + var branchInit: StructInitializer let b = lastSon(obj[selectedBranch]) # designated initilization is the only way to init non first element of unions # branches are allowed to have no members (b.len == 0), in this case they don't need initializer if b.kind == nkRecList and not isEmptyCaseObjectBranch(b): - res.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {" - getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info) - res.add "}" + res.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = " + res.addStructInitializer(branchInit, kind = siOrderedStruct): + getNullValueAux(p, t, b, constOrNil, res, branchInit, isConst, info) elif b.kind == nkSym: res.add "." & mangleRecFieldName(p.module, b.sym) & " = " - getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info) + res.addStructInitializer(branchInit, kind = siWrapper): + getNullValueAux(p, t, b, constOrNil, res, branchInit, isConst, info) else: return - result.add res - result.add "}" + result.addField(init, name = ""): + # XXX figure out name for the union, see use of `addAnonUnion` + result.add res + result.add "}" of nkSym: - if count > 0: result.add ", " - inc count let field = obj.sym - if constOrNil != nil: - for i in 1.. 0: result.add ",\n" - if it.kind == nkExprColonExpr: genBracedInit(p, it[1], isConst, it[0].typ, result) - else: genBracedInit(p, it, isConst, it.typ, result) - result.add("}\n") - -proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType; result: var Rope) = - result.add "{" - if p.vccAndC and n.len == 0: - result.add "0" - for i in 0.. 0: result.add ",\n" - if it.kind == nkExprColonExpr: genBracedInit(p, it[1], isConst, tup[i], result) - else: genBracedInit(p, it, isConst, tup[i], result) - result.add("}\n") - -proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) = - var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope] - let base = t.skipTypes(abstractInst)[0] - if n.len > 0: - # array part needs extra curlies: - data.add(", {") +proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Builder) = + var arrInit: StructInitializer + result.addStructInitializer(arrInit, kind = siArray): + if p.vccAndC and n.len == 0 and n.typ.kind == tyArray: + result.addField(arrInit, name = ""): + getDefaultValue(p, n.typ.elementType, n.info, result) for i in 0.. 0: data.addf(",$n", []) - genBracedInit(p, n[i], isConst, base, data) - data.add("}") - data.add("}") + let it = n[i] + var ind, val: PNode + if it.kind == nkExprColonExpr: + ind = it[0] + val = it[1] + else: + ind = it + val = it + result.addField(arrInit, name = ""): + genBracedInit(p, val, isConst, ind.typ, result) +proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType; result: var Builder) = + var tupleInit: StructInitializer + result.addStructInitializer(tupleInit, kind = siOrderedStruct): + if p.vccAndC and n.len == 0: + result.addField(tupleInit, name = "dummy"): + result.add("0") + for i in 0.. 0: + def.addField(structInit, name = "data"): + var arrInit: StructInitializer + def.addStructInitializer(arrInit, kind = siArray): + for i in 0.. 0: - data.add(", {") - for i in 0.. 0: data.addf(",$n", []) - genBracedInit(p, n[i], isConst, base, data) - data.add("}") - let payload = getTempName(p.module) - appcg(p.module, cfsStrData, - "static $5 struct {$n" & - " NI cap; $1 data[$2];$n" & - "} $3 = {$2 | NIM_STRLIT_FLAG$4};$n", [ - getTypeDesc(p.module, base), n.len, payload, data, - if isConst: "const" else: ""]) - result.add "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload] -proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Rope) = + var def = newBuilder("") + def.addVarWithTypeAndInitializer( + if isConst: AlwaysConst else: Global, + name = payload): + def.addSimpleStruct(p.module, name = "", baseType = ""): + def.addField(name = "cap", typ = "NI") + def.addArrayField(name = "data", elementType = getTypeDesc(p.module, base), len = n.len) + do: + var structInit: StructInitializer + def.addStructInitializer(structInit, kind = siOrderedStruct): + def.addField(structInit, name = "cap"): + def.add(bitOr(rope(n.len), "NIM_STRLIT_FLAG")) + if n.len > 0: + def.addField(structInit, name = "data"): + var arrInit: StructInitializer + def.addStructInitializer(arrInit, kind = siArray): + for i in 0..