From 3a394651f8942059d9bee7e17761d8dd2b1cde6b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:48:44 +0800 Subject: [PATCH 1/2] implements `incompleteStruct` --- doc/tags.md | 1 + lib/std/posix/posix.nim | 2 +- src/hexer/nifcgen.nim | 2 +- src/models/nimony_tags.nim | 3 +- src/models/tags.nim | 184 +++++++++++++++++++------------------ src/nimony/sem.nim | 2 +- 6 files changed, 99 insertions(+), 95 deletions(-) diff --git a/doc/tags.md b/doc/tags.md index 7bbca91bd..935e66eae 100644 --- a/doc/tags.md +++ b/doc/tags.md @@ -222,6 +222,7 @@ | `(build X)`; `(build STR STR STR)` | NimonyPragma, NifIndexKind | `build` pragma | | `(string)` | NimonyPragma | `string` pragma | | `(view)` | NimonyPragma | `view` pragma | +| `(incompleteStruct)` | NimonyPragma | `incompleteStruct` pragma | | `(quoted X+)` | NimonyExpr, NiflerKind | name in backticks | | `(hderef X)` | NimonyExpr | hidden pointer deref operation | | `(ddot X)` | NimonyExpr | deref dot | diff --git a/lib/std/posix/posix.nim b/lib/std/posix/posix.nim index 918b1e7ce..59471fc7e 100644 --- a/lib/std/posix/posix.nim +++ b/lib/std/posix/posix.nim @@ -117,7 +117,7 @@ when defined(posix): # Directory operations type - DIR* {.importc: "DIR", header: "".} = object + DIR* {.importc: "DIR", header: "", incompleteStruct.} = object Dirent* {.importc: "struct dirent", header: "".} = object d_type* {.importc: "d_type".}: uint8 d_name* {.importc: "d_name".}: array[256, char] diff --git a/src/hexer/nifcgen.nim b/src/hexer/nifcgen.nim index f78760b52..3ea9480dc 100644 --- a/src/hexer/nifcgen.nim +++ b/src/hexer/nifcgen.nim @@ -761,7 +761,7 @@ proc parsePragmas(c: var EContext; n: var Cursor): CollectedPragmas = of NodeclP, SelectanyP, ThreadvarP, GlobalP, DiscardableP, NoReturnP, VarargsP, NoSideEffectP, NoDestroyP, ByCopyP, ByRefP, InlineP, NoinlineP, NoInitP, InjectP, GensymP, UntypedP, ViewP, - InheritableP, PureP, ClosureP, PackedP, UnionP: + InheritableP, PureP, ClosureP, PackedP, UnionP, IncompleteStructP: result.flags.incl pk inc n of BorrowP: diff --git a/src/models/nimony_tags.nim b/src/models/nimony_tags.nim index c5a83f232..da5d071dc 100644 --- a/src/models/nimony_tags.nim +++ b/src/models/nimony_tags.nim @@ -314,6 +314,7 @@ type BuildP = (ord(BuildTagId), "build") ## `build` pragma StringP = (ord(StringTagId), "string") ## `string` pragma ViewP = (ord(ViewTagId), "view") ## `view` pragma + IncompleteStructP = (ord(IncompleteStructTagId), "incompleteStruct") ## `incompleteStruct` pragma InjectP = (ord(InjectTagId), "inject") ## `inject` pragma GensymP = (ord(GensymTagId), "gensym") ## `gensym` pragma ErrorP = (ord(ErrorTagId), "error") ## `error` pragma @@ -336,7 +337,7 @@ type PassCP = (ord(PassCTagId), "passC") ## `passC` pragma adds options to the backend compiler proc rawTagIsNimonyPragma*(raw: TagEnum): bool {.inline.} = - raw in {CursorTagId, EmitTagId, UnionTagId, InlineTagId, NoinlineTagId, ClosureTagId, VarargsTagId, SelectanyTagId, AlignTagId, BitsTagId, NodeclTagId, RaisesTagId, UntypedTagId, MagicTagId, ImportcTagId, ImportcppTagId, DynlibTagId, ExportcTagId, HeaderTagId, ThreadvarTagId, GlobalTagId, DiscardableTagId, NoreturnTagId, BorrowTagId, NoSideEffectTagId, NodestroyTagId, PluginTagId, BycopyTagId, ByrefTagId, NoinitTagId, RequiresTagId, EnsuresTagId, AssumeTagId, AssertTagId, BuildTagId, StringTagId, ViewTagId, InjectTagId, GensymTagId, ErrorTagId, ReportTagId, TagsTagId, DeprecatedTagId, SideEffectTagId, KeepOverflowFlagTagId, SemanticsTagId, InheritableTagId, BaseTagId, PureTagId, FinalTagId, PragmaTagId, PackedTagId, PassiveTagId, PushTagId, PopTagId, PassLTagId, PassCTagId} + raw in {CursorTagId, EmitTagId, UnionTagId, InlineTagId, NoinlineTagId, ClosureTagId, VarargsTagId, SelectanyTagId, AlignTagId, BitsTagId, NodeclTagId, RaisesTagId, UntypedTagId, MagicTagId, ImportcTagId, ImportcppTagId, DynlibTagId, ExportcTagId, HeaderTagId, ThreadvarTagId, GlobalTagId, DiscardableTagId, NoreturnTagId, BorrowTagId, NoSideEffectTagId, NodestroyTagId, PluginTagId, BycopyTagId, ByrefTagId, NoinitTagId, RequiresTagId, EnsuresTagId, AssumeTagId, AssertTagId, BuildTagId, StringTagId, ViewTagId, IncompleteStructTagId, InjectTagId, GensymTagId, ErrorTagId, ReportTagId, TagsTagId, DeprecatedTagId, SideEffectTagId, KeepOverflowFlagTagId, SemanticsTagId, InheritableTagId, BaseTagId, PureTagId, FinalTagId, PragmaTagId, PackedTagId, PassiveTagId, PushTagId, PopTagId, PassLTagId, PassCTagId} type NimonySym* = enum diff --git a/src/models/tags.nim b/src/models/tags.nim index 56bb89282..6f369256a 100644 --- a/src/models/tags.nim +++ b/src/models/tags.nim @@ -225,6 +225,7 @@ type BuildTagId StringTagId ViewTagId + IncompleteStructTagId QuotedTagId HderefTagId DdotTagId @@ -541,95 +542,96 @@ const ("build", 220), ("string", 221), ("view", 222), - ("quoted", 223), - ("hderef", 224), - ("ddot", 225), - ("haddr", 226), - ("newref", 227), - ("newobj", 228), - ("tup", 229), - ("tupconstr", 230), - ("setconstr", 231), - ("tabconstr", 232), - ("ashr", 233), - ("baseobj", 234), - ("hconv", 235), - ("dconv", 236), - ("callstrlit", 237), - ("infix", 238), - ("prefix", 239), - ("hcall", 240), - ("compiles", 241), - ("declared", 242), - ("defined", 243), - ("astToStr", 244), - ("instanceof", 245), - ("proccall", 246), - ("high", 247), - ("low", 248), - ("typeof", 249), - ("unpack", 250), - ("fields", 251), - ("fieldpairs", 252), - ("enumtostr", 253), - ("ismainmodule", 254), - ("defaultobj", 255), - ("defaulttup", 256), - ("defaultdistinct", 257), - ("delay", 258), - ("expr", 259), - ("do", 260), - ("arrat", 261), - ("tupat", 262), - ("plusset", 263), - ("minusset", 264), - ("mulset", 265), - ("xorset", 266), - ("eqset", 267), - ("leset", 268), - ("ltset", 269), - ("inset", 270), - ("card", 271), - ("emove", 272), - ("destroy", 273), - ("dup", 274), - ("copy", 275), - ("wasmoved", 276), - ("sinkh", 277), - ("trace", 278), - ("errv", 279), - ("staticstmt", 280), - ("bind", 281), - ("mixin", 282), - ("using", 283), - ("asm", 284), - ("defer", 285), - ("index", 286), - ("public", 287), - ("private", 288), - ("inject", 289), - ("gensym", 290), - ("error", 291), - ("report", 292), - ("tags", 293), - ("deprecated", 294), - ("sideEffect", 295), - ("keepOverflowFlag", 296), - ("semantics", 297), - ("inheritable", 298), - ("base", 299), - ("pure", 300), - ("final", 301), - ("pragma", 302), - ("internalTypeName", 303), - ("internalFieldPairs", 304), - ("failed", 305), - ("is", 306), - ("envp", 307), - ("packed", 308), - ("passive", 309), - ("push", 310), - ("pop", 311), - ("passL", 312), - ("passC", 313) + ("incompleteStruct", 223), + ("quoted", 224), + ("hderef", 225), + ("ddot", 226), + ("haddr", 227), + ("newref", 228), + ("newobj", 229), + ("tup", 230), + ("tupconstr", 231), + ("setconstr", 232), + ("tabconstr", 233), + ("ashr", 234), + ("baseobj", 235), + ("hconv", 236), + ("dconv", 237), + ("callstrlit", 238), + ("infix", 239), + ("prefix", 240), + ("hcall", 241), + ("compiles", 242), + ("declared", 243), + ("defined", 244), + ("astToStr", 245), + ("instanceof", 246), + ("proccall", 247), + ("high", 248), + ("low", 249), + ("typeof", 250), + ("unpack", 251), + ("fields", 252), + ("fieldpairs", 253), + ("enumtostr", 254), + ("ismainmodule", 255), + ("defaultobj", 256), + ("defaulttup", 257), + ("defaultdistinct", 258), + ("delay", 259), + ("expr", 260), + ("do", 261), + ("arrat", 262), + ("tupat", 263), + ("plusset", 264), + ("minusset", 265), + ("mulset", 266), + ("xorset", 267), + ("eqset", 268), + ("leset", 269), + ("ltset", 270), + ("inset", 271), + ("card", 272), + ("emove", 273), + ("destroy", 274), + ("dup", 275), + ("copy", 276), + ("wasmoved", 277), + ("sinkh", 278), + ("trace", 279), + ("errv", 280), + ("staticstmt", 281), + ("bind", 282), + ("mixin", 283), + ("using", 284), + ("asm", 285), + ("defer", 286), + ("index", 287), + ("public", 288), + ("private", 289), + ("inject", 290), + ("gensym", 291), + ("error", 292), + ("report", 293), + ("tags", 294), + ("deprecated", 295), + ("sideEffect", 296), + ("keepOverflowFlag", 297), + ("semantics", 298), + ("inheritable", 299), + ("base", 300), + ("pure", 301), + ("final", 302), + ("pragma", 303), + ("internalTypeName", 304), + ("internalFieldPairs", 305), + ("failed", 306), + ("is", 307), + ("envp", 308), + ("packed", 309), + ("passive", 310), + ("push", 311), + ("pop", 312), + ("passL", 313), + ("passC", 314) ] diff --git a/src/nimony/sem.nim b/src/nimony/sem.nim index af7e200ad..885e7431f 100644 --- a/src/nimony/sem.nim +++ b/src/nimony/sem.nim @@ -1391,7 +1391,7 @@ proc semPragma(c: var SemContext; n: var Cursor; crucial: var CrucialPragma; kin c.dest.addParRi() of NodeclP, SelectanyP, ThreadvarP, GlobalP, DiscardableP, NoreturnP, BorrowP, NoSideEffectP, NodestroyP, BycopyP, ByrefP, InlineP, NoinlineP, NoinitP, - InjectP, GensymP, UntypedP, SideEffectP, BaseP, ClosureP, PassiveP: + InjectP, GensymP, UntypedP, SideEffectP, BaseP, ClosureP, PassiveP, IncompleteStructP: crucial.flags.incl pk c.dest.add parLeToken(pk, n.info) c.dest.addParRi() From edf6ca967fc76882c683a03ea80baf1d07f09606 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:47:15 +0800 Subject: [PATCH 2/2] fixes #1539; prepareMutationAt: cannot pass prepareMutation(s) to var/out T parameter --- doc/stdlib.dgn.md | 4 ++++ lib/std/system/stringimpl.nim | 4 ++++ src/nimony/derefs.nim | 2 +- tests/nimony/sysbasics/tstrings.nim | 5 +++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/stdlib.dgn.md b/doc/stdlib.dgn.md index 0de46e0f2..99ee992df 100644 --- a/doc/stdlib.dgn.md +++ b/doc/stdlib.dgn.md @@ -327,6 +327,10 @@ Converts a Nim string to a C string. Prepares a string for mutation. String literals are "copy on write", so you need to call `prepareMutation` before modifying strings via `addr`. +####prepareMutationAt + +Prepares the given string for mutation and returns an addressable +reference to the character at index `i`. ####& diff --git a/lib/std/system/stringimpl.nim b/lib/std/system/stringimpl.nim index afa8a48e4..848f22352 100644 --- a/lib/std/system/stringimpl.nim +++ b/lib/std/system/stringimpl.nim @@ -287,6 +287,10 @@ proc prepareMutation*(s: var string) = s.i = EmptyI s.a = a # also do this for `a == nil` +proc prepareMutationAt*(s: var string; i: int): var char {.requires: (i < len(s) and i >= 0), inline.} = + prepareMutation(s) + result = s.a[i] + proc newString*(len: int): string = let a = cast[StrData](alloc(len)) if a != nil: diff --git a/src/nimony/derefs.nim b/src/nimony/derefs.nim index 78ba8774b..536606a10 100644 --- a/src/nimony/derefs.nim +++ b/src/nimony/derefs.nim @@ -383,7 +383,7 @@ proc trProcDecl(c: var Context; n: var Cursor) = takeParRi c, n else: var body = n - trSons c, n, c.r.returnExpects + tr c, n, c.r.returnExpects if c.r.dangerousLocations.len > 0: checkForDangerousLocations c, body takeParRi c, n diff --git a/tests/nimony/sysbasics/tstrings.nim b/tests/nimony/sysbasics/tstrings.nim index d871e048a..57511cccf 100644 --- a/tests/nimony/sysbasics/tstrings.nim +++ b/tests/nimony/sysbasics/tstrings.nim @@ -143,3 +143,8 @@ block: # issue #1444 assert substr("abc", 3, 1) == "" assert substr("abc", 3, 2) == "" assert substr("abc", 3, 3) == "" + +block: + var s = "12234" + var m = prepareMutationAt(s, 1) + assert m == '2'