From d2eb275fd852a37aeb645042da8a25d5991f9c7a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Apr 2020 20:09:27 -0700 Subject: [PATCH 1/9] emit(here): "things" + other emit fixes --- compiler/ccgstmts.nim | 53 +++++++++++++++++++++++++++++++------------ compiler/cgendata.nim | 1 + compiler/pragmas.nim | 22 +++++++++++------- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index bb9d30b8fca4..9cb4599834d3 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1446,6 +1446,31 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = res.add("\L") result = res.rope +type SectionKind = enum kUnknown, kFile, kProc + +proc determineSection(p: BProc, n: PNode): tuple[kind: SectionKind, filesec: TCFileSection, procsec: TCProcSection] = + template bail() = + localError(p.config, n.info, "invalid emit section") + return + template retFile(sec) = result = (kFile, sec, TCProcSection.default) + if n.len == 3: + let n1 = n[1] + if n1.kind != nkIdent: bail() + case n1.ident.s.normalize + of "typeSection": retFile cfsTypes + of "varSection": retFile cfsVars + of "includeSection": retFile cfsHeaders + of "here": result = (kProc, TCFileSection.default, cpsStmts) + else: bail() + else: # legacy syntax; no need to add new section values here + if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}: + let sec = n[0].strVal + if sec.startsWith("/*TYPESECTION*/"): retFile cfsTypes + elif sec.startsWith("/*VARSECTION*/"): retFile cfsVars + elif sec.startsWith("/*INCLUDESECTION*/"): retFile cfsHeaders + if result.kind == kUnknown: + result = (kUnknown, cfsProcHeaders, cpsStmts) + proc genAsmStmt(p: BProc, t: PNode) = assert(t.kind == nkAsmStmt) genLineDir(p, t) @@ -1459,24 +1484,24 @@ proc genAsmStmt(p: BProc, t: PNode) = else: p.s(cpsStmts).add indentLine(p, runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s])) -proc determineSection(n: PNode): TCFileSection = - result = cfsProcHeaders - if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}: - let sec = n[0].strVal - if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes - elif sec.startsWith("/*VARSECTION*/"): result = cfsVars - elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders +proc isModuleLevel(p: BProc): bool = + p.prc == nil and p.breakIdx == 0 proc genEmit(p: BProc, t: PNode) = - var s = genAsmOrEmitStmt(p, t[1]) - if p.prc == nil: - # top level emit pragma? - let section = determineSection(t[1]) + var s = genAsmOrEmitStmt(p, t[^1]) + let (status, fileSection, procSection) = determineSection(p, t) + template emitProcSection(section) = + genLineDir(p, t) + line(p, section, s) + template emitFileSection(section) = genCLineDir(p.module.s[section], t.info, p.config) p.module.s[section].add(s) - else: - genLineDir(p, t) - line(p, cpsStmts, s) + + case status + of kFile: emitFileSection(fileSection) + of kProc: emitProcSection(procSection) + elif p.isModuleLevel: emitFileSection(fileSection) + else: emitProcSection(procSection) # could be inside a top level `block:` proc genPragma(p: BProc, n: PNode) = for it in n.sons: diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index bf7daeea6969..884b45f43e07 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -39,6 +39,7 @@ type cfsDynLibInit, # section for init of dynamic library binding cfsDynLibDeinit # section for deinitialization of dynamic # libraries + TCTypeKind* = enum # describes the type kind of a C type ctVoid, ctChar, ctBool, ctInt, ctInt8, ctInt16, ctInt32, ctInt64, diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 4504d1cc5c16..f21251b8b297 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -531,10 +531,10 @@ proc processLink(c: PContext, n: PNode) = recordPragma(c, n, "link", found.string) proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = - case n[1].kind + case n[^1].kind of nkStrLit, nkRStrLit, nkTripleStrLit: result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info) - var str = n[1].strVal + var str = n[^1].strVal if str == "": localError(con.config, n.info, "empty 'asm' statement") return @@ -567,20 +567,21 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = result = newNode(nkAsmStmt, n.info) proc pragmaEmit(c: PContext, n: PNode) = - if n.kind notin nkPragmaCallKinds or n.len != 2: + if n.kind notin nkPragmaCallKinds: localError(c.config, n.info, errStringLiteralExpected) else: - let n1 = n[1] + let last = n.len-1 # easier to spot than `^1` here + let n1 = n[last] if n1.kind == nkBracket: var b = newNodeI(nkBracket, n1.info, n1.len) for i in 0.. 1 and it[0].kind in {nkCall}: + # pragma(args...): arg -> pragma(args..., arg) ; eg, for `emit(section): "foo"` + it = newTree(nkCall, it[0].sons & it[1]) + n[i] = it + var key = if it.kind in nkPragmaCallKinds and it.len > 1: it[0] else: it if key.kind == nkBracketExpr: processNote(c, it) From 987e2d7ea65bd3dfa7ea4bd8f36640025c2da7a8 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Apr 2020 20:35:27 -0700 Subject: [PATCH 2/9] fixup --- compiler/cgendata.nim | 1 - compiler/pragmas.nim | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 884b45f43e07..bf7daeea6969 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -39,7 +39,6 @@ type cfsDynLibInit, # section for init of dynamic library binding cfsDynLibDeinit # section for deinitialization of dynamic # libraries - TCTypeKind* = enum # describes the type kind of a C type ctVoid, ctChar, ctBool, ctInt, ctInt8, ctInt16, ctInt32, ctInt64, diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index f21251b8b297..2028b7319622 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -567,21 +567,20 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = result = newNode(nkAsmStmt, n.info) proc pragmaEmit(c: PContext, n: PNode) = - if n.kind notin nkPragmaCallKinds: + if n.kind notin nkPragmaCallKinds or (n.len != 2 and n.len != 3): localError(c.config, n.info, errStringLiteralExpected) else: - let last = n.len-1 # easier to spot than `^1` here - let n1 = n[last] + let n1 = n[^1] if n1.kind == nkBracket: var b = newNodeI(nkBracket, n1.info, n1.len) for i in 0.. Date: Fri, 10 Apr 2020 22:59:17 -0700 Subject: [PATCH 3/9] fixup --- compiler/ccgstmts.nim | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 9cb4599834d3..668992fccb56 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -9,6 +9,8 @@ # included from cgen.nim +from strutils import format + const RangeExpandLimit = 256 # do not generate ranges # over 'RangeExpandLimit' elements @@ -1449,19 +1451,19 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = type SectionKind = enum kUnknown, kFile, kProc proc determineSection(p: BProc, n: PNode): tuple[kind: SectionKind, filesec: TCFileSection, procsec: TCProcSection] = - template bail() = - localError(p.config, n.info, "invalid emit section") + template bail(msg) = + localError(p.config, n.info, msg) return template retFile(sec) = result = (kFile, sec, TCProcSection.default) if n.len == 3: let n1 = n[1] - if n1.kind != nkIdent: bail() + if n1.kind != nkIdent: bail("expected: nkIdent, got $1".format n1.kind) case n1.ident.s.normalize - of "typeSection": retFile cfsTypes - of "varSection": retFile cfsVars - of "includeSection": retFile cfsHeaders - of "here": result = (kProc, TCFileSection.default, cpsStmts) - else: bail() + of "typeSection".normalize: retFile cfsTypes + of "varSection".normalize: retFile cfsVars + of "includeSection".normalize: retFile cfsHeaders + of "here".normalize: result = (kProc, TCFileSection.default, cpsStmts) + else: bail("expected: `typeSection, varSection, includeSection, here`, got: $1".format n1.ident.s) else: # legacy syntax; no need to add new section values here if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}: let sec = n[0].strVal From 0da90e7d9f6c5a9dde74e923590813262f60c249 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Apr 2020 22:59:28 -0700 Subject: [PATCH 4/9] lib/experimental/backendutils.nim --- compiler/ccgstmts.nim | 7 +- lib/experimental/backendutils.nim | 38 +++++++++++ tests/stdlib/tbackendutils.nim | 106 ++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 lib/experimental/backendutils.nim create mode 100644 tests/stdlib/tbackendutils.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 668992fccb56..919fd5f8d67d 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1457,8 +1457,11 @@ proc determineSection(p: BProc, n: PNode): tuple[kind: SectionKind, filesec: TCF template retFile(sec) = result = (kFile, sec, TCProcSection.default) if n.len == 3: let n1 = n[1] - if n1.kind != nkIdent: bail("expected: nkIdent, got $1".format n1.kind) - case n1.ident.s.normalize + if n1.kind != nkStrLit: bail("expected: 'nkStrLit', got '$1'".format n1.kind) + # using nkStrLit instead of nkIdent as it'll allow to pass a constant + # string argument to emit without ambiguity, eg: + # const section = "here"; emit(section): "/**/" + case n1.strVal.normalize of "typeSection".normalize: retFile cfsTypes of "varSection".normalize: retFile cfsVars of "includeSection".normalize: retFile cfsHeaders diff --git a/lib/experimental/backendutils.nim b/lib/experimental/backendutils.nim new file mode 100644 index 000000000000..9f4f153011df --- /dev/null +++ b/lib/experimental/backendutils.nim @@ -0,0 +1,38 @@ +##[ +## experimental API! + +Utilities to interface with generated backend (for now C/C++, later js) code +]## + +import macros + +static: doAssert defined(c) or defined(cpp) + +macro c_astToStr*(T: typedesc): string = + ## returns the backend + result = newStmtList() + var done {.global.}: bool + if not done: + done = true + result.add quote do: + {.emit("typeSection"): "#define c_astToStrImpl(T) #T".} + + result.add quote do: + var s: cstring + {.emit("here"): [s, " = c_astToStrImpl(", `T`, ");"].} + $s + +template c_currentSourcePath*(): string = + var s: cstring + {.emit("here"): [s, "= __FILE__;"].} + $s + +template c_currentFunction*(): string = + var s: cstring + {.emit("here"): [s, "= __FUNCTION__;"].} + $s + +template c_sizeof*(T: typedesc): int = + var s: int + {.emit("here"): [s," = sizeof(", T, ");"].} + s diff --git a/tests/stdlib/tbackendutils.nim b/tests/stdlib/tbackendutils.nim new file mode 100644 index 000000000000..358a82bf568b --- /dev/null +++ b/tests/stdlib/tbackendutils.nim @@ -0,0 +1,106 @@ +discard """ + joinable: false +""" + +import experimental/backendutils +import macros, strutils, os +import unittest + +macro test(body: untyped): untyped = + result = newStmtList() + for T in body: + result.add quote do: + let s1 = `T`.sizeof + let s2 = `T`.c_sizeof + if s1 != s2: + echo "$1 $2 => sizeof: $3 vs c_sizeof: $4" % [$astToStr(`T`), c_astToStr(`T`), $s1, $s2] + +type FooEmpty = object +const N = 10 +type FooEmptyArr = array[N, FooEmpty] +type Bar = object + x: FooEmpty + y: cint + +type BarTup = (FooEmpty, cint) +type BarTup2 = (().type, cint) + +# type MyEnum = enum k1, k2 +type MyEnum {.exportc.} = enum k1, k2 +type Obj = object + x1: MyEnum + x2: cint + +test: + FooEmpty + FooEmptyArr + Bar + BarTup + BarTup2 + MyEnum + Obj + +block: # c_currentFunction + proc test1(){.exportc.} = + doAssert c_currentFunction == "test1" + proc test2() = + doAssert c_currentFunction.startsWith "test2_", c_currentFunction + test1() + test2() + +block: # c_currentFunction + let file = c_currentSourcePath + let name = currentSourcePath.splitFile.name + doAssert file.contains name + + let code = file.readFile + let z = "abc123" + doAssert code.count(z) == 1 # string generated in code + +block: + # checks `c_astToStr` generates top-level macro `c_astToStrImp` only once + let code = c_currentSourcePath.readFile + proc compose(a, b: string): string = + ## avoids forming a&b at CT, which could end up in cgen'd file + ## and affect the count + result = a & b + doAssert code.count(compose("#define ", "c_astToStrImp")) == 1 + +block: # c_astToStr + doAssert c_astToStr(cint) == "int" + type Foo = object + doAssert c_astToStr(Foo).startsWith "tyObject_Foo_" + +block: # c_sizeof + doAssert char.c_sizeof == 1 + {.emit("here"):""" +typedef struct Foo1{ +} Foo1; +typedef enum FooEnum{ + k1, k2 +} FooEnum; +""".} + + # type Foo1 {.importc, completeStruct.} = object # pending https://github.com/nim-lang/Nim/pull/13926 + type Foo1 {.importc.} = object + type Foo1Alias = object + + type FooEnum {.importc.} = enum k1, k2 + when defined(cpp): + doAssert Foo1.c_sizeof == 1 + else: + doAssert Foo1.c_sizeof == 0 + + template checkSize(T) = + let s1 = T.c_sizeof + let s2 = T.sizeof + # check s1 == s2, $($T, c_astToStr(T), s1, s2) # pending https://github.com/nim-lang/Nim/pull/10558 + if s1 != s2: + echo "sizeof mismatch " & $($T, c_astToStr(T), s1, s2) + check s1 == s2 + checkSize cint + checkSize int + checkSize Foo1 + when false: + checkSize Foo1Alias # pending https://github.com/nim-lang/Nim/issues/13945 + checkSize FooEnum # pending https://github.com/nim-lang/Nim/issues/13927 From b7349654536ab1d504a86dca83f072e30413ccdd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Apr 2020 23:26:23 -0700 Subject: [PATCH 5/9] cstaticIf --- lib/experimental/backendutils.nim | 5 +++++ tests/stdlib/tbackendutils.nim | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/experimental/backendutils.nim b/lib/experimental/backendutils.nim index 9f4f153011df..98b691a16a71 100644 --- a/lib/experimental/backendutils.nim +++ b/lib/experimental/backendutils.nim @@ -36,3 +36,8 @@ template c_sizeof*(T: typedesc): int = var s: int {.emit("here"): [s," = sizeof(", T, ");"].} s + +template cstaticIf*(cond: string, body) = + {.emit("here"): ["""#if """, cond, "\n"].} + body + {.emit("here"): "#endif\n".} diff --git a/tests/stdlib/tbackendutils.nim b/tests/stdlib/tbackendutils.nim index 358a82bf568b..625197baa459 100644 --- a/tests/stdlib/tbackendutils.nim +++ b/tests/stdlib/tbackendutils.nim @@ -104,3 +104,12 @@ typedef enum FooEnum{ when false: checkSize Foo1Alias # pending https://github.com/nim-lang/Nim/issues/13945 checkSize FooEnum # pending https://github.com/nim-lang/Nim/issues/13927 + +block: # cstaticIf + var a = 1 + cstaticIf "defined(nonexistant)": + a = 2 + doAssert a == 1 + cstaticIf "defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L": + a = 3 + doAssert a == 3, "really old compiler" From 7be499fcced3b676d185130b3827261cc14b3505 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Apr 2020 23:39:46 -0700 Subject: [PATCH 6/9] simplify --- compiler/ccgstmts.nim | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 919fd5f8d67d..0a388835237f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1495,18 +1495,12 @@ proc isModuleLevel(p: BProc): bool = proc genEmit(p: BProc, t: PNode) = var s = genAsmOrEmitStmt(p, t[^1]) let (status, fileSection, procSection) = determineSection(p, t) - template emitProcSection(section) = + if status == kFile or (status == kUnknown and p.isModuleLevel): + genCLineDir(p.module.s[fileSection], t.info, p.config) + p.module.s[fileSection].add(s) + else: genLineDir(p, t) - line(p, section, s) - template emitFileSection(section) = - genCLineDir(p.module.s[section], t.info, p.config) - p.module.s[section].add(s) - - case status - of kFile: emitFileSection(fileSection) - of kProc: emitProcSection(procSection) - elif p.isModuleLevel: emitFileSection(fileSection) - else: emitProcSection(procSection) # could be inside a top level `block:` + line(p, procSection, s) proc genPragma(p: BProc, n: PNode) = for it in n.sons: From 2c249d9aa840f5140e71b5fe436f99b4b889a139 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Apr 2020 23:59:15 -0700 Subject: [PATCH 7/9] add runnableExamples --- lib/experimental/backendutils.nim | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/experimental/backendutils.nim b/lib/experimental/backendutils.nim index 98b691a16a71..20e289831e11 100644 --- a/lib/experimental/backendutils.nim +++ b/lib/experimental/backendutils.nim @@ -1,15 +1,18 @@ ##[ ## experimental API! -Utilities to interface with generated backend (for now C/C++, later js) code +Utilities to interface with generated backend (for now C/C++, later js) code, +abstracting away platform differences and taking care of needy greedy details. ]## import macros -static: doAssert defined(c) or defined(cpp) +static: doAssert defined(c) or defined(cpp) or defined(nimdoc) macro c_astToStr*(T: typedesc): string = - ## returns the backend + ## returns the backend analog of `astToStr` + runnableExamples: + doAssert cint.c_astToStr == "int" result = newStmtList() var done {.global.}: bool if not done: @@ -23,21 +26,31 @@ macro c_astToStr*(T: typedesc): string = $s template c_currentSourcePath*(): string = + ## returns the generated backend file var s: cstring {.emit("here"): [s, "= __FILE__;"].} $s template c_currentFunction*(): string = + runnableExamples: + proc fun(){.exportc.} = doAssert c_currentFunction == "fun" + fun() var s: cstring - {.emit("here"): [s, "= __FUNCTION__;"].} + # cast needed for C++ + {.emit("here"): [s, "= (char*) __FUNCTION__;"].} $s template c_sizeof*(T: typedesc): int = + runnableExamples: + doAssert c_sizeof(cint) == cint.sizeof var s: int {.emit("here"): [s," = sizeof(", T, ");"].} s template cstaticIf*(cond: string, body) = + runnableExamples: + cstaticIf "defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L": + {.emit("HERE"): """_Static_assert(sizeof(_Bool) == 1, "bad"); """.} {.emit("here"): ["""#if """, cond, "\n"].} body {.emit("here"): "#endif\n".} From a9982061031df23a14ce19dd65bfb7842b33db7a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 11 Apr 2020 01:22:01 -0700 Subject: [PATCH 8/9] fixup --- compiler/ccgstmts.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 0a388835237f..eae02b2e6f8e 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1467,14 +1467,15 @@ proc determineSection(p: BProc, n: PNode): tuple[kind: SectionKind, filesec: TCF of "includeSection".normalize: retFile cfsHeaders of "here".normalize: result = (kProc, TCFileSection.default, cpsStmts) else: bail("expected: `typeSection, varSection, includeSection, here`, got: $1".format n1.ident.s) - else: # legacy syntax; no need to add new section values here + elif n.len == 2: # legacy syntax; no need to add new section values here + let n = n[1] if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}: let sec = n[0].strVal if sec.startsWith("/*TYPESECTION*/"): retFile cfsTypes elif sec.startsWith("/*VARSECTION*/"): retFile cfsVars elif sec.startsWith("/*INCLUDESECTION*/"): retFile cfsHeaders - if result.kind == kUnknown: - result = (kUnknown, cfsProcHeaders, cpsStmts) + if result.kind == kUnknown: result = (kUnknown, cfsProcHeaders, cpsStmts) + else: doAssert false, $n.len proc genAsmStmt(p: BProc, t: PNode) = assert(t.kind == nkAsmStmt) From 844ef10c0dc3ed7ff9578192c964d58adcd1f79d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sat, 11 Apr 2020 03:58:24 -0700 Subject: [PATCH 9/9] improve tests --- tests/stdlib/tbackendutils.nim | 113 ++++++++++++++++----------------- 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/tests/stdlib/tbackendutils.nim b/tests/stdlib/tbackendutils.nim index 625197baa459..4971476df60a 100644 --- a/tests/stdlib/tbackendutils.nim +++ b/tests/stdlib/tbackendutils.nim @@ -6,39 +6,16 @@ import experimental/backendutils import macros, strutils, os import unittest -macro test(body: untyped): untyped = +macro checkSizes(body: untyped): untyped = result = newStmtList() for T in body: result.add quote do: let s1 = `T`.sizeof let s2 = `T`.c_sizeof if s1 != s2: + # improve pending https://github.com/nim-lang/Nim/pull/10558 echo "$1 $2 => sizeof: $3 vs c_sizeof: $4" % [$astToStr(`T`), c_astToStr(`T`), $s1, $s2] - -type FooEmpty = object -const N = 10 -type FooEmptyArr = array[N, FooEmpty] -type Bar = object - x: FooEmpty - y: cint - -type BarTup = (FooEmpty, cint) -type BarTup2 = (().type, cint) - -# type MyEnum = enum k1, k2 -type MyEnum {.exportc.} = enum k1, k2 -type Obj = object - x1: MyEnum - x2: cint - -test: - FooEmpty - FooEmptyArr - Bar - BarTup - BarTup2 - MyEnum - Obj + check s1 == s2 block: # c_currentFunction proc test1(){.exportc.} = @@ -71,45 +48,63 @@ block: # c_astToStr type Foo = object doAssert c_astToStr(Foo).startsWith "tyObject_Foo_" +block: # cstaticIf + var a = 1 + cstaticIf "defined(nonexistant)": + a = 2 + cstaticIf "0 || 1": + a = 3 + doAssert a == 3 + block: # c_sizeof doAssert char.c_sizeof == 1 {.emit("here"):""" typedef struct Foo1{ } Foo1; -typedef enum FooEnum{ - k1, k2 -} FooEnum; """.} - # type Foo1 {.importc, completeStruct.} = object # pending https://github.com/nim-lang/Nim/pull/13926 type Foo1 {.importc.} = object - type Foo1Alias = object - - type FooEnum {.importc.} = enum k1, k2 - when defined(cpp): - doAssert Foo1.c_sizeof == 1 - else: - doAssert Foo1.c_sizeof == 0 - - template checkSize(T) = - let s1 = T.c_sizeof - let s2 = T.sizeof - # check s1 == s2, $($T, c_astToStr(T), s1, s2) # pending https://github.com/nim-lang/Nim/pull/10558 - if s1 != s2: - echo "sizeof mismatch " & $($T, c_astToStr(T), s1, s2) - check s1 == s2 - checkSize cint - checkSize int - checkSize Foo1 - when false: - checkSize Foo1Alias # pending https://github.com/nim-lang/Nim/issues/13945 - checkSize FooEnum # pending https://github.com/nim-lang/Nim/issues/13927 -block: # cstaticIf - var a = 1 - cstaticIf "defined(nonexistant)": - a = 2 - doAssert a == 1 - cstaticIf "defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L": - a = 3 - doAssert a == 3, "really old compiler" + when defined(cpp): doAssert Foo1.c_sizeof == 1 + else: doAssert Foo1.c_sizeof == 0 + + checkSizes: + cint + int + Foo1 + +when false: # broken tests + block: + {.emit("here"):""" + typedef struct Foo2{ + } Foo2; + """.} + + # add this after https://github.com/nim-lang/Nim/pull/13926 + # type Foo2 {.importc, completeStruct.} = object + + type FooEmpty = object + const N = 10 + type FooEmptyArr = array[N, FooEmpty] + type Bar = object + x: FooEmpty + y: cint + + type BarTup = (FooEmpty, cint) + type BarTup2 = (().type, cint) + + type MyEnum1 = enum g1, g2 + type MyEnum2 {.exportc.} = enum k1, k2 + type Obj = object + x1: MyEnum2 + x2: cint + + checkSizes: + FooEmpty # pending https://github.com/nim-lang/Nim/issues/13945 + FooEmptyArr + Bar + BarTup + BarTup2 + MyEnum1 + MyEnum2 # pending https://github.com/nim-lang/Nim/issues/13927 + Obj