]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/mod.rs
auto merge of #10676 : eddyb/rust/ast-box-in-enums, r=cmr
[rust.git] / src / libsyntax / parse / mod.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The main parser interface
12
13
14 use ast;
15 use codemap::{Span, CodeMap, FileMap, FileSubstr};
16 use codemap;
17 use diagnostic::{span_handler, mk_span_handler, mk_handler, Emitter};
18 use parse::attr::parser_attr;
19 use parse::lexer::reader;
20 use parse::parser::Parser;
21
22 use std::io;
23 use std::io::File;
24 use std::str;
25
26 pub mod lexer;
27 pub mod parser;
28 pub mod token;
29 pub mod comments;
30 pub mod attr;
31
32 /// Common routines shared by parser mods
33 pub mod common;
34
35 /// Routines the parser uses to classify AST nodes
36 pub mod classify;
37
38 /// Reporting obsolete syntax
39 pub mod obsolete;
40
41 // info about a parsing session.
42 pub struct ParseSess {
43     cm: @codemap::CodeMap, // better be the same as the one in the reader!
44     span_diagnostic: @mut span_handler, // better be the same as the one in the reader!
45     /// Used to determine and report recursive mod inclusions
46     included_mod_stack: ~[Path],
47 }
48
49 pub fn new_parse_sess(demitter: Option<@Emitter>) -> @mut ParseSess {
50     let cm = @CodeMap::new();
51     @mut ParseSess {
52         cm: cm,
53         span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
54         included_mod_stack: ~[],
55     }
56 }
57
58 pub fn new_parse_sess_special_handler(sh: @mut span_handler,
59                                       cm: @codemap::CodeMap)
60                                    -> @mut ParseSess {
61     @mut ParseSess {
62         cm: cm,
63         span_diagnostic: sh,
64         included_mod_stack: ~[],
65     }
66 }
67
68 // a bunch of utility functions of the form parse_<thing>_from_<source>
69 // where <thing> includes crate, expr, item, stmt, tts, and one that
70 // uses a HOF to parse anything, and <source> includes file and
71 // source_str.
72
73 pub fn parse_crate_from_file(
74     input: &Path,
75     cfg: ast::CrateConfig,
76     sess: @mut ParseSess
77 ) -> ast::Crate {
78     new_parser_from_file(sess, /*bad*/ cfg.clone(), input).parse_crate_mod()
79     // why is there no p.abort_if_errors here?
80 }
81
82 pub fn parse_crate_from_source_str(
83     name: @str,
84     source: @str,
85     cfg: ast::CrateConfig,
86     sess: @mut ParseSess
87 ) -> ast::Crate {
88     let p = new_parser_from_source_str(sess,
89                                        /*bad*/ cfg.clone(),
90                                        name,
91                                        source);
92     maybe_aborted(p.parse_crate_mod(),p)
93 }
94
95 pub fn parse_expr_from_source_str(
96     name: @str,
97     source: @str,
98     cfg: ast::CrateConfig,
99     sess: @mut ParseSess
100 ) -> @ast::Expr {
101     let p = new_parser_from_source_str(
102         sess,
103         cfg,
104         name,
105         source
106     );
107     maybe_aborted(p.parse_expr(), p)
108 }
109
110 pub fn parse_item_from_source_str(
111     name: @str,
112     source: @str,
113     cfg: ast::CrateConfig,
114     attrs: ~[ast::Attribute],
115     sess: @mut ParseSess
116 ) -> Option<@ast::item> {
117     let p = new_parser_from_source_str(
118         sess,
119         cfg,
120         name,
121         source
122     );
123     maybe_aborted(p.parse_item(attrs),p)
124 }
125
126 pub fn parse_meta_from_source_str(
127     name: @str,
128     source: @str,
129     cfg: ast::CrateConfig,
130     sess: @mut ParseSess
131 ) -> @ast::MetaItem {
132     let p = new_parser_from_source_str(
133         sess,
134         cfg,
135         name,
136         source
137     );
138     maybe_aborted(p.parse_meta_item(),p)
139 }
140
141 pub fn parse_stmt_from_source_str(
142     name: @str,
143     source: @str,
144     cfg: ast::CrateConfig,
145     attrs: ~[ast::Attribute],
146     sess: @mut ParseSess
147 ) -> @ast::Stmt {
148     let p = new_parser_from_source_str(
149         sess,
150         cfg,
151         name,
152         source
153     );
154     maybe_aborted(p.parse_stmt(attrs),p)
155 }
156
157 pub fn parse_tts_from_source_str(
158     name: @str,
159     source: @str,
160     cfg: ast::CrateConfig,
161     sess: @mut ParseSess
162 ) -> ~[ast::token_tree] {
163     let p = new_parser_from_source_str(
164         sess,
165         cfg,
166         name,
167         source
168     );
169     *p.quote_depth += 1u;
170     // right now this is re-creating the token trees from ... token trees.
171     maybe_aborted(p.parse_all_token_trees(),p)
172 }
173
174 // given a function and parsing information (source str,
175 // filename, crate cfg, and sess), create a parser,
176 // apply the function, and check that the parser
177 // consumed all of the input before returning the function's
178 // result.
179 pub fn parse_from_source_str<T>(
180                              f: |&Parser| -> T,
181                              name: @str,
182                              ss: codemap::FileSubstr,
183                              source: @str,
184                              cfg: ast::CrateConfig,
185                              sess: @mut ParseSess)
186                              -> T {
187     let p = new_parser_from_source_substr(sess, cfg, name, ss, source);
188     let r = f(&p);
189     if !p.reader.is_eof() {
190         p.reader.fatal(~"expected end-of-string");
191     }
192     maybe_aborted(r,p)
193 }
194
195 // Create a new parser from a source string
196 pub fn new_parser_from_source_str(sess: @mut ParseSess,
197                                   cfg: ast::CrateConfig,
198                                   name: @str,
199                                   source: @str)
200                                -> Parser {
201     filemap_to_parser(sess,string_to_filemap(sess,source,name),cfg)
202 }
203
204 // Create a new parser from a source string where the origin
205 // is specified as a substring of another file.
206 pub fn new_parser_from_source_substr(sess: @mut ParseSess,
207                                   cfg: ast::CrateConfig,
208                                   name: @str,
209                                   ss: codemap::FileSubstr,
210                                   source: @str)
211                                -> Parser {
212     filemap_to_parser(sess,substring_to_filemap(sess,source,name,ss),cfg)
213 }
214
215 /// Create a new parser, handling errors as appropriate
216 /// if the file doesn't exist
217 pub fn new_parser_from_file(
218     sess: @mut ParseSess,
219     cfg: ast::CrateConfig,
220     path: &Path
221 ) -> Parser {
222     filemap_to_parser(sess,file_to_filemap(sess,path,None),cfg)
223 }
224
225 /// Given a session, a crate config, a path, and a span, add
226 /// the file at the given path to the codemap, and return a parser.
227 /// On an error, use the given span as the source of the problem.
228 pub fn new_sub_parser_from_file(
229     sess: @mut ParseSess,
230     cfg: ast::CrateConfig,
231     path: &Path,
232     sp: Span
233 ) -> Parser {
234     filemap_to_parser(sess,file_to_filemap(sess,path,Some(sp)),cfg)
235 }
236
237 /// Given a filemap and config, return a parser
238 pub fn filemap_to_parser(sess: @mut ParseSess,
239                          filemap: @FileMap,
240                          cfg: ast::CrateConfig) -> Parser {
241     tts_to_parser(sess,filemap_to_tts(sess,filemap),cfg)
242 }
243
244 // must preserve old name for now, because quote! from the *existing*
245 // compiler expands into it
246 pub fn new_parser_from_tts(sess: @mut ParseSess,
247                      cfg: ast::CrateConfig,
248                      tts: ~[ast::token_tree]) -> Parser {
249     tts_to_parser(sess,tts,cfg)
250 }
251
252
253 // base abstractions
254
255 /// Given a session and a path and an optional span (for error reporting),
256 /// add the path to the session's codemap and return the new filemap.
257 pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option<Span>)
258     -> @FileMap {
259     let err = |msg: &str| {
260         match spanopt {
261             Some(sp) => sess.span_diagnostic.span_fatal(sp, msg),
262             None => sess.span_diagnostic.handler().fatal(msg),
263         }
264     };
265     let bytes = match io::result(|| File::open(path).read_to_end()) {
266         Ok(bytes) => bytes,
267         Err(e) => {
268             err(format!("couldn't read {}: {}", path.display(), e.desc));
269             unreachable!()
270         }
271     };
272     match str::from_utf8_owned_opt(bytes) {
273         Some(s) => {
274             return string_to_filemap(sess, s.to_managed(),
275                                      path.as_str().unwrap().to_managed());
276         }
277         None => {
278             err(format!("{} is not UTF-8 encoded", path.display()))
279         }
280     }
281     unreachable!()
282 }
283
284 // given a session and a string, add the string to
285 // the session's codemap and return the new filemap
286 pub fn string_to_filemap(sess: @mut ParseSess, source: @str, path: @str)
287     -> @FileMap {
288     sess.cm.new_filemap(path, source)
289 }
290
291 // given a session and a string and a path and a FileSubStr, add
292 // the string to the CodeMap and return the new FileMap
293 pub fn substring_to_filemap(sess: @mut ParseSess, source: @str, path: @str,
294                            filesubstr: FileSubstr) -> @FileMap {
295     sess.cm.new_filemap_w_substr(path,filesubstr,source)
296 }
297
298 // given a filemap, produce a sequence of token-trees
299 pub fn filemap_to_tts(sess: @mut ParseSess, filemap: @FileMap)
300     -> ~[ast::token_tree] {
301     // it appears to me that the cfg doesn't matter here... indeed,
302     // parsing tt's probably shouldn't require a parser at all.
303     let cfg = ~[];
304     let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap);
305     let p1 = Parser(sess, cfg, srdr as @mut reader);
306     p1.parse_all_token_trees()
307 }
308
309 // given tts and cfg, produce a parser
310 pub fn tts_to_parser(sess: @mut ParseSess,
311                      tts: ~[ast::token_tree],
312                      cfg: ast::CrateConfig) -> Parser {
313     let trdr = lexer::new_tt_reader(sess.span_diagnostic, None, tts);
314     Parser(sess, cfg, trdr as @mut reader)
315 }
316
317 // abort if necessary
318 pub fn maybe_aborted<T>(result : T, p: Parser) -> T {
319     p.abort_if_errors();
320     result
321 }
322
323
324
325 #[cfg(test)]
326 mod test {
327     use super::*;
328     use extra::serialize::Encodable;
329     use extra;
330     use std::io;
331     use std::io::Decorator;
332     use std::io::mem::MemWriter;
333     use std::str;
334     use codemap::{Span, BytePos, Spanned};
335     use opt_vec;
336     use ast;
337     use abi;
338     use parse::parser::Parser;
339     use parse::token::{str_to_ident};
340     use util::parser_testing::{string_to_tts, string_to_parser};
341     use util::parser_testing::{string_to_expr, string_to_item};
342     use util::parser_testing::string_to_stmt;
343
344     #[cfg(test)]
345     fn to_json_str<'a, E: Encodable<extra::json::Encoder<'a>>>(val: &E) -> ~str {
346         let mut writer = MemWriter::new();
347         let mut encoder = extra::json::Encoder::init(&mut writer as &mut io::Writer);
348         val.encode(&mut encoder);
349         str::from_utf8_owned(writer.inner())
350     }
351
352     // produce a codemap::span
353     fn sp(a: u32, b: u32) -> Span {
354         Span{lo:BytePos(a),hi:BytePos(b),expn_info:None}
355     }
356
357     #[test] fn path_exprs_1() {
358         assert_eq!(string_to_expr(@"a"),
359                    @ast::Expr{
360                     id: ast::DUMMY_NODE_ID,
361                     node: ast::ExprPath(ast::Path {
362                         span: sp(0, 1),
363                         global: false,
364                         segments: ~[
365                             ast::PathSegment {
366                                 identifier: str_to_ident("a"),
367                                 lifetimes: opt_vec::Empty,
368                                 types: opt_vec::Empty,
369                             }
370                         ],
371                     }),
372                     span: sp(0, 1)
373                    })
374     }
375
376     #[test] fn path_exprs_2 () {
377         assert_eq!(string_to_expr(@"::a::b"),
378                    @ast::Expr {
379                     id: ast::DUMMY_NODE_ID,
380                     node: ast::ExprPath(ast::Path {
381                             span: sp(0, 6),
382                             global: true,
383                             segments: ~[
384                                 ast::PathSegment {
385                                     identifier: str_to_ident("a"),
386                                     lifetimes: opt_vec::Empty,
387                                     types: opt_vec::Empty,
388                                 },
389                                 ast::PathSegment {
390                                     identifier: str_to_ident("b"),
391                                     lifetimes: opt_vec::Empty,
392                                     types: opt_vec::Empty,
393                                 }
394                             ]
395                         }),
396                     span: sp(0, 6)
397                    })
398     }
399
400     #[should_fail]
401     #[test] fn bad_path_expr_1() {
402         string_to_expr(@"::abc::def::return");
403     }
404
405     // check the token-tree-ization of macros
406     #[test] fn string_to_tts_macro () {
407         let tts = string_to_tts(@"macro_rules! zip (($a)=>($a))");
408         match tts {
409             [ast::tt_tok(_,_),
410              ast::tt_tok(_,token::NOT),
411              ast::tt_tok(_,_),
412              ast::tt_delim(delim_elts)] =>
413                 match *delim_elts {
414                 [ast::tt_tok(_,token::LPAREN),
415                  ast::tt_delim(first_set),
416                  ast::tt_tok(_,token::FAT_ARROW),
417                  ast::tt_delim(second_set),
418                  ast::tt_tok(_,token::RPAREN)] =>
419                     match *first_set {
420                     [ast::tt_tok(_,token::LPAREN),
421                      ast::tt_tok(_,token::DOLLAR),
422                      ast::tt_tok(_,_),
423                      ast::tt_tok(_,token::RPAREN)] =>
424                         match *second_set {
425                         [ast::tt_tok(_,token::LPAREN),
426                          ast::tt_tok(_,token::DOLLAR),
427                          ast::tt_tok(_,_),
428                          ast::tt_tok(_,token::RPAREN)] =>
429                             assert_eq!("correct","correct"),
430                         _ => assert_eq!("wrong 4","correct")
431                     },
432                     _ => {
433                         error!("failing value 3: {:?}",first_set);
434                         assert_eq!("wrong 3","correct")
435                     }
436                 },
437                 _ => {
438                     error!("failing value 2: {:?}",delim_elts);
439                     assert_eq!("wrong","correct");
440                 }
441
442             },
443             _ => {
444                 error!("failing value: {:?}",tts);
445                 assert_eq!("wrong 1","correct");
446             }
447         }
448     }
449
450     #[test] fn string_to_tts_1 () {
451         let tts = string_to_tts(@"fn a (b : int) { b; }");
452         assert_eq!(to_json_str(@tts),
453         ~"[\
454     {\
455         \"variant\":\"tt_tok\",\
456         \"fields\":[\
457             null,\
458             {\
459                 \"variant\":\"IDENT\",\
460                 \"fields\":[\
461                     \"fn\",\
462                     false\
463                 ]\
464             }\
465         ]\
466     },\
467     {\
468         \"variant\":\"tt_tok\",\
469         \"fields\":[\
470             null,\
471             {\
472                 \"variant\":\"IDENT\",\
473                 \"fields\":[\
474                     \"a\",\
475                     false\
476                 ]\
477             }\
478         ]\
479     },\
480     {\
481         \"variant\":\"tt_delim\",\
482         \"fields\":[\
483             [\
484                 {\
485                     \"variant\":\"tt_tok\",\
486                     \"fields\":[\
487                         null,\
488                         \"LPAREN\"\
489                     ]\
490                 },\
491                 {\
492                     \"variant\":\"tt_tok\",\
493                     \"fields\":[\
494                         null,\
495                         {\
496                             \"variant\":\"IDENT\",\
497                             \"fields\":[\
498                                 \"b\",\
499                                 false\
500                             ]\
501                         }\
502                     ]\
503                 },\
504                 {\
505                     \"variant\":\"tt_tok\",\
506                     \"fields\":[\
507                         null,\
508                         \"COLON\"\
509                     ]\
510                 },\
511                 {\
512                     \"variant\":\"tt_tok\",\
513                     \"fields\":[\
514                         null,\
515                         {\
516                             \"variant\":\"IDENT\",\
517                             \"fields\":[\
518                                 \"int\",\
519                                 false\
520                             ]\
521                         }\
522                     ]\
523                 },\
524                 {\
525                     \"variant\":\"tt_tok\",\
526                     \"fields\":[\
527                         null,\
528                         \"RPAREN\"\
529                     ]\
530                 }\
531             ]\
532         ]\
533     },\
534     {\
535         \"variant\":\"tt_delim\",\
536         \"fields\":[\
537             [\
538                 {\
539                     \"variant\":\"tt_tok\",\
540                     \"fields\":[\
541                         null,\
542                         \"LBRACE\"\
543                     ]\
544                 },\
545                 {\
546                     \"variant\":\"tt_tok\",\
547                     \"fields\":[\
548                         null,\
549                         {\
550                             \"variant\":\"IDENT\",\
551                             \"fields\":[\
552                                 \"b\",\
553                                 false\
554                             ]\
555                         }\
556                     ]\
557                 },\
558                 {\
559                     \"variant\":\"tt_tok\",\
560                     \"fields\":[\
561                         null,\
562                         \"SEMI\"\
563                     ]\
564                 },\
565                 {\
566                     \"variant\":\"tt_tok\",\
567                     \"fields\":[\
568                         null,\
569                         \"RBRACE\"\
570                     ]\
571                 }\
572             ]\
573         ]\
574     }\
575 ]"
576         );
577     }
578
579     #[test] fn ret_expr() {
580         assert_eq!(string_to_expr(@"return d"),
581                    @ast::Expr{
582                     id: ast::DUMMY_NODE_ID,
583                     node:ast::ExprRet(Some(@ast::Expr{
584                         id: ast::DUMMY_NODE_ID,
585                         node:ast::ExprPath(ast::Path{
586                             span: sp(7, 8),
587                             global: false,
588                             segments: ~[
589                                 ast::PathSegment {
590                                     identifier: str_to_ident("d"),
591                                     lifetimes: opt_vec::Empty,
592                                     types: opt_vec::Empty,
593                                 }
594                             ],
595                         }),
596                         span:sp(7,8)
597                     })),
598                     span:sp(0,8)
599                    })
600     }
601
602     #[test] fn parse_stmt_1 () {
603         assert_eq!(string_to_stmt(@"b;"),
604                    @Spanned{
605                        node: ast::StmtExpr(@ast::Expr {
606                            id: ast::DUMMY_NODE_ID,
607                            node: ast::ExprPath(ast::Path {
608                                span:sp(0,1),
609                                global:false,
610                                segments: ~[
611                                 ast::PathSegment {
612                                     identifier: str_to_ident("b"),
613                                     lifetimes: opt_vec::Empty,
614                                     types: opt_vec::Empty,
615                                 }
616                                ],
617                             }),
618                            span: sp(0,1)},
619                                            ast::DUMMY_NODE_ID),
620                        span: sp(0,1)})
621
622     }
623
624     fn parser_done(p: Parser){
625         assert_eq!((*p.token).clone(), token::EOF);
626     }
627
628     #[test] fn parse_ident_pat () {
629         let parser = string_to_parser(@"b");
630         assert_eq!(parser.parse_pat(),
631                    @ast::Pat{id: ast::DUMMY_NODE_ID,
632                              node: ast::PatIdent(
633                                 ast::BindByValue(ast::MutImmutable),
634                                 ast::Path {
635                                     span:sp(0,1),
636                                     global:false,
637                                     segments: ~[
638                                         ast::PathSegment {
639                                             identifier: str_to_ident("b"),
640                                             lifetimes: opt_vec::Empty,
641                                             types: opt_vec::Empty,
642                                         }
643                                     ],
644                                 },
645                                 None /* no idea */),
646                              span: sp(0,1)});
647         parser_done(parser);
648     }
649
650     // check the contents of the tt manually:
651     #[test] fn parse_fundecl () {
652         // this test depends on the intern order of "fn" and "int"
653         assert_eq!(string_to_item(@"fn a (b : int) { b; }"),
654                   Some(
655                       @ast::item{ident:str_to_ident("a"),
656                             attrs:~[],
657                             id: ast::DUMMY_NODE_ID,
658                             node: ast::item_fn(ast::P(ast::fn_decl{
659                                 inputs: ~[ast::arg{
660                                     ty: ast::P(ast::Ty{id: ast::DUMMY_NODE_ID,
661                                                        node: ast::ty_path(ast::Path{
662                                         span:sp(10,13),
663                                         global:false,
664                                         segments: ~[
665                                             ast::PathSegment {
666                                                 identifier:
667                                                     str_to_ident("int"),
668                                                 lifetimes: opt_vec::Empty,
669                                                 types: opt_vec::Empty,
670                                             }
671                                         ],
672                                         }, None, ast::DUMMY_NODE_ID),
673                                         span:sp(10,13)
674                                     }),
675                                     pat: @ast::Pat {
676                                         id: ast::DUMMY_NODE_ID,
677                                         node: ast::PatIdent(
678                                             ast::BindByValue(ast::MutImmutable),
679                                             ast::Path {
680                                                 span:sp(6,7),
681                                                 global:false,
682                                                 segments: ~[
683                                                     ast::PathSegment {
684                                                         identifier:
685                                                             str_to_ident("b"),
686                                                         lifetimes: opt_vec::Empty,
687                                                         types: opt_vec::Empty,
688                                                     }
689                                                 ],
690                                             },
691                                             None // no idea
692                                         ),
693                                         span: sp(6,7)
694                                     },
695                                     id: ast::DUMMY_NODE_ID
696                                 }],
697                                 output: ast::P(ast::Ty{id: ast::DUMMY_NODE_ID,
698                                                        node: ast::ty_nil,
699                                                        span:sp(15,15)}), // not sure
700                                 cf: ast::return_val,
701                                 variadic: false
702                             }),
703                                     ast::impure_fn,
704                                     abi::AbiSet::Rust(),
705                                     ast::Generics{ // no idea on either of these:
706                                         lifetimes: opt_vec::Empty,
707                                         ty_params: opt_vec::Empty,
708                                     },
709                                     ast::P(ast::Block {
710                                         view_items: ~[],
711                                         stmts: ~[@Spanned{
712                                             node: ast::StmtSemi(@ast::Expr{
713                                                 id: ast::DUMMY_NODE_ID,
714                                                 node: ast::ExprPath(
715                                                       ast::Path{
716                                                         span:sp(17,18),
717                                                         global:false,
718                                                         segments: ~[
719                                                             ast::PathSegment {
720                                                                 identifier:
721                                                                 str_to_ident(
722                                                                     "b"),
723                                                                 lifetimes:
724                                                                 opt_vec::Empty,
725                                                                 types:
726                                                                 opt_vec::Empty
727                                                             }
728                                                         ],
729                                                       }),
730                                                 span: sp(17,18)},
731                                                 ast::DUMMY_NODE_ID),
732                                             span: sp(17,18)}],
733                                         expr: None,
734                                         id: ast::DUMMY_NODE_ID,
735                                         rules: ast::DefaultBlock, // no idea
736                                         span: sp(15,21),
737                                     })),
738                             vis: ast::inherited,
739                             span: sp(0,21)}));
740     }
741
742
743     #[test] fn parse_exprs () {
744         // just make sure that they parse....
745         string_to_expr(@"3 + 4");
746         string_to_expr(@"a::z.froob(b,@(987+3))");
747     }
748
749     #[test] fn attrs_fix_bug () {
750         string_to_item(@"pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
751                    -> Result<@Writer, ~str> {
752     #[cfg(windows)]
753     fn wb() -> c_int {
754       (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
755     }
756
757     #[cfg(unix)]
758     fn wb() -> c_int { O_WRONLY as c_int }
759
760     let mut fflags: c_int = wb();
761 }");
762     }
763
764 }