Last active
August 29, 2015 14:02
-
-
Save pdemanget/6585af289ff8b2c82105 to your computer and use it in GitHub Desktop.
YamlParser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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