Skip to content

Instantly share code, notes, and snippets.

@pdemanget
Last active August 29, 2015 14:02
Show Gist options
  • Save pdemanget/6585af289ff8b2c82105 to your computer and use it in GitHub Desktop.
Save pdemanget/6585af289ff8b2c82105 to your computer and use it in GitHub Desktop.
YamlParser
package fr.warlog.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Stack;
/**
* Old school parsing:
* lexer is (ID : - STRING SPACES >)
* grammar:
* s-> arrayObject(0)
* arrayObject(n)-> array(0) | object(0)
* object(0)-> objectAttribute(n)+
* ObjectAttribute(n)-> \n indent(n) id:val(n)
* val(n)-> STRING valSuiv | arrayObject(n+1)
* valSuiv -> >\n indent(n) STRING valSuiv|epsilon
* array(n)->arrayLine(n)+
* arrayLine(n)-> \n indent(n) - val(n+1)
* indent(n)->n* "__"
*/
@SuppressWarnings({"rawtypes","unchecked"})
public class YamlParser {
private static final String INDENTATION = "INDENTATION";
private static int nbSpaces = 1;
private BufferedReader reader;
private Queue<String> queue;
private int lineNumber=0;
private Deque<String> indentation;
public YamlParser(BufferedReader reader) {
super();
this.reader = reader;
this.queue = new LinkedList<String>();
indentation=new LinkedList<String>();
}
public YamlParser(String s){
this(new BufferedReader(new StringReader(s)));
}
private void log(String s){
System.out.println(s);
}
/**
* splits token for (\s*)-?(id:)?string?
* @return
* @throws IOException
*/
private String getCurrent() {
if(queue.isEmpty()){
readOneLine();
}
return queue.peek();
}
private void readOneLine() {
String line;
try {
line = reader.readLine();
lineNumber++;
} catch (IOException e) {
return;
}
if (line == null) return;
int spaces=0;
while(line.charAt(spaces)==' ') spaces++;
//TODO match spaces from a stack
// if(spaces>0)
queue.add(new String(new char[spaces]).replace("\0", " "));
line=line.substring(spaces);
if (line.startsWith("-")){
queue.add("-");
line=line.substring(1).trim();
}
String[] tokens=line.split(":",2);
if(tokens.length==1){
queue.add(line);
}else{
queue.add(tokens[0]);
queue.add(":");
if(tokens[1].length()>0)
queue.add(tokens[1]);
}
queue.add("\n");
}
private String getNthToken(int n){
if(queue.size()<=n)
readOneLine();
if(queue.size()>n)
return ((List<String>)queue).get(n);
return null;
}
private String getNext(){
String current = getCurrent();
queue.poll();
return current;
}
private String getNext(String s) {
String current = getCurrent();
if(!current.equals(s)) throw new IllegalArgumentException("Syntax error, expected: "+s+" at line "+lineNumber);
return getNext();
}
public Object parse() {
return arrayObject(0);
}
private Object arrayObject(int i) {
if("-".equals( getNthToken(1))){
return array(i);
}
return object(i);
}
private static boolean isLevel(String spaces, int i){
return spaces != null && spaces.matches("^\\s*$") && spaces.length()/nbSpaces == i;
}
private Object object(int i) {
Map object= new LinkedHashMap();
while(isLevel(getCurrent(),i)){
objectAttribute(i,object);
}
return object;
}
private Object array(int i){
List<Object> array = new ArrayList<>();
while(isLevel(getCurrent(),i)){
arrayLine(i,array);
}
return array;
}
private void arrayLine(int i, List<Object> array) {
getNext();//INDENTATION
getNext("-");
array.add(value(i+1));
}
private void objectAttribute(int i, Map object) {
getNext();//INDENTATION
String key = getNext();
getNext(":");
Object value=value(i);
object.put(key,value);
}
private Object value(int i) {
String value = getCurrent();
if(value.equals("\n")){
getNext("\n");
return arrayObject(i+1);
}else{
getNext();
return valueSuiv(i,value);
}
}
private Object valueSuiv(int i, String value) {
while(getCurrent().equals(">")){
getNext(">");
getNext("\n");
if(i!=0) getNext();//SPACES
while (!getCurrent().equals('\n')){
value+=getNext();
}
}
getNext("\n");
return value;
}
public static void main(String[] args) {
//aa:\n bb:bb\n"
Object parsed = new YamlParser("aa:aa\nbb:bb\nc:\n - 1\n - 2").parse();
System.out.println(parsed);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment