[vala/wip/vapicheck: 329/330] vapicheck: Run compile check on given vapi file
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/vapicheck: 329/330] vapicheck: Run compile check on given vapi file
- Date: Tue, 25 Jan 2022 17:26:41 +0000 (UTC)
commit e499872b1314afbf99947b805a7fb55611008c70
Author: Rico Tzschichholz <ricotz ubuntu com>
Date: Sun Jan 31 13:04:52 2021 +0100
vapicheck: Run compile check on given vapi file
vapigen/valavapicheck.vala | 1031 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 923 insertions(+), 108 deletions(-)
---
diff --git a/vapigen/valavapicheck.vala b/vapigen/valavapicheck.vala
index 9214e16ec..45833d7c0 100644
--- a/vapigen/valavapicheck.vala
+++ b/vapigen/valavapicheck.vala
@@ -1,6 +1,6 @@
/* valavapicheck.vala
*
- * Copyright (C) 2007 Mathias Hasselmann
+ * Copyright (C) 2021 Rico Tzschichholz
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,164 +17,979 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author:
- * Mathias Hasselmann <mathias hasselmann gmx de>
+ * Rico Tzschichholz <ricotz ubuntu com>
*/
using GLib;
-class Vala.VAPICheck {
- public VAPICheck (string gidlname, CodeContext context = new CodeContext ()) {
- gidl = new SourceFile (context, SourceFileType.SOURCE, gidlname);
- metadata = new SourceFile (context, SourceFileType.SOURCE, gidlname.substring (0,
gidlname.length - 5) + ".metadata");
- this.context = context;
+class Vala.VapiCheck {
+ private const string DEFAULT_COLORS =
"error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01";
+
+ static string basedir;
+ static string directory;
+ static bool version;
+ static bool api_version;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] sources;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] vapi_directories;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] gir_directories;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] metadata_directories;
+ static string vapi_filename;
+ static string library;
+ static string shared_library;
+ static string gir;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] packages;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] fast_vapis;
+ static string target_glib;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] gresources;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] gresources_directories;
+
+ static bool ccode_only;
+ static bool abi_stability;
+ static string header_filename;
+ static string internal_header_filename;
+ static string internal_vapi_filename;
+ static string fast_vapi_filename;
+ static bool vapi_comments;
+ static string symbols_filename;
+ static string includedir;
+ static bool compile_only;
+ static string output;
+ static bool debug;
+ static bool mem_profiler;
+ static bool disable_assert;
+ static bool enable_checking;
+ static bool deprecated;
+ static bool hide_internal;
+ static bool experimental;
+ static bool experimental_non_null;
+ static bool gobject_tracing;
+ static bool disable_since_check;
+ static bool disable_warnings;
+ static bool keep_going;
+ static bool list_sources;
+ static string cc_command;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] cc_options;
+ static string pkg_config_command;
+ static string dump_tree;
+ static bool save_temps;
+ [CCode (array_length = false, array_null_terminated = true)]
+ static string[] defines;
+ static bool quiet_mode;
+ static bool verbose_mode;
+ static Profile profile;
+ static bool nostdpkg;
+ static bool enable_version_header;
+ static bool disable_version_header;
+ static bool fatal_warnings;
+ static bool disable_colored_output;
+ static Report.Colored colored_output = Report.Colored.AUTO;
+ static string dependencies;
+ static string depfile;
+
+ static string entry_point;
+
+ static bool run_output;
+ static string run_args;
+
+ private CodeContext context;
+
+ const OptionEntry[] options = {
+ { "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref vapi_directories, "Look for package bindings
in DIRECTORY", "DIRECTORY..." },
+ { "girdir", 0, 0, OptionArg.FILENAME_ARRAY, ref gir_directories, "Look for .gir files in
DIRECTORY", "DIRECTORY..." },
+ { "metadatadir", 0, 0, OptionArg.FILENAME_ARRAY, ref metadata_directories, "Look for GIR
.metadata files in DIRECTORY", "DIRECTORY..." },
+ { "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE",
"PACKAGE..." },
+ { "vapi", 0, 0, OptionArg.FILENAME, ref vapi_filename, "Output VAPI file name", "FILE" },
+ { "library", 0, 0, OptionArg.STRING, ref library, "Library name", "NAME" },
+ { "shared-library", 0, 0, OptionArg.STRING, ref shared_library, "Shared library name used in
generated gir", "NAME" },
+ { "gir", 0, 0, OptionArg.STRING, ref gir, "GObject-Introspection repository file name",
"NAME-VERSION.gir" },
+ { "basedir", 'b', 0, OptionArg.FILENAME, ref basedir, "Base source directory", "DIRECTORY" },
+ { "directory", 'd', 0, OptionArg.FILENAME, ref directory, "Change output directory from
current working directory", "DIRECTORY" },
+ { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null },
+ { "api-version", 0, 0, OptionArg.NONE, ref api_version, "Display API version number", null },
+ { "ccode", 'C', 0, OptionArg.NONE, ref ccode_only, "Output C code", null },
+ { "header", 'H', 0, OptionArg.FILENAME, ref header_filename, "Output C header file", "FILE" },
+ { "use-header", 0, OptionFlags.OPTIONAL_ARG | OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*)
option_deprecated, "Use C header file (DEPRECATED AND IGNORED)", null },
+ { "includedir", 0, 0, OptionArg.FILENAME, ref includedir, "Directory used to include the C
header file", "DIRECTORY" },
+ { "internal-header", 'h', 0, OptionArg.FILENAME, ref internal_header_filename, "Output
internal C header file", "FILE" },
+ { "internal-vapi", 0, 0, OptionArg.FILENAME, ref internal_vapi_filename, "Output vapi with
internal api", "FILE" },
+ { "fast-vapi", 0, 0, OptionArg.STRING, ref fast_vapi_filename, "Output vapi without
performing symbol resolution", null },
+ { "use-fast-vapi", 0, 0, OptionArg.STRING_ARRAY, ref fast_vapis, "Use --fast-vapi output
during this compile", null },
+ { "vapi-comments", 0, 0, OptionArg.NONE, ref vapi_comments, "Include comments in generated
vapi", null },
+ { "deps", 0, 0, OptionArg.STRING, ref dependencies, "Write make-style dependency information
to this file", null },
+ { "depfile", 0, 0, OptionArg.STRING, ref depfile, "Write make-style external dependency
information for build systems to this file", null },
+ { "list-sources", 0, 0, OptionArg.NONE, ref list_sources, "Output a list of all source and
binding files which are used", null },
+ { "symbols", 0, 0, OptionArg.FILENAME, ref symbols_filename, "Output symbols file", "FILE" },
+ { "compile", 'c', 0, OptionArg.NONE, ref compile_only, "Compile but do not link", null },
+ { "output", 'o', 0, OptionArg.FILENAME, ref output, "Place output in file FILE", "FILE" },
+ { "debug", 'g', 0, OptionArg.NONE, ref debug, "Produce debug information", null },
+ { "thread", 0, OptionFlags.OPTIONAL_ARG | OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*)
option_deprecated, "Enable multithreading support (DEPRECATED AND IGNORED)", null },
+ { "enable-mem-profiler", 0, 0, OptionArg.NONE, ref mem_profiler, "Enable GLib memory
profiler", null },
+ { "define", 'D', 0, OptionArg.STRING_ARRAY, ref defines, "Define SYMBOL", "SYMBOL..." },
+ { "main", 0, 0, OptionArg.STRING, ref entry_point, "Use SYMBOL as entry point", "SYMBOL..." },
+ { "nostdpkg", 0, 0, OptionArg.NONE, ref nostdpkg, "Do not include standard packages", null },
+ { "disable-assert", 0, 0, OptionArg.NONE, ref disable_assert, "Disable assertions", null },
+ { "enable-checking", 0, 0, OptionArg.NONE, ref enable_checking, "Enable additional run-time
checks", null },
+ { "enable-deprecated", 0, 0, OptionArg.NONE, ref deprecated, "Enable deprecated features",
null },
+ { "hide-internal", 0, 0, OptionArg.NONE, ref hide_internal, "Hide symbols marked as
internal", null },
+ { "enable-experimental", 0, 0, OptionArg.NONE, ref experimental, "Enable experimental
features", null },
+ { "disable-warnings", 0, 0, OptionArg.NONE, ref disable_warnings, "Disable warnings", null },
+ { "fatal-warnings", 0, 0, OptionArg.NONE, ref fatal_warnings, "Treat warnings as fatal", null
},
+ { "disable-since-check", 0, 0, OptionArg.NONE, ref disable_since_check, "Do not check whether
used symbols exist in local packages", null },
+ { "keep-going", 'k', 0, OptionArg.NONE, ref keep_going, "Continue as much as possible after
an error", null },
+ { "enable-experimental-non-null", 0, 0, OptionArg.NONE, ref experimental_non_null, "Enable
experimental enhancements for non-null types", null },
+ { "enable-gobject-tracing", 0, 0, OptionArg.NONE, ref gobject_tracing, "Enable GObject
creation tracing", null },
+ { "cc", 0, 0, OptionArg.STRING, ref cc_command, "Use COMMAND as C compiler command",
"COMMAND" },
+ { "Xcc", 'X', 0, OptionArg.STRING_ARRAY, ref cc_options, "Pass OPTION to the C compiler",
"OPTION..." },
+ { "pkg-config", 0, 0, OptionArg.STRING, ref pkg_config_command, "Use COMMAND as pkg-config
command", "COMMAND" },
+ { "dump-tree", 0, 0, OptionArg.FILENAME, ref dump_tree, "Write code tree to FILE", "FILE" },
+ { "save-temps", 0, 0, OptionArg.NONE, ref save_temps, "Keep temporary files", null },
+ { "profile", 0, OptionFlags.OPTIONAL_ARG, OptionArg.CALLBACK, (void*) option_parse_profile,
"Use the given profile instead of the default, options are 'gobject' or 'posix'", "PROFILE" },
+ { "quiet", 'q', 0, OptionArg.NONE, ref quiet_mode, "Do not print messages to the console",
null },
+ { "verbose", 'v', 0, OptionArg.NONE, ref verbose_mode, "Print additional messages to the
console", null },
+ { "no-color", 0, 0, OptionArg.NONE, ref disable_colored_output, "Disable colored output,
alias for --color=never", null },
+ { "color", 0, OptionFlags.OPTIONAL_ARG, OptionArg.CALLBACK, (void*) option_parse_color,
"Enable color output, options are 'always', 'never', or 'auto'", "WHEN" },
+ { "target-glib", 0, 0, OptionArg.STRING, ref target_glib, "Target version of glib for code
generation", "'MAJOR.MINOR', or 'auto'" },
+ { "gresources", 0, 0, OptionArg.FILENAME_ARRAY, ref gresources, "XML of gresources",
"FILE..." },
+ { "gresourcesdir", 0, 0, OptionArg.FILENAME_ARRAY, ref gresources_directories, "Look for
resources in DIRECTORY", "DIRECTORY..." },
+ { "enable-version-header", 0, 0, OptionArg.NONE, ref enable_version_header, "Write vala build
version in generated files", null },
+ { "disable-version-header", 0, 0, OptionArg.NONE, ref disable_version_header, "Do not write
vala build version in generated files", null },
+ { "run-args", 0, 0, OptionArg.STRING, ref run_args, "Arguments passed to directly compiled
executable", null },
+ { "abi-stability", 0, 0, OptionArg.NONE, ref abi_stability, "Enable support for ABI
stability", null },
+ { OPTION_REMAINING, 0, 0, OptionArg.FILENAME_ARRAY, ref sources, null, "VAPI_FILE..." },
+ { null }
+ };
+
+ static bool option_parse_color (string option_name, string? val, void* data) throws OptionError {
+ switch (val) {
+ case "auto": colored_output = Report.Colored.AUTO; break;
+ case "never": colored_output = Report.Colored.NEVER; break;
+ case null:
+ case "always": colored_output = Report.Colored.ALWAYS; break;
+ default: throw new OptionError.FAILED ("Invalid --color argument '%s'", val);
+ }
+ return true;
}
- public CodeContext context { get; private set; }
- public SourceFile gidl { get; private set; }
- public SourceFile metadata { get; private set; }
-
- private List<string> _scope;
- private Set<string> _symbols;
+ static bool option_parse_profile (string option_name, string? val, void* data) throws OptionError {
+ switch (val) {
+ case null:
+ case "gobject-2.0":
+ case "gobject": profile = Profile.GOBJECT; break;
+ case "posix": profile = Profile.POSIX; break;
+ default: throw new OptionError.FAILED ("Invalid --profile argument '%s'", val);
+ }
+ return true;
+ }
- private void parse_gidl () {
- _scope = new ArrayList<string> ();
- _symbols = new HashSet<string> (str_hash, str_equal);
+ static bool option_deprecated (string option_name, string? val, void* data) throws OptionError {
+ stdout.printf ("Command-line option `%s` is deprecated and will be ignored\n", option_name);
+ return true;
+ }
- try {
- foreach (weak IdlModule module in Idl.parse_file (gidl.filename)) {
- parse_members (module.name, module.entries);
+ private int quit () {
+ if (context.report.get_errors () == 0 && context.report.get_warnings () == 0) {
+ CodeContext.pop ();
+ return 0;
+ }
+ if (context.report.get_errors () == 0 && (!fatal_warnings || context.report.get_warnings ()
== 0)) {
+ if (!quiet_mode) {
+ stdout.printf ("Compilation succeeded - %d warning(s)\n",
context.report.get_warnings ());
}
- } catch (MarkupError e) {
- stderr.printf ("%s: %s\n", gidl.filename, e.message);
- }
+ CodeContext.pop ();
+ return 0;
+ } else {
+ if (!quiet_mode) {
+ stdout.printf ("Compilation failed: %d error(s), %d warning(s)\n",
context.report.get_errors (), context.report.get_warnings ());
+ }
+ CodeContext.pop ();
+ return 1;
+ }
}
- private void add_symbol (string name, string? separator = null) {
+ private int run () {
+ context = new CodeContext ();
+ CodeContext.push (context);
+
+ if (disable_colored_output) {
+ colored_output = Report.Colored.NEVER;
+ }
+
+ if (colored_output != Report.Colored.NEVER) {
+ unowned string env_colors = Environment.get_variable ("VALA_COLORS");
+ if (env_colors != null) {
+ context.report.set_colors (env_colors, colored_output);
+ } else {
+ context.report.set_colors (DEFAULT_COLORS, colored_output);
+ }
+ }
+
+
+ // default to build executable
+ if (!ccode_only && !compile_only && output == null) {
+ // strip extension if there is one
+ // else we use the default output file of the C compiler
+ if (sources[0].last_index_of_char ('.') != -1) {
+ int dot = sources[0].last_index_of_char ('.');
+ output = Path.get_basename (sources[0].substring (0, dot));
+ }
+ }
+
+ context.assert = !disable_assert;
+ context.checking = enable_checking;
+ context.deprecated = deprecated;
+ context.since_check = !disable_since_check;
+ context.hide_internal = hide_internal;
+ context.experimental = experimental;
+ context.experimental_non_null = experimental_non_null;
+ context.gobject_tracing = gobject_tracing;
+ context.keep_going = keep_going;
+ context.report.enable_warnings = !disable_warnings;
+ context.report.set_verbose_errors (!quiet_mode);
+ context.verbose_mode = verbose_mode;
+ context.version_header = !disable_version_header;
+
+ context.ccode_only = ccode_only;
+ if (ccode_only && cc_options != null) {
+ Report.warning (null, "-X has no effect when -C or --ccode is set");
+ }
+ context.abi_stability = abi_stability;
+ context.compile_only = compile_only;
+ context.header_filename = header_filename;
+ context.internal_header_filename = internal_header_filename;
+ context.symbols_filename = symbols_filename;
+ context.includedir = includedir;
+ context.output = output;
+ if (output != null && ccode_only) {
+ Report.warning (null, "--output and -o have no effect when -C or --ccode is set");
+ }
+ if (basedir == null) {
+ context.basedir = CodeContext.realpath (".");
+ } else {
+ context.basedir = CodeContext.realpath (basedir);
+ }
+ if (directory != null) {
+ context.directory = CodeContext.realpath (directory);
+ } else {
+ context.directory = context.basedir;
+ }
+ context.vapi_directories = vapi_directories;
+ context.vapi_comments = vapi_comments;
+ context.gir_directories = gir_directories;
+ context.metadata_directories = metadata_directories;
+ context.debug = debug;
+ context.mem_profiler = mem_profiler;
+ context.save_temps = save_temps;
+ if (ccode_only && save_temps) {
+ Report.warning (null, "--save-temps has no effect when -C or --ccode is set");
+ }
+ nostdpkg |= fast_vapi_filename != null;
+
+ context.entry_point_name = entry_point;
+
+ context.run_output = run_output;
+
+ if (pkg_config_command == null) {
+ pkg_config_command = Environment.get_variable ("PKG_CONFIG") ?? "pkg-config";
+ }
+ context.pkg_config_command = pkg_config_command;
+
+ context.set_target_profile (profile, !nostdpkg);
+
+ if (target_glib != null) {
+ context.set_target_glib_version (target_glib);
+ }
+
+ if (defines != null) {
+ foreach (string define in defines) {
+ context.add_define (define);
+ }
+ }
+
+ if (packages != null) {
+ foreach (string package in packages) {
+ context.add_external_package (package);
+ }
+ packages = null;
+ }
+
+ if (fast_vapis != null) {
+ foreach (string vapi in fast_vapis) {
+ var rpath = CodeContext.realpath (vapi);
+ var source_file = new SourceFile (context, SourceFileType.FAST, rpath);
+ context.add_source_file (source_file);
+ }
+ context.use_fast_vapi = true;
+ }
+
+ context.gresources = gresources;
+ context.gresources_directories = gresources_directories;
+
+ if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () >
0)) {
+ return quit ();
+ }
+
+ if (context.profile == Profile.GOBJECT) {
+ //context.codegen = new GDBusServerModule ();
+ } else {
+ //context.codegen = new CCodeDelegateModule ();
+ }
+
+ bool has_c_files = false;
+ bool has_h_files = false;
+
+ var source_filename = CodeContext.realpath (sources[0]);
+ context.add_source_filename (sources[0], run_output, true);
+
+ int last_dot;
+ var source_basename = Path.get_basename (source_filename);
+ if ((last_dot = source_basename.last_index_of_char ('.')) != -1) {
+ var deps_filename = Path.build_path (Path.DIR_SEPARATOR_S, Path.get_dirname
(source_filename), source_basename.substring (0, last_dot) + ".deps");
+ context.add_packages_from_file (deps_filename);
+ }
+
+ sources = null;
+ if (ccode_only && (has_c_files || has_h_files)) {
+ Report.warning (null, "C header and source files are ignored when -C or --ccode is
set");
+ }
+
+ if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () >
0)) {
+ return quit ();
+ }
+
+ if (list_sources) {
+ foreach (SourceFile file in context.get_source_files ()) {
+ print ("%s\n", file.filename);
+ }
+ if (!ccode_only) {
+ foreach (string filename in context.get_c_source_files ()) {
+ print ("%s\n", filename);
+ }
+ }
+ return 0;
+ }
+
+ var parser = new Parser ();
+ parser.parse (context);
+
+ var genie_parser = new Genie.Parser ();
+ genie_parser.parse (context);
+
+ var gir_parser = new GirParser ();
+ gir_parser.parse (context);
+
+ if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () >
0)) {
+ return quit ();
+ }
+
+ if (fast_vapi_filename != null) {
+ var interface_writer = new CodeWriter (CodeWriterType.FAST);
+ interface_writer.write_file (context, fast_vapi_filename);
+ return quit ();
+ }
+
+ context.check ();
+
+ if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () >
0)) {
+ return quit ();
+ }
+
+ if (!ccode_only && !compile_only && library == null) {
+ // building program, require entry point
+ if (!has_c_files && context.entry_point == null) {
+ Report.warning (null, "program does not contain a static `main' method");
+ }
+ }
+
+ var codegen = new Codegen ();
+ foreach (SourceFile file in context.get_source_files ()) {
+ if (file.filename != source_filename) {
+ continue;
+ }
+ codegen.run (context, file);
+ break;
+ }
+
+ if (dump_tree != null) {
+ var code_writer = new CodeWriter (CodeWriterType.DUMP);
+ code_writer.write_file (context, dump_tree);
+ }
+
+ if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () >
0)) {
+ return quit ();
+ }
+
+ //context.codegen.emit (context);
- if (null != separator) {
- string fullname = get_scope () + separator + name;
- _symbols.add (fullname);
+ if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () >
0)) {
+ return quit ();
+ }
+
+ if (vapi_filename == null && library != null) {
+ // keep backward compatibility with --library option
+ vapi_filename = "%s.vapi".printf (library);
+ }
+
+ if (library != null) {
+ if (gir != null) {
+ if (context.profile == Profile.GOBJECT) {
+ string gir_base = Path.get_basename (gir);
+ long gir_len = gir_base.length;
+ int last_hyphen = gir_base.last_index_of_char ('-');
+
+ if (last_hyphen == -1 || !gir_base.has_suffix (".gir")) {
+ Report.error (null, "GIR file name `%s' is not well-formed,
expected NAME-VERSION.gir", gir);
+ } else {
+ string gir_namespace = gir_base.substring (0, last_hyphen);
+ string gir_version = gir_base.substring (last_hyphen + 1,
gir_len - last_hyphen - 5);
+ gir_version.canon ("0123456789.", '?');
+ if (gir_namespace == "" || gir_version == "" ||
!gir_version[0].isdigit () || gir_version.contains ("?")) {
+ Report.error (null, "GIR file name `%s' is not
well-formed, expected NAME-VERSION.gir", gir);
+ } else {
+ //var gir_writer = new GIRWriter ();
+
+ // put .gir file in current directory unless -d has
been explicitly specified
+ string gir_directory = ".";
+ if (directory != null) {
+ gir_directory = context.directory;
+ }
+
+ //gir_writer.write_file (context, gir_directory, gir,
gir_namespace, gir_version, library, shared_library);
+ }
+ }
+ }
+
+ gir = null;
+ }
+
+ library = null;
} else {
- _symbols.add (name);
+ if (gir != null) {
+ Report.warning (null, "--gir has no effect without --library");
+ gir = null;
+ }
+ }
+
+ // The GIRWriter places the gir_namespace and gir_version into the top namespace, so write
the vapi after that stage
+ if (vapi_filename != null) {
+ var interface_writer = new CodeWriter ();
+
+ // put .vapi file in current directory unless -d has been explicitly specified
+ if (directory != null && !Path.is_absolute (vapi_filename)) {
+ vapi_filename = "%s%c%s".printf (context.directory, Path.DIR_SEPARATOR,
vapi_filename);
+ }
+
+ interface_writer.write_file (context, vapi_filename);
+ }
+
+ if (internal_vapi_filename != null) {
+ if (internal_header_filename == null ||
+ header_filename == null) {
+ Report.error (null, "--internal-vapi may only be used in combination with
--header and --internal-header");
+ return quit();
+ }
+
+ var interface_writer = new CodeWriter (CodeWriterType.INTERNAL);
+
+ if (context.includedir != null) {
+ var prefixed_header_filename = Path.build_path ("/", context.includedir,
Path.get_basename (header_filename));
+ var prefixed_internal_header_filename = Path.build_path ("/",
context.includedir, Path.get_basename (internal_header_filename));
+ interface_writer.set_cheader_override (prefixed_header_filename,
prefixed_internal_header_filename);
+ } else {
+ interface_writer.set_cheader_override (header_filename,
internal_header_filename);
+ }
+
+ string vapi_filename = internal_vapi_filename;
+
+ // put .vapi file in current directory unless -d has been explicitly specified
+ if (directory != null && !Path.is_absolute (vapi_filename)) {
+ vapi_filename = "%s%c%s".printf (context.directory, Path.DIR_SEPARATOR,
vapi_filename);
+ }
+
+ interface_writer.write_file (context, vapi_filename);
+
+ internal_vapi_filename = null;
+ }
+
+ if (dependencies != null) {
+ context.write_dependencies (dependencies);
+ }
+
+ if (depfile != null) {
+ context.write_external_dependencies (depfile);
}
+
+ if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () >
0)) {
+ return quit ();
+ }
+
+ if (!ccode_only) {
+ //var ccompiler = new CCodeCompiler ();
+ if (cc_command == null && Environment.get_variable ("CC") != null) {
+ cc_command = Environment.get_variable ("CC");
+ }
+ if (cc_options == null) {
+ //ccompiler.compile (context, cc_command, new string[] { });
+ } else {
+ //ccompiler.compile (context, cc_command, cc_options);
+ }
+ }
+
+ return quit ();
}
- private string get_scope () {
- return _scope[_scope.size - 1];
+//////////////////////////////////////////
+
+public class Codegen : Vala.CodeVisitor {
+
+ CodeContext context;
+ SourceFile file;
+ Block block;
+ Block run_block;
+ Block current_block;
+
+ public void run (CodeContext ctx, SourceFile f) {
+ context = ctx;
+ file = f;
+
+ stdout.printf ("Checking %s...\n", file.filename);
+
+ var main = new Method ("main", new VoidType ());
+ main.access = SymbolAccessibility.PUBLIC;
+ main.binding = MemberBinding.STATIC;
+ main.body = new Block ();
+ var run_call = new MethodCall (new MemberAccess (null, "run"));
+ main.body.add_statement (new ExpressionStatement (run_call));
+ context.root.add_method (main);
+
+ var syntax = new Method ("syntax", new VoidType ());
+ syntax.add_parameter (new Parameter ("first", new PointerType (new VoidType ())));
+ syntax.add_parameter (new Parameter.with_ellipsis ());
+ syntax.access = SymbolAccessibility.PUBLIC;
+ syntax.binding = MemberBinding.STATIC;
+ block = new Block ();
+ syntax.body = block;
+ context.root.add_method (syntax);
+
+ var run = new Method ("run", new VoidType ());
+ run.access = SymbolAccessibility.PUBLIC;
+ run.binding = MemberBinding.STATIC;
+ run_block = new Block ();
+ run.body = run_block;
+ context.root.add_method (run);
+
+ context.accept (this);
+ context = null;
}
- private void enter_scope (string name) {
- _scope.add (name);
- add_symbol (name);
+ public override void visit_namespace (Vala.Namespace element) {
+ element.accept_children (this);
}
- private void leave_scope () {
- _scope.remove_at (_scope.size - 1);
+ public override void visit_class (Vala.Class element) {
+ if (element.source_reference.file != file) {
+ return;
+ }
+
+ //TODO
+ if (element.get_type_parameters ().size > 0) {
+ return;
+ }
+
+ add_message (element.get_full_name ());
+
+ var b = new Block ();
+ var decl = new DeclarationStatement (new LocalVariable (new ObjectType (element), "p",
get_default_initializer (SemanticAnalyzer.get_data_type_for_symbol (element)), element.source_reference));
+ b.add_statement (decl);
+ block.add_statement (b);
+
+ b.check (context);
+ current_block = b;
+ element.accept_children (this);
}
- private void parse_members (string name, GLib.List<IdlNode> members) {
- enter_scope (name);
+ public override void visit_interface (Vala.Interface element) {
+ if (element.source_reference.file != file) {
+ return;
+ }
- foreach (weak IdlNode node in members) {
- switch (node.type) {
- case IdlNodeTypeId.ENUM:
- parse_members (((IdlNodeEnum) node).gtype_name,
- ((IdlNodeEnum) node).values);
- break;
+ add_message (element.get_full_name ());
- case IdlNodeTypeId.FUNCTION:
- parse_members (((IdlNodeFunction) node).symbol,
- (GLib.List<IdlNode>) ((IdlNodeFunction)
node).parameters);
- break;
+ var b = new Block ();
+ var decl = new DeclarationStatement (new LocalVariable (new ObjectType (element), "p",
get_default_initializer (SemanticAnalyzer.get_data_type_for_symbol (element)), element.source_reference));
+ b.add_statement (decl);
+ block.add_statement (b);
- case IdlNodeTypeId.BOXED:
- parse_members (((IdlNodeBoxed) node).gtype_name,
- ((IdlNodeBoxed) node).members);
- break;
+ b.check (context);
+ current_block = b;
+ element.accept_children (this);
+ }
- case IdlNodeTypeId.INTERFACE:
- case IdlNodeTypeId.OBJECT:
- parse_members (((IdlNodeInterface) node).gtype_name,
- ((IdlNodeInterface) node).members);
- break;
+ public override void visit_struct (Vala.Struct element) {
+ if (element.source_reference.file != file) {
+ return;
+ }
- case IdlNodeTypeId.FIELD:
- case IdlNodeTypeId.PARAM:
- add_symbol (node.name, ".");
- break;
+ // Skip those
+ if (element.get_full_name () == "va_list") {
+ return;
+ }
- case IdlNodeTypeId.PROPERTY:
- case IdlNodeTypeId.SIGNAL:
- add_symbol (node.name, "::");
- break;
+ add_message (element.get_full_name ());
- case IdlNodeTypeId.STRUCT:
- parse_members (node.name, ((IdlNodeStruct) node).members);
- break;
+ var b = new Block ();
+ var decl = new DeclarationStatement (new LocalVariable (new StructValueType (element), "p",
get_default_initializer (SemanticAnalyzer.get_data_type_for_symbol (element)), element.source_reference));
+ b.add_statement (decl);
+ block.add_statement (b);
- case IdlNodeTypeId.VALUE:
- case IdlNodeTypeId.VFUNC:
- // Not applicable?
- break;
+ b.check (context);
+ current_block = b;
+ element.accept_children (this);
+ }
- default:
- warning ("TODO: %s: Implement support for type %d nodes", node.name,
node.type);
- break;
- }
+ public override void visit_field (Vala.Field element) {
+ if (element.source_reference.file != file) {
+ return;
}
- leave_scope ();
+ var b = new Block ();
+
+ if (element.parent_symbol is Namespace || element.binding == MemberBinding.STATIC) {
+ var decl = new DeclarationStatement (new LocalVariable (get_local_type
(element.variable_type), "v", get_member_access (element), element.source_reference));
+ b.add_statement (decl);
+ } else if (element.access == SymbolAccessibility.PUBLIC && element.binding ==
MemberBinding.INSTANCE) {
+ var decl = new DeclarationStatement (new LocalVariable (get_local_type
(element.variable_type), "v", new MemberAccess (new MemberAccess (null, "p"), element.name),
element.source_reference));
+ b.add_statement (decl);
+ }
+
+ current_block.add_statement (b);
+ current_block.check (context);
}
- private int check_metadata () {
- try {
- var metafile = new IOChannel.file (metadata.filename, "r");
- string line;
- int lineno = 1;
+ public override void visit_property (Vala.Property element) {
+ }
- while (IOStatus.NORMAL == metafile.read_line (out line, null, null)) {
- var tokens = line.split (" ", 2);
- var symbol = tokens[0];
+ public override void visit_creation_method (Vala.CreationMethod element) {
+ if (element.source_reference.file != file) {
+ return;
+ }
- if (symbol.length > 0 && !_symbols.contains (symbol)) {
- var src = new SourceReference (metadata, SourceLocation (null,
lineno, 1), SourceLocation (null, lineno, (int)symbol.length));
- Report.error (src, "Symbol `%s' not found", symbol);
- }
+ if (element.access != SymbolAccessibility.PUBLIC) {
+ return;
+ }
- lineno += 1;
- }
+ //TODO
+ if (element.coroutine || element.get_type_parameters ().size > 0) {
+ return;
+ }
- return 0;
- } catch (Error error) {
- Report.error (null, "%s: %s", metadata.filename, error.message);
- return 1;
+ add_message (element.get_full_name ());
+
+ var b = new Block ();
+
+ MemberAccess ma = get_member_access (element);
+ ma.creation_member = true;
+ List<Parameter> parameters;
+ if (element.coroutine) {
+ parameters = element.get_async_begin_parameters ();
+ } else {
+ parameters = element.get_parameters ();
}
+ var mcall = new ObjectCreationExpression (ma, element.source_reference);
+ mcall.struct_creation = element.parent_symbol is Struct;
+
+ int i = 0;
+ append_arguments (b, mcall, parameters, ref i);
+
+ var stmt = new ExpressionStatement (mcall);
+ b.add_statement (stmt);
+ b.check (context);
+ block.add_statement (b);
}
- public int run () {
- if (!FileUtils.test (gidl.filename, FileTest.IS_REGULAR)) {
- Report.error (null, "%s not found", gidl.filename);
- return 2;
+ public override void visit_method (Vala.Method element) {
+ if (element.source_reference.file != file) {
+ return;
}
- if (!FileUtils.test (metadata.filename, FileTest.IS_REGULAR)) {
- Report.error (null, "%s not found", metadata.filename);
- return 2;
+ if (element.access == SymbolAccessibility.PRIVATE) {
+ return;
}
- parse_gidl ();
+ //TODO
+ if (element.get_type_parameters ().size > 0) {
+ return;
+ }
- return check_metadata ();
+ add_message (element.get_full_name ());
+
+ var b = new Block ();
+
+ MemberAccess ma = get_member_access (element);
+ switch (element.binding) {
+ case MemberBinding.STATIC:
+ // nothing to do
+ break;
+ case MemberBinding.INSTANCE:
+ var instance_type = SemanticAnalyzer.get_data_type_for_symbol (element.parent_symbol);
+ var decl = new DeclarationStatement (new LocalVariable (instance_type, "p",
get_default_initializer (instance_type), element.source_reference));
+ b.add_statement (decl);
+ ma.inner = new MemberAccess (null, "p", element.source_reference);
+ break;
+ //TODO
+ case MemberBinding.CLASS:
+ default:
+ return;
+ }
+
+ int i = 0;
+ MethodCall mcall;
+ List<Parameter> parameters;
+ if (element.coroutine) {
+ parameters = element.get_async_begin_parameters ();
+ mcall = new MethodCall (new MemberAccess (ma, "begin"));
+ } else {
+ mcall = new MethodCall (ma);
+ parameters = element.get_parameters ();
+ }
+
+ append_arguments (b, mcall, parameters, ref i);
+ b.add_statement (new ExpressionStatement (mcall));
+
+ if (element.coroutine) {
+ parameters = element.get_async_end_parameters ();
+ mcall = new MethodCall (new MemberAccess (ma, "end"));
+
+ append_arguments (b, mcall, parameters, ref i);
+ b.add_statement (new ExpressionStatement (mcall));
+ }
+
+ b.check (context);
+ block.add_statement (b);
+ }
+
+ public override void visit_signal (Vala.Signal element) {
+ }
+
+ public override void visit_delegate (Vala.Delegate element) {
+ if (element.source_reference.file != file) {
+ return;
+ }
+
+ //TODO
+ if (element.get_type_parameters ().size > 0) {
+ return;
+ }
+
+ add_message (element.get_full_name ());
+
+ var b = new Block ();
+ var decl = new DeclarationStatement (new LocalVariable (new DelegateType (element), "func",
new NullLiteral (), element.source_reference));
+ b.add_statement (decl);
+
+ int i = 0;
+ MethodCall mcall;
+ List<Parameter> parameters;
+ mcall = new MethodCall (new MemberAccess (null, "func"));
+ parameters = element.get_parameters ();
+
+ append_arguments (b, mcall, parameters, ref i);
+ b.add_statement (new ExpressionStatement (mcall));
+
+ b.check (context);
+ block.add_statement (b);
}
+ public override void visit_enum (Vala.Enum element) {
+ element.accept_children (this);
+ }
+
+ public override void visit_enum_value (Vala.EnumValue element) {
+ if (element.source_reference.file != file) {
+ return;
+ }
+
+ var b = new Block ();
+ var decl = new DeclarationStatement (new LocalVariable (new VarType (false), "v",
get_member_access (element), element.source_reference));
+ b.add_statement (decl);
+ b.check (context);
+
+ var assert = new MethodCall (new MemberAccess (null, "assert"));
+ assert.add_argument (new BinaryExpression (BinaryOperator.EQUALITY, new MemberAccess (null,
"v"), get_member_access (element)));
+ b.add_statement (new ExpressionStatement (assert));
+
+ run_block.add_statement (b);
+ }
+
+ public override void visit_constant (Vala.Constant element) {
+ if (element.source_reference.file != file) {
+ return;
+ }
+
+ var b = new Block ();
+ var decl = new DeclarationStatement (new LocalVariable (get_local_type
(element.type_reference), "v", get_member_access (element), element.source_reference));
+ b.add_statement (decl);
+ b.check (context);
+
+ var assert = new MethodCall (new MemberAccess (null, "assert"));
+ assert.add_argument (new BinaryExpression (BinaryOperator.EQUALITY, new MemberAccess (null,
"v"), get_member_access (element)));
+ b.add_statement (new ExpressionStatement (assert));
+
+ run_block.add_statement (b);
+ }
+
+ public override void visit_error_domain (Vala.ErrorDomain element) {
+ element.accept_children (this);
+ }
+
+ public override void visit_error_code (Vala.ErrorCode element) {
+ }
+
+ public override void visit_type_parameter (Vala.TypeParameter element) {
+ }
+
+ public override void visit_formal_parameter (Vala.Parameter element) {
+ }
+
+ void append_arguments (Block b, CallableExpression call, List<Parameter> parameters, ref int i) {
+ foreach (var param in parameters) {
+ if (param.ellipsis) {
+ continue;
+ }
+
+ var arg_name = "arg%i".printf (i++);
+ Expression? initializer = null;
+ DataType type;
+ if (param.params_array) {
+ type = ((ArrayType) param.variable_type).element_type.copy ();
+ } else {
+ type = param.variable_type.copy ();
+ }
+
+ switch (param.direction) {
+ case ParameterDirection.IN:
+ initializer = get_default_initializer (type);
+ if (param.variable_type.value_owned) {
+ call.add_argument (new ReferenceTransferExpression (new MemberAccess
(null, arg_name, param.source_reference), param.source_reference));
+ } else {
+ call.add_argument (new MemberAccess (null, arg_name,
param.source_reference));
+ }
+ break;
+ case ParameterDirection.REF:
+ initializer = get_default_initializer (type);
+ call.add_argument (new UnaryExpression (UnaryOperator.REF, new MemberAccess
(null, arg_name, param.source_reference), param.source_reference));
+ break;
+ case ParameterDirection.OUT:
+ call.add_argument (new UnaryExpression (UnaryOperator.OUT, new MemberAccess
(null, arg_name, param.source_reference), param.source_reference));
+ break;
+ default:
+ assert_not_reached ();
+ }
+
+ var decl = new DeclarationStatement (new LocalVariable (type, arg_name, initializer,
param.source_reference));
+ b.add_statement (decl);
+ }
+ }
+
+ void add_message (string s) {
+ var call = new MethodCall (new MemberAccess (null, "print"));
+ call.add_argument (new StringLiteral ("\"%s\\n\"".printf (s)));
+ block.add_statement (new ExpressionStatement (call));
+ }
+
+ MemberAccess get_member_access (Symbol s) {
+ MemberAccess res = new MemberAccess (null, s.name, s.source_reference);
+ MemberAccess? inner = res;
+ while (s.parent_symbol != null && s.parent_symbol != context.root) {
+ s = s.parent_symbol;
+ inner.inner = new MemberAccess (null, s.name, s.source_reference);
+ inner = (MemberAccess) inner.inner;
+ }
+ return res;
+ }
+
+ DataType get_local_type (DataType d) {
+ if (d is ArrayType && ((ArrayType) d).fixed_length) {
+ return new PointerType (new VoidType ());
+ } else {
+ return new VarType (false);
+ }
+ }
+
+ Expression? get_default_initializer (DataType d) {
+ if (d is ArrayType && ((ArrayType) d).fixed_length) {
+ return null;
+ } else if (d.is_reference_type_or_type_parameter () || d is PointerType || d is DelegateType)
{
+ return new NullLiteral ();
+ } else if (d is EnumValueType) {
+ return new IntegerLiteral ("0");
+ } else if (d.is_real_struct_type ()) {
+ return new InitializerList ();
+ } else if (d.type_symbol is Struct) {
+ if (((Struct) d.type_symbol).is_boolean_type ()) {
+ return new BooleanLiteral (false);
+ } else if (((Struct) d.type_symbol).is_integer_type ()) {
+ return new IntegerLiteral ("0");
+ } else if (((Struct) d.type_symbol).is_floating_type ()) {
+ return new IntegerLiteral ("0");
+ } else if (((Struct) d.type_symbol).get_full_name () == "va_list") {
+ d.value_owned = true;
+ return new MethodCall (new MemberAccess (null, "va_list"));
+ } else if (d.is_non_null_simple_type ()) {
+ return new InitializerList ();
+ } else {
+ return new NullLiteral ();
+ }
+ } else {
+ return new NullLiteral ();
+ }
+ }
+}
+
+//////////////////////////////////////////
+
static int main (string[] args) {
- if (2 != args.length || !args[1].has_suffix (".gidl")) {
- stdout.printf ("Usage: %s library.gidl\n",
- Path.get_basename (args[0]));
- return 2;
+ // initialize locale
+ Intl.setlocale (LocaleCategory.ALL, "");
+
+ if (Vala.get_build_version () != Vala.BUILD_VERSION) {
+ stderr.printf ("Integrity check failed (libvala %s doesn't match vapicheck %s)\n",
Vala.get_build_version (), Vala.BUILD_VERSION);
+ return 1;
}
- var vapicheck = new VAPICheck (args[1]);
- return vapicheck.run ();
+ try {
+ var opt_context = new OptionContext ("- Vala API Checker");
+ opt_context.set_help_enabled (true);
+ opt_context.add_main_entries (options, null);
+ opt_context.parse (ref args);
+ } catch (OptionError e) {
+ stdout.printf ("%s\n", e.message);
+ stdout.printf ("Run '%s --help' to see a full list of available command line
options.\n", args[0]);
+ return 1;
+ }
+
+ if (version) {
+ stdout.printf ("Vala API Checker %s\n", Vala.BUILD_VERSION);
+ return 0;
+ } else if (api_version) {
+ stdout.printf ("%s\n", Vala.API_VERSION);
+ return 0;
+ }
+
+ if (sources == null && fast_vapis == null) {
+ stderr.printf ("No source file specified.\n");
+ return 1;
+ }
+
+ var checker = new VapiCheck ();
+ return checker.run ();
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]