1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 * 25 */ 26 27 package jdk.incubator.jextract.tool; 28 29 import jdk.incubator.foreign.MemoryLayout; 30 import jdk.incubator.jextract.Declaration; 31 import jdk.incubator.jextract.Position; 32 33 import java.util.ArrayDeque; 34 import java.util.Deque; 35 import java.util.List; 36 import java.util.stream.Collectors; 37 38 final class GroupNameHandler implements Declaration.Visitor<Declaration, Void> { 39 private final Deque<Declaration> parents = new ArrayDeque<>(); 40 private int id; 41 42 Declaration.Scoped fillNames(Declaration.Scoped toplevel) { 43 return (Declaration.Scoped)toplevel.accept(this, null); 44 } 45 46 @Override 47 public Declaration visitScoped(Declaration.Scoped d, Void aVoid) { 48 parents.addFirst(d); 49 Declaration[] newMembers = d.members().stream() 50 .map(decl -> decl.accept(this, null)).toArray(Declaration[]::new); 51 parents.removeFirst(); 52 return switch (d.kind()) { 53 case ENUM -> makeGroup(d, newMembers, Declaration::enum_, Declaration::enum_); 54 case UNION -> makeGroup(d, newMembers, Declaration::union, Declaration::union); 55 case STRUCT -> makeGroup(d, newMembers, Declaration::struct, Declaration::struct); 56 case CLASS -> makeGroup(d, newMembers, Declaration::class_, Declaration::class_); 57 case BITFIELDS -> Declaration.bitfields(d.pos(), d.name(), d.layout().get(), 58 List.of(newMembers).toArray(new Declaration.Variable[0])); 59 case NAMESPACE -> Declaration.namespace(d.pos(), d.name(), newMembers); 60 case TYPEDEF -> Declaration.typedef(d.pos(), d.name(), newMembers[0]); 61 case TOPLEVEL -> Declaration.toplevel(d.pos(), newMembers); 62 }; 63 } 64 65 private interface GroupFactoryNoLayout { 66 Declaration make(Position pos, String name, Declaration... members); 67 } 68 69 private interface GroupFactoryLayout { 70 Declaration make(Position pos, String name, MemoryLayout layout, Declaration... members); 71 } 72 73 private Declaration makeGroup(Declaration.Scoped d, Declaration[] newMembers, GroupFactoryNoLayout factoryNoLayout, GroupFactoryLayout factoryLayout) { 74 String name = groupName(d.name()); 75 if (d.layout().isEmpty()) { 76 return factoryNoLayout.make(d.pos(), name, newMembers); 77 } else { 78 return factoryLayout.make(d.pos(), name, d.layout().get().withName(name), newMembers); 79 } 80 } 81 82 private String groupName(String name) { 83 if (!name.isEmpty()) { 84 return name; 85 } else { 86 String prefix = parents.stream() 87 .filter(d -> ((Declaration.Scoped)d).kind() != Declaration.Scoped.Kind.TOPLEVEL && !d.name().isEmpty()) 88 .map(Declaration::name) 89 .collect(Collectors.joining("$")); 90 if (((Declaration.Scoped)parents.peek()).kind() == Declaration.Scoped.Kind.TYPEDEF) { 91 return prefix; 92 } else { 93 return prefix + "$" + id++; 94 } 95 } 96 } 97 98 @Override 99 public Declaration visitDeclaration(Declaration d, Void aVoid) { 100 return d; 101 } 102 }