Skip to content

Commit

Permalink
Replaced auto binding functions with compile time instance calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Rohansi committed Feb 6, 2025
1 parent 63b2219 commit 30b61aa
Show file tree
Hide file tree
Showing 21 changed files with 188 additions and 255 deletions.
37 changes: 19 additions & 18 deletions Mond.SourceGenerator/MondSourceGenerator.Class.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,11 @@ private static void ClassBindings(GeneratorExecutionContext context, INamedTypeS
{
if (property.GetMethod is { DeclaredAccessibility: Accessibility.Public })
{
writer.WriteLine($"public static MondValue {name}__Getter(MondState state, MondValue instance, params MondValue[] args)");
writer.WriteLine($"public static MondValue {name}__Getter(MondState state, params MondValue[] args)");
writer.OpenBracket();

Prologue($"get{name}");

writer.WriteLine("if (args.Length != 0)");
writer.OpenBracket();
writer.WriteLine($"throw new MondRuntimeException(\"{className}.get{name}: expected 0 arguments\");");
writer.CloseBracket();

writer.WriteLine($"var value = obj.{property.Name};");
writer.WriteLine($"return {ConvertToMondValue(context, "value", property.Type, property)};");
writer.CloseBracket();
Expand All @@ -85,17 +80,17 @@ private static void ClassBindings(GeneratorExecutionContext context, INamedTypeS
{
var parameter = Parameter.Create(context, property.SetMethod.Parameters[0]);

writer.WriteLine($"public static MondValue {name}__Setter(MondState state, MondValue instance, params MondValue[] args)");
writer.WriteLine($"public static MondValue {name}__Setter(MondState state, params MondValue[] args)");
writer.OpenBracket();

Prologue($"set{name}");

writer.WriteLine($"if (args.Length != 1 || !{CompareArgument(0, parameter)})");
writer.WriteLine($"if (args.Length != 2 || !{CompareArgument(1, parameter)})");
writer.OpenBracket();
writer.WriteLine($"throw new MondRuntimeException(\"{className}.set{name}: expected 1 argument of type {parameter.TypeName}\");");
writer.CloseBracket();

writer.WriteLine($"obj.{property.Name} = {ConvertFromMondValue(context, 0, property.Type, property)};");
writer.WriteLine($"obj.{property.Name} = {ConvertFromMondValue(context, 1, property.Type, property)};");

writer.WriteLine("return MondValue.Undefined;");
writer.CloseBracket();
Expand All @@ -107,17 +102,17 @@ private static void ClassBindings(GeneratorExecutionContext context, INamedTypeS
{
var isNormalMethod = table.Name != "#ctor";

writer.WriteLine(isNormalMethod
? $"public static MondValue {table.Identifier}__Dispatch(MondState state, MondValue instance, params MondValue[] args)"
: $"public static MondValue {table.Identifier}__Dispatch(MondState state, params MondValue[] args)");
writer.WriteLine($"public static MondValue {table.Identifier}__Dispatch(MondState state, params MondValue[] args)");
writer.OpenBracket();

var firstArg = 0;
if (isNormalMethod)
{
firstArg = 1; // skip first argument (instance)
Prologue(table.Name);
}

writer.WriteLine("switch (args.Length)");
writer.WriteLine($"switch (args.Length - {firstArg})");
writer.OpenBracket();

for (var i = 0; i < table.Methods.Count; i++)
Expand All @@ -127,14 +122,14 @@ private static void ClassBindings(GeneratorExecutionContext context, INamedTypeS
{
continue;
}

writer.WriteLine($"case {i}:");
writer.OpenBracket();
foreach (var method in tableMethods)
{
writer.WriteLine($"if ({CompareArguments(method, i)})");
writer.WriteLine($"if ({CompareArguments(method, firstArg, i)})");
writer.OpenBracket();
CallMethod(context, writer, "obj", method, i);
CallMethod(context, writer, "obj", method, firstArg, i);
writer.CloseBracket();
}
writer.WriteLine("break;");
Expand All @@ -145,9 +140,9 @@ private static void ClassBindings(GeneratorExecutionContext context, INamedTypeS

foreach (var method in table.ParamsMethods)
{
writer.WriteLine($"if (args.Length >= {method.RequiredMondParameterCount} && {CompareArguments(method)})");
writer.WriteLine($"if (args.Length >= {firstArg + method.RequiredMondParameterCount} && {CompareArguments(method, firstArg)})");
writer.OpenBracket();
CallMethod(context, writer, "obj", method);
CallMethod(context, writer, "obj", method, firstArg);
writer.CloseBracket();
}

Expand All @@ -166,6 +161,12 @@ private static void ClassBindings(GeneratorExecutionContext context, INamedTypeS

void Prologue(string methodName)
{
writer.WriteLine("if (args.Length < 1)");
writer.OpenBracket();
writer.WriteLine($"throw new MondRuntimeException(\"{className}.{methodName}: missing instance argument\");");
writer.CloseBracket();

writer.WriteLine("var instance = args[0];");
writer.WriteLine($"if (instance.Type != MondValueType.Object || instance.UserData is not {qualifier} obj)");
writer.OpenBracket();
writer.WriteLine($"throw new MondRuntimeException(\"{className}.{methodName}: can only be called on an instance of {className}\");");
Expand Down
6 changes: 3 additions & 3 deletions Mond.SourceGenerator/MondSourceGenerator.Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ private static void ModuleBindings(GeneratorExecutionContext context, INamedType
foreach (var method in tableMethods)
{
var methodQualifier = method.Info.IsStatic ? qualifier : "_instance";
writer.WriteLine($"if ({CompareArguments(method, i)})");
writer.WriteLine($"if ({CompareArguments(method, 0, i)})");
writer.OpenBracket();
CallMethod(context, writer, methodQualifier, method, i);
CallMethod(context, writer, methodQualifier, method, 0, i);
writer.CloseBracket();
}
writer.WriteLine("break;");
Expand All @@ -195,7 +195,7 @@ private static void ModuleBindings(GeneratorExecutionContext context, INamedType
var methodQualifier = method.Info.IsStatic ? qualifier : "_instance";
writer.WriteLine($"if (args.Length >= {method.RequiredMondParameterCount} && {CompareArguments(method)})");
writer.OpenBracket();
CallMethod(context, writer, methodQualifier, method);
CallMethod(context, writer, methodQualifier, method, 0);
writer.CloseBracket();
}

Expand Down
71 changes: 13 additions & 58 deletions Mond.SourceGenerator/MondSourceGenerator.Prototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ private static void PrototypeBindings(GeneratorExecutionContext context, INamedT
? prototypeAttr.GetArgument<string>() ?? prototype.Name
: prototype.Name;

var properties = GetProperties(context, prototype, true);
var methods = GetMethods(context, prototype, true);
var methodTables = MethodTable.Build(context, methods);

Expand All @@ -23,19 +22,6 @@ private static void PrototypeBindings(GeneratorExecutionContext context, INamedT
writer.WriteLine("var dict = result.ObjectValue.Values;");
writer.WriteLine();

foreach (var (property, name) in properties)
{
if (property.GetMethod is { DeclaredAccessibility: Accessibility.Public })
{
writer.WriteLine($"dict[\"get{name}\"] = MondValue.Function({name}__Getter);");
}

if (property.SetMethod is { DeclaredAccessibility: Accessibility.Public })
{
writer.WriteLine($"dict[\"set{name}\"] = MondValue.Function({name}__Setter);");
}
}

foreach (var table in methodTables)
{
writer.WriteLine($"dict[\"{table.Identifier}\"] = MondValue.Function({table.Identifier}__Dispatch);");
Expand All @@ -56,50 +42,19 @@ private static void PrototypeBindings(GeneratorExecutionContext context, INamedT

var qualifier = $"global::{prototype.GetFullyQualifiedName()}";

foreach (var (property, name) in properties)
{
if (property.GetMethod is { DeclaredAccessibility: Accessibility.Public })
{
writer.WriteLine($"private static MondValue {name}__Getter(MondState state, MondValue instance, params MondValue[] args)");
writer.OpenBracket();

writer.WriteLine("if (args.Length != 0)");
writer.OpenBracket();
writer.WriteLine($"throw new MondRuntimeException(\"{prototypeName}.get{name}: expected 0 arguments\");");
writer.CloseBracket();

writer.WriteLine($"var value = {qualifier}.{property.Name};");
writer.WriteLine($"return {ConvertToMondValue(context, "value", property.Type, property)};");
writer.CloseBracket();
writer.WriteLine();
}

if (property.SetMethod is { DeclaredAccessibility: Accessibility.Public })
{
var parameter = Parameter.Create(context, property.SetMethod.Parameters[0]);

writer.WriteLine($"private static MondValue {name}__Setter(MondState state, MondValue instance, params MondValue[] args)");
writer.OpenBracket();

writer.WriteLine($"if (args.Length != 1 || !{CompareArgument(0, parameter)})");
writer.OpenBracket();
writer.WriteLine($"throw new MondRuntimeException(\"{prototypeName}.set{name}: expected 1 argument of type {parameter.TypeName}\");");
writer.CloseBracket();

writer.WriteLine($"{qualifier}.{property.Name} = {ConvertFromMondValue(context, 0, property.Type, property)};");

writer.WriteLine("return MondValue.Undefined;");
writer.CloseBracket();
writer.WriteLine();
}
}

foreach (var table in methodTables)
{
writer.WriteLine($"private static MondValue {table.Identifier}__Dispatch(MondState state, MondValue instance, params MondValue[] args)");
writer.WriteLine($"private static MondValue {table.Identifier}__Dispatch(MondState state, params MondValue[] args)");
writer.OpenBracket();

writer.WriteLine("switch (args.Length)");
writer.WriteLine("if (args.Length < 1)");
writer.OpenBracket();
writer.WriteLine($"throw new MondRuntimeException(\"{prototypeName}.{table.Name}: missing instance argument\");");
writer.CloseBracket();
writer.WriteLine();

writer.WriteLine("var instance = args[0];");
writer.WriteLine("switch (args.Length - 1)");
writer.OpenBracket();

for (var i = 0; i < table.Methods.Count; i++)
Expand All @@ -114,9 +69,9 @@ private static void PrototypeBindings(GeneratorExecutionContext context, INamedT
writer.OpenBracket();
foreach (var method in tableMethods)
{
writer.WriteLine($"if ({CompareArguments(method, i)})");
writer.WriteLine($"if ({CompareArguments(method, 1, i)})");
writer.OpenBracket();
CallMethod(context, writer, qualifier, method, i);
CallMethod(context, writer, qualifier, method, 1, i);
writer.CloseBracket();
}
writer.WriteLine("break;");
Expand All @@ -127,9 +82,9 @@ private static void PrototypeBindings(GeneratorExecutionContext context, INamedT

foreach (var method in table.ParamsMethods)
{
writer.WriteLine($"if (args.Length >= {method.RequiredMondParameterCount} && {CompareArguments(method)})");
writer.WriteLine($"if (args.Length >= {1 + method.RequiredMondParameterCount} && {CompareArguments(method, 1)})");
writer.OpenBracket();
CallMethod(context, writer, qualifier, method);
CallMethod(context, writer, qualifier, method, 1);
writer.CloseBracket();
}

Expand Down
14 changes: 7 additions & 7 deletions Mond.SourceGenerator/MondSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ static string FullName(INamedTypeSymbol type)
}
}

private static void CallMethod(GeneratorExecutionContext context, IndentTextWriter writer, string qualifier, Method method, int argCount = 10000)
private static void CallMethod(GeneratorExecutionContext context, IndentTextWriter writer, string qualifier, Method method, int offset, int argCount = 10000)
{
var isConstructor = method.Info.MethodKind == MethodKind.Constructor;
var returnType = isConstructor
Expand All @@ -99,14 +99,14 @@ private static void CallMethod(GeneratorExecutionContext context, IndentTextWrit
writer.Write("var result = ");
}
writer.WriteLine(isConstructor
? $"new {method.Info.ContainingType.GetFullyQualifiedName()}({BindArguments(context, method, argCount)});"
: $"{qualifier}.{method.Info.Name}({BindArguments(context, method, argCount)});");
? $"new {method.Info.ContainingType.GetFullyQualifiedName()}({BindArguments(context, method, offset, argCount)});"
: $"{qualifier}.{method.Info.Name}({BindArguments(context, method, offset, argCount)});");
writer.WriteLine(hasReturn
? $"return {ConvertToMondValue(context, "result", returnType, method.Info)};"
: "return MondValue.Undefined;");
}

private static string BindArguments(GeneratorExecutionContext context, Method method, int argCount)
private static string BindArguments(GeneratorExecutionContext context, Method method, int offset, int argCount)
{
var valueIdx = 0;
var args = new List<string>();
Expand All @@ -117,7 +117,7 @@ private static string BindArguments(GeneratorExecutionContext context, Method me
continue;
}

args.Add(BindArgument(context, valueIdx, param));
args.Add(BindArgument(context, offset + valueIdx, param));

if (param.Type == ParameterType.Value)
{
Expand Down Expand Up @@ -240,12 +240,12 @@ private static string ConvertToMondValue(GeneratorExecutionContext context, stri
}
}

private static string CompareArguments(Method method, int limit = 10000)
private static string CompareArguments(Method method, int offset = 0, int limit = 10000)
{
var argComparers = method.Parameters
.Take(limit)
.Where(p => p.Type == ParameterType.Value)
.Select((p, i) => CompareArgument(i, p))
.Select((p, i) => CompareArgument(offset + i, p))
.ToList();
return argComparers.Count > 0
? string.Join(" && ", argComparers)
Expand Down
4 changes: 2 additions & 2 deletions Mond.Tests/Expressions/DestructuringTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ public class DestructuringTests
public void Array()
{
var result = Script.Run(@"
var array = [ 1, 2, 3, 4, 5 ];
var array = [ 1, 2, 3, 4, 5 ];
var [ a, b ] = array;
return [ a, b ];
return [ a, b ];
");

var expected = new MondValue[] { 1, 2 };
Expand Down
6 changes: 3 additions & 3 deletions Mond.Tests/Expressions/ObjectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ public void Classes()
var result = Script.Run(@"
fun Base() {
return {
number: fun () -> 10,
add: fun (x, y) -> x + y
number: fun (_) -> 10,
add: fun (_, x, y) -> x + y
};
}
fun Class() {
var base, this = {
number: fun () -> this.add(base.number(), 5)
number: fun (_) -> this.add(base.number(), 5)
};
base = Base();
Expand Down
15 changes: 0 additions & 15 deletions Mond.Tests/MondStateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,6 @@ public void NativeFunction()
Assert.True(result == "arg");
}

[Test]
public void NativeInstanceFunction()
{
var state = new MondState();

state["value"] = 123;
state["function"] = new MondInstanceFunction((_, instance, arguments) => instance[arguments[0]]);

var result = state.Run(@"
return global.function('value');
");

Assert.True(result == 123);
}

[Test]
[TestCase("runtime", false)]
[TestCase("generic", false)]
Expand Down
15 changes: 0 additions & 15 deletions Mond.Tests/MondValueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -395,21 +395,6 @@ public void ObjectPrototype()
Assert.Throws<MondRuntimeException>(() => obj.Prototype = MondValue.Undefined, "modify locked object prototype");
}

[Test]
public void WrappedInstanceFunction()
{
var obj = MondValue.Object();

var func = MondValue.Function((state, instance, args) => MondValue.Undefined);
Assert.True(func.FunctionValue.Type == ClosureType.InstanceNative);

obj["test"] = func;
var closure = obj["test"];
Assert.True(closure.FunctionValue.Type == ClosureType.Native);

Assert.True(new MondState().Call(obj["test"]) == MondValue.Undefined);
}

[Test]
public void UserData()
{
Expand Down
Loading

0 comments on commit 30b61aa

Please sign in to comment.