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.Deque; 013import java.util.LinkedList; 014import java.util.concurrent.atomic.AtomicLong; 015 016/** 017 * Name generator for synthetic objects. 018 * <p> 019 * The generated name follows the patter {@code __$$_<name>_<counter>}. 020 * The default name is {@code symbol}. 021 * <p> 022 * The generator maintains a stack of scope names, to generate hierarchical names. 023 * <pre class="listing"><code class="lang-java" data-lang="java"> 024 * SymbolGenerator sym = new SymbolGenerator("closure"); 025 * sym.next(); // __$$_closure_0 026 * sym.next(); // __$$_closure_1 027 * sym.enter("scope"); 028 * sym.next(); // __$$_closure_scope_2 029 * sym.enter("subscope"); 030 * sym.next(); // __$$_closure_scope_subscope_3 031 * sym.exit().exit(); 032 * sym.next(); // __$$_closure_4 033 * </code></pre> 034 * <p> 035 * Since the counter maintains uniqueness, the name and scopes only purpose is to give 036 * somewhat readable names to help debugging. 037 * <p> 038 * Be warned that the uniqueness is only preserved in the context of a single generator. 039 * Two independent generators with the same name (and scope) can produce identical names. 040 */ 041public final class SymbolGenerator { 042 private static final String FORMAT = "__$$_%s_%d"; 043 private static final String DEFAULT_NAME = "symbol"; 044 private final AtomicLong counter = new AtomicLong(); 045 private final Deque<String> prefixes = new LinkedList<>(); 046 047 public SymbolGenerator(String name) { 048 this.prefixes.addLast(name == null ? DEFAULT_NAME : name); 049 } 050 051 public SymbolGenerator() { 052 this.prefixes.addLast(DEFAULT_NAME); 053 } 054 055 private String name(String localName) { 056 String name = String.join("_", prefixes); 057 if (localName != null && !"".equals(localName)) { 058 name += "_" + localName; 059 } 060 return name; 061 } 062 063 public String next() { 064 return next(null); 065 } 066 067 public String next(String name) { 068 return String.format(FORMAT, name(name), counter.getAndIncrement()); 069 } 070 071 public SymbolGenerator exit() { 072 if (this.prefixes.size() == 1) { 073 return this; 074 } 075 this.prefixes.removeLast(); 076 return this; 077 } 078 079 public SymbolGenerator enter(String scopeName) { 080 this.prefixes.addLast(scopeName); 081 return this; 082 } 083 084}