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, 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!(
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 Token { 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_note(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_note(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_note(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_note(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::<Box<'_, [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_note(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_note(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, Box<'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),
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, Box<'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 Token { kind: TokenKind::Literal(TokenLitKind::Str, symbol), span } = self.token else {
934 unreachable!()
935 };
936 self.bump();
937 Some(StrLit { span, value: symbol })
938 }
939
940 fn parse_data_location(&mut self) -> Option<DataLocation> {
942 if self.eat_keyword(kw::Storage) {
943 Some(DataLocation::Storage)
944 } else if self.eat_keyword(kw::Memory) {
945 Some(DataLocation::Memory)
946 } else if self.eat_keyword(kw::Calldata) {
947 Some(DataLocation::Calldata)
948 } else if self.check_keyword(sym::transient)
949 && !matches!(
950 self.look_ahead(1).kind,
951 TokenKind::Eq | TokenKind::Semi | TokenKind::CloseDelim(_) | TokenKind::Comma
952 )
953 {
954 self.bump(); Some(DataLocation::Transient)
956 } else {
957 None
958 }
959 }
960
961 pub(super) fn parse_visibility(&mut self) -> Option<Visibility> {
963 if self.eat_keyword(kw::Public) {
964 Some(Visibility::Public)
965 } else if self.eat_keyword(kw::Private) {
966 Some(Visibility::Private)
967 } else if self.eat_keyword(kw::Internal) {
968 Some(Visibility::Internal)
969 } else if self.eat_keyword(kw::External) {
970 Some(Visibility::External)
971 } else {
972 None
973 }
974 }
975
976 pub(super) fn parse_state_mutability(&mut self) -> Option<StateMutability> {
978 if self.eat_keyword(kw::Payable) {
979 Some(StateMutability::Payable)
980 } else if self.eat_keyword(kw::Pure) {
981 Some(StateMutability::Pure)
982 } else if self.eat_keyword(kw::View) {
983 Some(StateMutability::View)
984 } else {
985 None
986 }
987 }
988}
989
990struct SemverVersionParser<'p, 'sess, 'ast> {
991 p: &'p mut Parser<'sess, 'ast>,
992 bumps: u32,
993 pos_inside: u32,
994}
995
996impl<'p, 'sess, 'ast> SemverVersionParser<'p, 'sess, 'ast> {
997 fn new(p: &'p mut Parser<'sess, 'ast>) -> Self {
998 Self { p, bumps: 0, pos_inside: 0 }
999 }
1000
1001 fn emit_err(&self, msg: impl Into<DiagMsg>) {
1002 self.p.dcx().err(msg).span(self.current_span()).emit();
1003 }
1004
1005 fn parse(mut self) -> SemverVersion {
1006 let lo = self.current_span();
1007 let major = self.parse_version_part();
1008 let mut minor = None;
1009 let mut patch = None;
1010 if self.eat_dot() {
1011 minor = Some(self.parse_version_part());
1012 if self.eat_dot() {
1013 patch = Some(self.parse_version_part());
1014 }
1015 }
1016 if self.pos_inside > 0 || self.bumps == 0 {
1017 self.emit_err("unexpected trailing characters");
1018 self.bump_token();
1019 }
1020 SemverVersion { span: lo.to(self.current_span()), major, minor, patch }
1021 }
1022
1023 fn eat_dot(&mut self) -> bool {
1024 let r = self.current_char() == Some('.');
1025 if r {
1026 self.bump_char();
1027 }
1028 r
1029 }
1030
1031 fn parse_version_part(&mut self) -> SemverVersionNumber {
1032 match self.current_char() {
1033 Some('*' | 'x' | 'X') => {
1034 self.bump_char();
1035 SemverVersionNumber::Wildcard
1036 }
1037 Some('0'..='9') => {
1038 let s = self.current_str().unwrap();
1039 let len = s.bytes().take_while(u8::is_ascii_digit).count();
1040 let result = s[..len].parse();
1041 self.bump_chars(len as u32);
1042 let Ok(n) = result else {
1043 self.emit_err("version number too large");
1044 return SemverVersionNumber::Wildcard;
1045 };
1046 SemverVersionNumber::Number(n)
1047 }
1048 _ => {
1049 self.emit_err("expected version number");
1050 self.bump_char();
1051 SemverVersionNumber::Wildcard
1052 }
1053 }
1054 }
1055
1056 fn current_char(&self) -> Option<char> {
1057 self.current_str()?.chars().next()
1058 }
1059
1060 fn current_str(&self) -> Option<&str> {
1061 self.current_token_str()?.get(self.pos_inside as usize..)
1062 }
1063
1064 fn current_token_str(&self) -> Option<&str> {
1065 Some(match &self.current_token().kind {
1066 TokenKind::Dot => ".",
1067 TokenKind::BinOp(BinOpToken::Star) => "*",
1068 TokenKind::Ident(s) | TokenKind::Literal(_, s) => s.as_str(),
1069 _ => return None,
1070 })
1071 }
1072
1073 fn current_token(&self) -> &Token {
1074 &self.p.token
1075 }
1076
1077 fn current_span(&self) -> Span {
1078 let mut s = self.current_token().span;
1079 if self.pos_inside > 0 {
1080 s = s.with_lo(s.lo() + self.pos_inside);
1081 }
1082 s
1083 }
1084
1085 fn bump_char(&mut self) {
1086 self.bump_chars(1);
1087 }
1088
1089 fn bump_chars(&mut self, n: u32) {
1090 if let Some(s) = self.current_token_str() {
1091 if self.pos_inside + n >= s.len() as u32 {
1092 self.bump_token();
1093 } else {
1094 self.pos_inside += n;
1095 }
1096 }
1097 }
1098
1099 fn bump_token(&mut self) {
1100 self.p.bump();
1101 self.bumps += 1;
1102 self.pos_inside = 0;
1103 }
1104}
1105
1106bitflags::bitflags! {
1107 #[derive(Clone, Copy, PartialEq, Eq)]
1109 pub(super) struct VarFlags: u16 {
1110 const DATALOC = 1 << 1;
1113 const INDEXED = 1 << 2;
1114
1115 const PRIVATE = 1 << 3;
1116 const INTERNAL = 1 << 4;
1117 const PUBLIC = 1 << 5;
1118 const EXTERNAL = 1 << 6; const VISIBILITY = Self::PRIVATE.bits()
1120 | Self::INTERNAL.bits()
1121 | Self::PUBLIC.bits()
1122 | Self::EXTERNAL.bits();
1123
1124 const CONSTANT = 1 << 7;
1125 const IMMUTABLE = 1 << 8;
1126
1127 const OVERRIDE = 1 << 9;
1128
1129 const NAME = 1 << 10;
1130 const NAME_WARN = 1 << 11;
1131
1132 const INITIALIZER = 1 << 12;
1133 const SEMI = 1 << 13;
1134
1135 const STRUCT = Self::NAME.bits();
1136 const ERROR = 0;
1137 const EVENT = Self::INDEXED.bits();
1138 const FUNCTION = Self::DATALOC.bits();
1139 const FUNCTION_TY = Self::DATALOC.bits() | Self::NAME_WARN.bits();
1140
1141 const STATE_VAR = Self::DATALOC.bits()
1143 | Self::PRIVATE.bits()
1144 | Self::INTERNAL.bits()
1145 | Self::PUBLIC.bits()
1146 | Self::CONSTANT.bits()
1147 | Self::IMMUTABLE.bits()
1148 | Self::OVERRIDE.bits()
1149 | Self::NAME.bits()
1150 | Self::INITIALIZER.bits()
1151 | Self::SEMI.bits();
1152
1153 const CONSTANT_VAR = Self::CONSTANT.bits()
1155 | Self::NAME.bits()
1156 | Self::INITIALIZER.bits()
1157 | Self::SEMI.bits();
1158
1159 const VAR = Self::DATALOC.bits() | Self::INITIALIZER.bits();
1161 }
1162
1163 #[derive(Clone, Copy, PartialEq, Eq)]
1165 pub(super) struct FunctionFlags: u16 {
1166 const NAME = 1 << 0;
1168 const PARAM_NAME = 1 << 1;
1170 const NO_PARENS = 1 << 2;
1172
1173 const PRIVATE = 1 << 3;
1175 const INTERNAL = 1 << 4;
1176 const PUBLIC = 1 << 5;
1177 const EXTERNAL = 1 << 6;
1178 const VISIBILITY = Self::PRIVATE.bits()
1179 | Self::INTERNAL.bits()
1180 | Self::PUBLIC.bits()
1181 | Self::EXTERNAL.bits();
1182
1183 const PURE = 1 << 7;
1185 const VIEW = 1 << 8;
1186 const PAYABLE = 1 << 9;
1187 const STATE_MUTABILITY = Self::PURE.bits()
1188 | Self::VIEW.bits()
1189 | Self::PAYABLE.bits();
1190
1191 const MODIFIERS = 1 << 10;
1192 const VIRTUAL = 1 << 11;
1193 const OVERRIDE = 1 << 12;
1194
1195 const RETURNS = 1 << 13;
1196 const ONLY_BLOCK = 1 << 14;
1198
1199 const CONSTRUCTOR = Self::MODIFIERS.bits()
1201 | Self::PAYABLE.bits()
1202 | Self::INTERNAL.bits()
1203 | Self::PUBLIC.bits()
1204 | Self::ONLY_BLOCK.bits();
1205
1206 const FUNCTION = Self::NAME.bits()
1208 | Self::VISIBILITY.bits()
1209 | Self::STATE_MUTABILITY.bits()
1210 | Self::MODIFIERS.bits()
1211 | Self::VIRTUAL.bits()
1212 | Self::OVERRIDE.bits()
1213 | Self::RETURNS.bits();
1214
1215 const MODIFIER = Self::NAME.bits()
1217 | Self::NO_PARENS.bits()
1218 | Self::VIRTUAL.bits()
1219 | Self::OVERRIDE.bits();
1220
1221 const FALLBACK = Self::EXTERNAL.bits()
1223 | Self::STATE_MUTABILITY.bits()
1224 | Self::MODIFIERS.bits()
1225 | Self::VIRTUAL.bits()
1226 | Self::OVERRIDE.bits()
1227 | Self::RETURNS.bits();
1228
1229 const RECEIVE = Self::EXTERNAL.bits()
1231 | Self::PAYABLE.bits()
1232 | Self::MODIFIERS.bits()
1233 | Self::VIRTUAL.bits()
1234 | Self::OVERRIDE.bits();
1235
1236 const FUNCTION_TY = Self::PARAM_NAME.bits()
1238 | Self::VISIBILITY.bits()
1239 | Self::STATE_MUTABILITY.bits()
1240 | Self::RETURNS.bits();
1241 }
1242}
1243
1244impl VarFlags {
1245 fn from_visibility(v: Visibility) -> Self {
1246 match v {
1247 Visibility::Private => Self::PRIVATE,
1248 Visibility::Internal => Self::INTERNAL,
1249 Visibility::Public => Self::PUBLIC,
1250 Visibility::External => Self::EXTERNAL,
1251 }
1252 }
1253
1254 fn into_visibility(self) -> Option<Visibility> {
1255 match self {
1256 Self::PRIVATE => Some(Visibility::Private),
1257 Self::INTERNAL => Some(Visibility::Internal),
1258 Self::PUBLIC => Some(Visibility::Public),
1259 Self::EXTERNAL => Some(Visibility::External),
1260 _ => None,
1261 }
1262 }
1263
1264 fn visibilities(self) -> Option<impl Iterator<Item = Visibility>> {
1265 self.supported(Self::VISIBILITY).map(|iter| iter.map(|x| x.into_visibility().unwrap()))
1266 }
1267
1268 fn from_varmut(v: VarMut) -> Self {
1269 match v {
1270 VarMut::Constant => Self::CONSTANT,
1271 VarMut::Immutable => Self::IMMUTABLE,
1272 }
1273 }
1274
1275 fn into_varmut(self) -> Option<VarMut> {
1276 match self {
1277 Self::CONSTANT => Some(VarMut::Constant),
1278 Self::IMMUTABLE => Some(VarMut::Immutable),
1279 _ => None,
1280 }
1281 }
1282
1283 fn varmuts(self) -> Option<impl Iterator<Item = VarMut>> {
1284 self.supported(Self::CONSTANT | Self::IMMUTABLE)
1285 .map(|iter| iter.map(|x| x.into_varmut().unwrap()))
1286 }
1287
1288 fn supported(self, what: Self) -> Option<impl Iterator<Item = Self>> {
1289 let s = self.intersection(what);
1290 if s.is_empty() { None } else { Some(s.iter()) }
1291 }
1292}
1293
1294impl FunctionFlags {
1295 fn from_kind(kind: FunctionKind) -> Self {
1296 match kind {
1297 FunctionKind::Constructor => Self::CONSTRUCTOR,
1298 FunctionKind::Function => Self::FUNCTION,
1299 FunctionKind::Modifier => Self::MODIFIER,
1300 FunctionKind::Receive => Self::RECEIVE,
1301 FunctionKind::Fallback => Self::FALLBACK,
1302 }
1303 }
1304
1305 fn from_visibility(visibility: Visibility) -> Self {
1306 match visibility {
1307 Visibility::Private => Self::PRIVATE,
1308 Visibility::Internal => Self::INTERNAL,
1309 Visibility::Public => Self::PUBLIC,
1310 Visibility::External => Self::EXTERNAL,
1311 }
1312 }
1313
1314 fn into_visibility(self) -> Option<Visibility> {
1315 match self {
1316 Self::PRIVATE => Some(Visibility::Private),
1317 Self::INTERNAL => Some(Visibility::Internal),
1318 Self::PUBLIC => Some(Visibility::Public),
1319 Self::EXTERNAL => Some(Visibility::External),
1320 _ => None,
1321 }
1322 }
1323
1324 fn visibilities(self) -> Option<impl Iterator<Item = Visibility>> {
1325 self.supported(Self::VISIBILITY).map(|iter| iter.map(|x| x.into_visibility().unwrap()))
1326 }
1327
1328 fn from_state_mutability(state_mutability: StateMutability) -> Self {
1329 match state_mutability {
1330 StateMutability::Pure => Self::PURE,
1331 StateMutability::View => Self::VIEW,
1332 StateMutability::Payable => Self::PAYABLE,
1333 StateMutability::NonPayable => unreachable!("NonPayable should not be parsed"),
1334 }
1335 }
1336
1337 fn into_state_mutability(self) -> Option<StateMutability> {
1338 match self {
1339 Self::PURE => Some(StateMutability::Pure),
1340 Self::VIEW => Some(StateMutability::View),
1341 Self::PAYABLE => Some(StateMutability::Payable),
1342 _ => None,
1343 }
1344 }
1345
1346 fn state_mutabilities(self) -> Option<impl Iterator<Item = StateMutability>> {
1347 self.supported(Self::STATE_MUTABILITY)
1348 .map(|iter| iter.map(|x| x.into_state_mutability().unwrap()))
1349 }
1350
1351 fn supported(self, what: Self) -> Option<impl Iterator<Item = Self>> {
1352 let s = self.intersection(what);
1353 if s.is_empty() { None } else { Some(s.iter()) }
1354 }
1355}
1356
1357fn visibility_error(v: Visibility, iter: Option<impl Iterator<Item = Visibility>>) -> String {
1358 common_flags_error(v, "visibility", iter)
1359}
1360
1361fn varmut_error(m: VarMut, iter: Option<impl Iterator<Item = VarMut>>) -> String {
1362 common_flags_error(m, "mutability", iter)
1363}
1364
1365fn state_mutability_error(
1366 m: StateMutability,
1367 iter: Option<impl Iterator<Item = StateMutability>>,
1368) -> String {
1369 common_flags_error(m, "state mutability", iter)
1370}
1371
1372fn common_flags_error<T: std::fmt::Display>(
1373 t: T,
1374 desc: &str,
1375 iter: Option<impl Iterator<Item = T>>,
1376) -> String {
1377 match iter {
1378 Some(iter) => format!("`{t}` not allowed here; allowed values: {}", iter.format(", ")),
1379 None => format!("{desc} is not allowed here"),
1380 }
1381}
1382
1383#[cfg(test)]
1384mod tests {
1385 use super::*;
1386 use solar_interface::{Result, Session, source_map::FileName};
1387
1388 fn assert_version_matches(tests: &[(&str, &str, bool)]) {
1389 let sess = Session::builder().with_test_emitter().build();
1390 sess.enter(|| -> Result {
1391 for (i, &(v, req_s, res)) in tests.iter().enumerate() {
1392 let name = i.to_string();
1393 let src = format!("{v} {req_s}");
1394 let arena = Arena::new();
1395 let mut parser =
1396 Parser::from_source_code(&sess, &arena, FileName::Custom(name), src)?;
1397
1398 let version = parser.parse_semver_version().map_err(|e| e.emit()).unwrap();
1399 assert_eq!(version.to_string(), v);
1400 let req: SemverReq<'_> = parser.parse_semver_req().map_err(|e| e.emit()).unwrap();
1401 sess.dcx.has_errors().unwrap();
1402 assert_eq!(req.matches(&version), res, "v={v:?}, req={req_s:?}");
1403 }
1404 Ok(())
1405 })
1406 .unwrap();
1407 }
1408
1409 #[test]
1410 fn semver_matches() {
1411 assert_version_matches(&[
1412 ("0.8.1", "0", true),
1414 ("0.8.1", "1", false),
1415 ("0.8.1", "1.0", false),
1416 ("0.8.1", "1.0.0", false),
1417 ("0.8.1", "0.7", false),
1418 ("0.8.1", "0.7.0", false),
1419 ("0.8.1", "0.7.1", false),
1420 ("0.8.1", "0.7.2", false),
1421 ("0.8.1", "0.8", true),
1422 ("0.8.1", "0.8.0", false),
1423 ("0.8.1", "0.8.1", true),
1424 ("0.8.1", "0.8.2", false),
1425 ("0.8.1", "0.9", false),
1426 ("0.8.1", "0.9.0", false),
1427 ("0.8.1", "0.9.1", false),
1428 ("0.8.1", "0.9.2", false),
1429 ("0.8.1", "=0", true),
1431 ("0.8.1", "=1", false),
1432 ("0.8.1", "=1.0", false),
1433 ("0.8.1", "=1.0.0", false),
1434 ("0.8.1", "=0.7", false),
1435 ("0.8.1", "=0.7.0", false),
1436 ("0.8.1", "=0.7.1", false),
1437 ("0.8.1", "=0.7.2", false),
1438 ("0.8.1", "=0.8", true),
1439 ("0.8.1", "=0.8.0", false),
1440 ("0.8.1", "=0.8.1", true),
1441 ("0.8.1", "=0.8.2", false),
1442 ("0.8.1", "=0.9", false),
1443 ("0.8.1", "=0.9.0", false),
1444 ("0.8.1", "=0.9.1", false),
1445 ("0.8.1", "=0.9.2", false),
1446 ("0.8.1", ">0", false),
1448 ("0.8.1", ">1", false),
1449 ("0.8.1", ">1.0", false),
1450 ("0.8.1", ">1.0.0", false),
1451 ("0.8.1", ">0.7", true),
1452 ("0.8.1", ">0.7.0", true),
1453 ("0.8.1", ">0.7.1", true),
1454 ("0.8.1", ">0.7.2", true),
1455 ("0.8.1", ">0.8", false),
1456 ("0.8.1", ">0.8.0", true),
1457 ("0.8.1", ">0.8.1", false),
1458 ("0.8.1", ">0.8.2", false),
1459 ("0.8.1", ">0.9", false),
1460 ("0.8.1", ">0.9.0", false),
1461 ("0.8.1", ">0.9.1", false),
1462 ("0.8.1", ">0.9.2", false),
1463 ("0.8.1", ">=0", true),
1465 ("0.8.1", ">=1", false),
1466 ("0.8.1", ">=1.0", false),
1467 ("0.8.1", ">=1.0.0", false),
1468 ("0.8.1", ">=0.7", true),
1469 ("0.8.1", ">=0.7.0", true),
1470 ("0.8.1", ">=0.7.1", true),
1471 ("0.8.1", ">=0.7.2", true),
1472 ("0.8.1", ">=0.8", true),
1473 ("0.8.1", ">=0.8.0", true),
1474 ("0.8.1", ">=0.8.1", true),
1475 ("0.8.1", ">=0.8.2", false),
1476 ("0.8.1", ">=0.9", false),
1477 ("0.8.1", ">=0.9.0", false),
1478 ("0.8.1", ">=0.9.1", false),
1479 ("0.8.1", ">=0.9.2", false),
1480 ("0.8.1", "<0", false),
1482 ("0.8.1", "<1", true),
1483 ("0.8.1", "<1.0", true),
1484 ("0.8.1", "<1.0.0", true),
1485 ("0.8.1", "<0.7", false),
1486 ("0.8.1", "<0.7.0", false),
1487 ("0.8.1", "<0.7.1", false),
1488 ("0.8.1", "<0.7.2", false),
1489 ("0.8.1", "<0.8", false),
1490 ("0.8.1", "<0.8.0", false),
1491 ("0.8.1", "<0.8.1", false),
1492 ("0.8.1", "<0.8.2", true),
1493 ("0.8.1", "<0.9", true),
1494 ("0.8.1", "<0.9.0", true),
1495 ("0.8.1", "<0.9.1", true),
1496 ("0.8.1", "<0.9.2", true),
1497 ("0.8.1", "<=0", true),
1499 ("0.8.1", "<=1", true),
1500 ("0.8.1", "<=1.0", true),
1501 ("0.8.1", "<=1.0.0", true),
1502 ("0.8.1", "<=0.7", false),
1503 ("0.8.1", "<=0.7.0", false),
1504 ("0.8.1", "<=0.7.1", false),
1505 ("0.8.1", "<=0.7.2", false),
1506 ("0.8.1", "<=0.8", true),
1507 ("0.8.1", "<=0.8.0", false),
1508 ("0.8.1", "<=0.8.1", true),
1509 ("0.8.1", "<=0.8.2", true),
1510 ("0.8.1", "<=0.9.0", true),
1511 ("0.8.1", "<=0.9.1", true),
1512 ("0.8.1", "<=0.9.2", true),
1513 ("0.8.1", "~0", true),
1515 ("0.8.1", "~1", false),
1516 ("0.8.1", "~1.0", false),
1517 ("0.8.1", "~1.0.0", false),
1518 ("0.8.1", "~0.7", false),
1519 ("0.8.1", "~0.7.0", false),
1520 ("0.8.1", "~0.7.1", false),
1521 ("0.8.1", "~0.7.2", false),
1522 ("0.8.1", "~0.8", true),
1523 ("0.8.1", "~0.8.0", true),
1524 ("0.8.1", "~0.8.1", true),
1525 ("0.8.1", "~0.8.2", false),
1526 ("0.8.1", "~0.9.0", false),
1527 ("0.8.1", "~0.9.1", false),
1528 ("0.8.1", "~0.9.2", false),
1529 ("0.8.1", "^0", true),
1531 ("0.8.1", "^1", false),
1532 ("0.8.1", "^1.0", false),
1533 ("0.8.1", "^1.0.0", false),
1534 ("0.8.1", "^0.7", false),
1535 ("0.8.1", "^0.7.0", false),
1536 ("0.8.1", "^0.7.1", false),
1537 ("0.8.1", "^0.7.2", false),
1538 ("0.8.1", "^0.8", true),
1539 ("0.8.1", "^0.8.0", true),
1540 ("0.8.1", "^0.8.1", true),
1541 ("0.8.1", "^0.8.2", false),
1542 ("0.8.1", "^0.9.0", false),
1543 ("0.8.1", "^0.9.1", false),
1544 ("0.8.1", "^0.9.2", false),
1545 ("0.8.1", "0 - 1", true),
1547 ("0.8.1", "0.1 - 1.1", true),
1548 ("0.8.1", "0.1.1 - 1.1.1", true),
1549 ("0.8.1", "0 - 0.8.1", true),
1550 ("0.8.1", "0 - 0.8.2", true),
1551 ("0.8.1", "0.7 - 0.8.1", true),
1552 ("0.8.1", "0.7 - 0.8.2", true),
1553 ("0.8.1", "0.8 - 0.8.1", true),
1554 ("0.8.1", "0.8 - 0.8.2", true),
1555 ("0.8.1", "0.8.0 - 0.8.1", true),
1556 ("0.8.1", "0.8.0 - 0.8.2", true),
1557 ("0.8.1", "0.8.0 - 0.9.0", true),
1558 ("0.8.1", "0.8.0 - 1.0.0", true),
1559 ("0.8.1", "0.8.1 - 0.8.1", true),
1560 ("0.8.1", "0.8.1 - 0.8.2", true),
1561 ("0.8.1", "0.8.1 - 0.9.0", true),
1562 ("0.8.1", "0.8.1 - 1.0.0", true),
1563 ("0.8.1", "0.7 - 0.8", true),
1564 ("0.8.1", "0.7.0 - 0.8", true),
1565 ("0.8.1", "0.8 - 0.8", true),
1566 ("0.8.1", "0.8.0 - 0.8", true),
1567 ("0.8.1", "0.8 - 0.8.0", false),
1568 ("0.8.1", "0.8 - 0.8.1", true),
1569 ("0.8.1", "0 || 0", true),
1571 ("0.8.1", "0 || 1", true),
1572 ("0.8.1", "1 || 0", true),
1573 ("0.8.1", "0.0 || 0.0", false),
1574 ("0.8.1", "0.0 || 1.0", false),
1575 ("0.8.1", "1.0 || 0.0", false),
1576 ("0.8.1", "0.7 || 0.8", true),
1577 ("0.8.1", "0.8 || 0.8", true),
1578 ("0.8.1", "0.8 || 0.8.1", true),
1579 ("0.8.1", "0.8 || 0.8.2", true),
1580 ("0.8.1", "0.8 || 0.9", true),
1581 ]);
1582 }
1583
1584 #[test]
1585 fn function_header_span() {
1588 let test_functions = [
1589 "function foo(uint256 a) public view returns (uint256) {
1590}",
1591 "modifier foo() {
1592 _;
1593}",
1594 "receive() external payable {
1595}",
1596 "fallback() external payable {
1597}",
1598 "constructor() {
1599}",
1600 ];
1601
1602 let test_function_headers = [
1603 "function foo(uint256 a) public view returns (uint256)",
1604 "modifier foo()",
1605 "receive() external payable",
1606 "fallback() external payable",
1607 "constructor()",
1608 ];
1609
1610 for (idx, src) in test_functions.iter().enumerate() {
1611 let sess = Session::builder().with_test_emitter().build();
1612 sess.enter(|| -> Result {
1613 let arena = Arena::new();
1614 let mut parser = Parser::from_source_code(
1615 &sess,
1616 &arena,
1617 FileName::Custom(String::from("test")),
1618 *src,
1619 )?;
1620
1621 parser.in_contract = true; let header_span = parser.parse_function().unwrap().header.span;
1624
1625 assert_eq!(
1626 header_span,
1627 Span::new(
1628 solar_interface::BytePos(0),
1629 solar_interface::BytePos(test_function_headers[idx].len() as u32,),
1630 ),
1631 );
1632
1633 Ok(())
1634 })
1635 .unwrap();
1636 }
1637 }
1638
1639 #[test]
1640 fn function_header_field_spans() {
1642 let test_cases = vec![
1643 ("function foo() public {}", Some("public"), None, None, "()", None),
1644 ("function foo() private view {}", Some("private"), Some("view"), None, "()", None),
1645 (
1646 "function foo() internal pure returns (uint) {}",
1647 Some("internal"),
1648 Some("pure"),
1649 None,
1650 "()",
1651 Some("(uint)"),
1652 ),
1653 (
1654 "function foo() external payable {}",
1655 Some("external"),
1656 Some("payable"),
1657 None,
1658 "()",
1659 None,
1660 ),
1661 ("function foo() pure {}", None, Some("pure"), None, "()", None),
1662 ("function foo() view {}", None, Some("view"), None, "()", None),
1663 ("function foo() payable {}", None, Some("payable"), None, "()", None),
1664 ("function foo() {}", None, None, None, "()", None),
1665 ("function foo(uint a) {}", None, None, None, "(uint a)", None),
1666 ("function foo(uint a, string b) {}", None, None, None, "(uint a, string b)", None),
1667 ("function foo() returns (uint) {}", None, None, None, "()", Some("(uint)")),
1668 (
1669 "function foo() returns (uint, bool) {}",
1670 None,
1671 None,
1672 None,
1673 "()",
1674 Some("(uint, bool)"),
1675 ),
1676 (
1677 "function foo(uint x) public view returns (bool) {}",
1678 Some("public"),
1679 Some("view"),
1680 None,
1681 "(uint x)",
1682 Some("(bool)"),
1683 ),
1684 ("function foo() public virtual {}", Some("public"), None, Some("virtual"), "()", None),
1685 ("function foo() virtual public {}", Some("public"), None, Some("virtual"), "()", None),
1686 (
1687 "function foo() public virtual view {}",
1688 Some("public"),
1689 Some("view"),
1690 Some("virtual"),
1691 "()",
1692 None,
1693 ),
1694 ("function foo() virtual override {}", None, None, Some("virtual"), "()", None),
1695 ("modifier bar() virtual {}", None, None, Some("virtual"), "()", None),
1696 (
1697 "function foo() public virtual returns (uint) {}",
1698 Some("public"),
1699 None,
1700 Some("virtual"),
1701 "()",
1702 Some("(uint)"),
1703 ),
1704 ];
1705
1706 let sess = Session::builder().with_test_emitter().build();
1707 sess.enter(|| -> Result {
1708 for (idx, (src, vis, sm, virt, params, returns)) in test_cases.iter().enumerate() {
1709 let arena = Arena::new();
1710 let mut parser = Parser::from_source_code(
1711 &sess,
1712 &arena,
1713 FileName::Custom(format!("test_{idx}")),
1714 *src,
1715 )?;
1716 parser.in_contract = true;
1717
1718 let func = parser.parse_function().unwrap();
1719 let header = &func.header;
1720
1721 if let Some(expected) = vis {
1722 let vis_span = header.visibility.as_ref().expect("Expected visibility").span;
1723 let vis_text = sess.source_map().span_to_snippet(vis_span).unwrap();
1724 assert_eq!(vis_text, *expected, "Test {idx}: visibility span mismatch");
1725 }
1726 if let Some(expected) = sm
1727 && let Some(state_mutability) = header.state_mutability
1728 {
1729 assert_eq!(
1730 *expected,
1731 sess.source_map().span_to_snippet(state_mutability.span).unwrap(),
1732 "Test {idx}: state mutability span mismatch",
1733 );
1734 }
1735 if let Some(expected) = virt {
1736 let virtual_span = header.virtual_.expect("Expected virtual span");
1737 let virtual_text = sess.source_map().span_to_snippet(virtual_span).unwrap();
1738 assert_eq!(virtual_text, *expected, "Test {idx}: virtual span mismatch");
1739 }
1740 let span = header.parameters.span;
1741 assert_eq!(
1742 *params,
1743 sess.source_map().span_to_snippet(span).unwrap(),
1744 "Test {idx}: params span mismatch"
1745 );
1746 if let Some(expected) = returns {
1747 let span = header.returns.as_ref().expect("Expected returns").span;
1748 assert_eq!(
1749 *expected,
1750 sess.source_map().span_to_snippet(span).unwrap(),
1751 "Test {idx}: returns span mismatch",
1752 );
1753 }
1754 }
1755 Ok(())
1756 })
1757 .unwrap();
1758 }
1759}