@@ -62,19 +62,25 @@ moduleForDeftype innerEnv typeEnv env pathStrings typeName typeVariables rest i
62
62
-- For example (module Vec2 [x Float]) creates bindings like Vec2.create, Vec2.x, etc.
63
63
insidePath = pathStrings ++ [typeName]
64
64
candidate = TypeCandidate {restriction = AllowOnlyNamesInScope , typename = typeName, variables = typeVariables, typemembers = [] , interfaceConstraints = [] , candidateTypeEnv = typeEnv, candidateEnv = env}
65
+ initmembers = case rest of
66
+ -- ANSI C does not allow empty structs. We add a dummy member here to account for this.
67
+ -- Note that we *don't* add this member for external types--we leave those definitions up to the user.
68
+ -- The corresponding field is emitted for the struct definition in Emit.hs
69
+ [(XObj (Arr [] ) ii t)] -> [(XObj (Arr [(XObj (Sym (SymPath [] " __dummy" ) Symbol ) Nothing Nothing ), (XObj (Sym (SymPath [] " Char" ) Symbol ) Nothing Nothing )]) ii t)]
70
+ _ -> rest
65
71
in do
66
- mems <- case rest of
72
+ mems <- case initmembers of
67
73
[XObj (Arr membersXObjs) _ _] -> Right membersXObjs
68
74
_ -> Left $ NotAValidType (XObj (Sym (SymPath pathStrings typeName) Symbol ) i (Just TypeTy ))
69
75
let structTy = StructTy (ConcreteNameTy (SymPath pathStrings typeName)) typeVariables
70
- ptrmembers = map (recursiveMembersToPointers structTy) rest
76
+ ptrmembers = map (recursiveMembersToPointers structTy) initmembers
71
77
innermems <- case ptrmembers of
72
78
[XObj (Arr membersXObjs) _ _] -> Right membersXObjs
73
79
_ -> Left $ NotAValidType (XObj (Sym (SymPath pathStrings typeName) Symbol ) i (Just TypeTy ))
74
80
okRecursive (candidate {typemembers = mems})
75
81
validateMembers typeEnv env (candidate {typemembers = innermems})
76
82
(okMembers, membersDeps) <- templatesForMembers typeEnv env insidePath structTy ptrmembers
77
- okInit <- if (any (isValueRecursive structTy) ptrmembers) then recursiveProductInitBinder insidePath structTy ptrmembers else binderForInit insidePath structTy ptrmembers
83
+ okInit <- if (any (isValueRecursive structTy) ptrmembers) then recursiveProductInitBinder insidePath structTy ptrmembers else binderForInit insidePath structTy initmembers
78
84
okMake <- recursiveProductMakeBinder insidePath structTy ptrmembers
79
85
(okStr, strDeps) <- binderForStrOrPrn typeEnv env insidePath structTy ptrmembers " str"
80
86
(okPrn, _) <- binderForStrOrPrn typeEnv env insidePath structTy ptrmembers" prn"
@@ -359,16 +365,22 @@ templateUpdater member _ =
359
365
360
366
-- | Helper function to create the binder for the 'init' template.
361
367
binderForInit :: [String ] -> Ty -> [XObj ] -> Either TypeError (String , Binder )
362
- binderForInit insidePath structTy@ (StructTy (ConcreteNameTy _) _) [(XObj (Arr membersXObjs) _ _)] =
363
- if isTypeGeneric structTy
364
- then Right (genericInit StackAlloc insidePath structTy membersXObjs)
365
- else
366
- Right $
367
- instanceBinder
368
- (SymPath insidePath " init" )
369
- (FuncTy (initArgListTypes membersXObjs) structTy StaticLifetimeTy )
370
- (concreteInit StackAlloc structTy membersXObjs)
371
- (" creates a `" ++ show structTy ++ " `." )
368
+ binderForInit insidePath structTy@ (StructTy (ConcreteNameTy _) _) [XObj (Arr membersXObjs) _ _] =
369
+ -- Remove the __dummy field from the members array to ensure we can call the initializer with no arguments.
370
+ -- See the implementation of moduleForDeftype for more details.
371
+ let nodummy = case membersXObjs of
372
+ [(XObj (Sym (SymPath [] " __dummy" ) Symbol ) Nothing Nothing ), (XObj (Sym (SymPath [] " Char" ) Symbol ) Nothing Nothing )] -> []
373
+ _ -> membersXObjs
374
+ in if isTypeGeneric structTy
375
+ then Right (genericInit StackAlloc insidePath structTy membersXObjs)
376
+ else
377
+ Right $
378
+ instanceBinder
379
+ (SymPath insidePath " init" )
380
+ -- don't include the dummy field in arg lists
381
+ (FuncTy (initArgListTypes nodummy) structTy StaticLifetimeTy )
382
+ (concreteInit StackAlloc structTy membersXObjs)
383
+ (" creates a `" ++ show structTy ++ " `." )
372
384
binderForInit _ _ _ = error " binderforinit"
373
385
374
386
-- | Generate a list of types from a deftype declaration.
@@ -385,7 +397,7 @@ concreteInit allocationMode originalStructTy@(StructTy (ConcreteNameTy _) _) mem
385
397
let mappings = unifySignatures originalStructTy concreteStructTy
386
398
correctedMembers = replaceGenericTypeSymbolsOnMembers mappings membersXObjs
387
399
memberPairs = memberXObjsToPairs correctedMembers
388
- in (toTemplate $ " $p $NAME(" ++ joinWithComma (map memberArg (unitless memberPairs)) ++ " )" )
400
+ in (toTemplate $ " $p $NAME(" ++ joinWithComma (map memberArg (nodummy ( unitless memberPairs) )) ++ " )" )
389
401
)
390
402
( \ (FuncTy _ concreteStructTy _) ->
391
403
let mappings = unifySignatures originalStructTy concreteStructTy
@@ -395,6 +407,9 @@ concreteInit allocationMode originalStructTy@(StructTy (ConcreteNameTy _) _) mem
395
407
(\ FuncTy {} -> [] )
396
408
where
397
409
unitless = remove (isUnit . snd )
410
+ nodummy = remove (isDummy . fst )
411
+ isDummy " __dummy" = True
412
+ isDummy _ = False
398
413
concreteInit _ _ _ = error " concreteinit"
399
414
400
415
-- | The template for the 'init' and 'new' functions for a generic deftype.
@@ -403,7 +418,7 @@ genericInit allocationMode pathStrings originalStructTy@(StructTy (ConcreteNameT
403
418
defineTypeParameterizedTemplate templateCreator path t docs
404
419
where
405
420
path = SymPath pathStrings " init"
406
- t = FuncTy (map snd (memberXObjsToPairs membersXObjs)) originalStructTy StaticLifetimeTy
421
+ t = FuncTy (map snd (nodummy ( memberXObjsToPairs membersXObjs) )) originalStructTy StaticLifetimeTy
407
422
docs = " creates a `" ++ show originalStructTy ++ " `."
408
423
templateCreator = TemplateCreator $
409
424
\ typeEnv env ->
@@ -413,7 +428,7 @@ genericInit allocationMode pathStrings originalStructTy@(StructTy (ConcreteNameT
413
428
let mappings = unifySignatures originalStructTy concreteStructTy
414
429
correctedMembers = replaceGenericTypeSymbolsOnMembers mappings membersXObjs
415
430
memberPairs = memberXObjsToPairs correctedMembers
416
- in (toTemplate $ " $p $NAME(" ++ joinWithComma (map memberArg (remove (isUnit . snd ) memberPairs)) ++ " )" )
431
+ in (toTemplate $ " $p $NAME(" ++ joinWithComma (map memberArg (nodummy ( remove (isUnit . snd ) memberPairs) )) ++ " )" )
417
432
)
418
433
( \ (FuncTy _ concreteStructTy _) ->
419
434
let mappings = unifySignatures originalStructTy concreteStructTy
@@ -425,6 +440,9 @@ genericInit allocationMode pathStrings originalStructTy@(StructTy (ConcreteNameT
425
440
Left _ -> []
426
441
Right ok -> ok
427
442
)
443
+ nodummy = remove (isDummy . fst )
444
+ isDummy " __dummy" = True
445
+ isDummy _ = False
428
446
genericInit _ _ _ _ = error " genericinit"
429
447
430
448
tokensForInit :: AllocationMode -> String -> [XObj ] -> [Token ]
@@ -445,7 +463,7 @@ tokensForInit allocationMode typeName membersXObjs =
445
463
" }"
446
464
]
447
465
where
448
- assignments [] = " instance.__dummy = 0; "
466
+ assignments [] = " "
449
467
assignments _ = go unitless
450
468
where
451
469
go [] = " "
@@ -562,9 +580,13 @@ calculateStructStrSize typeEnv env members s@(StructTy (ConcreteNameTy _) _) =
562
580
calculateStructStrSize _ _ _ _ = error " calculatestructstrsize"
563
581
564
582
-- | Generate C code for assigning to a member variable.
565
- -- | Needs to know if the instance is a pointer or stack variable.
583
+ -- Needs to know if the instance is a pointer or stack variable.
584
+ -- Also handles the special dummy member we add for empty structs to be ANSI C compatible.
566
585
memberAssignment :: AllocationMode -> String -> String
567
- memberAssignment allocationMode memberName = " instance" ++ sep ++ memberName ++ " = " ++ memberName ++ " ;"
586
+ memberAssignment allocationMode memberName =
587
+ case memberName of
588
+ " __dummy" -> " instance" ++ sep ++ memberName ++ " = " ++ " 0" ++ " ;"
589
+ _ -> " instance" ++ sep ++ memberName ++ " = " ++ memberName ++ " ;"
568
590
where
569
591
sep = case allocationMode of
570
592
StackAlloc -> " ."
0 commit comments