/*
* Copyright (c) 2008-2022 Jonathan Schleifer <js@nil.im>
*
* All rights reserved.
*
* This file is part of ObjFW. It may be distributed under the terms of the
* Q Public License 1.0, which can be found in the file LICENSE.QPL included in
* the packaging of this file.
*
* Alternatively, it may be distributed under the terms of the GNU General
* Public License, either version 2 or 3, which can be found in the file
* LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
* file.
*/
#include "config.h"
#import "OFArray.h"
#import "OFXMLAttribute.h"
#import "GlueGenerator.h"
#import "OFInvalidFormatException.h"
#import "OFUnsupportedVersionException.h"
#import "copyright.h"
@implementation GlueGenerator
- (instancetype)initWithLibrary: (OFXMLElement *)library
header: (OFStream *)header
implementation: (OFStream *)impl
{
self = [super init];
@try {
OFXMLAttribute *version;
if (![library.name isEqual: @"amiga-library"] ||
library.namespace != nil)
@throw [OFInvalidFormatException exception];
if ((version = [library attributeForName: @"version"]) == nil)
@throw [OFInvalidFormatException exception];
if (![version.stringValue isEqual: @"1.0"])
@throw [OFUnsupportedVersionException
exceptionWithVersion: version.stringValue];
_library = [library retain];
_header = [header retain];
_impl = [impl retain];
} @catch (id e) {
[self release];
@throw e;
}
return self;
}
- (void)dealloc
{
[_library release];
[_header release];
[_impl release];
[super dealloc];
}
- (void)generate
{
[_header writeString: COPYRIGHT];
[_impl writeString: COPYRIGHT];
[_header writeString:
@"/* This file is automatically generated from amiga-library.xml */"
@"\n\n"];
[_impl writeString:
@"/* This file is automatically generated from amiga-library.xml */"
@"\n\n"
@"#include \"config.h\"\n"
@"\n"
@"#import \"amiga-glue.h\"\n"
@"\n"];
for (OFXMLElement *include in [_library elementsForName: @"include"])
[_header writeFormat: @"#import \"%@\"\n", include.stringValue];
[_header writeString:
@"\n"
@"#ifdef OF_AMIGAOS_M68K\n"
@"# define PPC_PARAMS(...) (void)\n"
@"# define M68K_ARG(type, name, reg)\t\t\\\n"
@"\tregister type reg##name __asm__(#reg);\t\\\n"
@"\ttype name = reg##name;\n"
@"#else\n"
@"# define PPC_PARAMS(...) (__VA_ARGS__)\n"
@"# define M68K_ARG(...)\n"
@"#endif\n"
@"\n"];
[_impl writeString:
@"#ifdef OF_MORPHOS\n"
@"/* All __saveds functions in this file need to use the SysV "
@"ABI */\n"
@"__asm__ (\n"
@" \".section .text\\n\"\n"
@" \".align 2\\n\"\n"
@" \"__restore_r13:\\n\"\n"
@" \"\tlwz\t%r13, 44(%r12)\\n\"\n"
@" \"\tblr\\n\"\n"
@");\n"
@"#endif\n"];
for (OFXMLElement *function in
[_library elementsForName: @"function"]) {
OFString *name =
[function attributeForName: @"name"].stringValue;
OFString *returnType =
[function attributeForName: @"return-type"].stringValue;
OFArray OF_GENERIC(OFXMLElement *) *arguments =
[function elementsForName: @"argument"];
size_t argumentIndex;
if (returnType == nil)
returnType = @"void";
[_header writeFormat:
@"extern %@%@glue_%@",
returnType,
(![returnType hasSuffix: @"*"] ? @" " : @""),
name];
[_impl writeFormat: @"\n"
@"%@ __saveds\n"
@"glue_%@",
returnType, name];
if (arguments.count > 0) {
[_header writeString: @" PPC_PARAMS("];
[_impl writeString: @" PPC_PARAMS("];
} else {
[_header writeString: @"(void"];
[_impl writeString: @"(void"];
}
argumentIndex = 0;
for (OFXMLElement *argument in arguments) {
OFString *argName =
[argument attributeForName: @"name"].stringValue;
OFString *argType =
[argument attributeForName: @"type"].stringValue;
if (argumentIndex++ > 0) {
[_header writeString: @", "];
[_impl writeString: @", "];
}
[_header writeString: argType];
[_impl writeString: argType];
if (![argType hasSuffix: @"*"]) {
[_header writeString: @" "];
[_impl writeString: @" "];
}
[_header writeString: argName];
[_impl writeString: argName];
}
[_header writeString: @");\n"];
[_impl writeString: @")\n{\n"];
for (OFXMLElement *argument in arguments) {
OFString *argName =
[argument attributeForName: @"name"].stringValue;
OFString *argType =
[argument attributeForName: @"type"].stringValue;
OFString *m68kReg = [argument
attributeForName: @"m68k-reg"].stringValue;
[_impl writeFormat: @"\tM68K_ARG(%@, %@, %@)\n",
argType, argName, m68kReg];
}
if (arguments.count > 0)
[_impl writeString: @"\n"];
if (![returnType isEqual: @"void"])
[_impl writeString: @"\treturn "];
else
[_impl writeString: @"\t"];
[_impl writeFormat: @"%@(", name];
argumentIndex = 0;
for (OFXMLElement *argument in arguments) {
OFString *argName =
[argument attributeForName: @"name"].stringValue;
if (argumentIndex++ > 0)
[_impl writeString: @", "];
[_impl writeString: argName];
}
[_impl writeString: @");\n}\n"];
}
}
@end