BadScript 2
Loading...
Searching...
No Matches
BadInteropObjectSourceGenerator.cs
Go to the documentation of this file.
1using System.CodeDom.Compiler;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
7using Microsoft.CodeAnalysis;
8
10
11public class BadInteropObjectSourceGenerator
12{
13 private readonly SourceProductionContext m_Context;
14
15 public BadInteropObjectSourceGenerator(SourceProductionContext context)
16 {
17 m_Context = context;
18 }
19
20 private string GenerateConstructor(ObjectModel model)
21 {
22 StringBuilder sb = new StringBuilder();
23 sb.Append($"new {model.ClassName}Wrapper(new {model.ClassName}(");
24 var method = model.Constructor;
25 bool hasCtx = method.Parameters.Any(x => x.IsContext);
26 List<string> args = new List<string>();
27
28 for (int i = 0; i < method.Parameters.Length; i++)
29 {
30 ParameterModel parameter = method.Parameters[i];
31
32 if (parameter.IsContext)
33 {
34 args.Add("ctx");
35 }
36 else
37 {
38 int index = i - (hasCtx ? 1 : 0);
39 string suppressNullable = parameter.IsNullable ? "" : "!";
40
41 if (parameter.IsRestArgs)
42 {
43 if (index == 0)
44 {
45 args.Add($"new BadArray(args.ToList()).Unwrap<{parameter.CsharpType}>()");
46 }
47 else
48 {
49 args.Add($"new BadArray(args.Skip({index}).ToList()).Unwrap<{parameter.CsharpType}>()");
50 }
51 }
52 else if (parameter.HasDefaultValue)
53 {
54 args.Add($"GetParameter<{parameter.CsharpType}>(args, {index}, {parameter.DefaultValue ?? $"default({parameter.CsharpType})"}){suppressNullable}"
55 );
56 }
57 else
58 {
59 args.Add($"GetParameter<{parameter.CsharpType}>(args, {index}){suppressNullable}");
60 }
61 }
62 }
63
64 sb.Append(string.Join(", ", args));
65 sb.Append("))");
66
67 return sb.ToString();
68 }
69 private string GenerateInvocation(MethodModel method, string className)
70 {
71 StringBuilder sb = new StringBuilder();
72
73 if (method.IsVoidReturn)
74 {
75 sb.Append("{");
76 }
77 else
78 {
79 sb.Append("BadObject.Wrap(");
80 }
81
82 sb.Append($"(({className})Value).{method.MethodName}(");
83 bool hasCtx = method.Parameters.Any(x => x.IsContext);
84 List<string> args = new List<string>();
85
86 for (int i = 0; i < method.Parameters.Length; i++)
87 {
88 ParameterModel parameter = method.Parameters[i];
89
90 if (parameter.IsContext)
91 {
92 args.Add("ctx");
93 }
94 else
95 {
96 int index = i - (hasCtx ? 1 : 0);
97 string suppressNullable = parameter.IsNullable ? "" : "!";
98
99 if (parameter.IsRestArgs)
100 {
101 if (index == 0)
102 {
103 args.Add($"new BadArray(args.ToList()).Unwrap<{parameter.CsharpType}>()");
104 }
105 else
106 {
107 args.Add($"new BadArray(args.Skip({index}).ToList()).Unwrap<{parameter.CsharpType}>()");
108 }
109 }
110 else if (parameter.HasDefaultValue)
111 {
112 args.Add($"GetParameter<{parameter.CsharpType}>(args, {index}, {parameter.DefaultValue ?? $"default({parameter.CsharpType})"}){suppressNullable}"
113 );
114 }
115 else
116 {
117 args.Add($"GetParameter<{parameter.CsharpType}>(args, {index}){suppressNullable}");
118 }
119 }
120 }
121
122 sb.Append(string.Join(", ", args));
123 sb.Append(")");
124
125 if (method.IsVoidReturn)
126 {
127 sb.Append("; return BadObject.Null; }");
128 }
129 else
130 {
131 sb.Append($", {method.AllowNativeReturn.ToString().ToLower()})");
132 }
133
134 return sb.ToString();
135 }
136
137 private string GenerateParameterSource(ParameterModel model)
138 {
139 return
140 $"new BadFunctionParameter(\"{model.Name}\", {model.HasDefaultValue.ToString().ToLower()}, {(!model.IsNullable).ToString().ToLower()}, {model.IsRestArgs.ToString().ToLower()}, null, BadNativeClassBuilder.GetNative(\"{model.Type}\"))";
141 }
142
143 private void GeneratePropertySource(IndentedTextWriter sb, PropertyModel model, string className)
144 {
145 if(model.IsReadOnly)
146 {
147 sb.WriteLine($"Properties[\"{model.ApiParameterName}\"] = BadObjectReference.Make(\"{model.ApiParameterName}\", p => Wrap((({className})Value).{model.ParameterName}));");
148 }
149 else
150 {
151 sb.WriteLine($"Properties[\"{model.ApiParameterName}\"] = ");
152 sb.Indent++;
153 sb.WriteLine($"BadObjectReference.Make(\"{model.ApiParameterName}\",");
154 sb.Indent++;
155 sb.WriteLine($"p => Wrap((({className})Value).{model.ParameterName}),");
156 sb.WriteLine($"(v, p, i) => (({className})Value).{model.ParameterName} = v.Unwrap<{model.ParameterType}>()");
157 sb.Indent--;
158 sb.WriteLine(");");
159 sb.Indent--;
160 }
161 }
162 private void GenerateMethodSource(IndentedTextWriter sb, MethodModel method, string className)
163 {
164 sb.WriteLine($"Properties[\"{method.ApiMethodName}\"] = ");
165 sb.Indent++;
166 sb.WriteLine($"BadObjectReference.Make(\"{method.ApiMethodName}\",");
167 sb.Indent++;
168 sb.WriteLine($"p => new BadInteropFunction(");
169 sb.Indent++;
170 sb.WriteLine($"\"{method.ApiMethodName}\",");
171 sb.WriteLine($"(ctx, args) => {GenerateInvocation(method, className)},");
172 sb.WriteLine("false,");
173 sb.Write($"BadNativeClassBuilder.GetNative(\"{method.ReturnType}\")");
174
175 if (method.Parameters.Any(x => !x.IsContext))
176 {
177 sb.WriteLine(",");
178 }
179 else
180 {
181 sb.WriteLine();
182 }
183
184 for (int i = 0; i < method.Parameters.Length; i++)
185 {
186 ParameterModel parameter = method.Parameters[i];
187
188 if (parameter.IsContext)
189 {
190 continue;
191 }
192
193 sb.WriteLine(GenerateParameterSource(parameter) + (i == method.Parameters.Length - 1 ? "" : ","));
194 }
195
196 sb.Indent--;
197 sb.WriteLine(").SetMetaData(");
198 sb.Indent++;
199 sb.WriteLine("new BadMetaData(");
200 sb.Indent++;
201 sb.WriteLine($"\"{method.Description}\",");
202 sb.WriteLine($"\"{method.ReturnDescription}\",");
203 sb.WriteLine($"\"{method.ReturnType}\",");
204 sb.WriteLine("new Dictionary<string, BadParameterMetaData>");
205 sb.WriteLine("{");
206 sb.Indent++;
207
208 foreach (ParameterModel parameter in method.Parameters)
209 {
210 if (parameter.IsContext)
211 {
212 continue;
213 }
214
215 if (parameter.HasDefaultValue)
216 {
217 sb.WriteLine($"{{\"{parameter.Name}\", new BadParameterMetaData(\"{parameter.Type}\", \"{parameter.Description}\\nDefault Value: {parameter.DefaultValue!.Replace("\"", "\\\"")}\")}},"
218 );
219 }
220 else
221 {
222 sb.WriteLine($"{{\"{parameter.Name}\", new BadParameterMetaData(\"{parameter.Type}\", \"{parameter.Description}\")}},"
223 );
224 }
225 }
226
227 sb.Indent--;
228 sb.WriteLine("}");
229 sb.Indent--;
230 sb.WriteLine(")");
231 sb.Indent--;
232 sb.WriteLine(")");
233 sb.Indent--;
234 sb.WriteLine(");");
235 sb.Indent--;
236 }
237
238 public string GenerateModelSource(SourceProductionContext context, ObjectModel apiModel, bool isError)
239 {
240 IndentedTextWriter tw = new IndentedTextWriter(new StringWriter());
241 tw.WriteLine("#nullable enable");
242 tw.WriteLine("using System.Collections.Generic;");
243 tw.WriteLine("using BadScript2.Parser;");
244 tw.WriteLine("using BadScript2.Runtime.Interop.Reflection;");
245 tw.WriteLine("using BadScript2.Runtime.Objects;");
246 tw.WriteLine("using BadScript2.Runtime.Interop.Functions;");
247 tw.WriteLine("using BadScript2.Runtime.Objects.Functions;");
248 tw.WriteLine("using BadScript2.Runtime.Objects.Types;");
249 tw.WriteLine("using BadScript2.Runtime.Interop;");
250 tw.WriteLine();
251 tw.WriteLine($"namespace {apiModel.Namespace};");
252 tw.WriteLine($"public partial class {apiModel.ClassName}Wrapper : {(string.IsNullOrEmpty(apiModel.BaseClassName) ? $"BadScript2.Runtime.Objects.Native.BadNative<{apiModel.ClassName}>": apiModel.BaseClassName)}");
253 tw.WriteLine("{");
254 tw.Indent++;
255
256 tw.WriteLine("private static BadClassPrototype? s_Prototype;");
257 tw.WriteLine("private static BadClassPrototype CreatePrototype()");
258 tw.WriteLine("{");
259 tw.Indent++;
260 tw.WriteLine("T? GetParameter<T>(BadObject[] args, int i, T? defaultValue = default(T)) => args.Length>i?args[i].Unwrap<T>():defaultValue;");
261 tw.WriteLine($"return new BadNativeClassPrototype<{apiModel.ClassName}Wrapper>(\"{apiModel.ObjectName}\", (ctx, args) => {GenerateConstructor(apiModel)}, {(string.IsNullOrEmpty(apiModel.BaseClassName) ? "null" : $"{apiModel.BaseClassName}.Prototype")});");
262 tw.Indent--;
263 tw.WriteLine("}");
264 tw.WriteLine("public static BadClassPrototype Prototype => s_Prototype ??= CreatePrototype();");
265
266 if(string.IsNullOrEmpty(apiModel.BaseClassName))
267 {
268 tw.WriteLine("protected readonly Dictionary<string, BadObjectReference> Properties = new Dictionary<string, BadObjectReference>();");
269 tw.WriteLine();
270 }
271 tw.WriteLine($"public {apiModel.ClassName}Wrapper({apiModel.ClassName} value) : base(value)");
272 tw.WriteLine("{");
273 tw.Indent++;
274 if (!isError)
275 {
276 tw.WriteLine("T? GetParameter<T>(BadObject[] args, int i, T? defaultValue = default(T)) => args.Length>i?args[i].Unwrap<T>():defaultValue;"
277 );
278
279 foreach (PropertyModel method in apiModel.Properties)
280 {
281 GeneratePropertySource(tw, method, apiModel.ClassName);
282 }
283 foreach (MethodModel method in apiModel.Methods)
284 {
285 GenerateMethodSource(tw, method, apiModel.ClassName);
286 }
287 }
288
289 tw.Indent--;
290 tw.WriteLine("}");
291
292 tw.WriteLine("public override bool HasProperty(string propName, BadScript2.Runtime.BadScope? caller = null)");
293 tw.WriteLine("{");
294 tw.Indent++;
295 tw.WriteLine("return Properties.ContainsKey(propName) || base.HasProperty(propName, caller);");
296 tw.Indent--;
297 tw.WriteLine("}");
298
299 tw.WriteLine("public override BadObjectReference GetProperty(string propName, BadScript2.Runtime.BadScope? caller = null)");
300 tw.WriteLine("{");
301 tw.Indent++;
302 tw.WriteLine("if(Properties.TryGetValue(propName, out BadObjectReference? ret))");
303 tw.WriteLine("{");
304 tw.Indent++;
305 tw.WriteLine("return ret;");
306 tw.Indent--;
307 tw.WriteLine("}");
308 tw.WriteLine("return base.GetProperty(propName, caller);");
309 tw.Indent--;
310 tw.WriteLine("}");
311
312
313 tw.WriteLine("public override BadClassPrototype GetPrototype() => Prototype;");
314 tw.WriteLine($"public static implicit operator {apiModel.ClassName}Wrapper({apiModel.ClassName} obj) => new {apiModel.ClassName}Wrapper(obj);");
315 tw.WriteLine($"public static implicit operator {apiModel.ClassName}({apiModel.ClassName}Wrapper obj) => ({apiModel.ClassName})obj.Value;");
316
317 tw.Indent--;
318 tw.WriteLine("}");
319
320 tw.Flush();
321
322 string str = tw.InnerWriter.ToString();
323
324 return str;
325 }
326}
Contains the Native Runtime Objects.
Definition BadBoolean.cs:6
Contains the Runtime Objects.
Definition BadArray.cs:10
Contains the Runtime Implementation.
The main namespace for the BadScript2 Language.
Definition BadConsole.cs:6