protected override void OnTranslate(ShaderTranslationContext sc, MethodDeclarationSyntax syntax, ScopeInfo scope) { MethodInfo info = sc.GetMethodInfo(syntax); if (info != null) { MappedEntryPoint ep = null; sc.EntryPointsByMethod.TryGetValue(info, out ep); sc.Source.AppendLineBreak(); ScopeInfo mScope = sc.Source.OpenScope(ScopeType.Method, null, ep); mScope.Method = info; ShaderType returnType = ShaderType.TranslateType(sc, syntax.ReturnType.ToString()); ep?.Translator?.TranslatePrefix(sc, info, syntax, ep); sc.Source.Append($"{returnType.Translation} {syntax.Identifier.ValueText}"); sc.Complete(syntax.ReturnType); sc.Complete(syntax.ConstraintClauses); sc.Complete(syntax.AttributeLists); if (syntax.TypeParameterList != null) { sc.CompleteSelfAndChildren(syntax.TypeParameterList); } // Translate parameters before method body. sc.Runner.Translate(sc, syntax.ParameterList, 0); ep?.Translator?.TranslatePostfix(sc, info, syntax, ep); } }
protected override void OnTranslate(ShaderTranslationContext sc, ParameterSyntax syntax, ScopeInfo scope) { ScopeInfo methodScope = scope.FindOfType(ScopeType.Method); MethodInfo methodInfo = null; MappedEntryPoint ep = null; if (scope.Type == ScopeType.Parentheses) { if (scope.Items.Last() != syntax) { sc.Source.OpenScope(ScopeType.ParenthesesItem); } } if (methodScope != null) { methodInfo = methodScope.Method; sc.EntryPointsByMethod.TryGetValue(methodInfo, out ep); } // TODO pass to language variable translation, since parameters can have attributes ShaderType type = ShaderType.TranslateType(sc, syntax.Type.ToString()); bool wasAppended = false; if (ep != null) { (ParameterInfo pInfo, int pIndex) = sc.GetParameterInfo(methodInfo, syntax.Identifier.ValueText); IEnumerable <Attribute> pAttributes = pInfo.GetCustomAttributes(); ep.Translator?.TranslateParameterPrefix(sc, syntax, ep, pInfo, pAttributes, pIndex); sc.Source.Append($"{type.Translation} {syntax.Identifier.ValueText}"); ep.Translator?.TranslateParameterPostfix(sc, syntax, ep, pInfo, pAttributes, pIndex); wasAppended = true; } if (!wasAppended) { sc.Source.Append($"{type.Translation} {syntax.Identifier.ValueText}"); } sc.Complete(syntax.Type); sc.Complete(syntax.AttributeLists); }
protected override void OnTranslate(ShaderTranslationContext sc, PropertyDeclarationSyntax syntax, ScopeInfo scope) { ScopeInfo classScope = scope.FindOfType(ScopeType.Class); ScopeInfo pScope = sc.Source.OpenScope(ScopeType.Property); pScope.Identifier = syntax.Identifier.ValueText; sc.Complete(syntax.Type); pScope.TypeInfo = ShaderType.TranslateType(sc, syntax.Type.ToString()); }
protected override void OnTranslate(ShaderTranslationContext sc, ObjectCreationExpressionSyntax syntax, ScopeInfo scope) { // Are we directly inside an initializer? (i.e. array initializer) if (scope.Type == ScopeType.ArrayInitializer) { if (syntax != scope.Items.Last()) { sc.Source.OpenScope(ScopeType.ArrayElement); } } string typeName = syntax.Type.ToString(); ShaderType type = ShaderType.TranslateType(sc, typeName); sc.Complete(syntax.Type); // Handle initializers. These require declaring as a local variable above the current syntax node. if (syntax.Initializer != null) { switch (syntax.Parent) { case ReturnStatementSyntax returnSyntax: case AssignmentExpressionSyntax assignSyntax: string strInit = type.Translation; string varName = sc.Parent.GetNewVariableName("oc_init"); scope.DeclareLocal(sc, () => { sc.Source.Append($"{type.Translation} {varName} = {type.Translation}"); sc.Runner.Translate(sc, syntax.ArgumentList); sc.Source.Append(";"); sc.Source.AppendLineBreak(); ScopeInfo iScope = sc.Source.OpenScope(ScopeType.ExpandedInitializer); iScope.Identifier = varName; sc.Runner.Translate(sc, syntax.Initializer); }); sc.Source.Append(varName); break; default: sc.Source.Append(type.Translation); break; } } else { sc.Source.Append(type.Translation); } }
protected override void OnTranslate(ShaderTranslationContext sc, ClassDeclarationSyntax syntax, ScopeInfo scope) { if ($"{sc.ShaderType.Namespace}.{syntax.Identifier.ValueText}" != sc.Name) { // TODO does the shader language support classes? // If not, we need a system to translate the class into another form of usable output source. Type t = sc.Parent.Reflection.Assembly.GetType($"{scope.Namespace}+{syntax.Identifier.ValueText}"); ScopeInfo cScope = sc.Source.OpenScope(ScopeType.Class, t); } else { sc.Complete(syntax.BaseList); } }
protected override void OnTranslate(ShaderTranslationContext sc, VariableDeclarationSyntax syntax, ScopeInfo scope) { string typeName = syntax.Type.ToString(); ShaderType type = ShaderType.TranslateType(sc, typeName); ScopeInfo tScope = sc.Source.OpenScope(ScopeType.Typed, type); tScope.TypeInfo = type; tScope.IsLocal = syntax.Parent is LocalDeclarationStatementSyntax; tScope.Items = syntax.Variables; if (syntax.Parent is FieldDeclarationSyntax fieldSyntax) { tScope.TranslatedModifiers = sc.Language.TranslateModifiers(fieldSyntax.Modifiers); } sc.Complete(syntax.Type); }
protected override void OnTranslate(ShaderTranslationContext sc, ArrayTypeSyntax syntax, ScopeInfo scope) { sc.Complete(syntax.ElementType); }
protected override void OnTranslate(ShaderTranslationContext sc, VariableDeclaratorSyntax syntax, ScopeInfo scope) { if (scope.Type == ScopeType.Typed) { FieldInfo fInfo = null; MappedField mField = null; MappedConstantBuffer cBufferMap = null; if (scope.Parent.Type == ScopeType.Struct) { fInfo = scope.Parent.TypeInfo.OriginalType.GetField(syntax.Identifier.ValueText); sc.ConstantBuffers.TryGetValue(scope.Parent.TypeInfo.OriginalType.Name, out cBufferMap); } if (fInfo == null) { sc.Fields.TryGetValue(syntax.Identifier.ValueText, out fInfo); } if (fInfo != null) { int fieldIndex = scope.Items.IndexOf(syntax); mField = Pooling.MappedFields.Get(); mField.Initialize(scope.TypeInfo, fInfo); cBufferMap?.AddField(mField); sc.Language.TranslateFieldPrefix(sc, syntax, mField, fieldIndex, cBufferMap); sc.Source.Append($"{scope.TranslatedModifiers} "); sc.Source.Append(scope.TypeInfo.Translation); sc.Source.Append($" {syntax.Identifier.ValueText}"); sc.Language.TranslateFieldPostfix(sc, syntax, mField, fieldIndex, cBufferMap); } else { sc.Source.Append($"{scope.TranslatedModifiers} "); sc.Source.Append(scope.TypeInfo.Translation); sc.Source.Append($" {syntax.Identifier.ValueText}"); } // Handle corner-cases for array initializers. if (scope.TypeInfo != null && syntax.Initializer != null) { if (scope.TypeInfo.WasArrayType) { switch (syntax.Initializer.Value) { case InitializerExpressionSyntax initSyntax: IEnumerable <SyntaxNode> initChildren = initSyntax.ChildNodes(); int arraySize = initChildren.Count(); sc.Source.Append($"[{arraySize}]"); if (mField != null) { mField.ArrayDimensions.Add(arraySize); } // TODO multi-dimensional array support (e.g. [4][2]). // - For multi-dimensional arrays, we can simply take the dimensions directly. // - For jagged arrays, we need to find the largest sub-array and use that as the size for it's respective dimension. break; case ArrayCreationExpressionSyntax arraySyntax: sc.Runner.Translate(sc, arraySyntax.Type); break; } } } bool isForInitializer = (syntax.Parent is VariableDeclarationSyntax varDecSyntax && varDecSyntax.Parent is ForStatementSyntax forSyntax); if (!isForInitializer) { if (syntax.Initializer != null && syntax.Initializer.Value is ObjectCreationExpressionSyntax objSyntax && objSyntax.Initializer != null) { ScopeInfo si = sc.Source.OpenScope(ScopeType.ExpandedInitializer); si.Identifier = syntax.Identifier.ValueText; sc.Source.Append(" = "); // Are we instantiating a new struct value with no args? if (objSyntax.ArgumentList.Arguments.Count == 0 && scope.TypeInfo.OriginalType.IsValueType) { sc.Source.Append($"({scope.TypeInfo.Translation})0;"); // TODO does GLSL allow this? Do we abstract or add a language property to check against? sc.Source.AppendLineBreak(); sc.Complete(objSyntax.ArgumentList); sc.Complete(objSyntax.Type); } else { sc.Source.Append(scope.TypeInfo.Translation); sc.Runner.Translate(sc, objSyntax.ArgumentList); sc.Source.Append(";"); sc.Source.AppendLineBreak(); sc.Runner.Translate(sc, objSyntax.Initializer); sc.Complete(objSyntax.ArgumentList); sc.Complete(objSyntax.Type); } // We no longer need to translate the object creation syntax, but we still want it's initializer. sc.Complete(syntax.Initializer); sc.Runner.Translate(sc, objSyntax.Initializer); } else { ScopeInfo si = sc.Source.OpenScope(ScopeType.Variable); si.Identifier = syntax.Identifier.ValueText; } } }
protected override void OnTranslate(ShaderTranslationContext sc, MemberAccessExpressionSyntax syntax, ScopeInfo scope) { switch (syntax.Expression) { case IdentifierNameSyntax idSyntax: // Is this a static class identifier? // Static classes are abstract and sealed at IL level. Type targetType = ShaderType.Resolve(sc, idSyntax.Identifier.ValueText); if (targetType != null && targetType.IsClass && targetType.IsAbstract && targetType.IsSealed) { // Is the member a constant value? If so, we can take it's value directly. FieldInfo fInfo = targetType.GetField(syntax.Name.Identifier.ValueText); if (fInfo != null && (fInfo.Attributes & FieldAttributes.Literal) == FieldAttributes.Literal) { object val = fInfo.GetValue(null); if (val != null) { sc.Source.Append(val.ToString()); sc.CompleteChildren(syntax); return; } } } else { ScopeInfo cScope = scope.FindOfType(ScopeType.Class); if (cScope == sc.Source.RootScope) { FieldInfo fInfo = cScope.TypeInfo.OriginalType.GetField(idSyntax.Identifier.ValueText); if (fInfo != null && sc.ConstantBuffers.Values.Any(x => x.TypeInfo == fInfo.FieldType)) { if (!sc.Language.InstancedConstantBuffers) { sc.CompleteSelfAndChildren(syntax.Expression); sc.Runner.Translate(sc, syntax.Name); return; } } } } break; case ThisExpressionSyntax thisSyntax: case BaseExpressionSyntax baseSyntax: ScopeInfo pScope = scope.FindOfType(ScopeType.Class); if (pScope.TypeInfo.OriginalType == sc.ShaderType) { sc.Complete(syntax.Expression); // Are we translating a shader intrinsic method/function? if (syntax.Name is IdentifierNameSyntax idSyntax && syntax.Parent is InvocationExpressionSyntax) { string translatedIntrinsic = ShaderType.GetIntrinsicTranslation(sc, idSyntax.Identifier.ValueText); sc.Source.Append(translatedIntrinsic); sc.Complete(syntax.Name); } return; } break; } sc.Runner.Translate(sc, syntax.Expression); sc.Source.Append(syntax.OperatorToken); sc.Runner.Translate(sc, syntax.Name); }