@@ -62,19 +62,25 @@ moduleForDeftype innerEnv typeEnv env pathStrings typeName typeVariables rest i
6262 -- For example (module Vec2 [x Float]) creates bindings like Vec2.create, Vec2.x, etc.
6363 insidePath = pathStrings ++ [typeName]
6464 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
6571 in do
66- mems <- case rest of
72+ mems <- case initmembers of
6773 [XObj (Arr membersXObjs) _ _] -> Right membersXObjs
6874 _ -> Left $ NotAValidType (XObj (Sym (SymPath pathStrings typeName) Symbol ) i (Just TypeTy ))
6975 let structTy = StructTy (ConcreteNameTy (SymPath pathStrings typeName)) typeVariables
70- ptrmembers = map (recursiveMembersToPointers structTy) rest
76+ ptrmembers = map (recursiveMembersToPointers structTy) initmembers
7177 innermems <- case ptrmembers of
7278 [XObj (Arr membersXObjs) _ _] -> Right membersXObjs
7379 _ -> Left $ NotAValidType (XObj (Sym (SymPath pathStrings typeName) Symbol ) i (Just TypeTy ))
7480 okRecursive (candidate {typemembers = mems})
7581 validateMembers typeEnv env (candidate {typemembers = innermems})
7682 (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
7884 okMake <- recursiveProductMakeBinder insidePath structTy ptrmembers
7985 (okStr, strDeps) <- binderForStrOrPrn typeEnv env insidePath structTy ptrmembers " str"
8086 (okPrn, _) <- binderForStrOrPrn typeEnv env insidePath structTy ptrmembers" prn"
@@ -359,16 +365,22 @@ templateUpdater member _ =
359365
360366-- | Helper function to create the binder for the 'init' template.
361367binderForInit :: [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 ++ " `." )
372384binderForInit _ _ _ = error " binderforinit"
373385
374386-- | Generate a list of types from a deftype declaration.
@@ -385,7 +397,7 @@ concreteInit allocationMode originalStructTy@(StructTy (ConcreteNameTy _) _) mem
385397 let mappings = unifySignatures originalStructTy concreteStructTy
386398 correctedMembers = replaceGenericTypeSymbolsOnMembers mappings membersXObjs
387399 memberPairs = memberXObjsToPairs correctedMembers
388- in (toTemplate $ " $p $NAME(" ++ joinWithComma (map memberArg (unitless memberPairs)) ++ " )" )
400+ in (toTemplate $ " $p $NAME(" ++ joinWithComma (map memberArg (nodummy ( unitless memberPairs) )) ++ " )" )
389401 )
390402 ( \ (FuncTy _ concreteStructTy _) ->
391403 let mappings = unifySignatures originalStructTy concreteStructTy
@@ -395,6 +407,9 @@ concreteInit allocationMode originalStructTy@(StructTy (ConcreteNameTy _) _) mem
395407 (\ FuncTy {} -> [] )
396408 where
397409 unitless = remove (isUnit . snd )
410+ nodummy = remove (isDummy . fst )
411+ isDummy " __dummy" = True
412+ isDummy _ = False
398413concreteInit _ _ _ = error " concreteinit"
399414
400415-- | The template for the 'init' and 'new' functions for a generic deftype.
@@ -403,7 +418,7 @@ genericInit allocationMode pathStrings originalStructTy@(StructTy (ConcreteNameT
403418 defineTypeParameterizedTemplate templateCreator path t docs
404419 where
405420 path = SymPath pathStrings " init"
406- t = FuncTy (map snd (memberXObjsToPairs membersXObjs)) originalStructTy StaticLifetimeTy
421+ t = FuncTy (map snd (nodummy ( memberXObjsToPairs membersXObjs) )) originalStructTy StaticLifetimeTy
407422 docs = " creates a `" ++ show originalStructTy ++ " `."
408423 templateCreator = TemplateCreator $
409424 \ typeEnv env ->
@@ -413,7 +428,7 @@ genericInit allocationMode pathStrings originalStructTy@(StructTy (ConcreteNameT
413428 let mappings = unifySignatures originalStructTy concreteStructTy
414429 correctedMembers = replaceGenericTypeSymbolsOnMembers mappings membersXObjs
415430 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) )) ++ " )" )
417432 )
418433 ( \ (FuncTy _ concreteStructTy _) ->
419434 let mappings = unifySignatures originalStructTy concreteStructTy
@@ -425,6 +440,9 @@ genericInit allocationMode pathStrings originalStructTy@(StructTy (ConcreteNameT
425440 Left _ -> []
426441 Right ok -> ok
427442 )
443+ nodummy = remove (isDummy . fst )
444+ isDummy " __dummy" = True
445+ isDummy _ = False
428446genericInit _ _ _ _ = error " genericinit"
429447
430448tokensForInit :: AllocationMode -> String -> [XObj ] -> [Token ]
@@ -445,7 +463,7 @@ tokensForInit allocationMode typeName membersXObjs =
445463 " }"
446464 ]
447465 where
448- assignments [] = " instance.__dummy = 0; "
466+ assignments [] = " "
449467 assignments _ = go unitless
450468 where
451469 go [] = " "
@@ -562,9 +580,13 @@ calculateStructStrSize typeEnv env members s@(StructTy (ConcreteNameTy _) _) =
562580calculateStructStrSize _ _ _ _ = error " calculatestructstrsize"
563581
564582-- | 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.
566585memberAssignment :: 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 ++ " ;"
568590 where
569591 sep = case allocationMode of
570592 StackAlloc -> " ."
0 commit comments