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