summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Atom.vala2
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/List.vala6
-rw-r--r--src/Parse.vala392
-rw-r--r--src/Pid.vala4
-rw-r--r--src/Port.vala4
-rw-r--r--src/Ref.vala4
-rw-r--r--src/String.vala2
-rw-r--r--src/Term.vala8
-rw-r--r--src/Util.vala4
-rw-r--r--test/Test.vala2
11 files changed, 417 insertions, 14 deletions
diff --git a/src/Atom.vala b/src/Atom.vala
index bb3a6fd..012b506 100644
--- a/src/Atom.vala
+++ b/src/Atom.vala
@@ -46,7 +46,7 @@ namespace Eva {
}
public void encode(Erl.Buffer buffer) {
- char[]? array = string_to_array(value);
+ char[]? array = string_to_binary(value);
assert(array != null);
buffer.encode_atom(array);
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 92f8340..bbe5c19 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,10 +9,11 @@ vala_precompile(EVA_C
Int.vala
List.vala
PacketHandler.vala
+ Parse.vala
Pid.vala
Port.vala
- String.vala
Ref.vala
+ String.vala
Term.vala
Tuple.vala
UInt.vala
diff --git a/src/List.vala b/src/List.vala
index 7637998..9340fd7 100644
--- a/src/List.vala
+++ b/src/List.vala
@@ -50,6 +50,12 @@ namespace Eva {
_tail = null;
}
+ public static List from_list(Gee.List<Term> list) {
+ if(list.is_empty)
+ return empty;
+ else
+ return new List(list.first(), List.from_list(list[1:list.size]));
+ }
protected bool do_match(Term o, Gee.Map<string, Term> vars, Gee.Map<string, string> aliases) {
if(o is Var) {
diff --git a/src/Parse.vala b/src/Parse.vala
new file mode 100644
index 0000000..7cadd35
--- /dev/null
+++ b/src/Parse.vala
@@ -0,0 +1,392 @@
+namespace Eva {
+ internal static Term? parse(string str) {
+ string s = str.chomp();
+
+ if(s.length == 0)
+ return null;
+
+ Term? ret = parse_term(ref s);
+
+ if(s.length != 0)
+ return null;
+ else
+ return ret;
+ }
+
+ private static Term? parse_term(ref string str) {
+ str = str.chug();
+ unichar c = str.get_char();
+
+ if(c.isdigit() || c == '-') {
+ return parse_number(ref str);
+ }
+ else if(c.islower() || c == '\'') {
+ return parse_atom(ref str);
+ }
+ else if(c == '"') {
+ return parse_string(ref str);
+ }
+ else if(c.isupper() || c == '_') {
+ return parse_var(ref str);
+ }
+ else if(c == '<') {
+ return parse_binary(ref str);
+ }
+ else if(c == '{') {
+ return parse_tuple(ref str);
+ }
+ else if(c == '[') {
+ return parse_list(ref str);
+ }
+ else {
+ return null;
+ }
+ }
+
+ private static Term? parse_number(ref string str) {
+ bool positive = true;
+ bool fractional = false;
+
+ unowned string s = str;
+
+ if(s.get_char() == '-') {
+ positive = false;
+ s = s.next_char();
+
+ if(s.length == 0 || !s.get_char().isdigit())
+ return null;
+ }
+
+ if(s.get_char() == '.')
+ return null;
+
+ while(s.length > 0) {
+ unichar c = s.get_char();
+
+ if(c == '.') {
+ if(fractional)
+ return null;
+
+ fractional = true;
+
+ s = s.next_char();
+ if(s.length == 0 || !s.get_char().isdigit())
+ return null;
+
+ continue;
+ }
+
+ if(!c.isdigit())
+ break;
+
+ s = s.next_char();
+ }
+
+ string number = str.substring(0, str.pointer_to_offset(s));
+ str = s;
+
+ if(fractional) {
+ return new Double(number.to_double());
+ }
+ else if(positive) {
+ return new UInt(number.to_ulong());
+ }
+ else {
+ return new Int(number.to_long());
+ }
+ }
+
+ private static Term? parse_atom(ref string str) {
+ if(str.get_char() == '\'') {
+ string atom = "";
+ unowned string s = str.next_char();
+
+ while(s.length > 0) {
+ unichar c = s.get_char();
+
+ if(c == '\'')
+ break;
+
+ if(c == '\\') {
+ s = s.next_char();
+ if(s.length == 0)
+ return null;
+ c = s.get_char();
+ }
+
+ if(c > 255) {
+ return null;
+ }
+
+ string buf = string.nfill(6, 0);
+ c.to_utf8(buf);
+ atom += buf;
+
+ s = s.next_char();
+ }
+
+ if(s.length == 0)
+ return null;
+
+ Term ret = new Atom(atom);
+ str = s.next_char();
+
+ return ret;
+ }
+ else {
+ unowned string s = str;
+
+ while(s.length > 0) {
+ unichar c = s.get_char();
+
+ if(c != '_' && !c.isalnum()) {
+ break;
+ }
+
+ s = s.next_char();
+ }
+
+ Term ret = new Atom(str.substring(0, str.pointer_to_offset(s)));
+ str = s;
+
+ return ret;
+ }
+ }
+
+ private static Term? parse_string(ref string str) {
+ string ret = do_parse_string(ref str);
+ if(ret == null)
+ return null;
+
+ return new String(ret);
+ }
+
+ private static string? do_parse_string(ref string str) {
+ if(str.get_char() != '"') {
+ return null;
+ }
+
+ string retstr = "";
+ unowned string s = str.next_char();
+
+ while(s.length > 0) {
+ unichar c = s.get_char();
+
+ if(c == '\"')
+ break;
+
+ if(c == '\\') {
+ s = s.next_char();
+ if(s.length == 0)
+ return null;
+ c = s.get_char();
+ }
+
+ string buf = string.nfill(6, 0);
+ c.to_utf8(buf);
+ retstr += buf;
+
+ s = s.next_char();
+ }
+
+ if(s.length == 0)
+ return null;
+
+ str = s.next_char();
+
+ return retstr;
+ }
+
+ private static Term? parse_var(ref string str) {
+ unowned string s = str;
+
+ while(s.length > 0) {
+ unichar c = s.get_char();
+
+ if(c != '_' && !c.isalnum()) {
+ break;
+ }
+
+ s = s.next_char();
+ }
+
+ Term ret = new Var(str.substring(0, str.pointer_to_offset(s)));
+ str = s;
+
+ return ret;
+ }
+
+ private static Term? parse_tuple(ref string str) {
+ Gee.ArrayList<Term> list = new Gee.ArrayList<Term>();
+
+ if(str.get_char() != '{')
+ return null;
+
+ unowned string s = str.next_char();
+
+ while(s.length > 0 && s.get_char().isspace()) {
+ s = s.next_char();
+ }
+
+ if(s.length == 0)
+ return null;
+
+ if(s.get_char() == '}') {
+ str = s.next_char();
+ return new Tuple({});
+ }
+
+ while(s.length > 0) {
+ if(s.get_char().isspace()) {
+ s = s.next_char();
+ continue;
+ }
+
+ str = s;
+ Term t = parse_term(ref str);
+ if(t == null)
+ return null;
+ list.add(t);
+
+ s = str;
+
+ while(s.length > 0 && s.get_char().isspace()) {
+ s = s.next_char();
+ }
+
+ unichar c = s.get_char();
+ if(c == '}') {
+ str = s.next_char();
+ Term[] terms = list.to_array();
+ return new Tuple(terms);
+ }
+ else if(c != ',') {
+ return null;
+ }
+ else {
+ s = s.next_char();
+ }
+ }
+
+ return null;
+ }
+
+ private static Term? parse_list(ref string str) {
+ if(str.get_char() != '[')
+ return null;
+
+ str = str.next_char();
+ return parse_list_tail(ref str);
+ }
+
+ private static Term? parse_list_tail(ref string str) {
+ str = str.chug();
+
+ if(str.length == 0)
+ return null;
+
+ if(str.get_char() == ']') {
+ str = str.next_char();
+ return List.empty;
+ }
+
+ Term head = parse_term(ref str);
+ if(head == null)
+ return null;
+
+ str = str.chug();
+ if(str.length == 0)
+ return null;
+ unichar c = str.get_char();
+ str = str.next_char();
+
+ switch(c) {
+ case ']':
+ return new List(head);
+ case ',':
+ return new List(head, parse_list_tail(ref str));
+ case '|':
+ Term ret = new List(head, parse_term(ref str));
+
+ str = str.chug();
+ if(str.length == 0 || str.get_char() != ']')
+ return null;
+ str = str.next_char();
+
+ return ret;
+ default:
+ return null;
+ }
+ }
+
+ private static Term? parse_binary(ref string str) {
+ if(str.length < 4)
+ return null;
+
+ if(str[0:2] != "<<")
+ return null;
+
+ str = str.offset(2).chug();
+
+ if(str[0:2] == ">>") {
+ str = str.offset(2);
+ return new Binary({});
+ }
+
+ if(str.get_char() == '"') {
+ string ret = do_parse_string(ref str);
+ if(ret == null)
+ return null;
+
+ str = str.chug();
+
+ if(str.length < 2 || str[0:2] != ">>")
+ return null;
+
+ str = str.offset(2);
+ char[] binary = string_to_binary(ret);
+ return new Binary(binary);
+ }
+ else {
+ Gee.ArrayList<char> data = new Gee.ArrayList<char>();
+
+ while(str.length > 0) {
+ unichar c = str.get_char();
+
+ if(c != '-' && !c.isdigit())
+ return null;
+
+ unowned string beg = str;
+ unowned string end = str.next_char();
+
+ while(end.length > 0 && end.get_char().isdigit())
+ end = end.next_char();
+
+ data.add((char)beg.substring(0, beg.pointer_to_offset(end)).to_int());
+
+ str = end.chug();
+
+ if(str.length >= 2 && str[0:2] == ">>") {
+ str = str.offset(2);
+
+ // Workaround for libgee to_array bug 597737
+ char[] array = new char[data.size];
+ int index = 0;
+ foreach(char i in data) {
+ array[index++] = i;
+ }
+
+ return new Binary(array);
+ }
+ else if(str.length != 0 && str.get_char() == ',') {
+ str = str.next_char().chug();
+ }
+ else {
+ return null;
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/Pid.vala b/src/Pid.vala
index 3f71df7..68f9a4f 100644
--- a/src/Pid.vala
+++ b/src/Pid.vala
@@ -6,7 +6,7 @@ namespace Eva {
public uint creation {get; construct;}
public Pid(Erl.Pid pid) {
- this.create(array_to_string(pid.node, Erl.MAXATOMLEN), pid.num, pid.serial, pid.creation);
+ this.create(binary_to_string(pid.node, Erl.MAXATOMLEN), pid.num, pid.serial, pid.creation);
}
private Pid.create(string node0, uint num0, uint serial0, uint creation0) {
@@ -32,7 +32,7 @@ namespace Eva {
public void encode(Erl.Buffer buffer) {
Erl.Pid pid = Erl.Pid();
- char[]? nodedata = string_to_array(node);
+ char[]? nodedata = string_to_binary(node);
assert(nodedata != null);
Memory.copy(pid.node, nodedata, int.min(Erl.MAXATOMLEN, nodedata.length));
diff --git a/src/Port.vala b/src/Port.vala
index b67c808..ae3980d 100644
--- a/src/Port.vala
+++ b/src/Port.vala
@@ -5,7 +5,7 @@ namespace Eva {
public uint creation {get; construct;}
public Port(Erl.Port port) {
- this.create(array_to_string(port.node, Erl.MAXATOMLEN), port.id, port.creation);
+ this.create(binary_to_string(port.node, Erl.MAXATOMLEN), port.id, port.creation);
}
private Port.create(string node0, uint id0, uint creation0) {
@@ -31,7 +31,7 @@ namespace Eva {
public void encode(Erl.Buffer buffer) {
Erl.Port port = Erl.Port();
- char[]? nodedata = string_to_array(node);
+ char[]? nodedata = string_to_binary(node);
assert(nodedata != null);
Memory.copy(port.node, nodedata, int.min(Erl.MAXATOMLEN, nodedata.length));
diff --git a/src/Ref.vala b/src/Ref.vala
index 2510d78..b1fd4e9 100644
--- a/src/Ref.vala
+++ b/src/Ref.vala
@@ -6,7 +6,7 @@ namespace Eva {
public uint creation {get; construct;}
public Ref(Erl.Ref reference) {
- this.create(array_to_string(reference.node, Erl.MAXATOMLEN), reference.len, reference.n, reference.creation);
+ this.create(binary_to_string(reference.node, Erl.MAXATOMLEN), reference.len, reference.n, reference.creation);
}
private Ref.create(string node0, int len0, uint* n0, uint creation0) {
@@ -46,7 +46,7 @@ namespace Eva {
public void encode(Erl.Buffer buffer) {
Erl.Ref reference = Erl.Ref();
- char[]? nodedata = string_to_array(node);
+ char[]? nodedata = string_to_binary(node);
assert(nodedata != null);
Memory.copy(reference.node, nodedata, int.min(Erl.MAXATOMLEN, nodedata.length));
diff --git a/src/String.vala b/src/String.vala
index 50563c2..ea749c1 100644
--- a/src/String.vala
+++ b/src/String.vala
@@ -27,7 +27,7 @@ namespace Eva {
}
public void encode(Erl.Buffer buffer) {
- char[]? array = string_to_array(value);
+ char[]? array = string_to_binary(value);
if(array != null) {
buffer.encode_string(array);
}
diff --git a/src/Term.vala b/src/Term.vala
index 698bfc2..273cfa2 100644
--- a/src/Term.vala
+++ b/src/Term.vala
@@ -60,7 +60,7 @@ namespace Eva {
case Erl.TermType.ATOM:
char[] value = new char[size+1];
assert(Erl.decode_atom(buffer, ref index, value) == 0);
- return new Atom(array_to_string(value, size));
+ return new Atom(binary_to_string(value, size));
case Erl.TermType.SMALL_TUPLE:
case Erl.TermType.LARGE_TUPLE:
@@ -87,7 +87,7 @@ namespace Eva {
case Erl.TermType.STRING:
char[] value = new char[size+1];
assert(Erl.decode_string(buffer, ref index, value) == 0);
- return new String(array_to_string(value, size));
+ return new String(binary_to_string(value, size));
case Erl.TermType.BINARY:
char[] value = new char[size];
@@ -129,5 +129,9 @@ namespace Eva {
return new List(head, tail);
}
+
+ public Term? parse(string str) {
+ return Eva.parse(str);
+ }
}
}
diff --git a/src/Util.vala b/src/Util.vala
index 7c704fb..28cce58 100644
--- a/src/Util.vala
+++ b/src/Util.vala
@@ -1,5 +1,5 @@
namespace Eva {
- private string array_to_string(uchar* array, ulong len) {
+ private string binary_to_string(uchar* array, ulong len) {
string ret = "";
for(ulong i = 0; i < len; ++i) {
@@ -15,7 +15,7 @@ namespace Eva {
return ret;
}
- private char[]? string_to_array(string str) {
+ private char[]? string_to_binary(string str) {
char[] ret = new char[str.len()];
int index = 0;
diff --git a/test/Test.vala b/test/Test.vala
index 86907ea..85afc6a 100644
--- a/test/Test.vala
+++ b/test/Test.vala
@@ -3,7 +3,7 @@ namespace Eva {
public static int main(string[] args) {
MainLoop main = new MainLoop();
- Eva.PacketHandler handler = new Eva.PacketHandler(new UnixInputStream(3, true), new UnixOutputStream(4, true), 4);
+ PacketHandler handler = new PacketHandler(new UnixInputStream(3, true), new UnixOutputStream(4, true), 4);
handler.received_term.connect((term) => {stdout.printf("Received term %s\n", term.to_string()); handler.send(term); main.quit();});
handler.start();