All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dyuproject.fbsgen.compiler.Writable Maven / Gradle / Ivy

//========================================================================
//Copyright 2013 David Yu
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at 
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================

package com.dyuproject.fbsgen.compiler;

import static com.dyuproject.fbsgen.compiler.CompilerUtil.$int;
import static com.dyuproject.fbsgen.compiler.TemplatedCodeGenerator.FORMAT_DELIM;
import static com.dyuproject.fbsgen.compiler.TemplatedCodeGenerator.chainedFormat;
import static com.dyuproject.fbsgen.compiler.TemplatedCodeGenerator.format;
import com.dyuproject.fbsgen.parser.Annotation;
import com.dyuproject.fbsgen.parser.AnnotationContainer;
import com.dyuproject.fbsgen.parser.HasName;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Allows string templates to write/modify the members of this class.
 * 
 * @author David Yu
 * @created Aug 10, 2013
 */
public final class Writable
{
    /**
     * Map used against the procedures of {@link Writable}.
     */
    @SuppressWarnings("serial")
    static final class NewMap extends HashMap {}
    
    static final FakeMap EMPTY = new FakeMap("EMPTY")
    {
        @Override
        public Object get(Object arg0)
        {
            return "";
        }
    };
    
    public Object key = null, val = null;
    
    public int number = 0;
    
    public final StringBuilder builder = new StringBuilder(),
            builder2 = new StringBuilder();
    
    public final ArrayList list = new ArrayList();
    
    public final LinkedHashMap map = new LinkedHashMap();
    
    int argCount = 0, argFalseCount = 0;
    
