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