manage nodes generation, add Scanner Loader & Processor classes
This commit is contained in:
parent
7ca8f68987
commit
62419bf3f7
21
main.vala
21
main.vala
|
@ -4,30 +4,19 @@ using Pluie;
|
|||
|
||||
int main (string[] args)
|
||||
{
|
||||
Echo.init(true);
|
||||
Echo.init(false);
|
||||
|
||||
var path = "resources/test.yml";
|
||||
var done = false;
|
||||
|
||||
of.title ("Pluie Yaml Parser", Pluie.Yaml.VERSION, "a-sansara");
|
||||
|
||||
of.action ("Reading file", path);
|
||||
of.echo ();
|
||||
var reader = new Io.Reader (path);
|
||||
while (reader.readable) {
|
||||
of.echo ("%s %s".printf (
|
||||
of.c (ECHO.DATE ).s ("%03d |".printf (reader.line)),
|
||||
of.c (ECHO.OPTION_SEP).s (reader.read ()))
|
||||
);
|
||||
var loader = new Yaml.Loader (path, true, true);
|
||||
if ((done = loader.done)) {
|
||||
Yaml.NodeRoot root = loader.get_nodes ();
|
||||
}
|
||||
of.echo ("EOF");
|
||||
of.state (true);
|
||||
|
||||
of.action ("Parsing file", path);
|
||||
var processor = new Yaml.Processor (path);
|
||||
done = processor.done;
|
||||
|
||||
of.state (done);
|
||||
of.rs (done);
|
||||
of.echo ();
|
||||
return (int) done;
|
||||
|
||||
|
|
|
@ -33,7 +33,10 @@ sources = [
|
|||
'src/vala/Pluie/Io.Reader.vala',
|
||||
'src/vala/Pluie/Io.StreamLineMark.vala',
|
||||
'src/vala/Pluie/Yaml.global.vala',
|
||||
'src/vala/Pluie/Yaml.Document.vala',
|
||||
'src/vala/Pluie/Yaml.Event.vala',
|
||||
'src/vala/Pluie/Yaml.Loader.vala',
|
||||
'src/vala/Pluie/Yaml.Scanner.vala',
|
||||
'src/vala/Pluie/Yaml.Processor.vala',
|
||||
'src/vala/Pluie/Yaml.BaseNode.vala',
|
||||
'src/vala/Pluie/Yaml.Node.vala',
|
||||
|
|
|
@ -12,6 +12,8 @@ public class Pluie.Yaml.BaseNode : Object, Pluie.Yaml.Node
|
|||
*/
|
||||
public string uuid { get; internal set; }
|
||||
|
||||
public string anchor { get; internal set; }
|
||||
|
||||
/**
|
||||
* find mode related to Yaml.FIND_MODE, default is Yaml.FIND_MODE.SQUARE_BRACKETS
|
||||
*/
|
||||
|
@ -75,6 +77,23 @@ public class Pluie.Yaml.BaseNode : Object, Pluie.Yaml.Node
|
|||
this.uuid = Yaml.uuid ();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected virtual void set_anchor_id (string id)
|
||||
{
|
||||
this.anchor = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* clone current node
|
||||
* @param the name of clone
|
||||
*/
|
||||
public virtual Yaml.Node clone_node (string? name = null)
|
||||
{
|
||||
return new BaseNode.standard (this.parent, this.indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* stuff on changing parent node
|
||||
* @param child the childto add
|
||||
|
@ -172,17 +191,17 @@ public class Pluie.Yaml.BaseNode : Object, Pluie.Yaml.Node
|
|||
public string to_string (bool withIndent = true)
|
||||
{
|
||||
|
||||
return "%s%s%s%s%s%s%s%s".printf (
|
||||
return "%s%s%s%s%s%s%s".printf (
|
||||
this.node_type.is_root () ? "" : of.s_indent ((int8) (withIndent ? this.indent : 0)),
|
||||
of.c (ECHO.OPTION).s ("<"),
|
||||
of.c (ECHO.OPTION_SEP).s (this.node_type.infos ()),
|
||||
this.name != null ? " %s".printf (this.name)
|
||||
: (this.node_type.is_scallar () ? " %s".printf (this.data) : ""),
|
||||
: (this.node_type.is_scalar () ? " %s".printf (this.data) : ""),
|
||||
"[%x]".printf (this.ref_count),
|
||||
this.parent == null ? "" : this.parent.name+"|"+this.indent.to_string(),
|
||||
//~ " (%d) ".printf (this.indent),
|
||||
of.c (ECHO.OPTION).s (">"),
|
||||
of.c (ECHO.DATE).s (" %s".printf(this.uuid))
|
||||
of.c (ECHO.OPTION).s (">")/*,
|
||||
of.c (ECHO.DATE).s (" %s".printf(this.uuid))*/
|
||||
);
|
||||
}
|
||||
|
||||
|
|
20
src/vala/Pluie/Yaml.Document.vala
Normal file
20
src/vala/Pluie/Yaml.Document.vala
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Pluie;
|
||||
|
||||
/**
|
||||
* a class representing a single/pair mapping node
|
||||
*/
|
||||
public class Pluie.Yaml.Document : Yaml.NodeMap
|
||||
{
|
||||
/**
|
||||
* construct a single/pair mapping node
|
||||
* @param parent the parent node
|
||||
* @param indent the current indentation in node representation string
|
||||
* @param name the current name (key) of sequence node
|
||||
* @param data the current scalar data
|
||||
*/
|
||||
public Document (Yaml.Node? parent = null, int indent = 0, string? name = null, string? data = null)
|
||||
{
|
||||
this.standard (null, -4, NODE_TYPE.ROOT);
|
||||
this.name = "PluieYamlRootNode";
|
||||
}
|
||||
}
|
63
src/vala/Pluie/Yaml.Loader.vala
Normal file
63
src/vala/Pluie/Yaml.Loader.vala
Normal file
|
@ -0,0 +1,63 @@
|
|||
using GLib;
|
||||
using Gee;
|
||||
using Pluie;
|
||||
|
||||
/**
|
||||
* a tiny Yaml Parser whose purpose is not to comply with all yaml specifications but to parse yaml configuration files
|
||||
* todo improve description of what is expected
|
||||
*/
|
||||
public class Pluie.Yaml.Loader
|
||||
{
|
||||
/**
|
||||
* Scanner
|
||||
*/
|
||||
Yaml.Scanner scanner { public get; internal set; }
|
||||
|
||||
public bool done { get; internal set; }
|
||||
|
||||
/**
|
||||
* Reader used to load content yaml file
|
||||
*/
|
||||
Io.Reader reader;
|
||||
|
||||
/**
|
||||
* @param path the path of file to parse
|
||||
*/
|
||||
public Loader (string path, bool displayFile = false, bool displayNode = false )
|
||||
{
|
||||
this.reader = new Io.Reader (path);
|
||||
if (displayFile) {
|
||||
this.displayFile ();
|
||||
}
|
||||
this.scanner = new Yaml.Scanner (path);
|
||||
if ((this.done = this.scanner.run()) && displayNode) {
|
||||
this.get_nodes ().display_childs ();
|
||||
of.state(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public Yaml.NodeRoot get_nodes ()
|
||||
{
|
||||
return this.scanner.get_nodes ();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void displayFile ()
|
||||
{
|
||||
of.action ("Reading file", this.reader.path);
|
||||
of.echo ();
|
||||
while (this.reader.readable) {
|
||||
of.echo ("%s %s".printf (
|
||||
of.c (ECHO.DATE ).s ("%03d |".printf (this.reader.line)),
|
||||
of.c (ECHO.OPTION_SEP).s (this.reader.read ()))
|
||||
);
|
||||
}
|
||||
of.echo ("EOF");
|
||||
of.state (true);
|
||||
}
|
||||
}
|
|
@ -48,6 +48,12 @@ public interface Pluie.Yaml.Node : Object
|
|||
*/
|
||||
protected abstract bool remove_child (Yaml.Node child);
|
||||
|
||||
/**
|
||||
* clone curent node
|
||||
* @param name the name of clone node
|
||||
*/
|
||||
public abstract Yaml.Node clone_node (string? name = null);
|
||||
|
||||
/**
|
||||
* check if node has child nodes
|
||||
*/
|
||||
|
|
|
@ -57,13 +57,21 @@ public class Pluie.Yaml.NodeMap : Yaml.BaseNode, Yaml.NodeCollection
|
|||
/**
|
||||
* display childs
|
||||
*/
|
||||
public void display_childs ()
|
||||
public void display_childs (bool root=true)
|
||||
{
|
||||
of.action ("display_childs map\n");
|
||||
if (root == true) {
|
||||
of.action ("display root node\n");
|
||||
}
|
||||
of.echo (this.to_string ());
|
||||
if (this.map.size > 0) {
|
||||
foreach (string key in this.map.keys) {
|
||||
of.echo (this.map.get(key).to_string ());
|
||||
var n = this.map.get(key);
|
||||
if (n.node_type.is_mapping ()) (n as Yaml.NodeMap).display_childs (false);
|
||||
else if (n.node_type.is_sequence ()) (n as Yaml.NodeSequence).display_childs (false);
|
||||
else if (n.node_type.is_single_pair ()) {
|
||||
of.echo (n.to_string ());
|
||||
of.echo ((n as Yaml.NodeSinglePair).scalar ().to_string ());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -138,4 +146,20 @@ public class Pluie.Yaml.NodeMap : Yaml.BaseNode, Yaml.NodeCollection
|
|||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* clone current node
|
||||
* @param the name of clone
|
||||
*/
|
||||
public override Yaml.Node clone_node (string? name = null)
|
||||
{
|
||||
var key = name != null ? name : this.name;
|
||||
Yaml.Node clone = new Yaml.NodeMap (this.parent, this.indent, key);
|
||||
foreach (string k in this.map.keys) {
|
||||
var n = this.map.get(k).clone_node();
|
||||
n.parent = clone;
|
||||
clone.add(n);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,4 +17,12 @@ public class Pluie.Yaml.NodeScalar : Yaml.BaseNode
|
|||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* clone current node
|
||||
* @param the name of clone
|
||||
*/
|
||||
public override Yaml.Node clone_node (string? name = null)
|
||||
{
|
||||
return new Yaml.NodeScalar (this.parent, this.indent, this.data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,13 +96,23 @@ public class Pluie.Yaml.NodeSequence : Yaml.BaseNode, Yaml.NodeCollection
|
|||
/**
|
||||
* display childs
|
||||
*/
|
||||
public void display_childs ()
|
||||
public void display_childs (bool root = true)
|
||||
{
|
||||
of.action ("display_childs sequence\n");
|
||||
if (root) {
|
||||
of.action ("display_childs sequence\n");
|
||||
}
|
||||
of.echo (this.to_string ());
|
||||
if (this.list!= null && this.list.size > 0) {
|
||||
foreach (Yaml.Node child in this.list) {
|
||||
of.echo (child.to_string ());
|
||||
if (child.node_type.is_mapping ()) (child as Yaml.NodeMap).display_childs (false);
|
||||
else if (child.node_type.is_sequence ()) (child as Yaml.NodeSequence).display_childs (false);
|
||||
else if (child.node_type.is_single_pair ()) {
|
||||
of.echo (child.to_string ());
|
||||
of.echo ((child as Yaml.NodeSinglePair).scalar ().to_string ());
|
||||
}
|
||||
else {
|
||||
of.echo (child.to_string ());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -114,7 +124,7 @@ public class Pluie.Yaml.NodeSequence : Yaml.BaseNode, Yaml.NodeCollection
|
|||
* count childnodes
|
||||
*/
|
||||
public int get_size () {
|
||||
return this.list.size;
|
||||
return this.list == null ? 0 : this.list.size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,4 +164,23 @@ public class Pluie.Yaml.NodeSequence : Yaml.BaseNode, Yaml.NodeCollection
|
|||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* clone current node
|
||||
* @param the name of clone
|
||||
*/
|
||||
public override Yaml.Node clone_node (string? name = null)
|
||||
{
|
||||
var key = name != null ? name : this.name;
|
||||
Yaml.Node clone = new Yaml.NodeSequence (this.parent, this.indent, key);
|
||||
if (this.list!= null && this.list.size > 0) {
|
||||
foreach (Yaml.Node child in this.list) {
|
||||
var n = child.clone_node();
|
||||
n.parent = clone;
|
||||
clone.add(n);
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,4 +31,15 @@ public class Pluie.Yaml.NodeSinglePair : Yaml.NodeMap
|
|||
{
|
||||
return this.map["singlepair"];
|
||||
}
|
||||
|
||||
/**
|
||||
* clone current node
|
||||
* @param the name of clone
|
||||
*/
|
||||
public override Yaml.Node clone_node (string? name = null)
|
||||
{
|
||||
var key = name != null ? name : this.name;
|
||||
Yaml.Node clone = new Yaml.NodeSinglePair (this.parent, this.indent, key, this.scalar ().data);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using GLib;
|
||||
using Gee;
|
||||
using Pluie;
|
||||
extern void yaml_parse_file(string srcPath, string destPath);
|
||||
|
||||
/**
|
||||
* a tiny Yaml Parser whose purpose is not to comply with all yaml specifications but to parse yaml configuration files
|
||||
|
@ -9,147 +8,62 @@ extern void yaml_parse_file(string srcPath, string destPath);
|
|||
*/
|
||||
public class Pluie.Yaml.Processor
|
||||
{
|
||||
const string REG_EVENT = "^([0-9]+), ([0-9]+)(.*)$";
|
||||
const string REG_VERSION = "^, ([0-9]+), ([0-9]+)$";
|
||||
const string REG_TAG = "^, \"([^\"]*)\", \"([^\"]*)\"$";
|
||||
const string REG_ERROR = "^, \"([^\"]*)\"$";
|
||||
const string REG_SCALAR = "^, ([0-9]+), \"([^\"]*)\"$";
|
||||
const string REG_ANCHOR = "^, \"([^\"]*)\"$";
|
||||
const string REG_ALIAS = "^, \"([^\"]*)\"$";
|
||||
|
||||
/**
|
||||
* enum linked to used RegExp in parse_line
|
||||
*/
|
||||
enum MIEVT
|
||||
{
|
||||
NONE,
|
||||
LINE,
|
||||
TYPE,
|
||||
DATA
|
||||
}
|
||||
|
||||
/**
|
||||
* enum linked to used RegExp in parse_line
|
||||
*/
|
||||
enum MIEVT_VERSION
|
||||
{
|
||||
NONE,
|
||||
MAJOR,
|
||||
MINOR
|
||||
}
|
||||
|
||||
/**
|
||||
* enum linked to used RegExp in parse_line
|
||||
*/
|
||||
enum MIEVT_SCALAR
|
||||
{
|
||||
NONE,
|
||||
STYLE,
|
||||
DATA
|
||||
}
|
||||
|
||||
/**
|
||||
* enum linked to used RegExp in parse_line
|
||||
*/
|
||||
enum MIEVT_TAG
|
||||
{
|
||||
NONE,
|
||||
HANDLE,
|
||||
SUFFIX
|
||||
}
|
||||
|
||||
/**
|
||||
* enum linked to used RegExp in parse_line
|
||||
*/
|
||||
enum MIEVT_ANCHOR
|
||||
{
|
||||
NONE,
|
||||
ID,
|
||||
}
|
||||
|
||||
/**
|
||||
* enum linked to used RegExp in parse_line
|
||||
*/
|
||||
enum MIEVT_ERROR
|
||||
{
|
||||
NONE,
|
||||
DATA,
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate if file has been sucessfully parsed
|
||||
*/
|
||||
public bool done;
|
||||
|
||||
/**
|
||||
* indicate if parsing msut stop
|
||||
*/
|
||||
bool stop;
|
||||
|
||||
/**
|
||||
* the mark use to rewind line throught Io.Reader
|
||||
*/
|
||||
Io.StreamLineMark? mark;
|
||||
|
||||
/**
|
||||
* Reader used to load content yaml file
|
||||
*/
|
||||
Io.Reader reader;
|
||||
|
||||
/**
|
||||
* Events list
|
||||
*/
|
||||
Gee.LinkedList<Yaml.Event> events { get; internal set; }
|
||||
public Gee.LinkedList<Yaml.Event> events { get; internal set; }
|
||||
|
||||
/**
|
||||
*Anchor map
|
||||
*/
|
||||
Gee.HashMap<string, int> anchors { get; internal set; }
|
||||
Gee.HashMap<string, Yaml.Node> anchors { get; internal set; }
|
||||
|
||||
/**
|
||||
* @param path the path of file to parse
|
||||
* the root Yaml.Node
|
||||
*/
|
||||
public Processor (string path)
|
||||
{
|
||||
var destPath = Path.build_filename (Environment.get_tmp_dir (), Path.get_basename(path));
|
||||
yaml_parse_file(path, destPath);
|
||||
this.reader = new Io.Reader (destPath);
|
||||
this.scan ();
|
||||
}
|
||||
public Yaml.Node root;
|
||||
|
||||
/**
|
||||
* parse a file related to specifiyed path
|
||||
* @param path the path to parse
|
||||
* current previous Yaml.Node
|
||||
*/
|
||||
public bool scan (string? path = null)
|
||||
Yaml.Node? prev_node;
|
||||
|
||||
/**
|
||||
* current parent Yaml.Node
|
||||
*/
|
||||
Yaml.Node? parent_node;
|
||||
|
||||
/**
|
||||
* current Yaml.Node
|
||||
*/
|
||||
Yaml.Node node;
|
||||
|
||||
/**
|
||||
* previous indent
|
||||
*/
|
||||
int prev_indent;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public Processor ()
|
||||
{
|
||||
Dbg.in (Log.METHOD, "path:'%s'".printf (path), Log.LINE, Log.FILE);
|
||||
if (path != null) {
|
||||
this.reader.load (path);
|
||||
}
|
||||
else {
|
||||
this.reader.rewind(new Io.StreamLineMark(0, 0));
|
||||
}
|
||||
this.events = new Gee.LinkedList<Yaml.Event>();
|
||||
this.anchors = new Gee.HashMap<string, int>();
|
||||
this.stop = this.done = false;
|
||||
of.action ("Scanning events", path);
|
||||
while (this.reader.readable) {
|
||||
this.scan_line (this.reader.read ());
|
||||
}
|
||||
this.process_events ();
|
||||
|
||||
this.done = true;
|
||||
Dbg.out (Log.METHOD, "done:%d".printf ((int)done), Log.LINE, Log.FILE);
|
||||
return this.done;
|
||||
this.anchors = new Gee.HashMap<string, Yaml.Node>();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void process_events ()
|
||||
public void read ()
|
||||
{
|
||||
of.action ("Reading events");
|
||||
EVT? prevEvent = null;
|
||||
foreach (Yaml.Event event in this.events) {
|
||||
int len = 24 - event.evtype.infos ().length;
|
||||
stdout.printf(" [ %s"+@" %$(len)s "+", %d, %s", event.evtype.infos (), " ", event.line, event.style != null ? event.style.to_string () : "0");
|
||||
|
@ -167,166 +81,136 @@ public class Pluie.Yaml.Processor
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set event version
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void set_event_version(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_VERSION);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("major", mi.fetch (MIEVT_VERSION.MAJOR));
|
||||
data.set("minor", mi.fetch (MIEVT_VERSION.MINOR));
|
||||
}
|
||||
this.events.offer(new Yaml.Event(EVT.VERSION_DIRECTIVE, line, null, data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set event tag
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*
|
||||
*/
|
||||
private void set_event_tag(string evtdata, int line) throws GLib.RegexError
|
||||
private Yaml.Event? next_event (Iterator<Yaml.Event> it)
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_TAG);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("handle", mi.fetch (MIEVT_TAG.HANDLE));
|
||||
data.set("suffix", mi.fetch (MIEVT_TAG.SUFFIX));
|
||||
Yaml.Event? evt = null;
|
||||
if (it.has_next () && it.next ()) {
|
||||
evt = it.get ();
|
||||
}
|
||||
this.events.offer(new Yaml.Event(EVT.TAG, line, null, data));
|
||||
return evt;
|
||||
}
|
||||
|
||||
/**
|
||||
* set event version
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*
|
||||
*/
|
||||
private void set_event_error(string evtdata, int line) throws GLib.RegexError
|
||||
private Yaml.Event? get_value_key_event (Iterator<Yaml.Event> it)
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_ERROR);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("error", mi.fetch (MIEVT_ERROR.DATA));
|
||||
Yaml.Event? evt = null;
|
||||
var e = it.get ();
|
||||
if (e != null && e.evtype.is_key ()) {
|
||||
evt = this.next_event (it);
|
||||
}
|
||||
this.events.offer(new Yaml.Event(EVT.NONE, line, null, data));
|
||||
return evt;
|
||||
}
|
||||
|
||||
/**
|
||||
* set event scalar
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*
|
||||
*/
|
||||
private void set_event_scalar(string evtdata, int line) throws GLib.RegexError
|
||||
private Yaml.Event? get_value_event (Iterator<Yaml.Event> it)
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_SCALAR);
|
||||
HashMap<string, string>? data = null;
|
||||
int? style = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
style = int.parse(mi.fetch (MIEVT_SCALAR.STYLE));
|
||||
data = new HashMap<string, string>();
|
||||
data.set("data", mi.fetch (MIEVT_SCALAR.DATA));
|
||||
Yaml.Event? evt = null;
|
||||
var e = it.get ();
|
||||
if (e != null && e.evtype.is_value ()) {
|
||||
evt = this.next_event (it);
|
||||
}
|
||||
this.events.offer(new Yaml.Event(EVT.SCALAR, line, style, data));
|
||||
return evt;
|
||||
}
|
||||
|
||||
/**
|
||||
* set event anchor
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*
|
||||
*/
|
||||
private void set_event_anchor(string evtdata, int line) throws GLib.RegexError
|
||||
public bool run ()
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_ANCHOR);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("id", mi.fetch (MIEVT_ANCHOR.ID));
|
||||
}
|
||||
this.anchors.set(data.get("id"), this.events.size);
|
||||
this.events.offer(new Yaml.Event(EVT.ANCHOR, line, null, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* set event alias
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void set_event_alias(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_ALIAS);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("id", mi.fetch (MIEVT_ANCHOR.ID));
|
||||
}
|
||||
this.events.offer(new Yaml.Event(EVT.ALIAS, line, null, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* parse specifiyed line
|
||||
* @param data the current line
|
||||
*/
|
||||
private void scan_line (string? data = null)
|
||||
{
|
||||
Dbg.in (Log.METHOD, null, Log.LINE, Log.FILE);
|
||||
if (data == null) {
|
||||
this.stop = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_EVENT);
|
||||
if (reg.match (data, 0, out mi)) {
|
||||
int line = int.parse(mi.fetch (MIEVT.LINE));
|
||||
int type = int.parse(mi.fetch (MIEVT.TYPE));
|
||||
string evtdata = mi.fetch (MIEVT.DATA);
|
||||
switch(type) {
|
||||
case EVT.SCALAR :
|
||||
this.set_event_scalar(evtdata, line);
|
||||
break;
|
||||
case EVT.ANCHOR :
|
||||
this.set_event_anchor(evtdata, line);
|
||||
break;
|
||||
case EVT.ALIAS :
|
||||
this.set_event_alias(evtdata, line);
|
||||
break;
|
||||
case EVT.TAG :
|
||||
this.set_event_tag(evtdata, line);
|
||||
break;
|
||||
case EVT.VERSION_DIRECTIVE :
|
||||
this.set_event_version(evtdata, line);
|
||||
break;
|
||||
case EVT.NONE :
|
||||
this.set_event_error(evtdata, line);
|
||||
break;
|
||||
default :
|
||||
this.events.offer(new Yaml.Event((Yaml.EVT)type, line, null, null));
|
||||
break;
|
||||
this.root = new Yaml.NodeRoot ();
|
||||
this.prev_node = this.root;
|
||||
this.parent_node = this.root;
|
||||
this.prev_indent = this.root.indent;
|
||||
int indent = this.root.indent +4;
|
||||
EVT? prevEvent = null;
|
||||
var it = this.events.iterator ();
|
||||
var change = false;
|
||||
string? key = null;
|
||||
string? id = null;
|
||||
Yaml.Event? evt;
|
||||
of.action ("Processing events");
|
||||
for (var has_next = it.next (); has_next; has_next = it.next ()) {
|
||||
evt = it.get ();
|
||||
if (evt.evtype.is_mapping_end () || evt.evtype.is_sequence_end ()) {
|
||||
indent -= 4;
|
||||
this.parent_node = this.prev_node.parent != this.root ? this.prev_node.parent.parent : this.root;
|
||||
this.prev_node = this.parent_node;
|
||||
continue;
|
||||
}
|
||||
if (evt.evtype.is_entry ()) {
|
||||
evt = this.next_event(it);
|
||||
if (evt.evtype.is_mapping_start ()) {
|
||||
key = "_%d".printf((this.parent_node as Yaml.NodeSequence).get_size());
|
||||
this.node = new Yaml.NodeMap (this.parent_node, indent, key);
|
||||
key = null;
|
||||
indent += 4;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if (evt.evtype.is_key () && (evt = this.get_value_key_event (it)) != null) {
|
||||
key = evt.data["data"];
|
||||
}
|
||||
if (evt.evtype.is_value () && (evt = this.get_value_event (it)) != null) {
|
||||
if (evt.evtype.is_scalar ()) {
|
||||
var content = evt.data["data"];
|
||||
if (key != null) {
|
||||
this.node = new Yaml.NodeSinglePair (this.parent_node, indent, key, content);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
else if (evt.evtype.is_anchor ()) {
|
||||
id = evt.data["id"];
|
||||
evt = this.next_event (it);
|
||||
}
|
||||
else if (evt.evtype.is_alias ()) {
|
||||
id = evt.data["id"];
|
||||
Yaml.Node? refnode = this.anchors.get(id);
|
||||
if (refnode != null) {
|
||||
this.node = refnode.clone_node (key);
|
||||
this.parent_node.add (this.node);
|
||||
this.prev_node = this.node;
|
||||
this.prev_indent = this.prev_node.indent;
|
||||
}
|
||||
}
|
||||
if (evt.evtype.is_mapping_start ()) {
|
||||
this.node = new Yaml.NodeMap (this.parent_node, indent, key);
|
||||
indent += 4;
|
||||
change = true;
|
||||
}
|
||||
else if (evt.evtype.is_sequence_start ()) {
|
||||
this.node = new Yaml.NodeSequence (this.parent_node, indent, key);
|
||||
indent += 4;
|
||||
change = true;
|
||||
}
|
||||
if (id != null) {
|
||||
if (this.node != null) {
|
||||
this.anchors.set(id, this.node);
|
||||
}
|
||||
id = null;
|
||||
}
|
||||
key = null;
|
||||
}
|
||||
if (change) {
|
||||
this.parent_node.add (this.node);
|
||||
if (this.node.node_type.is_collection ()) {
|
||||
this.parent_node = this.node;
|
||||
}
|
||||
this.prev_node = this.node;
|
||||
this.prev_indent = this.prev_node.indent;
|
||||
this.node = null;
|
||||
change = false;
|
||||
}
|
||||
}
|
||||
catch (GLib.RegexError e) {
|
||||
Dbg.error (e.message, Log.METHOD, Log.LINE, Log.FILE);
|
||||
}
|
||||
Dbg.out (Log.METHOD, null, Log.LINE, Log.FILE);
|
||||
this.done = this.root != null;
|
||||
return done;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
270
src/vala/Pluie/Yaml.Scanner.vala
Normal file
270
src/vala/Pluie/Yaml.Scanner.vala
Normal file
|
@ -0,0 +1,270 @@
|
|||
using GLib;
|
||||
using Gee;
|
||||
using Pluie;
|
||||
extern void yaml_parse_file(string srcPath, string destPath);
|
||||
|
||||
/**
|
||||
* a tiny Yaml Parser whose purpose is not to comply with all yaml specifications but to parse yaml configuration files
|
||||
* todo improve description of what is expected
|
||||
*/
|
||||
public class Pluie.Yaml.Scanner
|
||||
{
|
||||
const string REG_EVENT = "^([0-9]+), ([0-9]+)(.*)$";
|
||||
const string REG_VERSION = "^, ([0-9]+), ([0-9]+)$";
|
||||
const string REG_TAG = "^, \"([^\"]*)\", \"([^\"]*)\"$";
|
||||
const string REG_ERROR = "^, \"([^\"]*)\"$";
|
||||
const string REG_SCALAR = "^, ([0-9]+), \"(.*)\"$";
|
||||
const string REG_ANCHOR = "^, \"([^\"]*)\"$";
|
||||
const string REG_ALIAS = "^, \"([^\"]*)\"$";
|
||||
|
||||
/**
|
||||
* enum linked to MatchInfo REG_EVENT
|
||||
*/
|
||||
enum MIEVT { NONE, LINE, TYPE, DATA }
|
||||
/**
|
||||
* enum linked to MatchInfo REG_VERSION
|
||||
*/
|
||||
enum MIEVT_VERSION { NONE, MAJOR, MINOR }
|
||||
/**
|
||||
* enum linked to MatchInfo REG_SCALAR
|
||||
*/
|
||||
enum MIEVT_SCALAR { NONE, STYLE, DATA }
|
||||
/**
|
||||
* enum linked to MatchInfo REG_TAG
|
||||
*/
|
||||
enum MIEVT_TAG { NONE, HANDLE, SUFFIX }
|
||||
/**
|
||||
* enum linked to MatchInfo REG_ANCHOR
|
||||
*/
|
||||
enum MIEVT_ANCHOR { NONE, ID }
|
||||
/**
|
||||
* enum linked to MatchInfo REG_ERROR
|
||||
*/
|
||||
enum MIEVT_ERROR { NONE, DATA }
|
||||
|
||||
/**
|
||||
* indicate if file has been sucessfully parsed
|
||||
*/
|
||||
public bool done { get; internal set; }
|
||||
|
||||
/**
|
||||
* the mark use to rewind line throught Io.Reader
|
||||
*/
|
||||
Io.StreamLineMark? mark;
|
||||
|
||||
/**
|
||||
* Reader used to load content yaml file
|
||||
*/
|
||||
Io.Reader reader;
|
||||
|
||||
/**
|
||||
* Yaml Processor
|
||||
*/
|
||||
Yaml.Processor processor { get; internal set; }
|
||||
|
||||
/**
|
||||
* @param path the path of file to parse
|
||||
*/
|
||||
public Scanner (string path)
|
||||
{
|
||||
var destPath = Path.build_filename (Environment.get_tmp_dir (), Path.get_basename(path));
|
||||
yaml_parse_file(path, destPath);
|
||||
this.reader = new Io.Reader (destPath);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public Yaml.NodeRoot get_nodes ()
|
||||
{
|
||||
return (this.processor.root as Yaml.NodeRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a file related to specifiyed path
|
||||
* @param path the path to parse
|
||||
*/
|
||||
public bool run (string? path = null)
|
||||
{
|
||||
Dbg.in (Log.METHOD, "path:'%s'".printf (path), Log.LINE, Log.FILE);
|
||||
if (path != null) {
|
||||
this.reader.load (path);
|
||||
}
|
||||
else {
|
||||
this.reader.rewind(new Io.StreamLineMark(0, 0));
|
||||
}
|
||||
this.processor = new Yaml.Processor ();
|
||||
this.done = false;
|
||||
of.action ("Scanning events", path);
|
||||
while (this.reader.readable) {
|
||||
this.scan_event (this.reader.read ());
|
||||
}
|
||||
this.done = true;
|
||||
of.state (this.done);
|
||||
this.done = this.done && this.processor.run ();
|
||||
of.state (this.done);
|
||||
Dbg.out (Log.METHOD, "done:%d".printf ((int)done), Log.LINE, Log.FILE);
|
||||
return this.done;
|
||||
}
|
||||
|
||||
/**
|
||||
* register event version
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void register_event_version(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_VERSION);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("major", mi.fetch (MIEVT_VERSION.MAJOR));
|
||||
data.set("minor", mi.fetch (MIEVT_VERSION.MINOR));
|
||||
}
|
||||
this.processor.events.offer(new Yaml.Event(EVT.VERSION_DIRECTIVE, line, null, data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* register event tag
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void register_event_tag(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_TAG);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("handle", mi.fetch (MIEVT_TAG.HANDLE));
|
||||
data.set("suffix", mi.fetch (MIEVT_TAG.SUFFIX));
|
||||
}
|
||||
this.processor.events.offer(new Yaml.Event(EVT.TAG, line, null, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* register event version
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void register_event_error(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_ERROR);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("error", mi.fetch (MIEVT_ERROR.DATA));
|
||||
}
|
||||
this.processor.events.offer(new Yaml.Event(EVT.NONE, line, null, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* register event scalar
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void register_event_scalar(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_SCALAR);
|
||||
HashMap<string, string>? data = null;
|
||||
int? style = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
style = int.parse(mi.fetch (MIEVT_SCALAR.STYLE));
|
||||
data = new HashMap<string, string>();
|
||||
data.set("data", mi.fetch (MIEVT_SCALAR.DATA));
|
||||
}
|
||||
this.processor.events.offer(new Yaml.Event(EVT.SCALAR, line, style, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* register event anchor
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void register_event_anchor(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_ANCHOR);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("id", mi.fetch (MIEVT_ANCHOR.ID));
|
||||
}
|
||||
this.processor.events.offer(new Yaml.Event(EVT.ANCHOR, line, null, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* register event alias
|
||||
* @param evtdata the current data event
|
||||
* @param line the current line
|
||||
* @throws GLib.RegexError
|
||||
*/
|
||||
private void register_event_alias(string evtdata, int line) throws GLib.RegexError
|
||||
{
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_ALIAS);
|
||||
HashMap<string, string>? data = null;
|
||||
if (reg.match (evtdata, 0, out mi)) {
|
||||
data = new HashMap<string, string>();
|
||||
data.set("id", mi.fetch (MIEVT_ANCHOR.ID));
|
||||
}
|
||||
this.processor.events.offer(new Yaml.Event(EVT.ALIAS, line, null, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* parse specifiyed line
|
||||
* @param data the current line
|
||||
*/
|
||||
private void scan_event (string? data = null)
|
||||
{
|
||||
Dbg.in (Log.METHOD, null, Log.LINE, Log.FILE);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
MatchInfo mi = null;
|
||||
Regex reg = new Regex (REG_EVENT);
|
||||
if (reg.match (data, 0, out mi)) {
|
||||
int line = int.parse(mi.fetch (MIEVT.LINE));
|
||||
int type = int.parse(mi.fetch (MIEVT.TYPE));
|
||||
string evtdata = mi.fetch (MIEVT.DATA);
|
||||
switch(type) {
|
||||
case EVT.SCALAR :
|
||||
this.register_event_scalar(evtdata, line);
|
||||
break;
|
||||
case EVT.ANCHOR :
|
||||
this.register_event_anchor(evtdata, line);
|
||||
break;
|
||||
case EVT.ALIAS :
|
||||
this.register_event_alias(evtdata, line);
|
||||
break;
|
||||
case EVT.TAG :
|
||||
this.register_event_tag(evtdata, line);
|
||||
break;
|
||||
case EVT.VERSION_DIRECTIVE :
|
||||
this.register_event_version(evtdata, line);
|
||||
break;
|
||||
case EVT.NONE :
|
||||
this.register_event_error(evtdata, line);
|
||||
break;
|
||||
default :
|
||||
this.processor.events.offer(new Yaml.Event((Yaml.EVT)type, line, null, null));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (GLib.RegexError e) {
|
||||
Dbg.error (e.message, Log.METHOD, Log.LINE, Log.FILE);
|
||||
}
|
||||
Dbg.out (Log.METHOD, null, Log.LINE, Log.FILE);
|
||||
}
|
||||
}
|
|
@ -47,12 +47,93 @@ namespace Pluie
|
|||
SCALAR;
|
||||
|
||||
/**
|
||||
*@return infos related to EVT
|
||||
* @return infos related to EVT
|
||||
*/
|
||||
public string infos ()
|
||||
{
|
||||
return this.to_string().substring("PLUIE_YAML_".length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is key
|
||||
*/
|
||||
public bool is_key ()
|
||||
{
|
||||
return this == EVT.KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is anchor
|
||||
*/
|
||||
public bool is_anchor ()
|
||||
{
|
||||
return this == EVT.ANCHOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is alias
|
||||
*/
|
||||
public bool is_alias ()
|
||||
{
|
||||
return this == EVT.ALIAS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is key
|
||||
*/
|
||||
public bool is_value ()
|
||||
{
|
||||
return this == EVT.VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is scalar
|
||||
*/
|
||||
public bool is_scalar ()
|
||||
{
|
||||
return this == EVT.SCALAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is mapping start event
|
||||
*/
|
||||
public bool is_mapping_start ()
|
||||
{
|
||||
return this == EVT.BLOCK_MAPPING_START || this == EVT.FLOW_MAPPING_START;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is sequence start event
|
||||
*/
|
||||
public bool is_sequence_start ()
|
||||
{
|
||||
return this == EVT.BLOCK_SEQUENCE_START || this == EVT.FLOW_SEQUENCE_START;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is sequence end event
|
||||
*/
|
||||
public bool is_sequence_end ()
|
||||
{
|
||||
return this == EVT.BLOCK_END || this == EVT.FLOW_SEQUENCE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is sequence entry event
|
||||
*/
|
||||
public bool is_entry ()
|
||||
{
|
||||
return this == EVT.BLOCK_ENTRY || this == EVT.FLOW_ENTRY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event is mapping end event
|
||||
*/
|
||||
public bool is_mapping_end ()
|
||||
{
|
||||
return this == EVT.BLOCK_END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,7 +197,7 @@ namespace Pluie
|
|||
/**
|
||||
* @return if current NODE_TYPE match a scalar node
|
||||
*/
|
||||
public bool is_scallar ()
|
||||
public bool is_scalar ()
|
||||
{
|
||||
return this == SCALAR;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user