1use super::{ExpectedToken, SeqSep};
2use crate::{PResult, Parser};
3use itertools::Itertools;
4use smallvec::SmallVec;
5use solar_ast::{token::*, *};
6use solar_interface::{diagnostics::DiagMsg, error_code, kw, sym, Ident, Span};
7
8impl<'sess, 'ast> Parser<'sess, 'ast> {
9 #[instrument(level = "debug", skip_all)]
11 pub fn parse_file(&mut self) -> PResult<'sess, SourceUnit<'ast>> {
12 self.parse_items(TokenKind::Eof).map(SourceUnit::new)
13 }
14
15 fn parse_items(&mut self, end: TokenKind) -> PResult<'sess, Box<'ast, [Item<'ast>]>> {
17 let get_msg_note = |this: &mut Self| {
18 let (prefix, list, link);
19 if this.in_contract {
20 prefix = "contract";
21 list = "function, variable, struct, or modifier definition";
22 link = "contractBodyElement";
23 } else {
24 prefix = "global";
25 list = "pragma, import directive, contract, interface, library, struct, enum, constant, function, modifier, or error definition";
26 link = "sourceUnit";
27 }
28 let msg =
29 format!("expected {prefix} item ({list}), found {}", this.token.full_description());
30 let note = format!("for a full list of valid {prefix} items, see <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.{link}>");
31 (msg, note)
32 };
33
34 let mut items = Vec::new();
35 while let Some(item) = self.parse_item()? {
36 if self.in_contract && !item.is_allowed_in_contract() {
37 let msg = format!("{}s are not allowed in contracts", item.description());
38 let (_, note) = get_msg_note(self);
39 self.dcx().err(msg).span(item.span).note(note).emit();
40 } else {
41 items.push(item);
42 }
43 }
44 if !self.eat(end) {
45 let (msg, note) = get_msg_note(self);
46 return Err(self.dcx().err(msg).span(self.token.span).note(note));
47 }
48 Ok(self.alloc_vec(items))
49 }
50
51 #[instrument(level = "debug", skip_all)]
53 pub fn parse_item(&mut self) -> PResult<'sess, Option<Item<'ast>>> {
54 let docs = self.parse_doc_comments();
55 self.parse_spanned(Self::parse_item_kind)
56 .map(|(span, kind)| kind.map(|kind| Item { docs, span, kind }))
57 }
58
59 fn parse_item_kind(&mut self) -> PResult<'sess, Option<ItemKind<'ast>>> {
60 let kind = if self.is_function_like() {
61 self.parse_function().map(ItemKind::Function)
62 } else if self.eat_keyword(kw::Struct) {
63 self.parse_struct().map(ItemKind::Struct)
64 } else if self.eat_keyword(kw::Event) {
65 self.parse_event().map(ItemKind::Event)
66 } else if self.is_contract_like() {
67 self.parse_contract().map(ItemKind::Contract)
68 } else if self.eat_keyword(kw::Enum) {
69 self.parse_enum().map(ItemKind::Enum)
70 } else if self.eat_keyword(kw::Type) {
71 self.parse_udvt().map(ItemKind::Udvt)
72 } else if self.eat_keyword(kw::Pragma) {
73 self.parse_pragma().map(ItemKind::Pragma)
74 } else if self.eat_keyword(kw::Import) {
75 self.parse_import().map(ItemKind::Import)
76 } else if self.eat_keyword(kw::Using) {
77 self.parse_using().map(ItemKind::Using)
78 } else if self.check_keyword(sym::error)
79 && self.look_ahead(1).is_ident()
80 && self.look_ahead(2).is_open_delim(Delimiter::Parenthesis)
81 {
82 self.bump(); self.parse_error().map(ItemKind::Error)
84 } else if self.is_variable_declaration() {
85 let flags = if self.in_contract { VarFlags::STATE_VAR } else { VarFlags::CONSTANT_VAR };
86 self.parse_variable_definition(flags).map(ItemKind::Variable)
87 } else {
88 return Ok(None);
89 };
90 kind.map(Some)
91 }
92
93 fn is_function_like(&self) -> bool {
95 (self.token.is_keyword(kw::Function)
96 && !self.look_ahead(1).is_open_delim(Delimiter::Parenthesis))
97 || self.token.is_keyword_any(&[
98 kw::Constructor,
99 kw::Fallback,
100 kw::Receive,
101 kw::Modifier,
102 ])
103 }
104
105 fn is_contract_like(&self) -> bool {
107 self.token.is_keyword_any(&[kw::Abstract, kw::Contract, kw::Interface, kw::Library])
108 }
109
110 pub(super) fn is_variable_declaration(&self) -> bool {
112 self.token.is_non_reserved_ident(false) || self.is_non_custom_variable_declaration()
114 }
115
116 pub(super) fn is_non_custom_variable_declaration(&self) -> bool {
117 self.token.is_keyword(kw::Mapping)
118 || (self.token.is_keyword(kw::Function)
119 && self.look_ahead(1).is_open_delim(Delimiter::Parenthesis))
120 || self.token.is_elementary_type()
121 }
122
123 fn parse_function(&mut self) -> PResult<'sess, ItemFunction<'ast>> {
130 let Token { span: lo, kind: TokenKind::Ident(kw) } = self.token else {
131 unreachable!("parse_function called without function-like keyword");
132 };
133 self.bump(); let kind = match kw {
136 kw::Constructor => FunctionKind::Constructor,
137 kw::Function => FunctionKind::Function,
138 kw::Fallback => FunctionKind::Fallback,
139 kw::Receive => FunctionKind::Receive,
140 kw::Modifier => FunctionKind::Modifier,
141 _ => unreachable!("parse_function called without function-like keyword"),
142 };
143 let flags = FunctionFlags::from_kind(kind);
144 let header = self.parse_function_header(flags)?;
145 let (body_span, body) = self.parse_spanned(|this| {
146 Ok(if !flags.contains(FunctionFlags::ONLY_BLOCK) && this.eat(TokenKind::Semi) {
147 None
148 } else {
149 Some(this.parse_block()?)
150 })
151 })?;
152
153 if !self.in_contract && !kind.allowed_in_global() {
154 let msg = format!("{kind}s are not allowed in the global scope");
155 self.dcx().err(msg).span(lo.to(self.prev_token.span)).emit();
156 }
157 Ok(ItemFunction { kind, header, body, body_span })
160 }
161
162 pub(super) fn parse_function_header(
164 &mut self,
165 flags: FunctionFlags,
166 ) -> PResult<'sess, FunctionHeader<'ast>> {
167 let lo = self.prev_token.span; let mut header = FunctionHeader::default();
170 let var_flags = if flags.contains(FunctionFlags::PARAM_NAME) {
171 VarFlags::FUNCTION_TY
172 } else {
173 VarFlags::FUNCTION
174 };
175
176 if flags.contains(FunctionFlags::NAME) {
177 let ident;
179 if flags == FunctionFlags::FUNCTION
180 && self.token.is_keyword_any(&[kw::Fallback, kw::Receive])
181 {
182 let kw_span = self.prev_token.span;
183 ident = self.parse_ident_any()?;
184 let msg = format!("function named `{ident}`");
185 let mut warn = self.dcx().warn(msg).span(ident.span).code(error_code!(3445));
186 if self.in_contract {
187 let help = format!("remove the `function` keyword if you intend this to be a contract's {ident} function");
188 warn = warn.span_help(kw_span, help);
189 }
190 warn.emit();
191 } else {
192 ident = self.parse_ident()?;
193 }
194 header.name = Some(ident);
195 } else if self.token.is_non_reserved_ident(false) {
196 let msg = "function names are not allowed here";
197 self.dcx().err(msg).span(self.token.span).emit();
198 self.bump();
199 }
200
201 if flags.contains(FunctionFlags::NO_PARENS)
202 && !self.token.is_open_delim(Delimiter::Parenthesis)
203 {
204 } else {
206 header.parameters = self.parse_parameter_list(true, var_flags)?;
207 }
208
209 let mut modifiers = Vec::new();
210 loop {
211 let vis_guard = (!(flags == FunctionFlags::FUNCTION_TY && header.visibility.is_some()))
217 .then_some(());
218 if let Some(visibility) = vis_guard.and_then(|()| self.parse_visibility()) {
219 if header.visibility.is_some() {
220 let msg = "visibility already specified";
221 self.dcx().err(msg).span(self.prev_token.span).emit();
222 } else {
223 header.visibility =
224 if !flags.contains(FunctionFlags::from_visibility(visibility)) {
225 let msg = visibility_error(visibility, flags.visibilities());
226 self.dcx().err(msg).span(self.prev_token.span).emit();
227 flags.visibilities().into_iter().flatten().next()
228 } else {
229 Some(visibility)
230 };
231 }
232 } else if let Some(state_mutability) = self.parse_state_mutability() {
233 if !header.state_mutability.is_non_payable() {
234 let msg = "state mutability already specified";
235 self.dcx().err(msg).span(self.prev_token.span).emit();
236 } else {
237 header.state_mutability = if !flags
238 .contains(FunctionFlags::from_state_mutability(state_mutability))
239 {
240 let msg =
241 state_mutability_error(state_mutability, flags.state_mutabilities());
242 self.dcx().err(msg).span(self.prev_token.span).emit();
243 flags.state_mutabilities().into_iter().flatten().next().unwrap_or_default()
244 } else {
245 state_mutability
246 }
247 }
248 } else if self.eat_keyword(kw::Virtual) {
249 if !flags.contains(FunctionFlags::VIRTUAL) {
250 let msg = "`virtual` is not allowed here";
251 self.dcx().err(msg).span(self.prev_token.span).emit();
252 } else if header.virtual_ {
253 let msg = "virtual already specified";
254 self.dcx().err(msg).span(self.prev_token.span).emit();
255 } else {
256 header.virtual_ = true;
257 }
258 } else if self.eat_keyword(kw::Override) {
259 let o = self.parse_override()?;
260 if !flags.contains(FunctionFlags::OVERRIDE) {
261 let msg = "`override` is not allowed here";
262 self.dcx().err(msg).span(self.prev_token.span).emit();
263 } else if header.override_.is_some() {
264 let msg = "override already specified";
265 self.dcx().err(msg).span(self.prev_token.span).emit();
266 } else {
267 header.override_ = Some(o);
268 }
269 } else if flags.contains(FunctionFlags::MODIFIERS)
270 && self.token.is_non_reserved_ident(false)
271 {
272 modifiers.push(self.parse_modifier()?);
273 } else {
274 break;
275 }
276 }
277
278 header.modifiers = self.alloc_vec(modifiers);
279
280 if flags.contains(FunctionFlags::RETURNS) && self.eat_keyword(kw::Returns) {
281 header.returns = self.parse_parameter_list(false, var_flags)?;
282 }
283
284 header.span = lo.to(self.prev_token.span);
285
286 Ok(header)
287 }
288
289 fn parse_struct(&mut self) -> PResult<'sess, ItemStruct<'ast>> {
291 let name = self.parse_ident()?;
292 let fields = self.parse_delim_seq(
293 Delimiter::Brace,
294 SeqSep::trailing_enforced(TokenKind::Semi),
295 true,
296 |this| this.parse_variable_definition(VarFlags::STRUCT),
297 )?;
298 Ok(ItemStruct { name, fields })
299 }
300
301 fn parse_event(&mut self) -> PResult<'sess, ItemEvent<'ast>> {
303 let name = self.parse_ident()?;
304 let parameters = self.parse_parameter_list(true, VarFlags::EVENT)?;
305 let anonymous = self.eat_keyword(kw::Anonymous);
306 self.expect_semi()?;
307 Ok(ItemEvent { name, parameters, anonymous })
308 }
309
310 fn parse_error(&mut self) -> PResult<'sess, ItemError<'ast>> {
312 let name = self.parse_ident()?;
313 let parameters = self.parse_parameter_list(true, VarFlags::ERROR)?;
314 self.expect_semi()?;
315 Ok(ItemError { name, parameters })
316 }
317
318 fn parse_contract(&mut self) -> PResult<'sess, ItemContract<'ast>> {
322 let TokenKind::Ident(kw) = self.token.kind else {
323 unreachable!("parse_contract called without contract-like keyword");
324 };
325 self.bump(); let kind = match kw {
328 kw::Abstract => {
329 self.expect_keyword(kw::Contract)?;
330 ContractKind::AbstractContract
331 }
332 kw::Contract => ContractKind::Contract,
333 kw::Interface => ContractKind::Interface,
334 kw::Library => ContractKind::Library,
335 _ => unreachable!("parse_contract called without contract-like keyword"),
336 };
337 let name = self.parse_ident()?;
338
339 let mut bases = None::<Box<'_, [Modifier<'_>]>>;
340 let mut layout = None::<StorageLayoutSpecifier<'_>>;
341 loop {
342 if self.eat_keyword(kw::Is) {
343 let new_bases = self.parse_inheritance()?;
344 if let Some(prev) = &bases {
345 let msg = "base contracts already specified";
346 let span = |bases: &[Modifier<'_>]| {
347 Span::join_first_last(bases.iter().map(|m| m.span()))
348 };
349 self.dcx()
350 .err(msg)
351 .span(span(new_bases))
352 .span_note(span(prev), "previous definition")
353 .emit();
354 } else if !new_bases.is_empty() {
355 bases = Some(new_bases);
356 }
357 } else if self.check_keyword(sym::layout) {
358 let new_layout = self.parse_storage_layout_specifier()?;
359 if let Some(prev) = &layout {
360 let msg = "storage layout already specified";
361 self.dcx()
362 .err(msg)
363 .span(new_layout.span)
364 .span_note(prev.span, "previous definition")
365 .emit();
366 } else {
367 layout = Some(new_layout);
368 }
369 } else {
370 break;
371 }
372 }
373
374 if let Some(layout) = &layout {
375 if !kind.is_contract() {
376 let msg = "storage layout is only allowed for contracts";
377 self.dcx().err(msg).span(layout.span).emit();
378 }
379 }
380
381 self.expect(TokenKind::OpenDelim(Delimiter::Brace))?;
382 let body =
383 self.in_contract(|this| this.parse_items(TokenKind::CloseDelim(Delimiter::Brace)))?;
384
385 Ok(ItemContract { kind, name, layout, bases: bases.unwrap_or_default(), body })
386 }
387
388 fn parse_enum(&mut self) -> PResult<'sess, ItemEnum<'ast>> {
390 let name = self.parse_ident()?;
391 let variants = self.parse_delim_comma_seq(Delimiter::Brace, true, Self::parse_ident)?;
392 Ok(ItemEnum { name, variants })
393 }
394
395 fn parse_udvt(&mut self) -> PResult<'sess, ItemUdvt<'ast>> {
397 let name = self.parse_ident()?;
398 self.expect_keyword(kw::Is)?;
399 let ty = self.parse_type()?;
400 self.expect_semi()?;
401 Ok(ItemUdvt { name, ty })
402 }
403
404 fn parse_pragma(&mut self) -> PResult<'sess, PragmaDirective<'ast>> {
406 let is_ident_or_strlit = |t: Token| t.is_ident() || t.is_str_lit();
407
408 let tokens = if self.check_keyword(sym::solidity)
409 || (self.token.is_ident()
410 && self.look_ahead_with(1, |t| t.is_op() || t.is_rational_lit()))
411 {
412 let ident = self.parse_ident_any()?;
414 let req = self.parse_semver_req()?;
415 PragmaTokens::Version(ident, req)
416 } else if (is_ident_or_strlit(self.token) && self.look_ahead(1).kind == TokenKind::Semi)
417 || (is_ident_or_strlit(self.token)
418 && self.look_ahead_with(1, is_ident_or_strlit)
419 && self.look_ahead(2).kind == TokenKind::Semi)
420 {
421 let k = self.parse_ident_or_strlit()?;
424 let v = if self.token.is_ident() || self.token.is_str_lit() {
425 Some(self.parse_ident_or_strlit()?)
426 } else {
427 None
428 };
429 PragmaTokens::Custom(k, v)
430 } else {
431 let mut tokens = Vec::new();
432 while !matches!(self.token.kind, TokenKind::Semi | TokenKind::Eof) {
433 tokens.push(self.token);
434 self.bump();
435 }
436 if !self.token.is_eof() && tokens.is_empty() {
437 let msg = "expected at least one token in pragma directive";
438 self.dcx().err(msg).span(self.prev_token.span).emit();
439 }
440 PragmaTokens::Verbatim(self.alloc_vec(tokens))
441 };
442 self.expect_semi()?;
443 Ok(PragmaDirective { tokens })
444 }
445
446 fn parse_ident_or_strlit(&mut self) -> PResult<'sess, IdentOrStrLit> {
447 if self.check_ident() {
448 self.parse_ident().map(IdentOrStrLit::Ident)
449 } else if self.check_str_lit() {
450 self.parse_str_lit().map(IdentOrStrLit::StrLit)
451 } else {
452 self.unexpected()
453 }
454 }
455
456 pub fn parse_semver_req(&mut self) -> PResult<'sess, SemverReq<'ast>> {
460 if self.check_noexpect(TokenKind::Semi) || self.check_noexpect(TokenKind::Eof) {
461 let msg = "empty version requirement";
462 let span = self.prev_token.span.to(self.token.span);
463 return Err(self.dcx().err(msg).span(span));
464 }
465 self.parse_semver_req_components_dis().map(|dis| SemverReq { dis })
466 }
467
468 fn parse_semver_req_components_dis(
470 &mut self,
471 ) -> PResult<'sess, Box<'ast, [SemverReqCon<'ast>]>> {
472 let mut dis = Vec::new();
474 loop {
475 dis.push(self.parse_semver_req_components_con()?);
476 if self.eat(TokenKind::OrOr) {
477 continue;
478 }
479 if self.check(TokenKind::Semi) || self.check(TokenKind::Eof) {
480 break;
481 }
482 debug_assert!(
485 matches!(
486 dis.last().map(|x| &x.components),
487 Some([
488 ..,
489 SemverReqComponent { span: _, kind: SemverReqComponentKind::Range(..) }
490 ])
491 ),
492 "not a range: last={:?}",
493 dis.last()
494 );
495 return Err(self.dcx().err("ranges can only be combined using the || operator"));
496 }
497 Ok(self.alloc_vec(dis))
498 }
499
500 fn parse_semver_req_components_con(&mut self) -> PResult<'sess, SemverReqCon<'ast>> {
502 let mut components = Vec::new();
506 let lo = self.token.span;
507 let (op, v) = self.parse_semver_component()?;
508 if self.eat(TokenKind::BinOp(BinOpToken::Minus)) {
509 let _ = op;
512 let (_second_op, right) = self.parse_semver_component()?;
513 let kind = SemverReqComponentKind::Range(v, right);
514 let span = lo.to(self.prev_token.span);
515 components.push(SemverReqComponent { span, kind });
516 } else {
517 let span = lo.to(self.prev_token.span);
519 let kind = SemverReqComponentKind::Op(op, v);
520 components.push(SemverReqComponent { span, kind });
521 while !matches!(self.token.kind, TokenKind::OrOr | TokenKind::Eof | TokenKind::Semi) {
523 let (span, (op, v)) = self.parse_spanned(Self::parse_semver_component)?;
524 let kind = SemverReqComponentKind::Op(op, v);
525 components.push(SemverReqComponent { span, kind });
526 }
527 }
528 let span = lo.to(self.prev_token.span);
529 let components = self.alloc_vec(components);
530 Ok(SemverReqCon { span, components })
531 }
532
533 fn parse_semver_component(&mut self) -> PResult<'sess, (Option<SemverOp>, SemverVersion)> {
534 let op = self.parse_semver_op();
535 let v = self.parse_semver_version()?;
536 Ok((op, v))
537 }
538
539 fn parse_semver_op(&mut self) -> Option<SemverOp> {
540 let op = match self.token.kind {
542 TokenKind::Eq => SemverOp::Exact,
543 TokenKind::Gt => SemverOp::Greater,
544 TokenKind::Ge => SemverOp::GreaterEq,
545 TokenKind::Lt => SemverOp::Less,
546 TokenKind::Le => SemverOp::LessEq,
547 TokenKind::Tilde => SemverOp::Tilde,
548 TokenKind::BinOp(BinOpToken::Caret) => SemverOp::Caret,
549 _ => return None,
550 };
551 self.bump();
552 Some(op)
553 }
554
555 fn parse_semver_version(&mut self) -> PResult<'sess, SemverVersion> {
556 Ok(SemverVersionParser::new(self).parse())
557 }
558
559 fn parse_import(&mut self) -> PResult<'sess, ImportDirective<'ast>> {
561 let path;
562 let items = if self.eat(TokenKind::BinOp(BinOpToken::Star)) {
563 let alias = self.parse_as_alias()?;
565 self.expect_keyword(sym::from)?;
566 path = self.parse_str_lit()?;
567 ImportItems::Glob(alias)
568 } else if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
569 let list = self.parse_delim_comma_seq(Delimiter::Brace, false, |this| {
571 let name = this.parse_ident()?;
572 let alias = this.parse_as_alias_opt()?;
573 Ok((name, alias))
574 })?;
575 self.expect_keyword(sym::from)?;
576 path = self.parse_str_lit()?;
577 ImportItems::Aliases(list)
578 } else {
579 path = self.parse_str_lit()?;
581 let alias = self.parse_as_alias_opt()?;
582 ImportItems::Plain(alias)
583 };
584 if path.value.as_str().is_empty() {
585 let msg = "import path cannot be empty";
586 self.dcx().err(msg).span(path.span).emit();
587 }
588 self.expect_semi()?;
589 Ok(ImportDirective { path, items })
590 }
591
592 fn parse_as_alias_opt(&mut self) -> PResult<'sess, Option<Ident>> {
594 if self.eat_keyword(kw::As) {
595 self.parse_ident().map(Some)
596 } else {
597 Ok(None)
598 }
599 }
600
601 fn parse_as_alias(&mut self) -> PResult<'sess, Ident> {
603 self.expect_keyword(kw::As)?;
604 self.parse_ident()
605 }
606
607 fn parse_using(&mut self) -> PResult<'sess, UsingDirective<'ast>> {
609 let list = self.parse_using_list()?;
610 self.expect_keyword(kw::For)?;
611 let ty = if self.eat(TokenKind::BinOp(BinOpToken::Star)) {
612 None
613 } else {
614 Some(self.parse_type()?)
615 };
616 let global = self.eat_keyword(sym::global);
617 self.expect_semi()?;
618 Ok(UsingDirective { list, ty, global })
619 }
620
621 fn parse_using_list(&mut self) -> PResult<'sess, UsingList<'ast>> {
622 if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
623 self.parse_delim_comma_seq(Delimiter::Brace, false, |this| {
624 let path = this.parse_path()?;
625 let op = if this.eat_keyword(kw::As) {
626 Some(this.parse_user_definable_operator()?)
627 } else {
628 None
629 };
630 Ok((path, op))
631 })
632 .map(UsingList::Multiple)
633 } else {
634 self.parse_path().map(UsingList::Single)
635 }
636 }
637
638 fn parse_user_definable_operator(&mut self) -> PResult<'sess, UserDefinableOperator> {
639 use BinOpToken::*;
640 use TokenKind::*;
641 use UserDefinableOperator as Op;
642 macro_rules! user_op {
643 ($($tok1:tt $(($tok2:tt))? => $op:expr),* $(,)?) => {
644 match self.token.kind {
645 $($tok1 $(($tok2))? => $op,)*
646 _ => {
647 self.expected_tokens.extend_from_slice(&[$(ExpectedToken::Token($tok1 $(($tok2))?)),*]);
648 return self.unexpected();
649 }
650 }
651 };
652 }
653 let op = user_op! {
654 BinOp(And) => Op::BitAnd,
655 Tilde => Op::BitNot,
656 BinOp(Or) => Op::BitOr,
657 BinOp(Caret) => Op::BitXor,
658 BinOp(Plus) => Op::Add,
659 BinOp(Slash) => Op::Div,
660 BinOp(Percent) => Op::Rem,
661 BinOp(Star) => Op::Mul,
662 BinOp(Minus) => Op::Sub,
663 EqEq => Op::Eq,
664 Ge => Op::Ge,
665 Gt => Op::Gt,
666 Le => Op::Le,
667 Lt => Op::Lt,
668 Ne => Op::Ne,
669 };
670 self.bump();
671 Ok(op)
672 }
673
674 pub(super) fn parse_variable_definition(
681 &mut self,
682 flags: VarFlags,
683 ) -> PResult<'sess, VariableDefinition<'ast>> {
684 self.parse_variable_definition_with(flags, None)
685 }
686
687 pub(super) fn parse_variable_definition_with(
688 &mut self,
689 flags: VarFlags,
690 ty: Option<Type<'ast>>,
691 ) -> PResult<'sess, VariableDefinition<'ast>> {
692 let mut lo = self.token.span;
693 let ty = match ty {
694 Some(ty) => {
695 lo = lo.with_lo(ty.span.lo());
696 ty
697 }
698 None => self.parse_type()?,
699 };
700
701 if ty.is_function()
702 && flags == VarFlags::STATE_VAR
703 && self.check_noexpect(TokenKind::OpenDelim(Delimiter::Brace))
704 {
705 let msg = "expected a state variable declaration";
706 let note = "this style of fallback function has been removed; use the `fallback` or `receive` keywords instead";
707 self.dcx().err(msg).span(self.token.span).note(note).emit();
708 let _ = self.parse_block()?;
709 return Ok(VariableDefinition {
710 span: lo.to(self.prev_token.span),
711 ty,
712 visibility: None,
713 mutability: None,
714 data_location: None,
715 override_: None,
716 indexed: false,
717 name: None,
718 initializer: None,
719 });
720 }
721
722 let mut data_location = None;
723 let mut visibility = None;
724 let mut mutability = None;
725 let mut override_ = None;
726 let mut indexed = false;
727 loop {
728 if let Some(s) = self.parse_data_location() {
729 if !flags.contains(VarFlags::DATALOC) {
730 let msg = "data locations are not allowed here";
731 self.dcx().err(msg).span(self.prev_token.span).emit();
732 } else if data_location.is_some() {
733 let msg = "data location already specified";
734 self.dcx().err(msg).span(self.prev_token.span).emit();
735 } else {
736 data_location = Some(s);
737 }
738 } else if let Some(v) = self.parse_visibility() {
739 if !flags.contains(VarFlags::from_visibility(v)) {
740 let msg = visibility_error(v, flags.visibilities());
741 self.dcx().err(msg).span(self.prev_token.span).emit();
742 } else if visibility.is_some() {
743 let msg = "visibility already specified";
744 self.dcx().err(msg).span(self.prev_token.span).emit();
745 } else {
746 visibility = Some(v);
747 }
748 } else if let Some(m) = self.parse_variable_mutability() {
749 if flags != VarFlags::CONSTANT_VAR && !flags.contains(VarFlags::from_varmut(m)) {
751 let msg = varmut_error(m, flags.varmuts());
752 self.dcx().err(msg).span(self.prev_token.span).emit();
753 } else if mutability.is_some() {
754 let msg = "mutability already specified";
755 self.dcx().err(msg).span(self.prev_token.span).emit();
756 } else {
757 mutability = Some(m);
758 }
759 } else if self.eat_keyword(kw::Indexed) {
760 if !flags.contains(VarFlags::INDEXED) {
761 let msg = "`indexed` is not allowed here";
762 self.dcx().err(msg).span(self.prev_token.span).emit();
763 } else if indexed {
764 let msg = "`indexed` already specified";
765 self.dcx().err(msg).span(self.prev_token.span).emit();
766 } else {
767 indexed = true;
768 }
769 } else if self.eat_keyword(kw::Virtual) {
770 let msg = "`virtual` is not allowed here";
771 self.dcx().err(msg).span(self.prev_token.span).emit();
772 } else if self.eat_keyword(kw::Override) {
773 let o = self.parse_override()?;
774 if !flags.contains(VarFlags::OVERRIDE) {
775 let msg = "`override` is not allowed here";
776 self.dcx().err(msg).span(self.prev_token.span).emit();
777 } else if override_.is_some() {
778 let msg = "override already specified";
779 self.dcx().err(msg).span(self.prev_token.span).emit();
780 } else {
781 override_ = Some(o);
782 }
783 } else {
784 break;
785 }
786 }
787
788 let name = if flags.contains(VarFlags::NAME) {
789 self.parse_ident().map(Some)
790 } else {
791 self.parse_ident_opt()
792 }?;
793 if let Some(name) = &name {
794 if flags.contains(VarFlags::NAME_WARN) {
795 debug_assert!(!flags.contains(VarFlags::NAME));
796 let msg = "named function type parameters are deprecated";
797 self.dcx().warn(msg).code(error_code!(6162)).span(name.span).emit();
798 }
799 }
800
801 let initializer = if flags.contains(VarFlags::INITIALIZER) && self.eat(TokenKind::Eq) {
802 Some(self.parse_expr()?)
803 } else {
804 None
805 };
806
807 if flags.contains(VarFlags::SEMI) {
808 self.expect_semi()?;
809 }
810
811 let span = lo.to(self.prev_token.span);
812
813 if mutability == Some(VarMut::Constant) && initializer.is_none() {
814 let msg = "constant variable must be initialized";
815 self.dcx().err(msg).span(span).emit();
816 }
817 if flags == VarFlags::CONSTANT_VAR && mutability != Some(VarMut::Constant) {
818 let msg = "only constant variables are allowed at file level";
819 self.dcx().err(msg).span(span).emit();
820 }
821
822 Ok(VariableDefinition {
823 span,
824 ty,
825 data_location,
826 visibility,
827 mutability,
828 override_,
829 indexed,
830 name,
831 initializer,
832 })
833 }
834
835 fn parse_variable_mutability(&mut self) -> Option<VarMut> {
837 if self.eat_keyword(kw::Constant) {
838 Some(VarMut::Constant)
839 } else if self.eat_keyword(kw::Immutable) {
840 Some(VarMut::Immutable)
841 } else {
842 None
843 }
844 }
845
846 pub(super) fn parse_parameter_list(
848 &mut self,
849 allow_empty: bool,
850 flags: VarFlags,
851 ) -> PResult<'sess, ParameterList<'ast>> {
852 self.parse_paren_comma_seq(allow_empty, |this| this.parse_variable_definition(flags))
853 }
854
855 fn parse_inheritance(&mut self) -> PResult<'sess, Box<'ast, [Modifier<'ast>]>> {
857 let mut list = SmallVec::<[_; 8]>::new();
858 loop {
859 list.push(self.parse_modifier()?);
860 if !self.eat(TokenKind::Comma) {
861 break;
862 }
863 }
864 Ok(self.alloc_smallvec(list))
865 }
866
867 fn parse_storage_layout_specifier(&mut self) -> PResult<'sess, StorageLayoutSpecifier<'ast>> {
869 let lo = self.token.span;
870 self.expect_keyword(sym::layout)?;
871 self.expect_keyword(sym::at)?;
872 let slot = self.parse_expr()?;
873 Ok(StorageLayoutSpecifier { span: lo.to(self.prev_token.span), slot })
874 }
875
876 fn parse_modifier(&mut self) -> PResult<'sess, Modifier<'ast>> {
878 let name = self.parse_path()?;
879 let arguments = if self.token.kind == TokenKind::OpenDelim(Delimiter::Parenthesis) {
880 self.parse_call_args()?
881 } else {
882 CallArgs::empty(name.span().shrink_to_hi())
883 };
884 Ok(Modifier { name, arguments })
885 }
886
887 fn parse_override(&mut self) -> PResult<'sess, Override<'ast>> {
891 debug_assert!(self.prev_token.is_keyword(kw::Override));
892 let lo = self.prev_token.span;
893 let paths = if self.token.is_open_delim(Delimiter::Parenthesis) {
894 self.parse_paren_comma_seq(false, Self::parse_path)?
895 } else {
896 Default::default()
897 };
898 let span = lo.to(self.prev_token.span);
899 Ok(Override { span, paths })
900 }
901
902 pub(super) fn parse_str_lit(&mut self) -> PResult<'sess, StrLit> {
905 match self.parse_str_lit_opt() {
906 Some(lit) => Ok(lit),
907 None => self.unexpected(),
908 }
909 }
910
911 pub(super) fn parse_str_lit_opt(&mut self) -> Option<StrLit> {
914 if !self.check_str_lit() {
915 return None;
916 }
917 let Token { kind: TokenKind::Literal(TokenLitKind::Str, symbol), span } = self.token else {
918 unreachable!()
919 };
920 self.bump();
921 Some(StrLit { span, value: symbol })
922 }
923
924 fn parse_data_location(&mut self) -> Option<DataLocation> {
926 if self.eat_keyword(kw::Storage) {
927 Some(DataLocation::Storage)
928 } else if self.eat_keyword(kw::Memory) {
929 Some(DataLocation::Memory)
930 } else if self.eat_keyword(kw::Calldata) {
931 Some(DataLocation::Calldata)
932 } else if self.check_keyword(sym::transient)
933 && !matches!(
934 self.look_ahead(1).kind,
935 TokenKind::Eq | TokenKind::Semi | TokenKind::CloseDelim(_) | TokenKind::Comma
936 )
937 {
938 self.bump(); Some(DataLocation::Transient)
940 } else {
941 None
942 }
943 }
944
945 pub(super) fn parse_visibility(&mut self) -> Option<Visibility> {
947 if self.eat_keyword(kw::Public) {
948 Some(Visibility::Public)
949 } else if self.eat_keyword(kw::Private) {
950 Some(Visibility::Private)
951 } else if self.eat_keyword(kw::Internal) {
952 Some(Visibility::Internal)
953 } else if self.eat_keyword(kw::External) {
954 Some(Visibility::External)
955 } else {
956 None
957 }
958 }
959
960 pub(super) fn parse_state_mutability(&mut self) -> Option<StateMutability> {
962 if self.eat_keyword(kw::Payable) {
963 Some(StateMutability::Payable)
964 } else if self.eat_keyword(kw::Pure) {
965 Some(StateMutability::Pure)
966 } else if self.eat_keyword(kw::View) {
967 Some(StateMutability::View)
968 } else {
969 None
970 }
971 }
972}
973
974struct SemverVersionParser<'p, 'sess, 'ast> {
975 p: &'p mut Parser<'sess, 'ast>,
976 bumps: u32,
977 pos_inside: u32,
978}
979
980impl<'p, 'sess, 'ast> SemverVersionParser<'p, 'sess, 'ast> {
981 fn new(p: &'p mut Parser<'sess, 'ast>) -> Self {
982 Self { p, bumps: 0, pos_inside: 0 }
983 }
984
985 fn emit_err(&self, msg: impl Into<DiagMsg>) {
986 self.p.dcx().err(msg).span(self.current_span()).emit();
987 }
988
989 fn parse(mut self) -> SemverVersion {
990 let lo = self.current_span();
991 let major = self.parse_version_part();
992 let mut minor = None;
993 let mut patch = None;
994 if self.eat_dot() {
995 minor = Some(self.parse_version_part());
996 if self.eat_dot() {
997 patch = Some(self.parse_version_part());
998 }
999 }
1000 if self.pos_inside > 0 || self.bumps == 0 {
1001 self.emit_err("unexpected trailing characters");
1002 self.bump_token();
1003 }
1004 SemverVersion { span: lo.to(self.current_span()), major, minor, patch }
1005 }
1006
1007 fn eat_dot(&mut self) -> bool {
1008 let r = self.current_char() == Some('.');
1009 if r {
1010 self.bump_char();
1011 }
1012 r
1013 }
1014
1015 fn parse_version_part(&mut self) -> SemverVersionNumber {
1016 match self.current_char() {
1017 Some('*' | 'x' | 'X') => {
1018 self.bump_char();
1019 SemverVersionNumber::Wildcard
1020 }
1021 Some('0'..='9') => {
1022 let s = self.current_str().unwrap();
1023 let len = s.bytes().take_while(u8::is_ascii_digit).count();
1024 let result = s[..len].parse();
1025 self.bump_chars(len as u32);
1026 let Ok(n) = result else {
1027 self.emit_err("version number too large");
1028 return SemverVersionNumber::Wildcard;
1029 };
1030 SemverVersionNumber::Number(n)
1031 }
1032 _ => {
1033 self.emit_err("expected version number");
1034 self.bump_char();
1035 SemverVersionNumber::Wildcard
1036 }
1037 }
1038 }
1039
1040 fn current_char(&self) -> Option<char> {
1041 self.current_str()?.chars().next()
1042 }
1043
1044 fn current_str(&self) -> Option<&str> {
1045 self.current_token_str()?.get(self.pos_inside as usize..)
1046 }
1047
1048 fn current_token_str(&self) -> Option<&str> {
1049 Some(match &self.current_token().kind {
1050 TokenKind::Dot => ".",
1051 TokenKind::BinOp(BinOpToken::Star) => "*",
1052 TokenKind::Ident(s) | TokenKind::Literal(_, s) => s.as_str(),
1053 _ => return None,
1054 })
1055 }
1056
1057 fn current_token(&self) -> &Token {
1058 &self.p.token
1059 }
1060
1061 fn current_span(&self) -> Span {
1062 let mut s = self.current_token().span;
1063 if self.pos_inside > 0 {
1064 s = s.with_lo(s.lo() + self.pos_inside);
1065 }
1066 s
1067 }
1068
1069 fn bump_char(&mut self) {
1070 self.bump_chars(1);
1071 }
1072
1073 fn bump_chars(&mut self, n: u32) {
1074 if let Some(s) = self.current_token_str() {
1075 if self.pos_inside + n >= s.len() as u32 {
1076 self.bump_token();
1077 } else {
1078 self.pos_inside += n;
1079 }
1080 }
1081 }
1082
1083 fn bump_token(&mut self) {
1084 self.p.bump();
1085 self.bumps += 1;
1086 self.pos_inside = 0;
1087 }
1088}
1089
1090bitflags::bitflags! {
1091 #[derive(Clone, Copy, PartialEq, Eq)]
1093 pub(super) struct VarFlags: u16 {
1094 const DATALOC = 1 << 1;
1097 const INDEXED = 1 << 2;
1098
1099 const PRIVATE = 1 << 3;
1100 const INTERNAL = 1 << 4;
1101 const PUBLIC = 1 << 5;
1102 const EXTERNAL = 1 << 6; const VISIBILITY = Self::PRIVATE.bits()
1104 | Self::INTERNAL.bits()
1105 | Self::PUBLIC.bits()
1106 | Self::EXTERNAL.bits();
1107
1108 const CONSTANT = 1 << 7;
1109 const IMMUTABLE = 1 << 8;
1110
1111 const OVERRIDE = 1 << 9;
1112
1113 const NAME = 1 << 10;
1114 const NAME_WARN = 1 << 11;
1115
1116 const INITIALIZER = 1 << 12;
1117 const SEMI = 1 << 13;
1118
1119 const STRUCT = Self::NAME.bits();
1120 const ERROR = 0;
1121 const EVENT = Self::INDEXED.bits();
1122 const FUNCTION = Self::DATALOC.bits();
1123 const FUNCTION_TY = Self::DATALOC.bits() | Self::NAME_WARN.bits();
1124
1125 const STATE_VAR = Self::DATALOC.bits()
1127 | Self::PRIVATE.bits()
1128 | Self::INTERNAL.bits()
1129 | Self::PUBLIC.bits()
1130 | Self::CONSTANT.bits()
1131 | Self::IMMUTABLE.bits()
1132 | Self::OVERRIDE.bits()
1133 | Self::NAME.bits()
1134 | Self::INITIALIZER.bits()
1135 | Self::SEMI.bits();
1136
1137 const CONSTANT_VAR = Self::CONSTANT.bits()
1139 | Self::NAME.bits()
1140 | Self::INITIALIZER.bits()
1141 | Self::SEMI.bits();
1142
1143 const VAR = Self::DATALOC.bits() | Self::INITIALIZER.bits();
1145 }
1146
1147 #[derive(Clone, Copy, PartialEq, Eq)]
1149 pub(super) struct FunctionFlags: u16 {
1150 const NAME = 1 << 0;
1152 const PARAM_NAME = 1 << 1;
1154 const NO_PARENS = 1 << 2;
1156
1157 const PRIVATE = 1 << 3;
1159 const INTERNAL = 1 << 4;
1160 const PUBLIC = 1 << 5;
1161 const EXTERNAL = 1 << 6;
1162 const VISIBILITY = Self::PRIVATE.bits()
1163 | Self::INTERNAL.bits()
1164 | Self::PUBLIC.bits()
1165 | Self::EXTERNAL.bits();
1166
1167 const PURE = 1 << 7;
1169 const VIEW = 1 << 8;
1170 const PAYABLE = 1 << 9;
1171 const STATE_MUTABILITY = Self::PURE.bits()
1172 | Self::VIEW.bits()
1173 | Self::PAYABLE.bits();
1174
1175 const MODIFIERS = 1 << 10;
1176 const VIRTUAL = 1 << 11;
1177 const OVERRIDE = 1 << 12;
1178
1179 const RETURNS = 1 << 13;
1180 const ONLY_BLOCK = 1 << 14;
1182
1183 const CONSTRUCTOR = Self::MODIFIERS.bits()
1185 | Self::PAYABLE.bits()
1186 | Self::INTERNAL.bits()
1187 | Self::PUBLIC.bits()
1188 | Self::ONLY_BLOCK.bits();
1189
1190 const FUNCTION = Self::NAME.bits()
1192 | Self::VISIBILITY.bits()
1193 | Self::STATE_MUTABILITY.bits()
1194 | Self::MODIFIERS.bits()
1195 | Self::VIRTUAL.bits()
1196 | Self::OVERRIDE.bits()
1197 | Self::RETURNS.bits();
1198
1199 const MODIFIER = Self::NAME.bits()
1201 | Self::NO_PARENS.bits()
1202 | Self::VIRTUAL.bits()
1203 | Self::OVERRIDE.bits();
1204
1205 const FALLBACK = Self::EXTERNAL.bits()
1207 | Self::STATE_MUTABILITY.bits()
1208 | Self::MODIFIERS.bits()
1209 | Self::VIRTUAL.bits()
1210 | Self::OVERRIDE.bits()
1211 | Self::RETURNS.bits();
1212
1213 const RECEIVE = Self::EXTERNAL.bits()
1215 | Self::PAYABLE.bits()
1216 | Self::MODIFIERS.bits()
1217 | Self::VIRTUAL.bits()
1218 | Self::OVERRIDE.bits();
1219
1220 const FUNCTION_TY = Self::PARAM_NAME.bits()
1222 | Self::VISIBILITY.bits()
1223 | Self::STATE_MUTABILITY.bits()
1224 | Self::RETURNS.bits();
1225 }
1226}
1227
1228impl VarFlags {
1229 fn from_visibility(v: Visibility) -> Self {
1230 match v {
1231 Visibility::Private => Self::PRIVATE,
1232 Visibility::Internal => Self::INTERNAL,
1233 Visibility::Public => Self::PUBLIC,
1234 Visibility::External => Self::EXTERNAL,
1235 }
1236 }
1237
1238 fn into_visibility(self) -> Option<Visibility> {
1239 match self {
1240 Self::PRIVATE => Some(Visibility::Private),
1241 Self::INTERNAL => Some(Visibility::Internal),
1242 Self::PUBLIC => Some(Visibility::Public),
1243 Self::EXTERNAL => Some(Visibility::External),
1244 _ => None,
1245 }
1246 }
1247
1248 fn visibilities(self) -> Option<impl Iterator<Item = Visibility>> {
1249 self.supported(Self::VISIBILITY).map(|iter| iter.map(|x| x.into_visibility().unwrap()))
1250 }
1251
1252 fn from_varmut(v: VarMut) -> Self {
1253 match v {
1254 VarMut::Constant => Self::CONSTANT,
1255 VarMut::Immutable => Self::IMMUTABLE,
1256 }
1257 }
1258
1259 fn into_varmut(self) -> Option<VarMut> {
1260 match self {
1261 Self::CONSTANT => Some(VarMut::Constant),
1262 Self::IMMUTABLE => Some(VarMut::Immutable),
1263 _ => None,
1264 }
1265 }
1266
1267 fn varmuts(self) -> Option<impl Iterator<Item = VarMut>> {
1268 self.supported(Self::CONSTANT | Self::IMMUTABLE)
1269 .map(|iter| iter.map(|x| x.into_varmut().unwrap()))
1270 }
1271
1272 fn supported(self, what: Self) -> Option<impl Iterator<Item = Self>> {
1273 let s = self.intersection(what);
1274 if s.is_empty() {
1275 None
1276 } else {
1277 Some(s.iter())
1278 }
1279 }
1280}
1281
1282impl FunctionFlags {
1283 fn from_kind(kind: FunctionKind) -> Self {
1284 match kind {
1285 FunctionKind::Constructor => Self::CONSTRUCTOR,
1286 FunctionKind::Function => Self::FUNCTION,
1287 FunctionKind::Modifier => Self::MODIFIER,
1288 FunctionKind::Receive => Self::RECEIVE,
1289 FunctionKind::Fallback => Self::FALLBACK,
1290 }
1291 }
1292
1293 fn from_visibility(visibility: Visibility) -> Self {
1294 match visibility {
1295 Visibility::Private => Self::PRIVATE,
1296 Visibility::Internal => Self::INTERNAL,
1297 Visibility::Public => Self::PUBLIC,
1298 Visibility::External => Self::EXTERNAL,
1299 }
1300 }
1301
1302 fn into_visibility(self) -> Option<Visibility> {
1303 match self {
1304 Self::PRIVATE => Some(Visibility::Private),
1305 Self::INTERNAL => Some(Visibility::Internal),
1306 Self::PUBLIC => Some(Visibility::Public),
1307 Self::EXTERNAL => Some(Visibility::External),
1308 _ => None,
1309 }
1310 }
1311
1312 fn visibilities(self) -> Option<impl Iterator<Item = Visibility>> {
1313 self.supported(Self::VISIBILITY).map(|iter| iter.map(|x| x.into_visibility().unwrap()))
1314 }
1315
1316 fn from_state_mutability(state_mutability: StateMutability) -> Self {
1317 match state_mutability {
1318 StateMutability::Pure => Self::PURE,
1319 StateMutability::View => Self::VIEW,
1320 StateMutability::Payable => Self::PAYABLE,
1321 StateMutability::NonPayable => unreachable!(),
1322 }
1323 }
1324
1325 fn into_state_mutability(self) -> Option<StateMutability> {
1326 match self {
1327 Self::PURE => Some(StateMutability::Pure),
1328 Self::VIEW => Some(StateMutability::View),
1329 Self::PAYABLE => Some(StateMutability::Payable),
1330 _ => None,
1331 }
1332 }
1333
1334 fn state_mutabilities(self) -> Option<impl Iterator<Item = StateMutability>> {
1335 self.supported(Self::STATE_MUTABILITY)
1336 .map(|iter| iter.map(|x| x.into_state_mutability().unwrap()))
1337 }
1338
1339 fn supported(self, what: Self) -> Option<impl Iterator<Item = Self>> {
1340 let s = self.intersection(what);
1341 if s.is_empty() {
1342 None
1343 } else {
1344 Some(s.iter())
1345 }
1346 }
1347}
1348
1349fn visibility_error(v: Visibility, iter: Option<impl Iterator<Item = Visibility>>) -> String {
1350 common_flags_error(v, "visibility", iter)
1351}
1352
1353fn varmut_error(m: VarMut, iter: Option<impl Iterator<Item = VarMut>>) -> String {
1354 common_flags_error(m, "mutability", iter)
1355}
1356
1357fn state_mutability_error(
1358 m: StateMutability,
1359 iter: Option<impl Iterator<Item = StateMutability>>,
1360) -> String {
1361 common_flags_error(m, "state mutability", iter)
1362}
1363
1364fn common_flags_error<T: std::fmt::Display>(
1365 t: T,
1366 desc: &str,
1367 iter: Option<impl Iterator<Item = T>>,
1368) -> String {
1369 match iter {
1370 Some(iter) => format!("`{t}` not allowed here; allowed values: {}", iter.format(", ")),
1371 None => format!("{desc} is not allowed here"),
1372 }
1373}
1374
1375#[cfg(test)]
1376mod tests {
1377 use super::*;
1378 use solar_interface::{source_map::FileName, Result, Session};
1379
1380 fn assert_version_matches(tests: &[(&str, &str, bool)]) {
1381 let sess = Session::builder().with_test_emitter().build();
1382 sess.enter(|| -> Result {
1383 for (i, &(v, req_s, res)) in tests.iter().enumerate() {
1384 let name = i.to_string();
1385 let src = format!("{v} {req_s}");
1386 let arena = Arena::new();
1387 let mut parser =
1388 Parser::from_source_code(&sess, &arena, FileName::Custom(name), src)?;
1389
1390 let version = parser.parse_semver_version().map_err(|e| e.emit()).unwrap();
1391 assert_eq!(version.to_string(), v);
1392 let req: SemverReq<'_> = parser.parse_semver_req().map_err(|e| e.emit()).unwrap();
1393 sess.dcx.has_errors().unwrap();
1394 assert_eq!(req.matches(&version), res, "v={v:?}, req={req_s:?}");
1395 }
1396 Ok(())
1397 })
1398 .unwrap();
1399 }
1400
1401 #[test]
1402 fn semver_matches() {
1403 assert_version_matches(&[
1404 ("0.8.1", "0", true),
1406 ("0.8.1", "1", false),
1407 ("0.8.1", "1.0", false),
1408 ("0.8.1", "1.0.0", false),
1409 ("0.8.1", "0.7", false),
1410 ("0.8.1", "0.7.0", false),
1411 ("0.8.1", "0.7.1", false),
1412 ("0.8.1", "0.7.2", false),
1413 ("0.8.1", "0.8", true),
1414 ("0.8.1", "0.8.0", false),
1415 ("0.8.1", "0.8.1", true),
1416 ("0.8.1", "0.8.2", false),
1417 ("0.8.1", "0.9", false),
1418 ("0.8.1", "0.9.0", false),
1419 ("0.8.1", "0.9.1", false),
1420 ("0.8.1", "0.9.2", false),
1421 ("0.8.1", "=0", true),
1423 ("0.8.1", "=1", false),
1424 ("0.8.1", "=1.0", false),
1425 ("0.8.1", "=1.0.0", false),
1426 ("0.8.1", "=0.7", false),
1427 ("0.8.1", "=0.7.0", false),
1428 ("0.8.1", "=0.7.1", false),
1429 ("0.8.1", "=0.7.2", false),
1430 ("0.8.1", "=0.8", true),
1431 ("0.8.1", "=0.8.0", false),
1432 ("0.8.1", "=0.8.1", true),
1433 ("0.8.1", "=0.8.2", false),
1434 ("0.8.1", "=0.9", false),
1435 ("0.8.1", "=0.9.0", false),
1436 ("0.8.1", "=0.9.1", false),
1437 ("0.8.1", "=0.9.2", false),
1438 ("0.8.1", ">0", false),
1440 ("0.8.1", ">1", false),
1441 ("0.8.1", ">1.0", false),
1442 ("0.8.1", ">1.0.0", false),
1443 ("0.8.1", ">0.7", true),
1444 ("0.8.1", ">0.7.0", true),
1445 ("0.8.1", ">0.7.1", true),
1446 ("0.8.1", ">0.7.2", true),
1447 ("0.8.1", ">0.8", false),
1448 ("0.8.1", ">0.8.0", true),
1449 ("0.8.1", ">0.8.1", false),
1450 ("0.8.1", ">0.8.2", false),
1451 ("0.8.1", ">0.9", false),
1452 ("0.8.1", ">0.9.0", false),
1453 ("0.8.1", ">0.9.1", false),
1454 ("0.8.1", ">0.9.2", false),
1455 ("0.8.1", ">=0", true),
1457 ("0.8.1", ">=1", false),
1458 ("0.8.1", ">=1.0", false),
1459 ("0.8.1", ">=1.0.0", false),
1460 ("0.8.1", ">=0.7", true),
1461 ("0.8.1", ">=0.7.0", true),
1462 ("0.8.1", ">=0.7.1", true),
1463 ("0.8.1", ">=0.7.2", true),
1464 ("0.8.1", ">=0.8", true),
1465 ("0.8.1", ">=0.8.0", true),
1466 ("0.8.1", ">=0.8.1", true),
1467 ("0.8.1", ">=0.8.2", false),
1468 ("0.8.1", ">=0.9", false),
1469 ("0.8.1", ">=0.9.0", false),
1470 ("0.8.1", ">=0.9.1", false),
1471 ("0.8.1", ">=0.9.2", false),
1472 ("0.8.1", "<0", false),
1474 ("0.8.1", "<1", true),
1475 ("0.8.1", "<1.0", true),
1476 ("0.8.1", "<1.0.0", true),
1477 ("0.8.1", "<0.7", false),
1478 ("0.8.1", "<0.7.0", false),
1479 ("0.8.1", "<0.7.1", false),
1480 ("0.8.1", "<0.7.2", false),
1481 ("0.8.1", "<0.8", false),
1482 ("0.8.1", "<0.8.0", false),
1483 ("0.8.1", "<0.8.1", false),
1484 ("0.8.1", "<0.8.2", true),
1485 ("0.8.1", "<0.9", true),
1486 ("0.8.1", "<0.9.0", true),
1487 ("0.8.1", "<0.9.1", true),
1488 ("0.8.1", "<0.9.2", true),
1489 ("0.8.1", "<=0", true),
1491 ("0.8.1", "<=1", true),
1492 ("0.8.1", "<=1.0", true),
1493 ("0.8.1", "<=1.0.0", true),
1494 ("0.8.1", "<=0.7", false),
1495 ("0.8.1", "<=0.7.0", false),
1496 ("0.8.1", "<=0.7.1", false),
1497 ("0.8.1", "<=0.7.2", false),
1498 ("0.8.1", "<=0.8", true),
1499 ("0.8.1", "<=0.8.0", false),
1500 ("0.8.1", "<=0.8.1", true),
1501 ("0.8.1", "<=0.8.2", true),
1502 ("0.8.1", "<=0.9.0", true),
1503 ("0.8.1", "<=0.9.1", true),
1504 ("0.8.1", "<=0.9.2", true),
1505 ("0.8.1", "~0", true),
1507 ("0.8.1", "~1", false),
1508 ("0.8.1", "~1.0", false),
1509 ("0.8.1", "~1.0.0", false),
1510 ("0.8.1", "~0.7", false),
1511 ("0.8.1", "~0.7.0", false),
1512 ("0.8.1", "~0.7.1", false),
1513 ("0.8.1", "~0.7.2", false),
1514 ("0.8.1", "~0.8", true),
1515 ("0.8.1", "~0.8.0", true),
1516 ("0.8.1", "~0.8.1", true),
1517 ("0.8.1", "~0.8.2", false),
1518 ("0.8.1", "~0.9.0", false),
1519 ("0.8.1", "~0.9.1", false),
1520 ("0.8.1", "~0.9.2", false),
1521 ("0.8.1", "^0", true),
1523 ("0.8.1", "^1", false),
1524 ("0.8.1", "^1.0", false),
1525 ("0.8.1", "^1.0.0", false),
1526 ("0.8.1", "^0.7", false),
1527 ("0.8.1", "^0.7.0", false),
1528 ("0.8.1", "^0.7.1", false),
1529 ("0.8.1", "^0.7.2", false),
1530 ("0.8.1", "^0.8", true),
1531 ("0.8.1", "^0.8.0", true),
1532 ("0.8.1", "^0.8.1", true),
1533 ("0.8.1", "^0.8.2", false),
1534 ("0.8.1", "^0.9.0", false),
1535 ("0.8.1", "^0.9.1", false),
1536 ("0.8.1", "^0.9.2", false),
1537 ("0.8.1", "0 - 1", true),
1539 ("0.8.1", "0.1 - 1.1", true),
1540 ("0.8.1", "0.1.1 - 1.1.1", true),
1541 ("0.8.1", "0 - 0.8.1", true),
1542 ("0.8.1", "0 - 0.8.2", true),
1543 ("0.8.1", "0.7 - 0.8.1", true),
1544 ("0.8.1", "0.7 - 0.8.2", true),
1545 ("0.8.1", "0.8 - 0.8.1", true),
1546 ("0.8.1", "0.8 - 0.8.2", true),
1547 ("0.8.1", "0.8.0 - 0.8.1", true),
1548 ("0.8.1", "0.8.0 - 0.8.2", true),
1549 ("0.8.1", "0.8.0 - 0.9.0", true),
1550 ("0.8.1", "0.8.0 - 1.0.0", true),
1551 ("0.8.1", "0.8.1 - 0.8.1", true),
1552 ("0.8.1", "0.8.1 - 0.8.2", true),
1553 ("0.8.1", "0.8.1 - 0.9.0", true),
1554 ("0.8.1", "0.8.1 - 1.0.0", true),
1555 ("0.8.1", "0.7 - 0.8", true),
1556 ("0.8.1", "0.7.0 - 0.8", true),
1557 ("0.8.1", "0.8 - 0.8", true),
1558 ("0.8.1", "0.8.0 - 0.8", true),
1559 ("0.8.1", "0.8 - 0.8.0", false),
1560 ("0.8.1", "0.8 - 0.8.1", true),
1561 ("0.8.1", "0 || 0", true),
1563 ("0.8.1", "0 || 1", true),
1564 ("0.8.1", "1 || 0", true),
1565 ("0.8.1", "0.0 || 0.0", false),
1566 ("0.8.1", "0.0 || 1.0", false),
1567 ("0.8.1", "1.0 || 0.0", false),
1568 ("0.8.1", "0.7 || 0.8", true),
1569 ("0.8.1", "0.8 || 0.8", true),
1570 ("0.8.1", "0.8 || 0.8.1", true),
1571 ("0.8.1", "0.8 || 0.8.2", true),
1572 ("0.8.1", "0.8 || 0.9", true),
1573 ]);
1574 }
1575
1576 #[test]
1577 fn function_header_span() {
1580 let test_functions = [
1581 "function foo(uint256 a) public view returns (uint256) {
1582}",
1583 "modifier foo() {
1584 _;
1585}",
1586 "receive() external payable {
1587}",
1588 "fallback() external payable {
1589}",
1590 "constructor() {
1591}",
1592 ];
1593
1594 let test_function_headers = [
1595 "function foo(uint256 a) public view returns (uint256)",
1596 "modifier foo()",
1597 "receive() external payable",
1598 "fallback() external payable",
1599 "constructor()",
1600 ];
1601
1602 for (idx, src) in test_functions.iter().enumerate() {
1603 let sess = Session::builder().with_test_emitter().build();
1604 sess.enter(|| -> Result {
1605 let arena = Arena::new();
1606 let mut parser = Parser::from_source_code(
1607 &sess,
1608 &arena,
1609 FileName::Custom(String::from("test")),
1610 *src,
1611 )?;
1612
1613 parser.in_contract = true; let header_span = parser.parse_function().unwrap().header.span;
1616
1617 assert_eq!(
1618 header_span,
1619 Span::new(
1620 solar_interface::BytePos(0),
1621 solar_interface::BytePos(test_function_headers[idx].len() as u32,),
1622 ),
1623 );
1624
1625 Ok(())
1626 })
1627 .unwrap();
1628 }
1629 }
1630}