Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image Upload data

369
LINES

< > BotCompany Repo | #1005597 - unstructure (v5, dev.)

JavaX fragment (include)

static Object unstructure(String text) {
  ret unstructure(text, false);
}

static Object unstructure(String text, final boolean allDynamic) {
  ret unstructure(text, allDynamic, null);
}

static int structure_internStringsLongerThan = 50;

// TODO: backrefs for hashmap{} etc.?
// classFinder: name -> class
static Object unstructure(String text, final boolean allDynamic,
  final O classFinder) {
  if (text == null) ret null;
  final L<S> tok = javaTokC(text);
  final boolean debug = unstructure_debug;
  
  class X {
    int i = 0;
    new HashMap<Integer, O> refs;
    new HashSet<S> concepts;

    Object parse() {
      String t = tok.get(i);
      
      int refID = 0;
      if (t.startsWith("m") && isInteger(t.substring(1))) {
        refID = parseInt(t.substring(1));
        i++;
        t = tok.get(i);
      }
      
      // if (debug) print("parse: " + quote(t));
        
      if (t.startsWith("'")) {
        char c = unquoteCharacter(tok.get(i));
        i++;
        return c;
      }
      if (t.equals("bigint"))
        return parseBigInt();
      if (t.equals("d"))
        return parseDouble();
      if (t.equals("fl"))
        return parseFloat();
      if (t.equals("false") || t.equals("f")) {
        i++; return false;
      }
      if (t.equals("true") || t.equals("t")) {
        i++; return true;
      }
      if (t.equals("-")) {
        t = tok.get(i+1);
        i += 2;
        ret isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t));
      }
      if (isInteger(t) || isLongConstant(t)) {
        i++;
        //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
        if (isLongConstant(t)) ret parseLong(t);
        long l = parseLong(t);
        bool isInt = l == (int) l;
        if (debug)
          print("l=" + l + ", isInt: " + isInt);
        ret isInt ? (O) new Integer((int) l) : (O) new Long(l);
      }
      
      if (t.equals("File")) {
        File f = new File(unquote(tok.get(i+1)));
        i += 2;
        ret f;
      }
      
      if (t.startsWith("r") && isInteger(t.substring(1))) {
        i++;
        int ref = Integer.parseInt(t.substring(1));
        O o = refs.get(ref);
        if (o == null)
          print("Warning: unsatisfied back reference " + ref);
        ret o;
      }
      
      O o = parse_inner(refID);
      if (refID != 0)
        refs.put(refID, o);
      ret o;
    }
    
    // everything that can be backreferenced
    O parse_inner(int refID) {
      String t = tok.get(i);
      
      // if (debug) print("parse_inner: " + quote(t));
        
      if (t.startsWith("\"")) {
        String s = internIfLongerThan(unquote(tok.get(i)), structure_internStringsLongerThan);
        i++;
        return s;
      }
      if (t.equals("hashset"))
        return parseHashSet();
      if (t.equals("treeset"))
        return parseTreeSet();
      if (eqOneOf(t, "hashmap", "hm"))
        return parseHashMap();
      if (t.equals("{"))
        return parseMap();
      if (t.equals("["))
        return parseList();
      if (t.equals("bitset"))
        return parseBitSet();
      if (t.equals("array") || t.equals("intarray"))
        return parseArray();
      if (t.equals("ba")) {
        S hex = unquote(tok.get(i+1));
        i += 2;
        ret hexToBytes(hex);
      }
      if (t.equals("boolarray")) {
        int n = parseInt(tok.get(i+1));
        S hex = unquote(tok.get(i+2));
        i += 6;
        ret boolArrayFromBytes(hexToBytes(hex), n);
      }
      if (t.equals("class"))
        return parseClass();
      if (t.equals("l"))
        return parseLisp();
      if (t.equals("null")) {
        i++; return null;
      }
      
      /* in dev.
      if (!allDynamic && t.equals("run")) {
        S snippetID = unquote(t.get(i+1));
        i += 2;
        run(
      }
      */
      
      bool concept = eq(t, "c");
      if (concept) {
        consume("c");
        t = tok.get(i);
        assertTrue(isJavaIdentifier(t));
        concepts.add(t);
      }

      // any other class name
      if (isJavaIdentifier(t)) {
        // First, find class
        Class c;
        if (allDynamic) c = null;
        else if (classFinder != null)
          c = (Class) callF(classFinder, t);
        else
          c = findClass(t);
          
        // Second, check if it has an outer reference
        i++;
        bool hasOuter = eq(get(tok, i), "(") && eq(get(tok, i+1), "this$1");
        
        DynamicObject dO = null;
        O o = null;
        if (c != null)
          o = hasOuter ? nuStubInnerObject(c) : nuEmptyObject(c);
        else {
          if (concepts.contains(t) && (c = findClass("Concept")) != null)
            o = dO = (DynamicObject) nuEmptyObject(c);
          else
            dO = new DynamicObject;
          dO.className = t;
          if (debug) print("Made dynamic object " + t + " " + shortClassName(dO));
        }
        
        // Now, save in references list.
        
        if (refID != 0)
          refs.put(refID, o != null ? o : dO);
        
        // NOW parse the fields!
        
        new Map<S, O> fields;
        if (i < tok.size() && tok.get(i).equals("(")) {
          consume("(");
          while (!tok.get(i).equals(")")) {
            String key = unquote(tok.get(i));
            i++;
            consume("=");
            Object value = parse();
            fields.put(key, value);
            if (tok.get(i).equals(",")) i++;
          }
          consume(")");
        }

        if (o != null)
          if (dO != null) {
            if (debug)
              printStructure("setOptAllDyn", fields);
            setOptAllDyn(dO, fields);
          } else
            setOptAll(o, fields);
        else
          dO.fieldValues.putAll(fields);

        if (o != null)
          pcallOpt(o, "_doneLoading");
        return o != null ? o : dO;
      }
      throw new RuntimeException("Unknown token " + (i+1) + ": " + t);
    }
    
    Object parseSet(Set set) {
      set.addAll((L) parseList());
      return set;
    }
    
    Object parseLisp() {
      consume("l");
      consume("(");
      new ArrayList list;
      while (!tok.get(i).equals(")")) {
        list.add(parse());
        if (tok.get(i).equals(",")) i++;
      }
      consume(")");
      return newObject("main$Lisp", (S) list.get(0), subList(list, 1));
    }
    
    Object parseBitSet() {
      consume("bitset");
      consume("{");
      new BitSet bs;
      while (!tok.get(i).equals("}")) {
        bs.set((Integer) parse());
        if (tok.get(i).equals(",")) i++;
      }
      consume("}");
      return bs;
    }
    
    Object parseList() {
      consume("[");
      new ArrayList list;
      while (!tok.get(i).equals("]")) {
        O o = parse();
        //if (debug) print("List element type: " + getClassName(o));
        list.add(o);
        if (tok.get(i).equals(",")) i++;
      }
      consume("]");
      return list;
    }
    
    Object parseArray() {
      S type = tok.get(i);
      i++;
      consume("{");
      List list = new ArrayList;
      
      while (!tok.get(i).equals("}")) {
        list.add(parse());
        if (tok.get(i).equals(",")) i++;
      }
      consume("}");
      if (type.equals("intarray"))
        return toIntArray(list);
      return list.toArray();
    }
    
    Object parseClass() {
      consume("class");
      consume("(");
      S name = tok.get(i);
      i++;
      consume(")");
      Class c = allDynamic ? null : findClass(name);
      if (c != null) ret c;
      new DynamicObject dO;
      dO.className = "java.lang.Class";
      dO.fieldValues.put("name", name);
      ret dO;
    }
    
    Object parseBigInt() {
      consume("bigint");
      consume("(");
      S val = tok.get(i);
      i++;
      if (eq(val, "-")) {
        val = "-" + tok.get(i);
        i++;
      }
      consume(")");
      ret new BigInteger(val);
    }
    
    Object parseDouble() {
      consume("d");
      consume("(");
      S val = unquote(tok.get(i));
      i++;
      consume(")");
      ret Double.parseDouble(val);
    }
    
    Object parseFloat() {
      consume("fl");
      S val;
      if (eq(tok.get(i), "(")) {
        consume("(");
        val = unquote(tok.get(i));
        i++;
        consume(")");
      } else {
        val = unquote(tok.get(i));
        i++;
      }
      ret Float.parseFloat(val);
    }
    
    Object parseHashMap() {
      i++;
      return parseMap(new HashMap);
    }
    
    Object parseHashSet() {
      consume("hashset");
      return parseSet(new HashSet);
    }
    
    Object parseTreeSet() {
      consume("treeset");
      return parseSet(new TreeSet);
    }
    
    Object parseMap() {
      return parseMap(new TreeMap);
    }
    
    Object parseMap(Map map) {
      consume("{");
      while (!tok.get(i).equals("}")) {
        O key = parse();
        consume("=");
        Object value = parse();
        map.put(key, value);
        if (tok.get(i).equals(",")) i++;
      }
      consume("}");
      return map;
    }
    
    void consume(String s) {
      if (!tok.get(i).equals(s)) {
        S prevToken = i-1 >= 0 ? tok.get(i-1) : "";
        S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size())));
        fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");
      }
      i++;
    }
  }
  
  return new X().parse();
}

static boolean unstructure_debug;

Author comment

Began life as a copy of #1003039

download  show line numbers  debug dex   

Travelled to 10 computer(s): aoiabmzegqzx, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, tslmcundralx, tvejysmllsmz

No comments. add comment

Snippet ID: #1005597
Snippet name: unstructure (v5, dev.)
Eternal ID of this version: #1005597/1
Text MD5: 8b0b636dc496820710e356863cb0c887
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-11-29 00:04:09
Source code size: 9792 bytes / 369 lines
Pitched / IR pitched: No / No
Views / Downloads: 285 / 244
Referenced in: [show references]