yaggo 1.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,127 @@
1
+ # This file is part of Yaggo.
2
+
3
+ # Yaggo is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+
8
+ # Yaggo is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with Yaggo. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+
17
+ $typejust = 30
18
+ $switchesjust = 40
19
+
20
+ $type_to_C_type = {
21
+ :uint32 => "uint32_t",
22
+ :uint64 => "uint64_t",
23
+ :int32 => "int32_t",
24
+ :int64 => "int64_t",
25
+ :int => "int",
26
+ :long => "long",
27
+ :double => "double",
28
+ :string => "string",
29
+ :c_string => "const char *",
30
+ :enum => "int",
31
+ }
32
+ $type_default = {
33
+ :uint32 => "0",
34
+ :uint64 => "0",
35
+ :int32 => "0",
36
+ :int64 => "0",
37
+ :int => "0",
38
+ :long => "0",
39
+ :double => "0.0",
40
+ :string => "",
41
+ :c_string => "",
42
+ :enum => "0",
43
+ }
44
+
45
+ def dflt_typestr(type, *argv)
46
+ case type
47
+ when :c_string
48
+ "string"
49
+ when :enum
50
+ argv[0].join("|")
51
+ else
52
+ type.to_s
53
+ end
54
+ end
55
+
56
+ def suffix_arg(suffix)
57
+ case suffix
58
+ when true
59
+ "true"
60
+ when false
61
+ "false"
62
+ when String
63
+ suffix
64
+ else
65
+ raise "Invalid suffix specifier"
66
+ end
67
+ end
68
+
69
+ def str_conv(arg, type, *argv)
70
+ case type
71
+ when :string
72
+ "string(#{arg})"
73
+ when :c_string
74
+ arg
75
+ when :uint32, :uint64
76
+ "conv_uint<#{$type_to_C_type[type]}>((const char*)#{arg}, err, #{suffix_arg(argv[0])})"
77
+ when :int32, :int64, :long, :int
78
+ "conv_int<#{$type_to_C_type[type]}>((const char*)#{arg}, err, #{suffix_arg(argv[0])})"
79
+ when :double
80
+ "conv_double((const char*)#{arg}, err, #{suffix_arg(argv[0])})"
81
+ when :enum
82
+ # Convert a string to its equivalent enum value
83
+ "conv_enum((const char*)#{arg}, err, #{argv[0]})"
84
+ end
85
+ end
86
+
87
+ def find_error_header bt
88
+ bt.each { |l| l =~ /^\(eval\):\d+:/ and return $& }
89
+ return ""
90
+ end
91
+
92
+ def run_block(name, b)
93
+ eval("#{$option_variables.join(" = ")} = nil", $main_binding)
94
+ b.call
95
+ $option_variables.each { |n| eval("#{n} #{n} unless #{n}.nil?", $main_binding) }
96
+ rescue NoMethodError => e
97
+ header = find_error_header(e.backtrace)
98
+ raise "#{header} In #{name}: invalid keyword '#{e.name}' in statement '#{e.name} #{e.args.map { |s| "\"#{s}\"" }.join(" ")}'"
99
+ rescue NameError => e
100
+ header = find_error_header(e.backtrace)
101
+ raise "#{header} In #{name}: invalid keyword '#{e.name}'"
102
+ rescue RuntimeError, ArgumentError => e
103
+ header = find_error_header(e.backtrace)
104
+ raise "#{header} In #{name}: #{e.message}"
105
+ end
106
+
107
+
108
+ def check_conflict_exclude
109
+ $options.each { |o|
110
+ $opt_hash[o.long] = o unless o.long.nil?
111
+ $opt_hash[o.short] = o unless o.short.nil?
112
+ }
113
+ $options.each { |o|
114
+ o.conflict.each { |co|
115
+ $opt_hash[co] or
116
+ raise "Unknown conflict option '#{co}' for switch #{o.long}|#{o.short}"
117
+ }
118
+ }
119
+ $options.each { |o|
120
+ o.imply.each { |ios|
121
+ io = $opt_hash[ios] or
122
+ raise "Unknown implied option '#{io}' for switch #{o.long}|#{o.short}"
123
+ io.type == :flag or
124
+ raise "Implied option '#{io}' for switch #{o.long}|#{o.short} is not a flag"
125
+ }
126
+ }
127
+ end
@@ -0,0 +1,209 @@
1
+ # This file is part of Yaggo.
2
+
3
+ # Yaggo is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+
8
+ # Yaggo is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with Yaggo. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+
17
+ def output_conversion_code file
18
+ file.puts(<<EOS)
19
+ static bool adjust_double_si_suffix(double &res, const char *suffix) {
20
+ if(*suffix == '\\0')
21
+ return true;
22
+ if(*(suffix + 1) != '\\0')
23
+ return false;
24
+
25
+ switch(*suffix) {
26
+ case 'a': res *= 1e-18; break;
27
+ case 'f': res *= 1e-15; break;
28
+ case 'p': res *= 1e-12; break;
29
+ case 'n': res *= 1e-9; break;
30
+ case 'u': res *= 1e-6; break;
31
+ case 'm': res *= 1e-3; break;
32
+ case 'k': res *= 1e3; break;
33
+ case 'M': res *= 1e6; break;
34
+ case 'G': res *= 1e9; break;
35
+ case 'T': res *= 1e12; break;
36
+ case 'P': res *= 1e15; break;
37
+ case 'E': res *= 1e18; break;
38
+ default: return false;
39
+ }
40
+ return true;
41
+ }
42
+
43
+ static double conv_double(const char *str, ::std::string &err, bool si_suffix) {
44
+ char *endptr = 0;
45
+ errno = 0;
46
+ double res = strtod(str, &endptr);
47
+ if(endptr == str) {
48
+ err.assign("Invalid floating point string");
49
+ return (double)0.0;
50
+ }
51
+ if(errno) {
52
+ err.assign(strerror(errno));
53
+ return (double)0.0;
54
+ }
55
+ bool invalid =
56
+ si_suffix ? !adjust_double_si_suffix(res, endptr) : *endptr != '\\0';
57
+ if(invalid) {
58
+ err.assign("Invalid character");
59
+ return (double)0.0;
60
+ }
61
+ return res;
62
+ }
63
+
64
+ static int conv_enum(const char* str, ::std::string& err, const char* const strs[]) {
65
+ int res = 0;
66
+ for(const char* const* cstr = strs; *cstr; ++cstr, ++res)
67
+ if(!strcmp(*cstr, str))
68
+ return res;
69
+ err += "Invalid constant '";
70
+ err += str;
71
+ err += "'. Expected one of { ";
72
+ for(const char* const* cstr = strs; *cstr; ++cstr) {
73
+ if(cstr != strs)
74
+ err += ", ";
75
+ err += *cstr;
76
+ }
77
+ err += " }";
78
+ return -1;
79
+ }
80
+
81
+ template<typename T>
82
+ static bool adjust_int_si_suffix(T &res, const char *suffix) {
83
+ if(*suffix == '\\0')
84
+ return true;
85
+ if(*(suffix + 1) != '\\0')
86
+ return false;
87
+
88
+ switch(*suffix) {
89
+ case 'k': res *= (T)1000; break;
90
+ case 'M': res *= (T)1000000; break;
91
+ case 'G': res *= (T)1000000000; break;
92
+ case 'T': res *= (T)1000000000000; break;
93
+ case 'P': res *= (T)1000000000000000; break;
94
+ case 'E': res *= (T)1000000000000000000; break;
95
+ default: return false;
96
+ }
97
+ return true;
98
+ }
99
+
100
+ template<typename T>
101
+ static T conv_int(const char *str, ::std::string &err, bool si_suffix) {
102
+ char *endptr = 0;
103
+ errno = 0;
104
+ long long int res = strtoll(str, &endptr, 0);
105
+ if(endptr == str) {
106
+ err.assign("Invalid signed int string");
107
+ return (T)0;
108
+ }
109
+ if(errno) {
110
+ err.assign(strerror(errno));
111
+ return (T)0;
112
+ }
113
+ bool invalid =
114
+ si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\\0';
115
+ if(invalid) {
116
+ err.assign("Invalid character");
117
+ return (T)0;
118
+ }
119
+ if(res > ::std::numeric_limits<T>::max() ||
120
+ res < ::std::numeric_limits<T>::min()) {
121
+ err.assign("Value out of range");
122
+ return (T)0;
123
+ }
124
+ return (T)res;
125
+ }
126
+
127
+ template<typename T>
128
+ static T conv_uint(const char *str, ::std::string &err, bool si_suffix) {
129
+ char *endptr = 0;
130
+ errno = 0;
131
+ while(isspace(*str)) { ++str; }
132
+ if(*str == '-') {
133
+ err.assign("Negative value");
134
+ return (T)0;
135
+ }
136
+ unsigned long long int res = strtoull(str, &endptr, 0);
137
+ if(endptr == str) {
138
+ err.assign("Invalid unsigned int string");
139
+ return (T)0;
140
+ }
141
+ if(errno) {
142
+ err.assign(strerror(errno));
143
+ return (T)0;
144
+ }
145
+ bool invalid =
146
+ si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\\0';
147
+ if(invalid) {
148
+ err.assign("Invalid character");
149
+ return (T)0;
150
+ }
151
+ if(res > ::std::numeric_limits<T>::max()) {
152
+ err.assign("Value out of range");
153
+ return (T)0;
154
+ }
155
+ return (T)res;
156
+ }
157
+
158
+ template<typename T>
159
+ static ::std::string vec_str(const std::vector<T> &vec) {
160
+ ::std::ostringstream os;
161
+ for(typename ::std::vector<T>::const_iterator it = vec.begin();
162
+ it != vec.end(); ++it) {
163
+ if(it != vec.begin())
164
+ os << ",";
165
+ os << *it;
166
+ }
167
+ return os.str();
168
+ }
169
+
170
+ class string : public ::std::string {
171
+ public:
172
+ string() : ::std::string() {}
173
+ explicit string(const ::std::string &s) : std::string(s) {}
174
+ explicit string(const char *s) : ::std::string(s) {}
175
+ int as_enum(const char* const strs[]) {
176
+ ::std::string err;
177
+ int res = #{str_conv("this->c_str()", :enum, "strs")};
178
+ if(!err.empty())
179
+ throw ::std::runtime_error(err);
180
+ return res;
181
+ }
182
+
183
+
184
+ EOS
185
+ [:uint32, :uint64, :int32, :int64, :int, :long, :double].each do |type|
186
+ file.puts(<<EOS)
187
+ #{$type_to_C_type[type]} as_#{type}_suffix() const { return as_#{type}(true); }
188
+ #{$type_to_C_type[type]} as_#{type}(bool si_suffix = false) const {
189
+ ::std::string err;
190
+ #{$type_to_C_type[type]} res = #{str_conv("this->c_str()", type, "si_suffix")};
191
+ if(!err.empty()) {
192
+ ::std::string msg("Invalid conversion of '");
193
+ msg += *this;
194
+ msg += "' to #{type}_t: ";
195
+ msg += err;
196
+ throw ::std::runtime_error(msg);
197
+ }
198
+ return res;
199
+ }
200
+ EOS
201
+ end
202
+
203
+ file.puts(<<EOS)
204
+ };
205
+
206
+ EOS
207
+ # }
208
+ end
209
+
@@ -0,0 +1,152 @@
1
+ # This file is part of Yaggo.
2
+
3
+ # Yaggo is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+
8
+ # Yaggo is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with Yaggo. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'optparse'
17
+
18
+ require 'yaggo/version'
19
+ require 'yaggo/man_page'
20
+ require 'yaggo/stub'
21
+ require 'yaggo/general'
22
+ require 'yaggo/library'
23
+ require 'yaggo/dsl'
24
+ require 'yaggo/parser'
25
+ require 'yaggo/zsh_completion'
26
+
27
+ def main
28
+ $yaggo_options = {
29
+ :output => nil,
30
+ :license => nil,
31
+ :stub => false,
32
+ :zc => nil,
33
+ :extended => false,
34
+ :debug => false,
35
+ }
36
+
37
+ parser = OptionParser.new do |o|
38
+ o.version = $yaggo_version
39
+ o.banner = "Usage: #{$0} [options] [file.yaggo]"
40
+ o.separator ""
41
+ o.separator "Specific options:"
42
+
43
+ o.on("-o", "--output FILE", "Output file") { |v|
44
+ $yaggo_options[:output] = v
45
+ }
46
+ o.on("-l", "--license PATH", "License file to copy in header") { |v|
47
+ $yaggo_options[:license] = v
48
+ }
49
+ o.on("-m", "--man [FILE]", "Display or write manpage") { |v|
50
+ display_man_page v
51
+ exit 0;
52
+ }
53
+ o.on("-s", "--stub", "Output a stub yaggo file") {
54
+ $yaggo_options[:stub] = true
55
+ }
56
+ o.on("--zc PATH", "Write zsh completion file") { |v|
57
+ $yaggo_options[:zc] = v
58
+ }
59
+ o.on("-e", "--extended-syntax", "Use extended syntax") {
60
+ $yaggo_options[:extended] = true
61
+ }
62
+ o.on("--debug", "Debug yaggo") {
63
+ $yaggo_options[:debug] = true
64
+ }
65
+
66
+ o.on_tail("-h", "--help", "Show this message") {
67
+ puts o
68
+ exit 0
69
+ }
70
+ end
71
+ parser.parse! ARGV
72
+
73
+ if $yaggo_options[:stub]
74
+ begin
75
+ display_stub_yaggo_file $yaggo_options[:output]
76
+ rescue => e
77
+ STDERR.puts("Failed to write stub: #{e.message}")
78
+ exit 1
79
+ end
80
+
81
+ exit
82
+ end
83
+
84
+ if !$yaggo_options[:stub] && !$yaggo_options[:manual] && ARGV.empty?
85
+ STDERR.puts "Error: some yaggo files and/or --lib switch is required", parser
86
+ exit 1
87
+ end
88
+ if !$yaggo_options[:output].nil?
89
+ if $yaggo_options[:stub]
90
+ if ARGV.size > 0
91
+ STDERR.puts "Error: no input file needed with the --stub switch", parser
92
+ exit 1
93
+ end
94
+ elsif ARGV.size != 1
95
+ STDERR.puts "Error: output switch meaningfull only with 1 input file", parser
96
+ exit 1
97
+ end
98
+ end
99
+
100
+ ARGV.each do |input_file|
101
+ pid = fork do
102
+ begin
103
+ yaggo_script = File.read(input_file)
104
+ if $yaggo_options[:extended]
105
+ yaggo_script.gsub!(/\)\s*\n\s*\{/, ") {")
106
+ end
107
+ eval(File.read(input_file))
108
+ parsed = true
109
+ check_conflict_exclude
110
+ rescue RuntimeError, SyntaxError, Errno::ENOENT, Errno::EACCES => e
111
+ raise e if $yaggo_options[:debug]
112
+ STDERR.puts(e.message.gsub(/^\(eval\)/, input_file))
113
+ exit 1
114
+ rescue NoMethodError => e
115
+ raise e if $yaggo_options[:debug]
116
+ STDERR.puts("Invalid keyword '#{e.name}'")
117
+ exit 1
118
+ end
119
+
120
+ fsplit = File.basename(input_file).split(/\./)
121
+ $klass ||= fsplit.size > 1 ? fsplit[0..-2].join(".") : fsplit[0]
122
+ $output = $yaggo_options[:output] if $yaggo_options[:output]
123
+ $output ||= input_file.gsub(/\.yaggo$/, "") + ".hpp"
124
+
125
+ begin
126
+ out_fd = open($output, "w")
127
+ output_cpp_parser(out_fd, $klass)
128
+ rescue RuntimeError => e
129
+ raise e if $yaggo_options[:debug]
130
+ STDERR.puts("#{input_file}: #{e.message}")
131
+ exit 1
132
+ ensure
133
+ out_fd.close if out_fd
134
+ end
135
+
136
+ if $yaggo_options[:zc]
137
+ begin
138
+ out_fd = open($yaggo_options[:zc], "w")
139
+ output_zsh_completion(out_fd, $yaggo_options[:zc])
140
+ rescue RuntimeError => e
141
+ raise e if $yaggo_options[:debug]
142
+ STDERR.puts("#{input_file}: #{e.message}")
143
+ exit 1
144
+ ensure
145
+ out_fd.close if out_fd
146
+ end
147
+ end
148
+ end
149
+ Process.waitpid pid
150
+ exit 1 if !$?.exited? || ($?.exited? && $?.exitstatus != 0)
151
+ end
152
+ end