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.
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.
11 // The Rust abstract syntax tree.
13 use codemap::{span, FileName, spanned};
16 use core::option::{None, Option, Some};
19 use core::to_str::ToStr;
20 use std::serialize::{Encodable, Decodable, Encoder, Decoder};
24 /* can't import macros yet, so this is copied from token.rs. See its comment
26 macro_rules! interner_key (
27 () => (cast::transmute::<(uint, uint),
28 &fn(+v: @@::parse::token::ident_interner)>(
32 // an identifier contains an index into the interner
33 // table and a SyntaxContext to track renaming and
34 // macro expansion per Flatt et al., "Macros
35 // That Work Together"
37 pub struct ident { repr: Name }
39 // a SyntaxContext represents a chain of macro-expandings
40 // and renamings. Each macro expansion corresponds to
43 pub enum SyntaxContext {
45 Mark (Mrk,~SyntaxContext),
46 Rename (~ident,Name,~SyntaxContext)
50 // ** this is going to have to apply to paths, not to idents.
51 // Returns true if these two identifiers access the same
52 // local binding or top-level binding... that's what it
53 // should do. For now, it just compares the names.
54 pub fn free_ident_eq (a : ident, b: ident) -> bool{
58 // a name represents a string, interned
60 // a mark represents a unique id associated
61 // with a macro expansion
64 impl<S:Encoder> Encodable<S> for ident {
65 fn encode(&self, s: &S) {
66 let intr = match unsafe {
67 task::local_data::local_data_get(interner_key!())
69 None => fail!(~"encode: TLS interner not set up"),
73 s.emit_owned_str(*(*intr).get(*self));
77 impl<D:Decoder> Decodable<D> for ident {
78 static fn decode(d: &D) -> ident {
79 let intr = match unsafe {
80 task::local_data::local_data_get(interner_key!())
82 None => fail!(~"decode: TLS interner not set up"),
86 (*intr).intern(@d.read_owned_str())
90 impl to_bytes::IterBytes for ident {
91 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
92 self.repr.iter_bytes(lsb0, f)
96 // Functions may or may not have names.
97 pub type fn_ident = Option<ident>;
102 pub struct Lifetime {
108 // a "Path" is essentially Rust's notion of a name;
109 // for instance: core::cmp::Eq . It's represented
110 // as a sequence of identifiers, along with a bunch
111 // of supporting information.
119 rp: Option<@Lifetime>,
123 pub type crate_num = int;
125 pub type node_id = int;
135 pub const local_crate: crate_num = 0;
136 pub const crate_node_id: node_id = 0;
141 // The AST represents all type param bounds as types.
142 // typeck::collect::compute_bounds matches these against
143 // the "special" built-in traits (see middle::lang_items) and
144 // detects Copy, Send, Owned, and Const.
145 pub enum TyParamBound {
146 TraitTyParamBound(@Ty),
156 bounds: @OptVec<TyParamBound>
162 pub struct Generics {
163 lifetimes: OptVec<Lifetime>,
164 ty_params: OptVec<TyParam>
168 fn is_parameterized(&self) -> bool {
169 self.lifetimes.len() + self.ty_params.len() > 0
171 fn is_lt_parameterized(&self) -> bool {
172 self.lifetimes.len() > 0
174 fn is_type_parameterized(&self) -> bool {
175 self.ty_params.len() > 0
183 def_fn(def_id, purity),
184 def_static_method(/* method */ def_id,
185 /* trait */ Option<def_id>,
187 def_self(node_id, bool /* is_implicit */),
188 def_self_ty(node_id),
190 def_foreign_mod(def_id),
192 def_arg(node_id, mode, bool /* is_mutbl */),
193 def_local(node_id, bool /* is_mutbl */),
194 def_variant(def_id /* enum */, def_id /* variant */),
196 def_prim_ty(prim_ty),
197 def_ty_param(def_id, uint),
198 def_binding(node_id, binding_mode),
200 def_upvar(node_id, // id of closed over var
201 @def, // closed over def
202 node_id, // expr node that creates the closure
203 node_id), // id for the block/body of the closure expr
205 def_typaram_binder(node_id), /* struct, impl or trait with ty params */
211 // The set of meta_items that define the compilation environment of the crate,
212 // used to drive conditional compilation
213 pub type crate_cfg = ~[@meta_item];
215 pub type crate = spanned<crate_>;
226 pub type meta_item = spanned<meta_item_>;
231 pub enum meta_item_ {
233 meta_list(@~str, ~[@meta_item]),
234 meta_name_value(@~str, lit),
237 pub type blk = spanned<blk_>;
243 view_items: ~[@view_item],
247 rules: blk_check_mode,
262 pub struct field_pat {
270 pub enum binding_mode {
272 bind_by_ref(mutability),
276 impl to_bytes::IterBytes for binding_mode {
277 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
279 bind_by_copy => 0u8.iter_bytes(lsb0, f),
281 bind_by_ref(ref m) =>
282 to_bytes::iter_bytes_2(&1u8, m, lsb0, f),
285 2u8.iter_bytes(lsb0, f),
295 // A pat_ident may either be a new bound variable,
296 // or a nullary enum (in which case the second field
298 // In the nullary enum case, the parser can't determine
299 // which it is. The resolver determines this, and
300 // records this pattern's node_id in an auxiliary
301 // set (of "pat_idents that refer to nullary enums")
302 pat_ident(binding_mode, @path, Option<@pat>),
303 pat_enum(@path, Option<~[@pat]>), /* "none" means a * pattern where
304 * we don't bind the fields to names */
305 pat_struct(@path, ~[field_pat], bool),
309 pat_region(@pat), // borrowed pointer pattern
311 pat_range(@expr, @expr),
312 // [a, b, ..i, y, z] is represented as
313 // pat_vec(~[a, b], Some(i), ~[y, z])
314 pat_vec(~[@pat], Option<@pat>, ~[@pat])
320 pub enum mutability { m_mutbl, m_imm, m_const, }
322 impl to_bytes::IterBytes for mutability {
323 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
324 (*self as u8).iter_bytes(lsb0, f)
335 impl to_bytes::IterBytes for Abi {
336 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
337 (*self as uint).iter_bytes(lsb0, f)
342 pure fn to_str(&self) -> ~str {
344 RustAbi => ~"\"rust\""
358 impl to_bytes::IterBytes for Sigil {
359 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
360 (*self as uint).iter_bytes(lsb0, f)
364 impl ToStr for Sigil {
365 pure fn to_str(&self) -> ~str {
367 BorrowedSigil => ~"&",
378 // FIXME (#3469): Change uint to @expr (actually only constant exprs)
379 vstore_fixed(Option<uint>), // [1,2,3,4]
380 vstore_uniq, // ~[1,2,3,4]
381 vstore_box, // @[1,2,3,4]
382 vstore_slice(Option<@Lifetime>) // &'foo? [1,2,3,4]
388 pub enum expr_vstore {
389 expr_vstore_fixed(Option<uint>), // [1,2,3,4]
390 expr_vstore_uniq, // ~[1,2,3,4]
391 expr_vstore_box, // @[1,2,3,4]
392 expr_vstore_mut_box, // @mut [1,2,3,4]
393 expr_vstore_slice, // &[1,2,3,4]
394 expr_vstore_mut_slice, // &mut [1,2,3,4]
432 // Generally, after typeck you can get the inferred value
433 // using ty::resolved_T(...).
437 pub enum inferable<T> {
442 impl<T:to_bytes::IterBytes> to_bytes::IterBytes for inferable<T> {
443 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
446 to_bytes::iter_bytes_2(&0u8, t, lsb0, f),
449 to_bytes::iter_bytes_2(&1u8, n, lsb0, f),
454 // "resolved" mode: the real modes.
458 pub enum rmode { by_ref, by_copy }
460 impl to_bytes::IterBytes for rmode {
461 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
462 (*self as u8).iter_bytes(lsb0, f)
467 pub type mode = inferable<rmode>;
469 pub type stmt = spanned<stmt_>;
475 stmt_decl(@decl, node_id),
477 // expr without trailing semi-colon (must have unit type):
478 stmt_expr(@expr, node_id),
480 // expr with trailing semi-colon (may have any type):
481 stmt_semi(@expr, node_id),
483 // bool: is there a trailing sem-colon?
487 // FIXME (pending discussion of #1697, #2178...): local should really be
488 // a refinement on pat.
500 pub type local = spanned<local_>;
502 pub type decl = spanned<decl_>;
507 pub enum decl_ { decl_local(~[@local]), decl_item(@item), }
514 guard: Option<@expr>,
527 pub type field = spanned<field_>;
532 pub enum blk_check_mode { default_blk, unsafe_blk, }
539 // Extra node ID is only used for index, assign_op, unary, binary, method
549 pub enum log_level { error, debug, log_other }
550 // 0 = error, 1 = debug, 2 = log_other
565 expr_vstore(@expr, expr_vstore),
566 expr_vec(~[@expr], mutability),
567 expr_call(@expr, ~[@expr], CallSugar),
568 expr_method_call(@expr, ident, ~[@Ty], ~[@expr], CallSugar),
570 expr_binary(binop, @expr, @expr),
571 expr_unary(unop, @expr),
573 expr_cast(@expr, @Ty),
574 expr_if(@expr, blk, Option<@expr>),
575 expr_while(@expr, blk),
576 /* Conditionless loop (can be exited with break, cont, or ret)
577 Same semantics as while(true) { body }, but typestate knows that the
578 (implicit) condition is always true. */
579 expr_loop(blk, Option<ident>),
580 expr_match(@expr, ~[arm]),
581 expr_fn_block(fn_decl, blk),
582 // Inner expr is always an expr_fn_block. We need the wrapping node to
583 // easily type this (a function returning nil on the inside but bool on
585 expr_loop_body(@expr),
586 // Like expr_loop_body but for 'do' blocks
591 expr_assign(@expr, @expr),
592 expr_swap(@expr, @expr),
593 expr_assign_op(binop, @expr, @expr),
594 expr_field(@expr, ident, ~[@Ty]),
595 expr_index(@expr, @expr),
597 expr_addr_of(mutability, @expr),
598 expr_break(Option<ident>),
599 expr_again(Option<ident>),
600 expr_ret(Option<@expr>),
601 expr_log(log_level, @expr, @expr),
603 expr_inline_asm(@~str, // asm
604 ~[(@~str, @expr)], // inputs
605 ~[(@~str, @expr)], // outputs
606 @~str, bool, bool), // clobbers, volatile, align stack
610 // A struct literal expression.
611 expr_struct(@path, ~[field], Option<@expr>),
613 // A vector literal constructed from one repeated element.
614 expr_repeat(@expr /* element */, @expr /* count */, mutability),
616 // No-op: used solely so we can pretty-print faithfully
620 // When the main rust parser encounters a syntax-extension invocation, it
621 // parses the arguments to the invocation as a token-tree. This is a very
622 // loose structure, such that all sorts of different AST-fragments can
623 // be passed to syntax extensions using a uniform type.
625 // If the syntax extension is an MBE macro, it will attempt to match its
626 // LHS "matchers" against the provided token tree, and if it finds a
627 // match, will transcribe the RHS token tree, splicing in any captured
628 // macro_parser::matched_nonterminals into the tt_nonterminals it finds.
630 // The RHS of an MBE macro is the only place a tt_nonterminal or tt_seq
631 // makes any real sense. You could write them elsewhere but nothing
632 // else knows what to do with them, so you'll probably get a syntax
638 #[doc="For macro invocations; parsing is delegated to the macro"]
639 pub enum token_tree {
641 tt_tok(span, ::parse::token::Token),
642 // a delimited sequence (the delimiters appear as the first
643 // and last elements of the vector)
644 tt_delim(~[token_tree]),
645 // These only make sense for right-hand-sides of MBE macros:
647 // a kleene-style repetition sequence with a span, a tt_forest,
648 // an optional separator (?), and a boolean where true indicates
649 // zero or more (*), and false indicates one or more (+).
650 tt_seq(span, ~[token_tree], Option<::parse::token::Token>, bool),
652 // a syntactic variable that will be filled in by macro expansion.
653 tt_nonterminal(span, ident)
657 // Matchers are nodes defined-by and recognized-by the main rust parser and
658 // language, but they're only ever found inside syntax-extension invocations;
659 // indeed, the only thing that ever _activates_ the rules in the rust parser
660 // for parsing a matcher is a matcher looking for the 'matchers' nonterminal
661 // itself. Matchers represent a small sub-language for pattern-matching
662 // token-trees, and are thus primarily used by the macro-defining extension
668 // A matcher that matches a single token, denoted by the token itself. So
669 // long as there's no $ involved.
675 // A matcher that matches a sequence of sub-matchers, denoted various
678 // $(M)* zero or more Ms
679 // $(M)+ one or more Ms
680 // $(M),+ one or more comma-separated Ms
681 // $(A B C);* zero or more semi-separated 'A B C' seqs
687 // A matcher that matches one of a few interesting named rust
688 // nonterminals, such as types, expressions, items, or raw token-trees. A
689 // black-box matcher on expr, for example, binds an expr to a given ident,
690 // and that ident can re-occur as an interpolation in the RHS of a
691 // macro-by-example rule. For example:
693 // $foo:expr => 1 + $foo // interpolate an expr
694 // $foo:tt => $foo // interpolate a token-tree
695 // $foo:tt => bar! $foo // only other valid interpolation
696 // // is in arg position for another
699 // As a final, horrifying aside, note that macro-by-example's input is
700 // also matched by one of these matchers. Holy self-referential! It is matched
701 // by an match_seq, specifically this one:
703 // $( $lhs:matchers => $rhs:tt );+
705 // If you understand that, you have closed to loop and understand the whole
706 // macro system. Congratulations.
708 pub type matcher = spanned<matcher_>;
715 match_tok(::parse::token::Token),
716 // match repetitions of a sequence: body, separator, zero ok?,
717 // lo, hi position-in-match-array used:
718 match_seq(~[matcher], Option<::parse::token::Token>, bool, uint, uint),
719 // parse a Rust NT: name to bind, name of NT, position in match array:
720 match_nonterminal(ident, ident, uint)
723 pub type mac = spanned<mac_>;
729 mac_invoc_tt(@path,~[token_tree]), // new macro-invocation
732 pub type lit = spanned<lit_>;
739 lit_int(i64, int_ty),
740 lit_uint(u64, uint_ty),
741 lit_int_unsuffixed(i64),
742 lit_float(@~str, float_ty),
743 lit_float_unsuffixed(@~str),
748 // NB: If you change this, you'll probably want to change the corresponding
749 // type structure in middle/ty.rs as well.
761 pub struct ty_field_ {
766 pub type ty_field = spanned<ty_field_>;
771 pub struct ty_method {
785 // A trait method is either required (meaning it doesn't have an
786 // implementation, just a signature) or provided (meaning it has a default
788 pub enum trait_method {
796 pub enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, }
798 impl ToStr for int_ty {
799 pure fn to_str(&self) -> ~str {
800 ::ast_util::int_ty_to_str(*self)
804 impl to_bytes::IterBytes for int_ty {
805 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
806 (*self as u8).iter_bytes(lsb0, f)
813 pub enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, }
815 impl ToStr for uint_ty {
816 pure fn to_str(&self) -> ~str {
817 ::ast_util::uint_ty_to_str(*self)
821 impl to_bytes::IterBytes for uint_ty {
822 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
823 (*self as u8).iter_bytes(lsb0, f)
830 pub enum float_ty { ty_f, ty_f32, ty_f64, }
832 impl ToStr for float_ty {
833 pure fn to_str(&self) -> ~str {
834 ::ast_util::float_ty_to_str(*self)
838 impl to_bytes::IterBytes for float_ty {
839 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
840 (*self as u8).iter_bytes(lsb0, f)
844 // NB Eq method appears below.
854 // Not represented directly in the AST, referred to by name through a ty_path.
874 impl ToStr for Onceness {
875 pure fn to_str(&self) -> ~str {
883 impl to_bytes::IterBytes for Onceness {
884 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
885 (*self as uint).iter_bytes(lsb0, f);
892 pub struct TyClosure {
894 region: Option<@Lifetime>,
903 pub struct TyBareFn {
914 ty_bot, /* bottom type */
918 ty_fixed_length_vec(mt, @expr),
920 ty_rptr(Option<@Lifetime>, mt),
921 ty_closure(@TyClosure),
922 ty_bare_fn(@TyBareFn),
924 ty_path(@path, node_id),
926 // ty_infer means the type should be inferred instead of it having been
927 // specified. This should only appear at the "top level" of a type and not
932 impl to_bytes::IterBytes for Ty {
933 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
934 to_bytes::iter_bytes_2(&self.span.lo, &self.span.hi, lsb0, f);
962 pure_fn, // declared with "pure fn"
963 unsafe_fn, // declared with "unsafe fn"
964 impure_fn, // declared with "fn"
965 extern_fn, // declared with "extern fn"
968 impl ToStr for purity {
969 pure fn to_str(&self) -> ~str {
971 impure_fn => ~"impure",
972 unsafe_fn => ~"unsafe",
974 extern_fn => ~"extern"
979 impl to_bytes::IterBytes for purity {
980 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
981 (*self as u8).iter_bytes(lsb0, f)
989 noreturn, // functions with return type _|_ that always
990 // raise an error or exit (i.e. never return to the caller)
991 return_val, // everything else
994 impl to_bytes::IterBytes for ret_style {
995 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
996 (*self as u8).iter_bytes(lsb0, f)
1004 sty_static, // no self: static method
1005 sty_by_ref, // old by-reference self: ``
1006 sty_value, // by-value self: `self`
1007 sty_region(mutability), // by-region self: `&self`
1008 sty_box(mutability), // by-managed-pointer self: `@self`
1009 sty_uniq(mutability) // by-unique-pointer self: `~self`
1013 fn is_borrowed(&self) -> bool {
1015 sty_region(_) => true,
1021 pub type self_ty = spanned<self_ty_>;
1028 attrs: ~[attribute],
1044 view_items: ~[@view_item],
1051 pub enum foreign_abi {
1052 foreign_abi_rust_intrinsic,
1054 foreign_abi_stdcall,
1057 // Foreign mods can be named or anonymous
1061 pub enum foreign_mod_sort { named, anonymous }
1066 pub struct foreign_mod {
1067 sort: foreign_mod_sort,
1069 view_items: ~[@view_item],
1070 items: ~[@foreign_item],
1076 pub struct variant_arg {
1084 pub enum variant_kind {
1085 tuple_variant_kind(~[variant_arg]),
1086 struct_variant_kind(@struct_def),
1087 enum_variant_kind(enum_def)
1093 pub struct enum_def {
1094 variants: ~[variant],
1095 common: Option<@struct_def>,
1101 pub struct variant_ {
1103 attrs: ~[attribute],
1106 disr_expr: Option<@expr>,
1110 pub type variant = spanned<variant_>;
1115 pub struct path_list_ident_ {
1120 pub type path_list_ident = spanned<path_list_ident_>;
1125 pub enum namespace { module_ns, type_value_ns }
1127 pub type view_path = spanned<view_path_>;
1132 pub enum view_path_ {
1134 // quux = foo::bar::baz
1138 // foo::bar::baz (with 'baz =' implicitly on the left)
1139 view_path_simple(ident, @path, namespace, node_id),
1142 view_path_glob(@path, node_id),
1144 // foo::bar::{a,b,c}
1145 view_path_list(@path, ~[path_list_ident], node_id)
1151 pub struct view_item {
1153 attrs: ~[attribute],
1161 pub enum view_item_ {
1162 view_item_extern_mod(ident, ~[@meta_item], node_id),
1163 view_item_use(~[@view_path]),
1166 // Meta-data associated with an item
1167 pub type attribute = spanned<attribute_>;
1169 // Distinguishes between attributes that decorate items and attributes that
1170 // are contained as statements within items. These two cases need to be
1171 // distinguished for pretty-printing.
1175 pub enum attr_style { attr_outer, attr_inner, }
1177 // doc-comments are promoted to attributes that have is_sugared_doc = true
1181 pub struct attribute_ {
1184 is_sugared_doc: bool,
1188 trait_refs appear in impls.
1189 resolve maps each trait_ref's ref_id to its defining trait; that's all
1190 that the ref_id is for. The impl_id maps to the "self type" of this impl.
1191 If this impl is an item_impl, the impl_id is redundant (it could be the
1192 same as the impl's node id).
1197 pub struct trait_ref {
1205 pub enum visibility { public, private, inherited }
1210 pub struct struct_field_ {
1211 kind: struct_field_kind,
1216 pub type struct_field = spanned<struct_field_>;
1221 pub enum struct_field_kind {
1222 named_field(ident, struct_mutability, visibility),
1223 unnamed_field // element of a tuple-like struct
1229 pub struct struct_def {
1230 fields: ~[@struct_field], /* fields */
1231 /* (not including ctor or dtor) */
1232 /* dtor is optional */
1233 dtor: Option<struct_dtor>,
1234 /* ID of the constructor. This is only used for tuple- or enum-like
1236 ctor_id: Option<node_id>
1240 FIXME (#3300): Should allow items to be anonymous. Right now
1241 we just use dummy names for anon items.
1248 attrs: ~[attribute],
1259 item_const(@Ty, @expr),
1260 item_fn(fn_decl, purity, Generics, blk),
1262 item_foreign_mod(foreign_mod),
1263 item_ty(@Ty, Generics),
1264 item_enum(enum_def, Generics),
1265 item_struct(@struct_def, Generics),
1266 item_trait(Generics, ~[@trait_ref], ~[trait_method]),
1268 Option<@trait_ref>, // (optional) trait this impl implements
1271 // a macro invocation (which includes macro definition)
1278 pub enum struct_mutability { struct_mutable, struct_immutable }
1280 impl to_bytes::IterBytes for struct_mutability {
1281 pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
1282 (*self as u8).iter_bytes(lsb0, f)
1286 pub type struct_dtor = spanned<struct_dtor_>;
1291 pub struct struct_dtor_ {
1293 attrs: ~[attribute],
1301 pub struct foreign_item {
1303 attrs: ~[attribute],
1304 node: foreign_item_,
1313 pub enum foreign_item_ {
1314 foreign_item_fn(fn_decl, purity, Generics),
1315 foreign_item_const(@Ty)
1318 // The data we save and restore about an inlined item or method. This is not
1319 // part of the AST that we parse from a file, but it becomes part of the tree
1324 pub enum inlined_item {
1326 ii_method(def_id /* impl id */, @method),
1327 ii_foreign(@foreign_item),
1328 ii_dtor(struct_dtor, ident, Generics, def_id /* parent id */)
1333 //are asts encodable?
1335 // it looks like this *will* be a compiler bug, after
1336 // I get deriving_eq for crates into incoming :)
1342 #[test] fn check_asts_encodable() {
1343 let bogus_span = span {lo:BytePos(10),
1349 module: _mod {view_items: ~[], items: ~[]},
1354 // doesn't matter which encoder we use....
1355 let _f = (_e as std::serialize::Encodable::<std::json::Encoder>);
1363 // indent-tabs-mode: nil
1364 // c-basic-offset: 4
1365 // buffer-file-coding-system: utf-8-unix