Skip to content

Commit

Permalink
Merge pull request #269 from NoiseStudio/feature/268/add-constructors…
Browse files Browse the repository at this point in the history
…-to-compiled-default-shader

Add constructors to compiled default shader
  • Loading branch information
Vixenka committed May 21, 2023
2 parents 1920332 + c725e84 commit 37ef8fe
Show file tree
Hide file tree
Showing 20 changed files with 427 additions and 81 deletions.
43 changes: 43 additions & 0 deletions NoiseEngine.Tests/Nesl/CompilerTools/Parsing/Methods/Assignment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using NoiseEngine.Tests.Environments;

namespace NoiseEngine.Tests.Nesl.CompilerTools.Parsing.Methods;

public class Assignment : NeslParsingTestEnvironment {

[Fact]
public void CompactValueFromVariable() {
CompileSingle(@"
void Main(f32 a, f32v3 b) {
a = b.Z;
}
");
}

[Fact]
public void CompactValueFromVariableConstructor() {
CompileSingle(@"
struct Foo {
Foo(f32 a, f32v3 b) {
a = b.Z;
}
}
");
}

[Fact]
public void CompactValueFromField() {
CompileSingle(@"
struct Foo {
f32 a;
f32v4 b;
void Main(f32 a) {
a = b.Y;
}
}
");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using NoiseEngine.Tests.Environments;

namespace NoiseEngine.Tests.Nesl.CompilerTools.Parsing.Methods;

public class GenericType : NeslParsingTestEnvironment {

[Fact]
public void Generic() {
CompileSingle(@"
struct Foo<T> {
T Method(T t) {
return t;
}
}
");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using NoiseEngine.Tests.Environments;

namespace NoiseEngine.Tests.Nesl.CompilerTools.Parsing.Structs;

public class Constructors : NeslParsingTestEnvironment {

[Fact]
public void WithoutParameters() {
CompileSingle(@"
struct Foo {
public u32 X;
public Foo() {
X = 42;
}
}
");
}

[Fact]
public void WithParameters() {
CompileSingle(@"
struct Foo {
public f32 X;
public Foo(f32 x) {
X = x;
}
}
");
}

}
7 changes: 7 additions & 0 deletions NoiseEngine/BuiltInResources/Shaders/Vector4.nesl
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,11 @@ public struct Vector4<T> {
public T Z;
public T W;

public Vector4(Vector3<T> xyz, T w) {
X = xyz.X;
Y = xyz.Y;
Z = xyz.Z;
W = w;
}

}
4 changes: 2 additions & 2 deletions NoiseEngine/Nesl/CompilationError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ namespace NoiseEngine.Nesl;

public readonly struct CompilationError {

private readonly string received;
private readonly object received;

public CompilationErrorType Type { get; }
public string Path { get; }
public uint Line { get; }
public uint Column { get; }
public CompilationErrorSeverity Severity { get; }

internal CompilationError(CodePointer pointer, CompilationErrorType type, string received) {
internal CompilationError(CodePointer pointer, CompilationErrorType type, object received) {
this.received = received;

Type = type;
Expand Down
8 changes: 7 additions & 1 deletion NoiseEngine/Nesl/CompilationErrorType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public enum CompilationErrorType {
[CompilationErrorType(CompilationErrorSeverity.Error)]
ExpectedExplicitCastNotExpression,
[CompilationErrorType(CompilationErrorSeverity.Error)]
ExpectedAssignmentOperator,
ExpectedAssigmentOperator,
[CompilationErrorType(CompilationErrorSeverity.Error)]
ExpectedAttribute,
[CompilationErrorType(CompilationErrorSeverity.Error)]
Expand Down Expand Up @@ -114,10 +114,16 @@ public enum CompilationErrorType {
[CompilationErrorType(CompilationErrorSeverity.Error)]
AttributeCreateMethodNotFound,
[CompilationErrorType(CompilationErrorSeverity.Error)]
VariableOrFieldOrPropertyNotFound,
[CompilationErrorType(CompilationErrorSeverity.Error)]
ImplicitCastOperatorNotFound,
[CompilationErrorType(CompilationErrorSeverity.Error)]
UsingGenericNotAllowed,
[CompilationErrorType(CompilationErrorSeverity.Error)]
AttributeGenericNotAllowed,
[CompilationErrorType(CompilationErrorSeverity.Error)]
AssigmentGenericNotAllowed,
[CompilationErrorType(CompilationErrorSeverity.Error)]
AttributeTargetNotMatch,
[CompilationErrorType(CompilationErrorSeverity.Error)]
SubtractionOperatorNotMatchExpression,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static void Initialize(Parser parser, NeslType type, uint constructedId,
}

if (!buffer.TryReadNext(TokenType.Assigment, out Token token)) {
parser.Throw(new CompilationError(token, CompilationErrorType.ExpectedAssignmentOperator));
parser.Throw(new CompilationError(token, CompilationErrorType.ExpectedAssigmentOperator));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public static ValueData Construct(ValueToken value, Parser parser) {
if (element is ValueToken token) {
if (token.Value is ValueToken innerToken)
return Construct(innerToken, parser);
if (token.Value is ConstValueToken constValue)
return new ValueData(null!, uint.MaxValue, constValue);
if (token.Value is not ExpressionValueContentContainer container)
throw new UnreachableException();

Expand Down Expand Up @@ -74,8 +76,19 @@ private static ValueData ConstructValue(Parser parser, ExpressionValueContent ex
string fragmentName = index != -1 ? identifier.Identifier[..index] : identifier.Identifier;

VariableData? variable = parser.GetVariable(fragmentName);
if (variable is null)
return CallMethod(parser, expression);
if (variable is null) {
uint i = 0;
foreach (NeslField f in parser.CurrentMethod.Type.Fields) {
if (f.Name == fragmentName) {
variable = new VariableData(f.FieldType, f.Name, i);
break;
}
i++;
}

if (variable is null)
return CallMethod(parser, expression);
}

if (index == -1)
return new ValueData(variable.Value.Type, variable.Value.Id);
Expand Down
51 changes: 48 additions & 3 deletions NoiseEngine/Nesl/CompilerTools/Parsing/Constructors/ValueData.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,52 @@
namespace NoiseEngine.Nesl.CompilerTools.Parsing.Constructors;
using NoiseEngine.Nesl.CompilerTools.Parsing.Tokens;
using NoiseEngine.Nesl.Emit;

internal readonly record struct ValueData(NeslType Type, uint Id) {
namespace NoiseEngine.Nesl.CompilerTools.Parsing.Constructors;

public static ValueData Invalid => new ValueData(null!, uint.MaxValue);
internal readonly record struct ValueData(NeslType Type, uint Id, object? AdditionalData) {

public static ValueData Invalid => new ValueData(null!, uint.MaxValue, null);

public bool IsInvalid => this == Invalid;

public ValueData(NeslType type, uint id) : this(type, id, null) {
}

public ValueData LoadConst(Parser parser, NeslType expected) {
const string Start = "System::System.";

if (AdditionalData is not ConstValueToken constValue)
return this;

IlGenerator il = parser.CurrentMethod.IlGenerator;
uint id = uint.MaxValue;
CompilationError error = default;

switch (expected.FullNameWithAssembly) {
case Start + "Float32":
if (constValue.ToFloat32(out float a, out error)) {
id = il.GetNextVariableId();
il.Emit(OpCode.DefVariable, expected);
il.Emit(OpCode.LoadFloat32, id, a);
}
break;
case Start + "UInt32":
if (constValue.ToUInt32(out uint b, out error)) {
id = il.GetNextVariableId();
il.Emit(OpCode.DefVariable, expected);
il.Emit(OpCode.LoadUInt32, id, b);
}
break;
default:
parser.Throw(new CompilationError(
constValue.Pointer, CompilationErrorType.ImplicitCastOperatorNotFound, constValue
));
break;
}

if (id == uint.MaxValue)
parser.Throw(error);
return new ValueData(expected, id);
}

}
23 changes: 23 additions & 0 deletions NoiseEngine/Nesl/CompilerTools/Parsing/DefaultConstructorHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using NoiseEngine.Nesl.Emit;
using System.Diagnostics;

namespace NoiseEngine.Nesl.CompilerTools.Parsing;

internal static class DefaultConstructorHelper {

public static void AppendHeader(NeslMethodBuilder method) {
NeslType type = method.ReturnType ?? throw new UnreachableException();
IlGenerator il = method.IlGenerator;

il.GetNextVariableId();
il.Emit(OpCode.DefVariable, type);
}

public static void AppendFooter(NeslMethodBuilder method) {
NeslType type = method.ReturnType ?? throw new UnreachableException();
IlGenerator il = method.IlGenerator;

il.Emit(OpCode.ReturnValue, (uint)type.Fields.Count);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using NoiseEngine.Nesl.CompilerTools.Parsing.Constructors;
using NoiseEngine.Nesl.CompilerTools.Parsing.Tokens;
using NoiseEngine.Nesl.Emit;
using System;

namespace NoiseEngine.Nesl.CompilerTools.Parsing.Expressions;

internal class AssignmentDeclaration : ParserExpressionContainer {

public AssignmentDeclaration(Parser parser) : base(parser) {
}

[ParserExpression(ParserStep.Method)]
[ParserExpressionParameter(ParserTokenType.TypeIdentifier)]
[ParserExpressionParameter(ParserTokenType.Operator)]
[ParserExpressionParameter(ParserTokenType.Value)]
[ParserExpressionTokenType(ParserTokenType.Semicolon)]
public void Define(TypeIdentifierToken identifier, OperatorToken op, ValueToken value) {
bool successful = true;
if (identifier.GenericTokens.Count != 0) {
Parser.Throw(new CompilationError(
identifier.GenericTokens[0].Pointer, CompilationErrorType.AssigmentGenericNotAllowed, identifier
));
successful = false;
}
if (!op.IsAssigment) {
Parser.Throw(new CompilationError(op.Pointer, CompilationErrorType.ExpectedAssigmentOperator, op));
successful = false;
}

int index = identifier.Identifier.IndexOf('.');
if (index != -1)
throw new NotImplementedException();

VariableData? variable = Parser.GetVariable(identifier.Identifier);
bool isField = false;

// Check fields.
if (variable is null) {
uint i = 0;
foreach (NeslField field in Parser.CurrentMethod.Type.Fields) {
if (field.Name == identifier.Identifier) {
variable = new VariableData(field.FieldType, field.Name, i);
isField = true;
break;
}
i++;
}
}

// TODO: Add properties.

if (variable is null) {
Parser.Throw(new CompilationError(
identifier.Pointer, CompilationErrorType.VariableOrFieldOrPropertyNotFound, identifier.Identifier
));
successful = false;
}

ValueData valueData = ValueConstructor.Construct(value, Parser);
if (!successful || valueData.IsInvalid)
return;
valueData = valueData.LoadConst(Parser, variable!.Value.Type);

IlGenerator il = Parser.CurrentMethod.IlGenerator;
if (!isField) {
il.Emit(OpCode.Load, variable!.Value.Id, valueData.Id);
} else {
il.Emit(OpCode.SetField, (uint)Parser.CurrentMethod.Type.Fields.Count, variable!.Value.Id, valueData.Id);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using NoiseEngine.Nesl.CompilerTools.Parsing.Tokens;

namespace NoiseEngine.Nesl.CompilerTools.Parsing.Expressions;

internal class ConstructorDeclaration : ParserExpressionContainer {

public ConstructorDeclaration(Parser parser) : base(parser) {
}

[ParserExpression(ParserStep.Type)]
[ParserExpressionParameter(ParserTokenType.Attributes)]
[ParserExpressionParameter(ParserTokenType.AccessModifiers)]
[ParserExpressionParameter(ParserTokenType.Name)]
[ParserExpressionParameter(ParserTokenType.RoundBrackets)]
[ParserExpressionParameter(ParserTokenType.CurlyBrackets)]
public void Define(
AttributesToken attributes, AccessModifiersToken accessModifiers, NameToken name, RoundBracketsToken parameters,
CurlyBracketsToken codeBlock
) {
Parser.DefineMethod(new MethodDefinitionData(
null, name with { Name = NeslOperators.Constructor }, parameters.Buffer, codeBlock.Buffer,
attributes.Compile(Parser, AttributeTargets.Method)
));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public void Define(
) {
Parser.DefineMethod(new MethodDefinitionData(
typeIdentifier, name, parameters.Buffer, codeBlock.Buffer,
attributes.Compile(Parser, AttributeTargets.Method
)));
attributes.Compile(Parser, AttributeTargets.Method)
));
}

}
Loading

0 comments on commit 37ef8fe

Please sign in to comment.