[gnome-code-assistance] [backends/vala] Use external helper to parse
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-code-assistance] [backends/vala] Use external helper to parse
- Date: Wed, 4 Dec 2013 18:09:07 +0000 (UTC)
commit bf72e7c7a408bb22d27ed2f1ab50ea675533cd94
Author: Jesse van den Kieboom <jessevdk gmail com>
Date: Wed Dec 4 17:06:16 2013 +0100
[backends/vala] Use external helper to parse
libvala has memory leaks which cannot be prevented at the
moment. Therefore, move the actual parsing out of process.
Makefile.am | 1 +
backends/vala/Makefile.am | 71 +++++++++--
backends/vala/config.vala.in | 26 ++++
backends/vala/dbus.vala | 96 ++++++++++++---
backends/vala/diagnostics.vala | 44 +++++---
backends/vala/hashutils.vala | 36 ++++++
backends/vala/helper.vala | 186 ++++++++++++++++++++++++++++
backends/vala/makefileintegration.vala | 28 ++---
backends/vala/rpc.vala | 21 +++
backends/vala/service.vala | 211 +++++++++++++++++++++++++++++--
backends/vala/types.vala | 14 ++-
backends/vala/valaoptionparser.vala | 151 ++++++++++++++++++++---
configure.ac | 1 +
13 files changed, 791 insertions(+), 95 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index bcbb933..2c53d34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,7 @@ BUILT_SOURCES =
DISTCLEANFILES =
gsettings_SCHEMAS =
TESTS =
+noinst_PROGRAMS =
include data/Makefile.am
include backends/Makefile.am
diff --git a/backends/vala/Makefile.am b/backends/vala/Makefile.am
index 21a5abd..cbc9948 100644
--- a/backends/vala/Makefile.am
+++ b/backends/vala/Makefile.am
@@ -1,40 +1,83 @@
valabackenddir = $(GCA_BACKENDS_EXEC_DIR)
-valabackend_PROGRAMS = backends/vala/vala
+
+noinst_LTLIBRARIES = backends/vala/libvalashared.la
+
+valabackend_PROGRAMS = backends/vala/vala backends/vala/valahelper
+
+backends_vala_libvalashared_la_SOURCES = \
+ backends/vala/types.vala \
+ backends/vala/rpc.vala \
+ backends/vala/hashutils.vala
backends_vala_vala_SOURCES = \
backends/vala/application.vala \
- backends/vala/types.vala \
backends/vala/dbus.vala \
- backends/vala/diagnostics.vala \
backends/vala/document.vala \
- backends/vala/service.vala
+ backends/vala/service.vala \
+ backends/vala/makefileintegration.vala \
+ backends/vala/config.vala
-backends_vala_vala_VALAFLAGS = \
+backends_vala_valahelper_SOURCES = \
+ backends/vala/valaoptionparser.vala \
+ backends/vala/diagnostics.vala \
+ backends/vala/helper.vala
+
+backends_vala_common_valaflags = \
--target-glib=2.36 \
--pkg gio-2.0 \
--pkg gee-0.8 \
--pkg $(BACKEND_VALA_LIBVALA)
-backends_vala_vala_CFLAGS = $(BACKEND_VALA_CFLAGS) -w
-backends_vala_vala_LDADD = $(BACKEND_VALA_LIBS)
-
if ENABLE_DEBUG
-backends_vala_vala_VALAFLAGS += --debug
+backends_vala_common_valaflags += --debug -X -O0
endif
+backends_vala_libvalashared_la_VALAFLAGS = \
+ $(backends_vala_common_valaflags) \
+ --library libvalashared \
+ --vapi backends/vala/libvalashared.vapi \
+ --header backends/vala/libvalashared.h \
+ --includedir backends/vala
+
+backends_vala_vala_VALAFLAGS = \
+ $(backends_vala_common_valaflags) \
+ --pkg libvalashared \
+ --vapidir backends/vala
+
+backends_vala_valahelper_VALAFLAGS = \
+ $(backends_vala_common_valaflags) \
+ --pkg libvalashared \
+ --vapidir backends/vala
+
+backends_vala_libvalashared_la_CFLAGS = $(BACKEND_VALA_CFLAGS) -w
+
+backends_vala_vala_CFLAGS = $(BACKEND_VALA_CFLAGS) -w
+backends_vala_vala_LDADD = $(BACKEND_VALA_LIBS) backends/vala/libvalashared.la
+
+backends_vala_valahelper_CFLAGS = $(BACKEND_VALA_CFLAGS) -w
+backends_vala_valahelper_LDADD = $(BACKEND_VALA_LIBS) backends/vala/libvalashared.la
+
valabackendservicedir = $(datadir)/dbus-1/services
valabackendservice_DATA = \
backends/vala/org.gnome.CodeAssist.v1.vala.service
-CLEANFILES += \
- $(backends_vala_vala_SOURCES:.vala=.c) \
- backends_vala_vala_vala.stamp
+CLEANFILES += \
+ $(backends_vala_vala_SOURCES:.vala=.c) \
+ $(backends_vala_valahelper_SOURCES:.vala=.c) \
+ $(backends_vala_libvalashared_la_SOURCES:.vala=.c) \
+ backends/vala/libvalashared.h \
+ backends/vala/libvalashared.vapi \
+ backends_vala_vala_vala.stamp \
+ backends_vala_valahelper_vala.stamp \
+ backends_vala_libvalashared_la_vala.stamp
GITIGNOREFILES += \
backends/vala/$(DEPDIR) \
+ backends/vala/.libs \
backends/vala/.dirstamp \
- backends/vala/*.o
+ backends/vala/*.o \
+ backends/vala/*.lo
-EXTRA_DIST += $(valabackendservide_DATA)
+EXTRA_DIST += $(valabackendservice_DATA)
GITIGNOREDEPS += backends/vala/Makefile.am
diff --git a/backends/vala/config.vala.in b/backends/vala/config.vala.in
new file mode 100644
index 0000000..40faea1
--- /dev/null
+++ b/backends/vala/config.vala.in
@@ -0,0 +1,26 @@
+/*
+ * This file is part of gnome-code-assistance.
+ *
+ * Copyright (C) 2013 - Melissa Wen <melissa srw gmail com>
+ * Copyright (C) 2013 - Jesse van den Kieboom <jessevdk gnome org>
+ *
+ * gnome-code-assistance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gnome-code-assistance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gnome-code-assistance. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Config
+{
+ public static const string BackendExecDir = "@backendexecdir@";
+}
+
+/* vi:ex:ts=4 */
diff --git a/backends/vala/dbus.vala b/backends/vala/dbus.vala
index d0fd6dc..fbcac3a 100644
--- a/backends/vala/dbus.vala
+++ b/backends/vala/dbus.vala
@@ -69,9 +69,9 @@ public class ServiceIface : Object
d_server = server;
}
- public ObjectPath parse(string path, string data_path, SourceLocation cursor, HashTable<string,
Variant> options, GLib.BusName sender) throws Error
+ public async ObjectPath parse(string path, string data_path, SourceLocation cursor, HashTable<string,
Variant> options, GLib.BusName sender) throws Error
{
- return d_server.parse(path, data_path, cursor, options, sender);
+ return yield d_server.parse(path, data_path, cursor, options, sender);
}
public new void dispose(string path, GLib.BusName sender)
@@ -80,6 +80,22 @@ public class ServiceIface : Object
}
}
+[DBus (name = "org.gnome.CodeAssist.v1.Project")]
+public class ProjectIface : Object
+{
+ private Server d_server;
+
+ public ProjectIface(Server server)
+ {
+ d_server = server;
+ }
+
+ public async RemoteDocument[] parse_all(string path, OpenDocument[] documents, SourceLocation cursor,
HashTable<string, Variant> options, GLib.BusName sender) throws Error
+ {
+ return yield d_server.parse_all(path, documents, cursor, options, sender);
+ }
+}
+
public class Server
{
class ExportedDocument
@@ -150,7 +166,10 @@ public class Server
{
if (newowner == "" && d_apps.has_key(oldowner))
{
- dispose_app(d_apps[oldowner]);
+ lock(d_apps)
+ {
+ dispose_app(d_apps[oldowner]);
+ }
}
}
@@ -285,35 +304,79 @@ public class Server
return (ObjectPath)("/org/gnome/CodeAssist/v1/vala/%u/documents/%u".printf(app.id, doc.id));
}
- public ObjectPath parse(string path, string data_path, SourceLocation cursor, HashTable<string,
Variant> options, GLib.BusName sender) throws Error
+ public async ObjectPath parse(string path, string data_path, SourceLocation cursor, HashTable<string,
Variant> options, GLib.BusName sender) throws Error
{
- var app = ensure_app(sender);
- var doc = ensure_document(app, path, data_path, cursor);
+ App app;
+ ExportedDocument doc;
- app.service.parse(doc.document, options);
+ lock(d_apps)
+ {
+ app = ensure_app(sender);
+ doc = ensure_document(app, path, data_path, cursor);
+ }
+
+ yield app.service.parse(doc.document, options);
return remote_document_path(app, doc.document);
}
public new void dispose(string path, GLib.BusName sender)
{
- if (d_apps.has_key(sender))
+ lock(d_apps)
{
- var app = d_apps[sender];
- var cpath = clean_path(path);
-
- if (app.docs.has_key(cpath))
+ if (d_apps.has_key(sender))
{
- dispose_document(app, app.docs[cpath]);
- app.docs.unset(cpath);
+ var app = d_apps[sender];
+ var cpath = clean_path(path);
- if (app.docs.size == 0)
+ if (app.docs.has_key(cpath))
{
- dispose_app(app);
+ dispose_document(app, app.docs[cpath]);
+ app.docs.unset(cpath);
+
+ if (app.docs.size == 0)
+ {
+ dispose_app(app);
+ }
}
}
}
}
+
+ public async RemoteDocument[] parse_all(string path, OpenDocument[] documents, SourceLocation cursor,
HashTable<string, Variant> options, GLib.BusName sender) throws Error
+ {
+ App app;
+ ExportedDocument doc;
+ Document[] opendocs;
+
+ lock(d_apps)
+ {
+ app = ensure_app(sender);
+ doc = ensure_document(app, path, "", cursor);
+
+ opendocs = new Document[documents.length];
+
+ for (var i = 0; i < documents.length; i++)
+ {
+ var rdoc = ensure_document(app, documents[i].path, documents[i].data_path);
+ opendocs[i] = rdoc.document;
+ }
+ }
+
+ var retdocs = yield app.service.parse_all(doc.document, opendocs, options);
+
+ var ret = new RemoteDocument[retdocs.length];
+
+ for (var i = 0; i < retdocs.length; i++)
+ {
+ ret[i] = RemoteDocument() {
+ path = retdocs[i].client_path,
+ remote_path = remote_document_path(app, retdocs[i])
+ };
+ }
+
+ return ret;
+ }
}
class Transport
@@ -333,6 +396,7 @@ class Transport
try
{
conn.register_object("/org/gnome/CodeAssist/v1/vala", new ServiceIface(d_server));
+ conn.register_object("/org/gnome/CodeAssist/v1/vala", new ProjectIface(d_server));
conn.register_object("/org/gnome/CodeAssist/v1/vala/document", new DocumentIface());
conn.register_object("/org/gnome/CodeAssist/v1/vala/document", new
DiagnosticsIface());
diff --git a/backends/vala/diagnostics.vala b/backends/vala/diagnostics.vala
index e9c7dff..8ee7492 100644
--- a/backends/vala/diagnostics.vala
+++ b/backends/vala/diagnostics.vala
@@ -22,17 +22,33 @@ using Vala;
class Diagnostics : Report
{
- private Diagnostic[] d_diagnostics;
- public string path { get; set; }
+ private Gee.HashMap<string, Gee.ArrayList<Diagnostic?>> d_diagnostics;
- public Diagnostics(string path)
+ public Diagnostics()
{
base();
- this.path = path;
+ d_diagnostics = new Gee.HashMap<string, Gee.ArrayList<Diagnostic?>>();
+ }
+
+ public Diagnostic[] diagnostics_for_path(string path)
+ {
+ Gee.ArrayList<Diagnostic?>? diagnostics = d_diagnostics[path];
+
+ if (diagnostics == null)
+ {
+ return new Diagnostic[0];
+ }
+
+ var ret = new Diagnostic[diagnostics.size];
+ ret.length = 0;
+
+ foreach (var d in diagnostics)
+ {
+ ret += d;
+ }
- d_diagnostics = new Diagnostic[20];
- d_diagnostics.length = 0;
+ return ret;
}
private void diags_report(SourceReference? source, string message, Severity severity)
@@ -42,9 +58,12 @@ class Diagnostics : Report
return;
}
- if (source.file.filename != path)
+ Gee.ArrayList<Diagnostic?>? diagnostics = d_diagnostics[source.file.filename];
+
+ if (diagnostics == null)
{
- return;
+ diagnostics = new Gee.ArrayList<Diagnostic?>();
+ d_diagnostics[source.file.filename] = diagnostics;
}
var start = SourceLocation() {
@@ -71,17 +90,12 @@ class Diagnostics : Report
end = end
};
- d_diagnostics += Diagnostic() {
+ diagnostics.add(Diagnostic() {
severity = severity,
fixits = new Fixit[] {},
locations = new SourceRange[] {range},
message = message
- };
- }
-
- public Diagnostic[] diagnostics
- {
- get { return d_diagnostics; }
+ });
}
public override void err(SourceReference? source, string message)
diff --git a/backends/vala/hashutils.vala b/backends/vala/hashutils.vala
new file mode 100644
index 0000000..04191b3
--- /dev/null
+++ b/backends/vala/hashutils.vala
@@ -0,0 +1,36 @@
+/*
+ * This file is part of gnome-code-assistance.
+ *
+ * Copyright (C) 2013 - Jesse van den Kieboom
+ *
+ * gnome-code-assistance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gnome-code-assistance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gnome-code-assistance. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+public class HashUtils
+{
+ public class File
+ {
+ public static uint hash(GLib.File f)
+ {
+ return f.hash();
+ }
+
+ public static bool equal(GLib.File f1, GLib.File f2)
+ {
+ return f1.equal(f2);
+ }
+ }
+}
+
+/* vi:ts=4:ex */
diff --git a/backends/vala/helper.vala b/backends/vala/helper.vala
new file mode 100644
index 0000000..e9b9b88
--- /dev/null
+++ b/backends/vala/helper.vala
@@ -0,0 +1,186 @@
+/*
+ * This file is part of gnome-code-assistance.
+ *
+ * Copyright (C) 2013 - Jesse van den Kieboom
+ *
+ * gnome-code-assistance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gnome-code-assistance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gnome-code-assistance. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Vala;
+
+class Helper
+{
+ static void add_to_context(CodeContext context, string path, string? data_path)
+ {
+ if (data_path == null || data_path == path)
+ {
+ context.add_source_filename(path, false, false);
+ return;
+ }
+
+ SourceFile? sf = null;
+
+ if (path.has_suffix(".vala") || path.has_suffix(".gs"))
+ {
+ sf = new SourceFile(context, SourceFileType.SOURCE, path, null, false);
+ var nsref = new UsingDirective(new UnresolvedSymbol(null, "GLib", null));
+
+ sf.add_using_directive(nsref);
+ context.root.add_using_directive(nsref);
+ }
+ else if (path.has_suffix(".vapi") || path.has_suffix(".gir"))
+ {
+ sf = new SourceFile(context, SourceFileType.PACKAGE, path, null, false);
+ }
+
+ if (sf != null)
+ {
+ try
+ {
+ string c;
+ FileUtils.get_contents(data_path, out c);
+
+ sf.content = c;
+ } catch {}
+
+ context.add_source_file(sf);
+ }
+ }
+
+ private static bool has_errors(ParserOptions opts)
+ {
+ var c = opts.context;
+ return c.report.get_errors() > 0 || (opts.fatal_warnings && c.report.get_warnings() > 0);
+ }
+
+ private static void parse(ParserOptions opts)
+ {
+ var parser = new Parser();
+ parser.parse(opts.context);
+
+ var genie_parser = new Genie.Parser();
+ genie_parser.parse(opts.context);
+
+ if (!has_errors(opts))
+ {
+ opts.context.check();
+ }
+ }
+
+ private static void extract_diagnostics(ParserOptions opts, Rpc.Document[] docs)
+ {
+ var d = opts.context.report as Diagnostics;
+
+ for (int i = 0; i < docs.length; i++)
+ {
+ docs[i].diagnostics = d.diagnostics_for_path(docs[i].path);
+ }
+ }
+
+ private static ParserOptions create_context(Rpc.Parse parse, out Rpc.Document[] rpcdocs)
+ {
+ var opts = OptionParser.parse_and_apply(".", parse.args);
+ var sources = OptionParser.real_sources(".");
+
+ var c = opts.context;
+ CodeContext.push(c);
+
+ var docs = new Gee.HashMap<File, OpenDocument?>(HashUtils.File.hash, HashUtils.File.equal);
+ var retdocs = new Rpc.Document[0];
+
+ foreach (var doc in parse.documents)
+ {
+ var f = File.new_for_path(doc.path);
+ docs[f] = doc;
+ }
+
+ foreach (var source in sources)
+ {
+ var f = File.new_for_path(source);
+ var doc = docs[f];
+
+ if (doc != null)
+ {
+ add_to_context(c, doc.path, doc.data_path);
+
+ retdocs += Rpc.Document() {
+ path = doc.path
+ };
+ }
+ else
+ {
+ add_to_context(c, source, null);
+ }
+ }
+
+ CodeContext.pop();
+
+ rpcdocs = retdocs;
+ return opts;
+ }
+
+ private static Rpc.Reply run(Rpc.Parse cmd)
+ {
+ Rpc.Document[] docs;
+
+ var opts = create_context(cmd, out docs);
+
+ parse(opts);
+
+ extract_diagnostics(opts, docs);
+
+ return Rpc.Reply() {
+ documents = docs
+ };
+ }
+
+ private static uint8[] read_all()
+ {
+ uint8[] buffer = new uint8[4096];
+ uint8[] ret = new uint8[4096];
+ ret.length = 0;
+
+ while (!stdin.eof())
+ {
+ var n = stdin.read(buffer);
+
+ for (var i = 0; i < n; i++)
+ {
+ ret += buffer[i];
+ }
+ }
+
+ return ret;
+ }
+
+ public static void main(string[] args)
+ {
+ Rpc.Parse p = Rpc.Parse();
+ Variant dummy = p;
+
+ var inp = read_all();
+ var parse = Variant.new_from_data<void>(dummy.get_type(), inp, true);
+ p = (Rpc.Parse)parse;
+
+ var reply = run(p);
+ Variant ret = reply;
+
+ uint8[] data = new uint8[(int)ret.get_size()];
+ ret.store((void *)data);
+
+ stdout.write(data);
+ }
+}
+
+/* vi:ex:ts=4 */
diff --git a/backends/vala/makefileintegration.vala b/backends/vala/makefileintegration.vala
index d69e67e..74df33f 100644
--- a/backends/vala/makefileintegration.vala
+++ b/backends/vala/makefileintegration.vala
@@ -19,16 +19,6 @@
class MakefileIntegration
{
- static uint file_hash(File f)
- {
- return f.hash();
- }
-
- static bool file_equal(File f1, File f2)
- {
- return f1.equal(f2);
- }
-
class Makefile
{
class Source
@@ -45,7 +35,7 @@ class MakefileIntegration
public Makefile(File file)
{
d_file = file;
- d_sources = new Gee.HashMap<File, Source>(file_hash, file_equal);
+ d_sources = new Gee.HashMap<File, Source>(HashUtils.File.hash, HashUtils.File.equal);
update_mtime();
@@ -172,8 +162,8 @@ class MakefileIntegration
public MakefileIntegration()
{
- d_cache = new Gee.HashMap<File, Makefile>(file_hash, file_equal);
- d_file_to_makefile = new Gee.HashMap<File, Makefile>(file_hash, file_equal);
+ d_cache = new Gee.HashMap<File, Makefile>(HashUtils.File.hash, HashUtils.File.equal);
+ d_file_to_makefile = new Gee.HashMap<File, Makefile>(HashUtils.File.hash,
HashUtils.File.equal);
}
public bool changed_for_file(File f)
@@ -210,15 +200,19 @@ class MakefileIntegration
}
}
- public string[]? flags_for_file(File f)
+ public string[]? flags_for_file(File f, out string? wd)
{
var makefile = makefile_for(f);
+ wd = null;
+
if (makefile == null)
{
return null;
}
+ wd = makefile.get_parent().get_path();
+
var m = d_cache[makefile];
if (m != null)
@@ -523,7 +517,7 @@ class MakefileIntegration
}
string[] retargs;
- var sargs = outstr[pos+fakevalac.length:epos-pos];
+ var sargs = outstr[pos:epos];
try
{
@@ -546,8 +540,8 @@ class MakefileIntegration
#if MAIN
public static int main(string[] a){
MakefileIntegration it = new MakefileIntegration();
-
- stdout.printf("Flags: %s\n", string.joinv(", ",
it.flags_for_file(File.new_for_commandline_arg(a[1]))));
+ string wd;
+ stdout.printf("Flags: %s\n", string.joinv(", ", it.flags_for_file(File.new_for_commandline_arg(a[1]),
out wd)));
return 0;
}
#endif
diff --git a/backends/vala/rpc.vala b/backends/vala/rpc.vala
new file mode 100644
index 0000000..0f8bdf8
--- /dev/null
+++ b/backends/vala/rpc.vala
@@ -0,0 +1,21 @@
+namespace Rpc
+{
+ public struct Parse
+ {
+ public string[] args;
+ public OpenDocument[] documents;
+ }
+
+ public struct Document
+ {
+ public string path;
+ public Diagnostic[] diagnostics;
+ }
+
+ public struct Reply
+ {
+ public Document[] documents;
+ }
+}
+
+/* vi:ex:ts=4 */
diff --git a/backends/vala/service.vala b/backends/vala/service.vala
index aa4f2b7..f292d84 100644
--- a/backends/vala/service.vala
+++ b/backends/vala/service.vala
@@ -20,33 +20,216 @@
using Vala;
-public class Service : Object
+public class Service
{
- public void parse(Document doc, HashTable<string, Variant> options) throws Error
+ private MakefileIntegration d_makefile;
+
+ public Service()
+ {
+ d_makefile = new MakefileIntegration();
+ }
+
+ private char[] read_all(IOChannel f)
+ {
+ char[] buffer = new char[4096];
+ char[] ret = new char[4096];
+ ret.length = 0;
+
+ while (true)
+ {
+ size_t n;
+ IOStatus st;
+
+ try
+ {
+ st = f.read_chars(buffer, out n);
+ }
+ catch
+ {
+ st = IOStatus.ERROR;
+ n = 0;
+ }
+
+ for (var i = 0; i < n; i++)
+ {
+ ret += buffer[i];
+ }
+
+ if (st == IOStatus.EOF || st == IOStatus.ERROR)
+ {
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ private async Rpc.Reply spawn_helper(Document[] documents, string wd, string[] flags)
+ {
+ SourceFunc cb = spawn_helper.callback;
+ var argv = new string[] {Path.build_filename(Config.BackendExecDir, "valahelper")};
+
+ Pid pid;
+ int inp, outp;
+
+ try
+ {
+ Process.spawn_async_with_pipes(wd, argv, null, 0, null, out pid, out inp, out outp,
null);
+ }
+ catch (SpawnError e)
+ {
+ log("GcaVala", LogLevelFlags.LEVEL_DEBUG, "Failed to spawn helper: %s", e.message);
+ return Rpc.Reply();
+ }
+
+ var outstr = new IOChannel.unix_new(outp);
+ var instr = new IOChannel.unix_new(inp);
+
+ char[] retb = new char[0];
+
+ Thread<void*>? reader = null;
+ Thread<void*>? writer = null;
+
+ try
+ {
+ reader = new Thread<void *>.try("reader", () => {
+ retb = read_all(outstr);
+ return null;
+ });
+ }
+ catch (Error e)
+ {
+ log("GcaVala", LogLevelFlags.LEVEL_DEBUG, "Failed to create reader thread: %s",
e.message);
+
+ try
+ {
+ outstr.shutdown(false);
+ } catch {}
+ }
+
+ try
+ {
+ writer = new Thread<void*>.try("writer", () => {
+ var odocs = new OpenDocument[documents.length];
+
+ for (int i = 0; i < documents.length; i++)
+ {
+ odocs[i].path = documents[i].path;
+ odocs[i].data_path = documents[i].data_path;
+ }
+
+ var cmd = Rpc.Parse() {
+ args = flags,
+ documents = odocs
+ };
+
+ Variant vv = cmd;
+ char[] data = new char[(int)vv.get_size()];
+
+ vv.store((void *)data);
+
+ try
+ {
+ size_t n;
+ instr.write_chars(data, out n);
+ } catch {}
+
+ try
+ {
+ instr.shutdown(true);
+ } catch {}
+
+ return null;
+ });
+ }
+ catch (Error e)
+ {
+ log("GcaVala", LogLevelFlags.LEVEL_DEBUG, "Failed to create writer thread: %s",
e.message);
+
+ try
+ {
+ instr.shutdown(false);
+ } catch {}
+ }
+
+ ChildWatch.add(pid, (p, st) => {
+ Process.close_pid(p);
+ cb();
+ });
+
+ yield;
+
+ if (writer != null)
+ {
+ writer.join();
+ }
+
+ if (reader != null)
+ {
+ reader.join();
+ }
+
+ try
+ {
+ outstr.shutdown(false);
+ instr.shutdown(false);
+ } catch {}
+
+ Rpc.Reply r = Rpc.Reply();
+ Variant dummy = r;
+
+ var reply = Variant.new_from_data<void>(dummy.get_type(), (uchar[])retb, true);
+ return (Rpc.Reply)reply;
+ }
+
+ private async Document[] parse_impl(Document doc, Document[] documents, HashTable<string, Variant>
options)
{
- CodeContext context = new CodeContext();
+ var f = File.new_for_path(doc.path);
- var diags = new Diagnostics(doc.path);
- context.report = diags;
+ string wd;
+ var flags = d_makefile.flags_for_file(f, out wd);
- CodeContext.push(context);
+ var reply = yield spawn_helper(documents, wd, flags);
- string source;
- FileUtils.get_contents(doc.data_path, out source);
+ var odocs = new Gee.HashMap<string, Document>();
- var sf = new SourceFile(context, SourceFileType.SOURCE, doc.path, source, true);
- context.add_source_file(sf);
+ foreach (var d in documents)
+ {
+ odocs[d.path] = doc;
+ }
- Parser ast = new Parser();
- ast.parse(context);
+ var retdocs = new Document[reply.documents.length];
+ retdocs.length = 0;
- CodeContext.pop();
+ foreach (var d in reply.documents)
+ {
+ var odoc = odocs[d.path];
- doc.diagnostics = diags.diagnostics;
+ if (odoc != null)
+ {
+ odoc.diagnostics = d.diagnostics;
+ retdocs += odoc;
+ }
+ }
+
+ return retdocs;
+ }
+
+ public async void parse(Document doc, HashTable<string, Variant> options)
+ {
+ yield parse_impl(doc, new Document[] {doc}, options);
+ }
+
+ public async Document[] parse_all(Document doc, Document[] documents, HashTable<string, Variant>
options)
+ {
+ return yield parse_impl(doc, documents, options);
}
public new void dispose(Document document)
{
+ var f = File.new_for_path(document.path);
+
+ d_makefile.dispose(f);
}
}
diff --git a/backends/vala/types.vala b/backends/vala/types.vala
index 2a485a2..50c8021 100644
--- a/backends/vala/types.vala
+++ b/backends/vala/types.vala
@@ -54,7 +54,7 @@ public struct Fixit
public string replacement;
}
-enum Severity
+public enum Severity
{
NONE,
INFO,
@@ -72,4 +72,16 @@ public struct Diagnostic
public string message;
}
+public struct RemoteDocument
+{
+ public string path;
+ public ObjectPath remote_path;
+}
+
+public struct OpenDocument
+{
+ public string path;
+ public string data_path;
+}
+
/* vi:ex:ts=4 */
diff --git a/backends/vala/valaoptionparser.vala b/backends/vala/valaoptionparser.vala
index f88d6f9..03766a2 100644
--- a/backends/vala/valaoptionparser.vala
+++ b/backends/vala/valaoptionparser.vala
@@ -23,8 +23,15 @@
*/
using GLib;
+using Vala;
-class Vala.OptionParser {
+struct ParserOptions
+{
+ public CodeContext context;
+ public bool fatal_warnings;
+}
+
+class OptionParser {
static string basedir;
static string directory;
static bool version;
@@ -140,7 +147,7 @@ class Vala.OptionParser {
{ null }
};
- private static bool apply (global::Vala.CodeContext context, string cwd) {
+ private static ParserOptions apply (CodeContext context, string[] args, string wd) {
context.assert = !disable_assert;
context.checking = enable_checking;
context.deprecated = deprecated;
@@ -164,18 +171,18 @@ class Vala.OptionParser {
context.includedir = includedir;
context.output = output;
if (basedir == null) {
- context.basedir = CodeContext.realpath (cwd);
+ context.basedir = wd;
} else {
- context.basedir = CodeContext.realpath (basedir);
+ context.basedir = realpath (wd, basedir);
}
if (directory != null) {
- context.directory = CodeContext.realpath (directory);
+ context.directory = realpath (wd, directory);
} else {
context.directory = context.basedir;
}
- context.vapi_directories = vapi_directories;
- context.gir_directories = gir_directories;
- context.metadata_directories = metadata_directories;
+ context.vapi_directories = realpaths(wd, vapi_directories);
+ context.gir_directories = realpaths(wd, gir_directories);
+ context.metadata_directories = realpaths(wd, metadata_directories);
context.debug = debug;
context.thread = thread;
context.mem_profiler = mem_profiler;
@@ -235,34 +242,142 @@ class Vala.OptionParser {
if (fast_vapis != null) {
foreach (string vapi in fast_vapis) {
- var rpath = CodeContext.realpath (vapi);
+ var rpath = realpath (wd, vapi);
var source_file = new SourceFile (context, SourceFileType.FAST, rpath);
context.add_source_file (source_file);
}
context.use_fast_vapi = true;
}
- return (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings ()
0));
+ return ParserOptions() {
+ fatal_warnings = fatal_warnings,
+ context = context
+ };
+ }
+
+ public static string[] real_sources(string wd)
+ {
+ return realpaths(wd, sources);
+ }
+
+ private static string[] realpaths(string wd, string[] paths)
+ {
+ var ret = new string[paths.length];
+
+ for (var i = 0; i < paths.length; i++)
+ {
+ ret[i] = realpath(wd, paths[i]);
+ }
+
+ return ret;
+ }
+
+ private static string realpath(string wd, string path)
+ {
+ var rpath = path;
+
+ if (!Path.is_absolute(path))
+ {
+ rpath = Path.build_filename(wd, rpath);
+ }
+
+ return File.new_for_path(rpath).get_path();
+ }
+
+ private static void clear()
+ {
+ basedir = null;
+ directory = null;
+ version = false;
+ api_version = false;
+ sources = null;
+ vapi_directories = null;
+ gir_directories = null;
+ metadata_directories = null;
+ vapi_filename = null;
+ library = null;
+ gir = null;
+ packages = null;
+ fast_vapis = null;
+ target_glib = null;
+ gresources = null;
+
+ ccode_only = false;
+ header_filename = null;
+ use_header = false;
+ internal_header_filename = null;
+ internal_vapi_filename = null;
+ fast_vapi_filename = null;
+ symbols_filename = null;
+ includedir = null;
+ compile_only = false;
+ output = null;
+ debug = false;
+ thread = false;
+ mem_profiler = false;
+ disable_assert = false;
+ enable_checking = false;
+ deprecated = false;
+ experimental = false;
+ experimental_non_null = false;
+ gobject_tracing = false;
+ disable_warnings = false;
+ cc_command = null;
+ cc_options = null;
+ dump_tree = null;
+ save_temps = false;
+ defines = null;
+ quiet_mode = false;
+ verbose_mode = false;
+ profile = null;
+ nostdpkg = false;
+ enable_version_header = false;
+ disable_version_header = false;
+ fatal_warnings = false;
+ dependencies = null;
+
+ entry_point = null;
+ run_output = false;
}
public static bool parse(string[] args) {
+ string[] myargs = args;
+
try {
+ unowned string[] unargs = myargs;
+
+ clear();
+
var opt_context = new OptionContext ("- Vala Compiler");
opt_context.set_help_enabled (false);
opt_context.add_main_entries (options, null);
opt_context.set_ignore_unknown_options (true);
- opt_context.parse (ref args);
- } catch { return false; }
+ opt_context.parse (ref unargs);
+ }
+ catch (Error e)
+ {
+ log("GcaVala",
+ LogLevelFlags.LEVEL_WARNING,
+ "Failed to parse flags `%s': %s",
+ string.joinv(", ", args), e.message);
+
+ clear();
+ return false;
+ }
return true;
}
- public static bool parse_and_apply(string cwd, global::Vala.CodeContext context, string[] args) {
- if (!parse(args))
- {
- return false;
- }
+ public static ParserOptions parse_and_apply(string wd, string[] args) {
+ parse(args);
+
+ var context = new CodeContext();
+ context.report = new Diagnostics();
+
+ CodeContext.push(context);
+ var ret = apply(context, args, wd);
+ CodeContext.pop();
- return apply(context, cwd);
+ return ret;
}
}
diff --git a/configure.ac b/configure.ac
index 29287db..75efaa1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -586,6 +586,7 @@ backends/ruby/ruby
backends/xml/org.gnome.CodeAssist.v1.xml.service
backends/xml/xml
backends/vala/org.gnome.CodeAssist.v1.vala.service
+backends/vala/config.vala
backends/go/org.gnome.CodeAssist.v1.go.service
backends/js/org.gnome.CodeAssist.v1.js.service
backends/js/js
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]