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

498
LINES

< > BotCompany Repo | #1005973 // unstructure (v9, working virtual stack)

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;

abstract sclass unstructure_Receiver {
  abstract void set(O o);
}

// classFinder: func(name) -> class (optional)
static Object unstructure(String text, boolean allDynamic,
  O classFinder) {
  if (text == null) ret null;
  final L<S> tok = javaTokC(text);
  ret unstructure_tok(tok, allDynamic, classFinder);
}

// so text can be freed
static Object unstructure_tempVar(Var<S> text) {
  L<S> tok = javaTokC(text.get());
  text.clear();
  ret unstructure_tok(tok, false, null);
}

static O unstructure_tok(final L<S> tok, final boolean allDynamic, final O classFinder) {
  final boolean debug = unstructure_debug;
  
  class X {
    int i = 0;
    new HashMap<Integer, O> refs;
    new HashMap<Integer, O> tokrefs;
    new HashSet<S> concepts;
    new HashMap<S, Class> classesMap;
    new L<Runnable> stack;

    void parse(final unstructure_Receiver out) {
      S t = tok.get(i);
      
      int refID = 0;
      if (structure_isMarker(t, 0, l(t))) {
        refID = parseInt(t.substring(1));
        i++;
      }
      final int _refID = refID;
      
      // if (debug) print("parse: " + quote(t));
      
      final int tokIndex = i;  
      parse_inner(refID, tokIndex, new unstructure_Receiver {
        void set(O o) {
          if (_refID != 0)
            refs.put(_refID, o);
          if (o != null)
            tokrefs.put(tokIndex, o);
          out.set(o);
        }
      });
    }
    
    void parse_inner(int refID, int tokIndex, final unstructure_Receiver out) {
      S t = tok.get(i);
      
      // if (debug) print("parse_inner: " + quote(t));
      
      Class c = classesMap.get(t);
      if (c == null) {
        if (t.startsWith("\"")) {
          S s = internIfLongerThan(unquote(tok.get(i)), structure_internStringsLongerThan);
          i++;
          out.set(s); ret;
        }
        
        if (t.startsWith("'")) {
          out.set(unquoteCharacter(tok.get(i++))); ret;
        }
        if (t.equals("bigint")) {
          out.set(parseBigInt()); ret;
        }
        if (t.equals("d")) {
          out.set(parseDouble()); ret;
        }
        if (t.equals("fl")) {
          out.set(parseFloat()); ret;
        }
        if (t.equals("false") || t.equals("f")) {
          i++; out.set(false); ret;
        }
        if (t.equals("true") || t.equals("t")) {
          i++; out.set(true); ret;
        }
        if (t.equals("-")) {
          t = tok.get(i+1);
          i += 2;
          out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret;
        }
        if (isInteger(t) || isLongConstant(t)) {
          i++;
          //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
          if (isLongConstant(t)) {
            out.set(parseLong(t)); ret;
          }
          long l = parseLong(t);
          bool isInt = l == (int) l;
          if (debug)
            print("l=" + l + ", isInt: " + isInt);
          out.set(isInt ? (O) new Integer((int) l) : (O) new Long(l)); ret;
        }
        
        if (t.equals("File")) {
          File f = new File(unquote(tok.get(i+1)));
          i += 2;
          out.set(f); ret;
        }
        
        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);
          out.set(o); ret;
        }
      
        if (t.startsWith("t") && isInteger(t.substring(1))) {
          i++;
          int ref = Integer.parseInt(t.substring(1));
          O o = tokrefs.get(ref);
          if (o == null)
            print("Warning: unsatisfied token reference " + ref);
          out.set(o); ret;
        }
        
        if (t.equals("hashset")) {
          parseHashSet(out); ret;
        }
        if (t.equals("treeset")) {
          parseTreeSet(out); ret;
        }
        if (eqOneOf(t, "hashmap", "hm")) {
          parseHashMap(out); ret;
        }
        if (t.equals("{")) {
          parseMap(out); ret;
        }
        if (t.equals("[")) {
          parseList(out); ret;
        }
        if (t.equals("bitset")) {
          parseBitSet(out); ret;
        }
        if (t.equals("array") || t.equals("intarray")) {
          parseArray(out); ret;
        }
        if (t.equals("ba")) {
          S hex = unquote(tok.get(i+1));
          i += 2;
          out.set(hexToBytes(hex)); ret;
        }
        if (t.equals("boolarray")) {
          int n = parseInt(tok.get(i+1));
          S hex = unquote(tok.get(i+2));
          i += 6;
          out.set(boolArrayFromBytes(hexToBytes(hex), n)); ret;
        }
        if (t.equals("class")) {
          out.set(parseClass()); ret;
        }
        if (t.equals("l")) {
          parseLisp(out); ret;
        }
        if (t.equals("null")) {
          i++; out.set(null); ret;
        }
        
        if (eq(t, "c")) {
          consume("c");
          t = tok.get(i);
          assertTrue(isJavaIdentifier(t));
          concepts.add(t);
        }
      }
      
      if (c == null && !isJavaIdentifier(t))
        throw new RuntimeException("Unknown token " + (i+1) + ": " + t);

      // any other class name
      if (c == null) {
        // First, find class
        if (allDynamic) c = null;
        else if (classFinder != null)
          c = (Class) callF(classFinder, t);
        else
          c = findClass(t);
        if (c != null)
          classesMap.put(t, c);
      }
          
      // 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));
      }
      
      // Save in references list early because contents of object
      // might link back to main object
      
      if (refID != 0)
        refs.put(refID, o != null ? o : dO);
      tokrefs.put(tokIndex, o != null ? o : dO);
      
      // NOW parse the fields!
      
      final new HashMap<S, O> fields;
      final O _o = o;
      final DynamicObject _dO = dO;
      if (i < tok.size() && tok.get(i).equals("(")) {
        consume("(");
        stack.add(r {
          if (tok.get(i).equals(")")) {
            consume(")");
            objRead(_o, _dO, fields);
            out.set(_o != null ? _o : _dO);
          } else {
            final S key = unquote(tok.get(i++));
            consume("=");
            stack.add(this);
            parse(new unstructure_Receiver {
              void set(O value) {
                fields.put(key, value);
                if (tok.get(i).equals(",")) i++;
              }
            });
          }
        });
      } else
        objRead(o, dO, fields);
    }
    
    void objRead(O o, DynamicObject dO, Map<S, O> fields) {
      if (o != null)
        if (dO != null) {
          if (debug)
            printStructure("setOptAllDyn", fields);
          setOptAllDyn(dO, fields);
        } else
          setOptAll(o, fields);
      else for (S field : keys(fields))
        dO.fieldValues.put(field.intern(), fields.get(field));

      if (o != null)
        pcallOpt_noArgs(o, "_doneLoading");
    }
    
    void parseSet(final Set set, final unstructure_Receiver out) {
      parseList(new unstructure_Receiver {
        void set(O o) {
          set.addAll((L) o);
          out.set(set);
        }
      });
    }
    
    void parseLisp(final unstructure_Receiver out) {
      consume("l");
      consume("(");
      final new ArrayList list;
      stack.add(r {
        if (tok.get(i).equals(")")) {
          consume(")");
          out.set(newObject("main$Lisp", (S) list.get(0), subList(list, 1)));
        } else {
          stack.add(this);
          parse(new unstructure_Receiver {
            void set(O o) {
              list.add(o);
              if (tok.get(i).equals(",")) i++;
            }
          });
        }
      });
    }
    
    void parseBitSet(final unstructure_Receiver out) {
      consume("bitset");
      consume("{");
      final new BitSet bs;
      stack.add(r {
        if (tok.get(i).equals("}")) {
          consume("}");
          out.set(bs);
        } else {
          stack.add(this);
          parse(new unstructure_Receiver {
            void set(O o) {
              bs.set((Integer) o);
              if (tok.get(i).equals(",")) i++;
            }
          });
        }
      });
    }
    
    void parseList(final unstructure_Receiver out) {
      consume("[");
      final new ArrayList list;
      stack.add(r {
        if (tok.get(i).equals("]")) {
          consume("]");
          out.set(list);
        } else {
          stack.add(this);
          parse(new unstructure_Receiver {
            void set(O o) {
              //if (debug) print("List element type: " + getClassName(o));
              list.add(o);
              if (tok.get(i).equals(",")) i++;
            }
          });
        }
      });
    }
    
    void parseArray(final unstructure_Receiver out) {
      final S type = tok.get(i);
      i++;
      consume("{");
      final List list = new ArrayList;
      
      stack.add(r {
        if (tok.get(i).equals("}")) {
          consume("}");
          out.set(type.equals("intarray") ? toIntArray(list) : list.toArray());
        } else {
          stack.add(this);
          parse(new unstructure_Receiver {
            void set(O o) {
              list.add(o);
              if (tok.get(i).equals(",")) i++;
            }
          });
        }
      });
    }
    
    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);
    }
    
    void parseHashMap(unstructure_Receiver out) {
      i++;
      parseMap(new HashMap, out);
    }
    
    void parseHashSet(unstructure_Receiver out) {
      consume("hashset");
      parseSet(new HashSet, out);
    }
    
    void parseTreeSet(unstructure_Receiver out) {
      consume("treeset");
      parseSet(new TreeSet, out);
    }
    
    void parseMap(unstructure_Receiver out) {
      parseMap(new TreeMap, out);
    }
    
    void parseMap(final Map map, final unstructure_Receiver out) {
      consume("{");
      stack.add(new Runnable {
        bool v;
        O key;
        
        public void run() { 
          if (v) {
            v = false;
            stack.add(this);
            consume("=");
            parse(new unstructure_Receiver {
              void set(O value) {
                map.put(key, value);
                if (debug)
                  print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(tok.get(i)));
                if (tok.get(i).equals(",")) i++;
              }
            });
          } else {
            if (tok.get(i).equals("}")) {
              consume("}");
              out.set(map);
            } else {
              v = true;
              stack.add(this);
              parse(new unstructure_Receiver {
                void set(O o) {
                  key = o;
                }
              });
            }
          } // if v else
        } // run()
      });
    }
    
    /*void parseSub(unstructure_Receiver out) {
      int n = l(stack);
      parse(out);
      while (l(stack) > n)
        stack
    }*/
    
    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++;
    }
    
    void parse_x(unstructure_Receiver out) {
      parse(out);
      while (nempty(stack))
        popLast(stack).run();
    }
  }
  
  final new Var v;
  new X().parse_x(new unstructure_Receiver {
    void set(O o) { v.set(o); }
  });
  ret v.get();
}

static boolean unstructure_debug;

Author comment

Began life as a copy of #1005658

download  show line numbers  debug dex  old transpilations   

Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1005973
Snippet name: unstructure (v9, working virtual stack)
Eternal ID of this version: #1005973/1
Text MD5: 412a9ac718f792869377c92067832700
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-12-13 18:20:20
Source code size: 13925 bytes / 498 lines
Pitched / IR pitched: No / No
Views / Downloads: 598 / 595
Referenced in: #1005975 - unstructure (v10, from stream, dev.)