    /**
     * Cast the argument as integer.
     * 
     *   «writable.as_int.("1")»
     * 
*/ public final FakeMap as_int = new FakeMap("as_int") { public Object get(Object entry) { return entry instanceof Integer ? entry : Integer.parseInt(String.valueOf(entry)); } }; /** * Appends the arg to the string builder. *
     *   «writable.b.("a").b.("b").str»
     * 
*/ public final FakeMap b = new FakeMap("b") { public Object get(Object arg) { if (arg != null) builder.append(arg.toString()); return Writable.this; } }; /** * Appends the arg to the string builder. *
     *   «writable.b2.("a").b2.("b").str2»
     * 
*/ public final FakeMap b2 = new FakeMap("b2") { public Object get(Object arg) { if (arg != null) builder2.append(arg.toString()); return Writable.this; } }; /** * Appends the arg to the string builder if val is truthy. *
     *   «writable.v.(true).b.("a").bvt.("b").»
     * 
*/ public final FakeMap bvt = new FakeMap("bvt") { public Object get(Object arg) { if (arg != null && val != null && !Boolean.FALSE.equals(val)) builder.append(arg.toString()); return Writable.this; } }; /** * Appends the arg to the string builder if val is not truthy. *
     *   «writable.v.(false).b.("a").bvf.("b").»
     * 
*/ public final FakeMap bvf = new FakeMap("bvf") { public Object get(Object arg) { if (arg != null && (val == null || Boolean.FALSE.equals(val))) builder.append(arg.toString()); return Writable.this; } }; /** * Get the element at index from list if k was set. Otherwise, the arg will * be read as 'key.0' where 'key' is used to retrieve the list from the map * and '0' is the index. *
     *   «writable.k.("0").get.(message.fields)»
     *   «writable.k.(1).get.(message.fields)»
     *   «(writable.get.("key.0"))»
     * 
*/ public final FakeMap get = new FakeMap("get") { @SuppressWarnings("unchecked") public Object get(Object entry) { if (key != null) { int index = key instanceof Number ? ((Number)key).intValue() : Integer.parseInt( key.toString()); key = null; return entry instanceof List ? $get(index, (List)entry) : null; } if (entry == null) return null; // key.0 String param = entry.toString(); int dot = param.indexOf('.'); if (dot == -1) return null; int index = Integer.parseInt(param.substring(dot+1)); String key = param.substring(0, dot); Object val = map.get(key); return val instanceof List ? $get(index, (List)val) : null; } }; /** * Get the element at index from list. *
     *   «writable.n.(1).get_from.(message.fields)»
     * 
*/ public final FakeMap get_from = new FakeMap("get_from") { @SuppressWarnings("unchecked") public Object get(Object entry) { return $get(number, (List)entry); } }; /** * Get the element at index (one-based, so we deduct 1) from list. *
     *   «writable.n.(1).get_from1.(message.fields)»
     * 
*/ public final FakeMap get_from1 = new FakeMap("get_from1") { @SuppressWarnings("unchecked") public Object get(Object entry) { return $get(number - 1, (List)entry); } }; static Object $get(int index, List list) { if (index < 0 && (index = list.size() + index) < 0) return null; return list.size() > index ? list.get(index) : null; } /** * Sets the first element of the list. *
     *   «writable.set0.("foo")»
     * 
*/ public final FakeMap set0 = new FakeMap("set0") { public Object get(Object entry) { if (list.isEmpty()) list.add(entry); else list.set(0, entry); return Writable.this; } }; /** * Returns the key if arg is null. *
     *   «writable.k.(field.name).kunless.(map.("field"))»
     * 
*/ public final FakeMap kunless = new FakeMap("kunless") { public Object get(Object arg) { Object k = key; key = null; return arg == null ? k : arg; } }; /** * Returns the val if arg is null. *
     *   «writable.v.(field.name).vunless.(map.("field"))»
     * 
*/ public final FakeMap vunless = new FakeMap("vunless") { public Object get(Object arg) { return arg == null ? val : arg; } }; /** * Returns the arg if val is null. *
     *   «writable.v.(message).velse.(foo)»
     * 
*/ public final FakeMap velse = new FakeMap("velse") { public Object get(Object arg) { return val == null ? arg : val; } }; /** * Formats the val with the arg. *
     *   «writable.v.(message.name).vfmt.("UC")»
     * 
*/ public final FakeMap vfmt = new FakeMap("vfmt") { public Object get(Object entry) { if (val == null) throw new RuntimeException("Misuse of chain (val must not be null)."); String formatName = entry.toString(), str = val.toString(); String[] formats = FORMAT_DELIM.split(formatName); return formats.length == 0 ? format(str, formatName) : chainedFormat(str, formats); } }; /** * Compares the number against the arg. *
     *   «writable.n.(0).eq.(0)»
     * 
*/ public final FakeMap eq = new FakeMap("eq") { public Object get(Object arg) { if (arg instanceof String) { String str = (String)arg; return !str.isEmpty() && number == Integer.parseInt(str) ? Boolean.TRUE : Boolean.FALSE; } return arg instanceof Integer && number == ((Integer)arg).intValue() ? Boolean.TRUE : Boolean.FALSE; } }; /** * Adds the number with the arg. *
     *   «writable.n.(0).plus.(1)»
     * 
*/ public final FakeMap plus = new FakeMap("plus") { public Object get(Object entry) { return number + $int(entry); } }; /** * Subtracts the number with the arg. *
     *   «writable.n.(0).minus.(1)»
     * 
*/ public final FakeMap minus = new FakeMap("minus") { public Object get(Object entry) { return number - $int(entry); } }; /** * Divides the number with the arg. *
     *   «writable.n.(4).div.(2)»
     * 
*/ public final FakeMap div = new FakeMap("div") { public Object get(Object entry) { return number / $int(entry); } }; /** * Multiplies the number with the arg. *
     *   «writable.n.(4).mul.(2)»
     * 
*/ public final FakeMap mul = new FakeMap("mul") { public Object get(Object entry) { return number * $int(entry); } }; /** * The operator "<<" applied to the number with the arg. *
     *   «writable.n.("1").lshift.("2")»
     * 
*/ public final FakeMap lshift = new FakeMap("lshift") { public Object get(Object arg) { return number << $int(arg); } }; /** * The operator "<<" applied to the number with the arg. *
     *   «writable.n.("2").rshift.("1")»
     * 
*/ public final FakeMap rshift = new FakeMap("rshift") { public Object get(Object arg) { return number >>> $int(arg); } }; /** * Compares the number against the arg. *
     *   «writable.n.(0).gt.(0)»
     * 
*/ public final FakeMap gt = new FakeMap("gt") { public Object get(Object entry) { return number > $int(entry); } }; /** * Compares the number against the arg. *
     *   «writable.n.(0).gte.(0)»
     * 
*/ public final FakeMap gte = new FakeMap("gte") { public Object get(Object entry) { return number >= $int(entry); } }; /** * Compares the number against the arg. *
     *   «writable.n.(0).lt.(0)»
     * 
*/ public final FakeMap lt = new FakeMap("lt") { public Object get(Object entry) { return number < $int(entry); } }; /** * Compares the number against the arg. *
     *   «writable.n.(0).lte.(0)»
     * 
*/ public final FakeMap lte = new FakeMap("lte") { public Object get(Object entry) { return number <= $int(entry); } }; /** * Compares the value against the arg. *
     *   «writable.v.("foo").veq.("foo")»
     * 
*/ public final FakeMap veq = new FakeMap("veq") { public Object get(Object arg) { if (arg == null && val == null) return true; else return arg != null && arg.equals(val); } }; /** * Compares the key against the arg. *
     *   «writable.k.("foo").keq.("foo")»
     * 
*/ public final FakeMap keq = new FakeMap("keq") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); Boolean ret = key.equals(arg) ? Boolean.TRUE : Boolean.FALSE; key = null; return ret; } }; /** * Compares the key against the arg via identify. *
     *   «writable.k.(foo).ksame.(bar)»
     * 
*/ public final FakeMap ksame = new FakeMap("ksame") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); Boolean ret = key == arg ? Boolean.TRUE : Boolean.FALSE; key = null; return ret; } }; /** * Removes a prefix of the key based on the arg. *
     *   «writable.k.("foo").ksubstr.("fo")»
     * 
*/ public final FakeMap ksubstr = new FakeMap("ksubstr") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); final String k = key.toString(); key = null; if (arg == null) return k; if (arg instanceof Integer) { int i = ((Integer)arg).intValue(); return i < 0 ? k.substring(0, k.length()+i) : k.substring(0, i); } final String sub = arg.toString(); return k.startsWith(sub) ? k.substring(sub.length()) : k; } }; /** * Appends the current key with the arg. *
     *   «writable.k.("foo").kappend.("bar")»
     * 
*/ public final FakeMap kappend = new FakeMap("kappend") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); final String k = key.toString(); key = null; if (arg == null) return k; return k + arg.toString(); } }; /** * Appends the current key with val if arg is true. *
     *   «writable.k.("foo").v.(".bar").kappendv.(true)»
     * 
*/ public final FakeMap kappendv = new FakeMap("kappendv") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); final String k = key.toString(); key = null; if (arg == null || Boolean.FALSE.equals(arg)) return k; return k + val.toString(); } }; /** * Prepends the current key with the arg. *
     *   «writable.k.("foo").kprepend.("bar")»
     * 
*/ public final FakeMap kprepend = new FakeMap("kprepend") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); final String k = key.toString(); key = null; if (arg == null) return k; return arg.toString() + k; } }; /** * Prepends the current key with val if arg is true. *
     *   «writable.v.("foo.").k.("bar").kprependv.(true)»
     * 
*/ public final FakeMap kprependv = new FakeMap("kprependv") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); final String k = key.toString(); key = null; if (arg == null || Boolean.FALSE.equals(arg)) return k; return val.toString() + k; } }; /** * Formats the current key with arg as the format. *
     *   «writable.k.("foo").kfmt.("bar")»
     * 
*/ public final FakeMap kfmt = new FakeMap("kfmt") { public Object get(Object arg) { if (key == null) throw new RuntimeException("Misuse of chain."); final String k = key.toString(); key = null; if (arg == null) return k; String formatName = arg.toString(); String[] formats = FORMAT_DELIM.split(formatName); return formats.length == 0 ? format(k, formatName) : chainedFormat(k, formats); } }; /** * Returns true if the key is found in the arg. *
     *   «writable.k.("foo").kin.("hellofooworld")»
     *   «writable.k.("foo").kin.(map_or_annotation)»
     * 
*/ public final FakeMap kin = new FakeMap("kin") { public Object get(Object entry) { if (key == null) throw new RuntimeException("Misuse of chain."); final String k = key.toString(); key = null; if (entry == null) return Boolean.FALSE; if (entry instanceof Annotation) return ((Annotation)entry).getP().get(k); if (entry instanceof Map) return ((Map)entry).get(k); return -1 != entry.toString().indexOf(k); } }; /** * Returns true if the key starts with the arg. *
     *   «writable.k.("foo").ksw.("foo")»
     * 
*/ public final FakeMap ksw = new FakeMap("ksw") { public Object get(Object entry) { if (key == null) throw new RuntimeException("Misuse of chain."); Boolean ret = entry != null && key.toString().startsWith(entry.toString()) ? Boolean.TRUE : Boolean.FALSE; key = null; return ret; } }; /** * Returns true if the key ends with the arg. *
     *   «writable.k.("foo").kew.("foo")»
     * 
*/ public final FakeMap kew = new FakeMap("kew") { public Object get(Object entry) { if (key == null) throw new RuntimeException("Misuse of chain."); Boolean ret = entry != null && key.toString().endsWith(entry.toString()) ? Boolean.TRUE : Boolean.FALSE; key = null; return ret; } }; /** * Returns true if {@link #number} & arg is not zero. *
     *   «writable.n.("5").intersect.("1")»
     * 
*/ public final FakeMap intersect = new FakeMap("intersect") { public Object get(Object arg) { return 0 != (number & $int(arg)) ? Boolean.TRUE : Boolean.FALSE; } }; /** * The operator "&=" applied to the number with the arg. *
     *   «writable.n.("5").and.("7")»
     * 
*/ public final FakeMap and = new FakeMap("and") { public Object get(Object arg) { number &= $int(arg); return Writable.this; } }; /** * The operator "|=" applied to the number with the arg. *
     *   «writable.n.("5").or.("7")»
     * 
*/ public final FakeMap or = new FakeMap("or") { public Object get(Object arg) { number |= $int(arg); return Writable.this; } }; /** * The operator "^=" applied to the number with the arg. *
     *   «writable.n.("5").xor.("7")»
     * 
*/ public final FakeMap xor = new FakeMap("xor") { public Object get(Object arg) { number ^= $int(arg); return Writable.this; } }; /** * Sets the number. *
     *   «(writable.setnumber.(field.number))»
     * 
*/ public final FakeMap setnumber = new FakeMap("setnumber") { public Object get(Object arg) { if (arg instanceof Map) number = ((Map)arg).size(); else if (arg instanceof Collection) number = ((Collection)arg).size(); else number = $int(arg); return Writable.this; } }; /** * Increments the number. *
     *   «(writable.incby.("2"))»
     * 
*/ public final FakeMap incby = new FakeMap("incby") { public Object get(Object arg) { number += $int(arg); return Writable.this; } }; /** * Decrements the number. *
     *   «(writable.decby.("2")»
     * 
*/ public final FakeMap decby = new FakeMap("decby") { public Object get(Object arg) { number -= $int(arg); return Writable.this; } }; /** * Removes an item from the map. *
     *   «(writable.map_remove.("foo"))»
     * 
*/ public final FakeMap map_remove = new FakeMap("map_remove") { public Object get(Object entry) { map.remove(entry); return Writable.this; } }; /** * Removes an item from the list. *
     *   «(writable.list_remove.(writable.number))»
     * 
*/ public final FakeMap list_remove = new FakeMap("list_remove") { public Object get(Object entry) { if (entry instanceof Integer) list.remove(((Integer)entry).intValue()); else list.remove(entry); return Writable.this; } }; /** * The arg is evaluated. *
     *   «if(writable.arg.({«message.o.("foo")»}).arg(message.o.({«message.o.("bar")»})).andArgs)»
     * 
*/ public final FakeMap arg = new FakeMap("arg") { public Object get(Object arg) { argCount++; if (arg.toString().isEmpty()) argFalseCount++; return Writable.this; } }; /** * The arg is evaluated. *
     *   «if(writable.notarg.({«message.o.("foo")»}).notarg(message.o.({«message.o.("bar")»})).andArgs)»
     * 
*/ public final FakeMap notarg = new FakeMap("notarg") { public Object get(Object arg) { argCount++; if (!arg.toString().isEmpty()) argFalseCount++; return Writable.this; } }; /** * Checks if the key is inside the arg. *
     *   «if(writable.k.("foo").in.(message.o).k.("bar").in.(message.o).andArgs)»
     * 
*/ public final FakeMap in = new FakeMap("in") { public Object get(Object map) { final Object k = key; if (k == null) throw new RuntimeException("Misuse of chain."); key = null; argCount++; if (!((Map)map).containsKey(k)) argFalseCount++; return Writable.this; } }; /** * Checks if the key is not inside the arg. *
     *   «if(writable.k.("foo").notin.(message.o).k.("bar").notin.(message.o).andArgs)»
     * 
*/ public final FakeMap notin = new FakeMap("notin") { public Object get(Object map) { final Object k = key; if (k == null) throw new RuntimeException("Misuse of chain."); key = null; argCount++; if (((Map)map).containsKey(k)) argFalseCount++; return Writable.this; } }; /** * Sets the key. *
     *   «writable.setkey.("key").put.("value")».
     * 
     * You can also chain it continuously as long as its the order is key->value.
     *   «writable.k.("k1").put.("v1").k.("k2").put.("v2")».
     * 
*/ public final FakeMap setkey = new FakeMap("setkey") { public Object get(Object newKey) { if (key != null) throw new RuntimeException("Misuse of chain."); if (newKey == null) throw new RuntimeException("Null key."); key = newKey; return Writable.this; } }; /** * Sets the value. *
     *   «writable.setval.("foo")»
     *   or
     *   «writable.v.("foo")».
     * 
*/ public final FakeMap setval = new FakeMap("setval") { public Object get(Object arg) { val = arg; return Writable.this; } }; /** * Adds to the list. *
     *   «writable.add.(field)»
     * 
*/ public final FakeMap add = new FakeMap("add") { public Object get(Object entry) { list.add(entry); return Writable.this; } }; /** * Adds all the elements to the list. * * Called from stringtemplate via «(writable.addall.(field))» */ public final FakeMap addall = new FakeMap("addall") { @SuppressWarnings("unchecked") public Object get(Object entry) { list.addAll((Collection)entry); return Writable.this; } }; /** * Adds to the list and puts to the map. *
     *   «writable.k.(field.name).add_and_put.(field)»
     * 
*/ public final FakeMap add_and_put = new FakeMap("add_and_put") { public Object get(Object entry) { if (key != null) { $add_and_put(key, entry); key = null; } else if (entry != null) $add_and_put(entry.toString(), entry); return Writable.this; } }; void $add_and_put(Object key, Object value) { list.add(value); map.put(key, value); } /** * Adds to the list and puts only the unique entry to the map. *
     *   «writable.k.(field.name).add_and_uput.(field)»
     * 
*/ public final FakeMap add_and_uput = new FakeMap("add_and_uput") { public Object get(Object entry) { if (key != null) { $add_and_uput(key, entry); key = null; } else if (entry != null) $add_and_uput(entry.toString(), entry); return Writable.this; } }; void $add_and_uput(Object key, Object value) { list.add(value); if (!map.containsKey(key)) { // unique, map.put(key, value); } } /** * Returns a new map filled with the csv arg. *
     *   «(writable.k.("foo").inc_map_value.(field))»
     * 
*/ public final FakeMap new_map_from_csv = new FakeMap("new_map_from_csv") { public Object get(Object arg) { if (key != null) throw new RuntimeException("Misuse of chain."); if (arg == null) return Collections.EMPTY_MAP; return CompilerUtil.fill(new LinkedHashMap(), arg.toString()); } }; /** * Increments the value with the arg. *
     *   «(writable.k.("foo").inc_map_value.(field))»
     * 
*/ public final FakeMap inc_map_value = new FakeMap("inc_map_value") { public Object get(Object arg) { final Object k = key; if (k == null) throw new RuntimeException("Misuse of chain."); key = null; Object value = map.get(k); if (value == null) map.put(k, arg); else map.put(k, ((Integer)value).intValue() + $int(arg)); return Writable.this; } }; /** * Clear the map or list. *
     *   «(writable.clear.(map_or_list))»
     * 
*/ public final FakeMap clear = new FakeMap("clear") { public Object get(Object entry) { if (key != null || entry == null) throw new RuntimeException("Misuse of chain."); if (entry instanceof String || entry instanceof HasName) entry = map.get(entry.toString()); if (entry instanceof Map) ((Map)entry).clear(); else if (entry instanceof Collection) ((Collection)entry).clear(); return Writable.this; } }; /** * Puts the entry into the map. *
     *   «(writable.k.("foo").put.(field))»
     * 
*/ public final FakeMap put = new FakeMap("put") { public Object get(Object entry) { if (key != null) { map.put(key, entry); key = null; } else if (entry != null) map.put(entry.toString(), entry); return Writable.this; } }; /** * Puts only unique entries into the map. *
     *   «(writable.k.(field.name).uput.(field))»
     * 
*/ public final FakeMap uput = new FakeMap("uput") { public Object get(Object entry) { if (entry instanceof NewMap) { final Object k = key; if (k == null) throw new RuntimeException("Misuse of chain."); key = null; // returns true if unique. return $uput(k, k, (NewMap)entry); } if (key != null) { $uput(key, entry, map); key = null; } else if (entry != null) $uput(entry.toString(), entry, map); return Writable.this; } }; boolean $uput(Object key, Object value, Map map) { final boolean unique = !map.containsKey(key); if (unique) map.put(key, value); return unique; } /** * Puts only unique entries into the map and added to list. *
     *   «(writable.k.(field.name).uput_and_add.(field))»
     * 
*/ public final FakeMap uput_and_add = new FakeMap("uput_and_add") { public Object get(Object entry) { if (key != null) { $uput_and_add(key, entry); key = null; } else if (entry != null) $uput_and_add(entry.toString(), entry); return Writable.this; } }; void $uput_and_add(Object key, Object value) { if (!map.containsKey(key)) { // unique map.put(key, value); list.add(value); } } /** * The entry will be a list that contains the values that are mapped to the same key. *
     *   «(writable.k.(field.name).putlist.(field))»
     * 
*/ public final FakeMap putlist = new FakeMap("putlist") { public Object get(Object entry) { if (key != null) { $putlist(key, entry); key = null; } else if (entry != null) $putlist(entry.toString(), entry); return Writable.this; } }; @SuppressWarnings("unchecked") void $putlist(Object key, Object value) { ArrayList existing = (ArrayList)map.get(key); if (existing == null) { existing = new ArrayList(); map.put(key, existing); } existing.add(value); } /** * Returns a sublist based on the arg. *
     *   «(writable.sublist.("2"))»
     * 
*/ public final FakeMap sublist = new FakeMap("sublist") { public Object get(Object entry) { if (entry instanceof List) { List l = (List)entry; return number == l.size() ? Collections.EMPTY_LIST : l.subList(number, l.size() - number); } int start = $int(entry); return start == list.size() ? Collections.EMPTY_LIST : list.subList(start, list.size() - start); } }; /** * Returns a sublist based on the arg. *
     *   «(writable.pfxlist.("2"))»
     * 
*/ public final FakeMap pfxlist = new FakeMap("pfxlist") { public Object get(Object entry) { if (entry instanceof List) { List l = (List)entry; return number == l.size() - 1 ? l : l.subList(0, number + 1); } int inclusiveEnd = $int(entry); return inclusiveEnd == list.size() - 1 ? list : list.subList(0, inclusiveEnd + 1); } }; /** * Returns a substring based on the arg. *
     *   «writable.k.("foo").substr.("1")» // returns oo
     * 
*/ public final FakeMap substr = new FakeMap("substr") { public Object get(Object entry) { if (key == null) throw new RuntimeException("Misuse of chain."); String str = key.toString(); key = null; int i = $int(entry); if (i == 0) return str; else if (i < 0) return str.substring(0, str.length() + i); else return str.substring(i); } }; /** * Returns a substring based on the arg. *
     *   «writable.k.("foo").pfxstr.(1)» // returns fo
     * 
*/ public final FakeMap pfxstr = new FakeMap("pfxstr") { public Object get(Object entry) { if (key == null) throw new RuntimeException("Misuse of chain."); String str = key.toString(); key = null; int inclusiveEnd = $int(entry); return inclusiveEnd == str.length() - 1 ? str : str.substring(0, inclusiveEnd + 1); } }; /** * Returns a substring (counting the delimiter) based on the arg. *
     *   «writable.k.("foo__bar__baz").pfxstr.("1")» // returns foo__bar
     * 
*/ public final FakeMap pfxstr__ = new FakeMap("pfxstr__") { public Object get(Object entry) { if (key == null) throw new RuntimeException("Misuse of chain."); String str = key.toString(); key = null; int count = 1 + $int(entry), start = 0; for (int i = 0; i < count; i++) { int idx = str.indexOf("__", start); if (idx == -1) throw new RuntimeException("No __ delimiter on " + str + " starting at " + start); start = idx + 2; } return str.substring(0, start - 2); } }; /** * Returns the {@link Writable} if the entry is unique. *
     *   «writable.k.(field.name).unique.(field).add.(field)» // adds the field if unique
     * 
*/ public final FakeMap unique = new FakeMap("unique") { public Object get(Object entry) { if (key != null) { Object ret = $unique(key, entry); key = null; return ret; } return entry == null ? null : $unique(entry.toString(), entry); } }; Object $unique(Object key, Object value) { if (!map.containsKey(key)) { // unique map.put(key, value); return this; } return EMPTY; } /** * Fill the contents based on the key. *
     *   «writable.k.("@Annotation.fK").fill.(message)»
     *   
     *   Example:
     *   @Annotation (f0 = "foo", f1 = "bar", f2 = "baz")
     *   message Foo {
     *     required string name = 1;
     *   }
     * 
     *   With the example above it is equivalent to:
     *     map.put("f", ["f0", "f1", "f2"])
     *   
     *   If the key is "@Annotation.fV", then it is equivalent to:
     *     map.put("f", ["foo", "bar", "baz"])
     *   
     *   If the key is "@Annotation.fI", then it is equivalent to:
     *     map.put("f", ["foo", "bar", "baz"])
     *     map.put("foo", 0)
     *     map.put("bar", 1)
     *     map.put("baz", 2)
     *   
     * 
*/ public final FakeMap fill = new FakeMap("fill") { public Object get(Object entry) { if (key != null) { Object ret = $fill(key.toString(), entry); key = null; return ret; } // the entry is the key and the target to fill will be the map/list // of this instance. return $fill(entry.toString(), null); } }; Object $fill(String key, Object value) { switch(key.charAt(0)) { case ':': // returns true if the string value contains the key return value instanceof String && -1 != value.toString().indexOf( key.substring(1)) ? Boolean.TRUE : Boolean.FALSE; case '@': // fills the map with entries from the annotation { final AnnotationContainer ac = (AnnotationContainer)value; final int dot = key.indexOf('.'); if (dot == -1) { // copies the contents. Annotation a = ac.getAnnotation(key.substring(1)); if (a != null) map.putAll(a.getP()); return this; } final Annotation a = ac.getAnnotation(key.substring(1, dot)); if (a != null) { //map.putAll(a.getP()); int last = key.length() - 1; switch(key.charAt(last)) { case 'K': { String entry = key.substring(dot+1, last); map.put("$" + entry, AnnotationUtil.fillKeys( new ArrayList(), a, entry)); break; } case 'V': { String entry = key.substring(dot+1, last); map.put("$" + entry, AnnotationUtil.fillList( new ArrayList(), a, entry)); break; } case 'I': { String entry = key.substring(dot+1, last); map.put("#" + entry, AnnotationUtil.fillList( new ArrayList(), a, entry, map)); break; } default: String entry = key.substring(dot+1); map.put("$" + entry, AnnotationUtil.fillMap( new LinkedHashMap(), a, entry)); } } return this; } } throw new RuntimeException("Unsupported fill param: " + key); } /* ================================================== */ /** * Compares the last two elements in the list. * * Called from stringtemplate via «writable.add.(obj1).add.(obj2).same» */ public boolean getSame() { int size = list.size(); return list.get(size-1) == list.get(size-2); } /** * Compares the last two elements in the list (and removes them at the same time). * * Called from stringtemplate via «writable.add.(obj1).add.(obj2).popsame» */ public boolean getPopsame() { int size = list.size(); return list.remove(size-1) == list.remove(size-2); } public int getIncandget() { return ++number; } public int getGetandinc() { return number++; } public int getDecandget() { return --number; } public int getGetanddec() { return number--; } public Writable getInc() { number++; return this; } public Writable getDec() { number--; return this; } /** * Sets the number to zero. */ public Writable getClearnum() { number = 0; return this; } /** * Shorthand to {@link #number}. */ public int getNum() { return number; } /** * Shorthand to {@link #setnumber}. */ public FakeMap getN() { return setnumber; } /** * Gets the list's first element (counterpart to {@link #set0}). */ public Object getGet0() { return list.get(0); } /** * Shorthand to {@link #arg}. */ public FakeMap getA() { return arg; } /** * Shorthand to {@link #notarg}. */ public FakeMap getNa() { return notarg; } /** * Evaluates the args (added to {@link #list}). * * Called from stringtemplate via «if(writable.a.(""+field.o.("1")).a.(""+field.o.("2")).andArgs)» */ public boolean getAndArgs() { final boolean ret = argFalseCount == 0; argCount = 0; argFalseCount = 0; return ret; } /** * Evaluates the args (added to {@link #list}). * * Called from stringtemplate via «if(writable.a.(""+field.o.("1")).a.(""+field.o.("2")).orArgs)» */ public boolean getOrArgs() { final boolean ret = argFalseCount != argCount; argCount = 0; argFalseCount = 0; return ret; } /* ================================================== */ /** * Shorthand to {@link #setkey}. */ public FakeMap getK() { return setkey; } /** * Shorthand to {@link #setval}. */ public FakeMap getV() { return setval; } /** * Returns {@link #builder}'s toString(); */ public String getStr() { String str = builder.toString(); builder.setLength(0); return str; } /** * Returns {@link #builder2}'s toString(); */ public String getStr2() { String str = builder2.toString(); builder2.setLength(0); return str; } public boolean isEmptyList() { return list.isEmpty(); } /** * Returns a copy of the list. */ public ArrayList getCopyList() { return new ArrayList(list); } /** * Clears the list. */ public Writable getClearList() { list.clear(); return this; } public boolean isEmptyMap() { return map.isEmpty(); } /** * Clears the map. */ public Writable getClearMap() { map.clear(); return this; } /** * Clears the map. */ public NewMap getNewMap() { return new NewMap(); } /** * Sets the number to zero and clears the list and map. */ public Writable getClearAll() { key = null; number = 0; list.clear(); map.clear(); builder.setLength(0); builder2.setLength(0); return this; } @SuppressWarnings("rawtypes") public boolean isListAndKeySameSize() { if (key == null) throw new RuntimeException("Misuse of chain."); Object existing = map.get(key); key = null; if (existing instanceof Map) return list.size() == ((Map)existing).size(); return list.size() == ((Collection)existing).size(); } public boolean isListAndMapSameSize() { return list.size() == map.size(); } @SuppressWarnings("unchecked") public T $val(Class clazz) { return val != null && clazz.isAssignableFrom(val.getClass()) ? (T)val : null; } @SuppressWarnings("unchecked") public T $get(Class clazz) { return (T)map.get(clazz.getSimpleName()); } @SuppressWarnings("unchecked") public T $remove(Class clazz) { return (T)map.remove(clazz.getSimpleName()); } /** * Purposely empty. */ public String toString() { return ""; } }