001/* 002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.golo.compiler.ir; 011 012import java.util.Collection; 013import java.util.Set; 014import java.util.LinkedHashSet; 015import java.util.LinkedList; 016 017import org.eclipse.golo.compiler.PackageAndClass; 018import org.eclipse.golo.compiler.parser.GoloASTNode; 019 020import static java.util.Collections.unmodifiableSet; 021 022/** 023 * "classical" augmentation. 024 * <p> 025 * Represents all the augmentations applied to a type, i.e. functions and named augmentations 026 * applied with the {@code with} construct. 027 * <p> 028 * This represents code such 029 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 030 * augment MyType { 031 * function foo = |this| -> ... 032 * } 033 * </code></pre> 034 * or 035 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 036 * augment MyType with MyAugmentation 037 * </code></pre> 038 */ 039public final class Augmentation extends GoloElement implements FunctionContainer { 040 private PackageAndClass target; 041 private final Set<GoloFunction> functions = new LinkedHashSet<>(); 042 private final Set<String> names = new LinkedHashSet<>(); 043 044 Augmentation(PackageAndClass target) { 045 super(); 046 this.target = target; 047 } 048 049 @Override 050 public Augmentation ofAST(GoloASTNode node) { 051 super.ofAST(node); 052 return this; 053 } 054 055 public PackageAndClass getTarget() { 056 return target; 057 } 058 059 public boolean hasLocalTarget() { 060 return target.packageName().isEmpty(); 061 } 062 063 public void setTargetPackage(String packageName) { 064 target = new PackageAndClass(packageName, target.className()); 065 } 066 067 @Override 068 public Set<GoloFunction> getFunctions() { 069 return unmodifiableSet(functions); 070 } 071 072 @Override 073 public void addFunction(GoloFunction func) { 074 functions.add(func); 075 makeParentOf(func); 076 } 077 078 @Override 079 public boolean hasFunctions() { 080 return !functions.isEmpty(); 081 } 082 083 public Set<String> getNames() { 084 return unmodifiableSet(names); 085 } 086 087 public boolean hasNames() { 088 return !names.isEmpty(); 089 } 090 091 public Augmentation with(Object... objects) { 092 return with(java.util.Arrays.asList(objects)); 093 } 094 095 public Augmentation with(Collection<?> objects) { 096 if (objects != null) { 097 for (Object o : objects) { 098 if (o instanceof String) { 099 names.add((String) o); 100 } else if (o instanceof GoloFunction) { 101 addFunction((GoloFunction) o); 102 } else { 103 throw cantConvert("string or function", o); 104 } 105 } 106 } 107 return this; 108 } 109 110 public void merge(Augmentation other) { 111 if (!other.getTarget().equals(target)) { 112 throw new IllegalArgumentException("Can't merge augmentations to different targets"); 113 } 114 if (other != this) { 115 this.names.addAll(other.getNames()); 116 addFunctions(other.getFunctions()); 117 } 118 } 119 120 @Override 121 public String toString() { 122 return String.format("Augmentation<target=%s, names=%s, functions=%s>", 123 getTarget(), 124 getNames(), 125 getFunctions()); 126 } 127 128 @Override 129 protected void replaceElement(GoloElement original, GoloElement newElement) { 130 if (functions.contains(original) && newElement instanceof GoloFunction) { 131 functions.remove((GoloFunction) original); 132 functions.add((GoloFunction) newElement); 133 } else { 134 throw cantReplace(original, newElement); 135 } 136 } 137 138 @Override 139 public void accept(GoloIrVisitor visitor) { 140 visitor.visitAugmentation(this); 141 } 142 143 @Override 144 public void walk(GoloIrVisitor visitor) { 145 for (GoloFunction func : new LinkedList<GoloFunction>(functions)) { 146 func.accept(visitor); 147 } 148 } 149}