diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2013-10-29 06:03:32 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2013-11-08 19:42:46 -0500 |
| commit | 1f4faaee401f8681e25afbcf3b6296b6cd2ca55a (patch) | |
| tree | f0dac4e7f58ebab635c4bba59a04fca2833db4a8 /src/libsyntax | |
| parent | 85c51d3b02e421e2ab99c330e0d8212293f64f04 (diff) | |
| download | rust-1f4faaee401f8681e25afbcf3b6296b6cd2ca55a.tar.gz rust-1f4faaee401f8681e25afbcf3b6296b6cd2ca55a.zip | |
Generalize AST and ty::Generics to accept multiple lifetimes.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/ast_map.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/ast_util.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 14 | ||||
| -rw-r--r-- | src/libsyntax/ext/concat_idents.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/generic.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/rand.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/ty.rs | 18 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/format.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 35 | ||||
| -rw-r--r-- | src/libsyntax/opt_vec.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 20 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 55 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 7 |
15 files changed, 120 insertions, 93 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c0c2e2822f1..6245c61dfa1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -28,7 +28,7 @@ use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; // table) and a SyntaxContext to track renaming and // macro expansion per Flatt et al., "Macros // That Work Together" -#[deriving(Clone, IterBytes, ToStr)] +#[deriving(Clone, IterBytes, ToStr, TotalEq, TotalOrd)] pub struct Ident { name: Name, ctxt: SyntaxContext } impl Ident { @@ -110,6 +110,7 @@ pub enum SyntaxContext_ { /// A name is a part of an identifier, representing a string or gensym. It's /// the result of interning. pub type Name = uint; + /// A mark represents a unique id associated with a macro expansion pub type Mrk = uint; @@ -156,9 +157,8 @@ pub struct Path { pub struct PathSegment { /// The identifier portion of this path segment. identifier: Ident, - /// The lifetime parameter for this path segment. Currently only one - /// lifetime parameter is allowed. - lifetime: Option<Lifetime>, + /// The lifetime parameters for this path segment. + lifetimes: OptVec<Lifetime>, /// The type parameters for this path segment, if present. types: OptVec<Ty>, } @@ -167,7 +167,7 @@ pub type CrateNum = int; pub type NodeId = int; -#[deriving(Clone, Eq, Encodable, Decodable, IterBytes, ToStr)] +#[deriving(Clone, TotalEq, TotalOrd, Eq, Encodable, Decodable, IterBytes, ToStr)] pub struct DefId { crate: CrateNum, node: NodeId, diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 17613d19c7e..f3d7ac1804d 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -488,3 +488,15 @@ pub fn node_item_query<Result>(items: map, id: NodeId, _ => fail!("{}", error_msg) } } + +pub fn item_span(items: map, + id: ast::NodeId) + -> Span { + match items.find(&id) { + Some(&node_item(item, _)) => item.span, + r => { + fail!(format!("item_span: expected item with id {} but found {:?}", + id, r)) + } + } +} diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 3ec87dbdd26..ccae25dc012 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -225,7 +225,7 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path { segments: ~[ ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -948,7 +948,7 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo for (idx,seg) in a.iter().enumerate() { if (seg.identifier.name != b[idx].identifier.name) // FIXME #7743: ident -> name problems in lifetime comparison? - || (seg.lifetime != b[idx].lifetime) + || (seg.lifetimes != b[idx].lifetimes) // can types contain idents? || (seg.types != b[idx].types) { return false; @@ -966,7 +966,9 @@ mod test { use std::hashmap::HashMap; fn ident_to_segment(id : &Ident) -> PathSegment { - PathSegment{identifier:id.clone(), lifetime: None, types: opt_vec::Empty} + PathSegment {identifier:id.clone(), + lifetimes: opt_vec::Empty, + types: opt_vec::Empty} } #[test] fn idents_name_eq_test() { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 0a5e20fc2b2..5ae158045e0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,7 +38,7 @@ pub trait AstBuilder { fn path_all(&self, sp: Span, global: bool, idents: ~[ast::Ident], - rp: Option<ast::Lifetime>, + lifetimes: OptVec<ast::Lifetime>, types: ~[ast::Ty]) -> ast::Path; @@ -237,19 +237,19 @@ pub trait AstBuilder { impl AstBuilder for @ExtCtxt { fn path(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { - self.path_all(span, false, strs, None, ~[]) + self.path_all(span, false, strs, opt_vec::Empty, ~[]) } fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path { self.path(span, ~[id]) } fn path_global(&self, span: Span, strs: ~[ast::Ident]) -> ast::Path { - self.path_all(span, true, strs, None, ~[]) + self.path_all(span, true, strs, opt_vec::Empty, ~[]) } fn path_all(&self, sp: Span, global: bool, mut idents: ~[ast::Ident], - rp: Option<ast::Lifetime>, + lifetimes: OptVec<ast::Lifetime>, types: ~[ast::Ty]) -> ast::Path { let last_identifier = idents.pop(); @@ -257,13 +257,13 @@ impl AstBuilder for @ExtCtxt { .map(|ident| { ast::PathSegment { identifier: ident, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect(); segments.push(ast::PathSegment { identifier: last_identifier, - lifetime: rp, + lifetimes: lifetimes, types: opt_vec::from(types), }); ast::Path { @@ -327,7 +327,7 @@ impl AstBuilder for @ExtCtxt { self.ident_of("option"), self.ident_of("Option") ], - None, + opt_vec::Empty, ~[ ty ]), None) } diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 0ca18f1208d..216bc3097ce 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -43,7 +43,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) segments: ~[ ast::PathSegment { identifier: res, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ] diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index cfb6048df18..b37757341ef 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -375,14 +375,10 @@ impl<'self> TraitDef<'self> { cx.ty_ident(trait_span, ty_param.ident) }; - let self_lifetime = if generics.lifetimes.is_empty() { - None - } else { - Some(*generics.lifetimes.get(0)) - }; + let self_lifetimes = generics.lifetimes.clone(); // Create the type of `self`. - let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetime, + let self_type = cx.ty_path(cx.path_all(trait_span, false, ~[ type_ident ], self_lifetimes, opt_vec::take_vec(self_ty_params)), None); let doc_attr = cx.attribute( diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 1e2a6fa2eb5..d014816c070 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -14,6 +14,7 @@ use codemap::Span; use ext::base::ExtCtxt; use ext::build::{AstBuilder}; use ext::deriving::generic::*; +use opt_vec; pub fn expand_deriving_rand(cx: @ExtCtxt, span: Span, @@ -77,7 +78,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr { let rand_name = cx.path_all(span, true, rand_ident.clone(), - None, + opt_vec::Empty, ~[]); let rand_name = cx.expr_path(rand_name); diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index c60259304ae..d1a5af5f7e8 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -19,6 +19,7 @@ use ext::base::ExtCtxt; use ext::build::AstBuilder; use codemap::{Span,respan}; use opt_vec; +use opt_vec::OptVec; /// The types of pointers pub enum PtrTy<'self> { @@ -71,7 +72,7 @@ impl<'self> Path<'self> { self_generics: &Generics) -> ast::Path { let idents = self.path.map(|s| cx.ident_of(*s) ); - let lt = mk_lifetime(cx, span, &self.lifetime); + let lt = mk_lifetimes(cx, span, &self.lifetime); let tys = self.params.map(|t| t.to_ty(cx, span, self_ty, self_generics)); cx.path_all(span, self.global, idents, lt, tys) @@ -116,6 +117,13 @@ fn mk_lifetime(cx: @ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifet } } +fn mk_lifetimes(cx: @ExtCtxt, span: Span, lt: &Option<&str>) -> OptVec<ast::Lifetime> { + match *lt { + Some(ref s) => opt_vec::with(cx.lifetime(span, cx.ident_of(*s))), + None => opt_vec::Empty + } +} + impl<'self> Ty<'self> { pub fn to_ty(&self, cx: @ExtCtxt, @@ -166,13 +174,9 @@ impl<'self> Ty<'self> { let self_params = do self_generics.ty_params.map |ty_param| { cx.ty_ident(span, ty_param.ident) }; - let lifetime = if self_generics.lifetimes.is_empty() { - None - } else { - Some(*self_generics.lifetimes.get(0)) - }; + let lifetimes = self_generics.lifetimes.clone(); - cx.path_all(span, false, ~[self_ty], lifetime, + cx.path_all(span, false, ~[self_ty], lifetimes, opt_vec::take_vec(self_params)) } Literal(ref p) => { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ba946d5fb1f..b74349da2a9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -169,7 +169,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, segments: ~[ ast::PathSegment { identifier: ident, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -628,7 +628,7 @@ impl Visitor<()> for NewNameFinderContext { segments: [ ast::PathSegment { identifier: id, - lifetime: _, + lifetimes: _, types: _ } ] diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 943279d2dc6..00919fce5db 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -15,7 +15,7 @@ use ext::base; use ext::build::AstBuilder; use rsparse = parse; use parse::token; - +use opt_vec; use std::fmt::parse; use std::hashmap::{HashMap, HashSet}; use std::vec; @@ -464,7 +464,7 @@ impl Context { sp, true, rtpath("Method"), - Some(life), + opt_vec::with(life), ~[] ), None); let st = ast::item_static(ty, ast::MutImmutable, method); @@ -582,7 +582,8 @@ impl Context { self.ecx.ident_of("rt"), self.ecx.ident_of("Piece"), ], - Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), + opt_vec::with( + self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), ~[] ), None); let ty = ast::ty_fixed_length_vec( diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 388de29b456..ea0ab95a451 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -144,7 +144,7 @@ pub trait ast_fold { ident: self.fold_ident(m.ident), attrs: m.attrs.map(|a| fold_attribute_(*a, self)), generics: fold_generics(&m.generics, self), - explicit_self: m.explicit_self, + explicit_self: self.fold_explicit_self(&m.explicit_self), purity: m.purity, decl: fold_fn_decl(&m.decl, self), body: self.fold_block(&m.body), @@ -245,12 +245,14 @@ pub trait ast_fold { ty_uniq(ref mt) => ty_uniq(fold_mt(mt, self)), ty_vec(ref mt) => ty_vec(fold_mt(mt, self)), ty_ptr(ref mt) => ty_ptr(fold_mt(mt, self)), - ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, self)), + ty_rptr(ref region, ref mt) => { + ty_rptr(fold_opt_lifetime(region, self), fold_mt(mt, self)) + } ty_closure(ref f) => { ty_closure(@TyClosure { sigil: f.sigil, purity: f.purity, - region: f.region, + region: fold_opt_lifetime(&f.region, self), onceness: f.onceness, bounds: fold_opt_bounds(&f.bounds, self), decl: fold_fn_decl(&f.decl, self), @@ -349,7 +351,7 @@ pub trait ast_fold { global: p.global, segments: p.segments.map(|segment| ast::PathSegment { identifier: self.fold_ident(segment.identifier), - lifetime: segment.lifetime, + lifetimes: segment.lifetimes.map(|l| fold_lifetime(l, self)), types: segment.types.map(|typ| self.fold_ty(typ)), }) } @@ -389,6 +391,24 @@ pub trait ast_fold { fn new_span(&self, sp: Span) -> Span { sp } + + fn fold_explicit_self(&self, es: &explicit_self) -> explicit_self { + Spanned { + span: self.new_span(es.span), + node: self.fold_explicit_self_(&es.node) + } + } + + fn fold_explicit_self_(&self, es: &explicit_self_) -> explicit_self_ { + match *es { + sty_static | sty_value(_) | sty_uniq(_) | sty_box(_) => { + *es + } + sty_region(ref lifetime, m) => { + sty_region(fold_opt_lifetime(lifetime, self), m) + } + } + } } /* some little folds that probably aren't useful to have in ast_fold itself*/ @@ -505,6 +525,11 @@ pub fn fold_lifetimes<T:ast_fold>(lts: &OptVec<Lifetime>, fld: &T) lts.map(|l| fold_lifetime(l, fld)) } +pub fn fold_opt_lifetime<T:ast_fold>(o_lt: &Option<Lifetime>, fld: &T) + -> Option<Lifetime> { + o_lt.as_ref().map(|lt| fold_lifetime(lt, fld)) +} + pub fn fold_generics<T:ast_fold>(generics: &Generics, fld: &T) -> Generics { Generics {ty_params: fold_ty_params(&generics.ty_params, fld), lifetimes: fold_lifetimes(&generics.lifetimes, fld)} @@ -675,7 +700,7 @@ pub fn noop_fold_type_method<T:ast_fold>(m: &TypeMethod, fld: &T) purity: m.purity, decl: fold_fn_decl(&m.decl, fld), generics: fold_generics(&m.generics, fld), - explicit_self: m.explicit_self, + explicit_self: fld.fold_explicit_self(&m.explicit_self), id: fld.new_id(m.id), span: fld.new_span(m.span), } diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 2000d0b9746..4d39d4df72f 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -165,3 +165,13 @@ impl<'self, T> Iterator<&'self T> for OptVecIterator<'self, T> { } } } + +impl<A> FromIterator<A> for OptVec<A> { + fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> OptVec<A> { + let mut r = Empty; + for x in *iterator { + r.push(x); + } + r + } +} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6c81784b5de..672865aadcc 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -368,7 +368,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("a"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -387,12 +387,12 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("a"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ] @@ -592,7 +592,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("d"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -614,7 +614,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -641,7 +641,7 @@ mod test { segments: ~[ ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -669,7 +669,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("int"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -687,7 +687,7 @@ mod test { ast::PathSegment { identifier: str_to_ident("b"), - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } ], @@ -724,8 +724,8 @@ mod test { identifier: str_to_ident( "b"), - lifetime: - None, + lifetimes: + opt_vec::Empty, types: opt_vec::Empty } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7c98d8d1c85..cfb4da87720 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1490,7 +1490,7 @@ impl Parser { segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, }, bound_set: bound_set @@ -1499,46 +1499,21 @@ impl Parser { } // Parse the `<` before the lifetime and types, if applicable. - let (any_lifetime_or_types, optional_lifetime, types) = - if mode != NoTypesAllowed && self.eat(&token::LT) { - // Parse an optional lifetime. - let optional_lifetime = match *self.token { - token::LIFETIME(*) => Some(self.parse_lifetime()), - _ => None, - }; - - // Parse type parameters. - let mut types = opt_vec::Empty; - let mut need_comma = optional_lifetime.is_some(); - loop { - // We're done if we see a `>`. - match *self.token { - token::GT | token::BINOP(token::SHR) => { - self.expect_gt(); - break - } - _ => {} // Go on. - } - - if need_comma { - self.expect(&token::COMMA) - } else { - need_comma = true - } - - types.push(self.parse_ty(false)) + let (any_lifetime_or_types, lifetimes, types) = { + if mode != NoTypesAllowed && self.eat(&token::LT) { + let (lifetimes, types) = + self.parse_generic_values_after_lt(); + (true, lifetimes, opt_vec::from(types)) + } else { + (false, opt_vec::Empty, opt_vec::Empty) } - - (true, optional_lifetime, types) - } else { - (false, None, opt_vec::Empty) }; // Assemble and push the result. segments.push(PathSegmentAndBoundSet { segment: ast::PathSegment { identifier: identifier, - lifetime: optional_lifetime, + lifetimes: lifetimes, types: types, }, bound_set: bound_set @@ -1609,11 +1584,11 @@ impl Parser { pub fn parse_lifetime(&self) -> ast::Lifetime { match *self.token { token::LIFETIME(i) => { - let span = self.span; + let span = *self.span; self.bump(); return ast::Lifetime { id: ast::DUMMY_NODE_ID, - span: *span, + span: span, ident: i }; } @@ -4856,7 +4831,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4892,7 +4867,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4910,7 +4885,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() @@ -4932,7 +4907,7 @@ impl Parser { segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetime: None, + lifetimes: opt_vec::Empty, types: opt_vec::Empty, } }).collect() diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 08c2ae88e4f..fd02ac68f4e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1566,13 +1566,13 @@ fn print_path_(s: @ps, } } - if segment.lifetime.is_some() || !segment.types.is_empty() { + if !segment.lifetimes.is_empty() || !segment.types.is_empty() { if colons_before_params { word(s.s, "::") } word(s.s, "<"); - for lifetime in segment.lifetime.iter() { + for lifetime in segment.lifetimes.iter() { print_lifetime(s, lifetime); if !segment.types.is_empty() { word_space(s, ",") @@ -1905,7 +1905,8 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) { pub fn print_view_path(s: @ps, vp: &ast::view_path) { match vp.node { ast::view_path_simple(ident, ref path, _) => { - if path.segments.last().identifier != ident { + // FIXME can't compare identifiers directly here + if path.segments.last().identifier.name != ident.name { print_ident(s, ident); space(s.s); word_space(s, "="); |
