using NubLang.Diagnostics; using NubLang.Syntax.Parsing.Node; namespace NubLang.Syntax.Templating; public class TemplateGenerator { private readonly SyntaxTree _syntaxTree; private readonly TemplateTable _templateTable; public TemplateGenerator(SyntaxTree syntaxTree, TemplateTable templateTable) { _syntaxTree = syntaxTree; _templateTable = templateTable; } public IReadOnlyList Generate() { var definitions = new List(); foreach (var type in _syntaxTree.ReferencedTemplatedCustomTypes) { definitions.Add(CreateDefinition(type)); } return definitions; } private DefinitionSyntax CreateDefinition(TemplatedCustomTypeSyntax type) { var structTemplates = _templateTable.LookupStructTemplate(type.Namespace, type.Name).ToArray(); if (structTemplates.Length > 0) { if (structTemplates.Length > 1) { throw new TemplateGeneratorException(Diagnostic.Error($"Struct template {type.Namespace}::{type.Name} has multiple definitions").Build()); } var structTemplate = structTemplates[0]; var transformations = new Dictionary(); for (var i = 0; i < structTemplate.TemplateParameters.Count; i++) { transformations[structTemplate.TemplateParameters[i]] = type.Arguments[i]; } var transformer = new TypeTransformer(transformations); var transformed = transformer.TransformStruct(structTemplate.Struct); return transformed with { Name = type.MangledName() }; } throw new TemplateGeneratorException(Diagnostic.Error($"Template {type.Namespace}::{type.Name} is not defined").Build()); } } public class TemplateGeneratorException : Exception { public Diagnostic Diagnostic { get; } public TemplateGeneratorException(Diagnostic diagnostic) : base(diagnostic.Message) { Diagnostic = diagnostic; } }