MLLIF
a MLIR-based Language to Language Interoperability Flyover
Loading...
Searching...
No Matches
CsBridgeGen.cxx
Go to the documentation of this file.
1/*
2 * Copyright 2025 Yeong-won Seo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
20
21namespace mllif {
22 auto Indent(size_t size) -> std::string {
23 std::string indent(size * 4, ' ');
24 return indent;
25 }
26} // namespace mllif
27
28namespace mllif::cs {
29 CsBridgeGen::CsBridgeGen(const std::string &libname) : LibraryName(libname) {
30 }
31
32 bool CsBridgeGen::handleAssemblyBegin(MLLIFContext &context, const AssemblyDecl &node, std::ostream &out, std::size_t indent) {
33 return true;
34 }
35 bool CsBridgeGen::handleAssemblyEnd(MLLIFContext &context, const AssemblyDecl &node, std::ostream &out, std::size_t indent) {
36 return true;
37 }
38 bool CsBridgeGen::handleNamespaceBegin(MLLIFContext &context, const NamespaceDecl &node, std::ostream &out, std::size_t indent) {
39 out << Indent(indent) << "namespace " << node.name() << " {\n";
40 return true;
41 }
42 bool CsBridgeGen::handleNamespaceEnd(MLLIFContext &context, const NamespaceDecl &node, std::ostream &out, std::size_t indent) {
43 out << Indent(indent) << "} // namespace " << node.name() << '\n';
44 return true;
45 }
46 bool CsBridgeGen::handleObjectBegin(MLLIFContext &context, const ObjectDecl &node, std::ostream &out, std::size_t indent) {
47 out << Indent(indent) << "[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit, Size=" << node.size() << ", Pack=" << node.align() << ")]\n"
48 << Indent(indent) << "public struct " << node.name() << " {\n";
49 return true;
50 }
51 bool CsBridgeGen::handleObjectEnd(MLLIFContext &context, const ObjectDecl &node, std::ostream &out, std::size_t indent) {
52 out << Indent(indent) << "}\n";
53 return true;
54 }
55
56 bool createFunctionStub(CsBridgeGen &gen, MLLIFContext &context, const FunctionDecl &node, std::ostream &out, const std::size_t indent) {
57
58 const auto isMemberFn = std::dynamic_pointer_cast<ObjectDecl>(node.parent()) != nullptr;
59
60 out << Indent(indent);
61
62 if (isMemberFn) {
63 // BEGIN fixed STATEMENT
64 out << "fixed (void* __self = &this) { ";
65 }
66
67 if (const auto ret = node.returns(); !(ret.builtin() && ret.terms()[0] == "void")) {
68 out << "return ";
69 }
70
71 out << "__stub("; // BEGIN STUB ARGUMENTS
72
73 if (isMemberFn) {
74 out << "__self, ";
75 }
76
77 for (auto i = 0; i < node.children().size(); i++) {
78 if (i != 0) {
79 out << ", ";
80 }
81
82 out << node.children()[i]->name();
83 }
84
85 auto ret = TypeToCs(node.returns());
86 if (!ret) {
87 context.error(std::format("unrecognized return type of function '{}'", node.symbol()));
88 return false;
89 }
90
91 out << ");\n"; // END STUB ARGUMENTS
92
93 if (isMemberFn) {
94 // END fixed STATEMENT
95 out << " }\n";
96 }
97
98 out << Indent(indent) << "[System.Runtime.InteropServices.DllImport(\"" << gen.LibraryName << "\", EntryPoint=\"" << node.symbol() << "\", ExactSpelling=true)]\n"
99 << Indent(indent) << "static extern " << ret.value() << " __stub(";
100
101 if (isMemberFn) {
102 out << "void* __self, ";
103 }
104
105 for (auto i = 0; i < node.children().size(); i++) {
106 if (i != 0) {
107 gen.writeParamDelimiter(out);
108 }
109
110 gen.handleParam(context, *std::dynamic_pointer_cast<ParamDecl>(node.children()[i]), out, indent);
111 }
112
113 out << ");\n";
114
115 return true;
116 }
117
118 static bool IsUnsafe(const FunctionDecl &node) {
119 if (node.returns().refs())
120 return true;
121
122 for (const auto &item : node.children()) {
123 if (auto arg = std::dynamic_pointer_cast<ParamDecl>(item);
124 arg && arg->type().refs()) {
125 return true;
126 }
127 }
128
129 return false;
130 }
131
132 bool CsBridgeGen::handleFunctionBegin(MLLIFContext &context, const FunctionDecl &node, std::ostream &out, std::size_t indent) {
133 const auto ret = TypeToCs(node.returns());
134 if (!ret) {
135 context.error(std::format("unrecognized return type of function '{}'", node.symbol()));
136 return false;
137 }
138
139 if (!std::dynamic_pointer_cast<ObjectDecl>(node.parent())) {
140 context.error(std::format("C# doesn't allow out-of-class functions ({})", node.symbol()));
141 return false;
142 }
143
144 out << Indent(indent) << "public static ";
145 if (IsUnsafe(node)) {
146 out << "unsafe ";
147 }
148 out << ret.value() << ' ' << node.name() << '(';
149
150 return true;
151 }
152 bool CsBridgeGen::handleFunctionEnd(MLLIFContext &context, const FunctionDecl &node, std::ostream &out, std::size_t indent) {
153 out << ") {\n";
154 out << Indent(indent + 1) << "unsafe {\n";
155 createFunctionStub(*this, context, node, out, indent + 2);
156 out << Indent(indent + 1) << "}\n";
157 out << Indent(indent) << "}\n";
158 return true;
159 }
160 bool CsBridgeGen::handleMethodBegin(MLLIFContext &context, const MethodDecl &node, std::ostream &out, std::size_t indent) {
161 const auto ret = TypeToCs(node.returns());
162 if (!ret) {
163 context.error(std::format("unrecognized builtin type '{}'", node.returns().terms()[0]));
164 return false;
165 }
166
167 out << Indent(indent) << "public ";
168 if (IsUnsafe(node)) {
169 out << "unsafe ";
170 }
171 out << ret.value() << ' ' << node.name() << '(';
172 return true;
173 }
174 bool CsBridgeGen::handleParam(MLLIFContext &context, const ParamDecl &node, std::ostream &out, std::size_t indent) {
175 const auto type = TypeToCs(node.type());
176 if (!type) {
177 context.error(std::format("unrecognized builtin type '{}'", node.type().terms()[0]));
178 return false;
179 }
180
181 out << type.value() << ' ' << node.name();
182 return true;
183 }
184 void CsBridgeGen::writeParamDelimiter(std::ostream &os) {
185 os << ", ";
186 }
187} // namespace mllif::cs
const std::shared_ptr< Decl > & parent() const
Definition Decl.h:51
const std::vector< std::shared_ptr< Decl > > & children() const
Definition Decl.h:50
const std::string & name() const
Definition Decl.h:49
const Type & returns() const
Definition Decl.h:84
const std::string & symbol() const
Definition Decl.h:85
void error(const std::string &what)
Definition Context.h:35
const std::string & align() const
Definition Decl.h:74
const std::string & size() const
Definition Decl.h:73
const Type & type() const
Definition Decl.h:99
std::size_t refs() const
Definition Decl.h:36
const std::vector< std::string > & terms() const
Definition Decl.h:35
bool handleFunctionBegin(MLLIFContext &context, const FunctionDecl &node, std::ostream &out, std::size_t indent) override
std::string LibraryName
Definition CsBridgeGen.h:24
bool handleMethodBegin(MLLIFContext &context, const MethodDecl &node, std::ostream &out, std::size_t indent) override
void writeParamDelimiter(std::ostream &os) override
bool handleObjectBegin(MLLIFContext &context, const ObjectDecl &node, std::ostream &out, std::size_t indent) override
bool handleNamespaceEnd(MLLIFContext &context, const NamespaceDecl &node, std::ostream &out, std::size_t indent) override
bool handleNamespaceBegin(MLLIFContext &context, const NamespaceDecl &node, std::ostream &out, std::size_t indent) override
bool handleAssemblyEnd(MLLIFContext &context, const AssemblyDecl &node, std::ostream &out, std::size_t indent) override
bool handleFunctionEnd(MLLIFContext &context, const FunctionDecl &node, std::ostream &out, std::size_t indent) override
bool handleAssemblyBegin(MLLIFContext &context, const AssemblyDecl &node, std::ostream &out, std::size_t indent) override
bool handleParam(MLLIFContext &context, const ParamDecl &node, std::ostream &out, std::size_t indent) override
bool handleObjectEnd(MLLIFContext &context, const ObjectDecl &node, std::ostream &out, std::size_t indent) override
CsBridgeGen(const std::string &libname)
bool createFunctionStub(CsBridgeGen &gen, MLLIFContext &context, const FunctionDecl &node, std::ostream &out, const std::size_t indent)
std::optional< std::string > TypeToCs(const Type &type)
Gets C#-compliant typename of type.
Definition Type.cxx:19
auto Indent(size_t size) -> std::string