001/* 002 * Copyright (c) 2012-2021 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package gololang.ir; 012 013import java.util.*; 014 015import static java.util.stream.Collectors.toList; 016 017/** 018 * An abstract class for struct-like types. 019 */ 020public abstract class TypeWithMembers<T extends TypeWithMembers<T>> extends GoloType<T> { 021 private final Set<Member> members = new LinkedHashSet<>(); 022 023 TypeWithMembers(String name) { 024 super(name); 025 } 026 027 protected String getFactoryDelegateName() { 028 return getFullName(); 029 } 030 031 String getFullName() { 032 return getPackageAndClass().toString(); 033 } 034 035 /** 036 * Adds all members to this type. 037 * 038 * @see #withMember(Object) 039 */ 040 public T members(Object... members) { 041 for (Object member : members) { 042 withMember(member); 043 } 044 return self(); 045 } 046 047 public boolean hasMembers() { 048 return !this.members.isEmpty(); 049 } 050 051 protected void addMember(Member member) { 052 this.members.add(makeParentOf(member)); 053 } 054 055 void addMembers(Iterable<Member> members) { 056 members.forEach(this::addMember); 057 } 058 059 /** 060 * Adds a member to this type. 061 * 062 * <p>This is a builder method. 063 * 064 * @param member a {@link Member} or any object whose {@code toString} method is used to create a member object. 065 */ 066 public T withMember(Object member) { 067 addMember(Member.of(member)); 068 return self(); 069 } 070 071 protected List<String> getMemberNames() { 072 return members.stream() 073 .map(Member::getName) 074 .collect(toList()); 075 } 076 077 public Set<Member> getMembers() { 078 return Collections.unmodifiableSet(members); 079 } 080 081 public List<Member> getPublicMembers() { 082 return members.stream() 083 .filter(Member::isPublic) 084 .collect(toList()); 085 } 086 087 protected Object[] getFullArgs() { 088 return members.stream() 089 .map(Member::getName) 090 .map(ReferenceLookup::of) 091 .toArray(); 092 } 093 094 /** 095 * Creates the factory functions for this type. 096 * 097 * <p>Internal API 098 */ 099 public Set<GoloFunction> createFactories() { 100 Set<GoloFunction> factories = new LinkedHashSet<>(); 101 factories.add(createFullArgsConstructor()); 102 return factories; 103 } 104 105 protected GoloFunction createFullArgsConstructor() { 106 return GoloFunction.function(getName()).synthetic() 107 .withParameters(getMemberNames()) 108 .returns(FunctionInvocation.of(getFactoryDelegateName()).withArgs(getFullArgs())); 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 @Override 115 public List<GoloElement<?>> children() { 116 return new ArrayList<>(members); 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override 123 protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) { 124 throw cantReplace(); 125 } 126}