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, 'cb> Parser<'sess, 'ast, 'cb> {
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().emit_err_note(item.span, msg, note);
42 } else {
43 if let Some(callback) = &mut self.import_callback
44 && let ItemKind::Import(import) = &item.kind
45 {
46 callback(ItemId::new(items.len()), item.span, import);
47 }
48 items.push(item);
49 }
50 }
51 if !self.eat(end) {
52 let (msg, note) = get_msg_note(self);
53 return Err(self.dcx().err(msg).span(self.token.span).note(note));
54 }
55 Ok(self.alloc_vec(items))
56 }
57
58 #[instrument(level = "debug", skip_all)]
60 pub fn parse_item(&mut self) -> PResult<'sess, Option<Item<'ast>>> {
61 let docs = self.parse_doc_comments();
62 self.parse_spanned(Self::parse_item_kind)
63 .map(|(span, kind)| kind.map(|kind| Item { docs, span, kind }))
64 }
65
66 fn parse_item_kind(&mut self) -> PResult<'sess, Option<ItemKind<'ast>>> {
67 let kind = if self.is_function_like() {
68 self.parse_function().map(ItemKind::Function)
69 } else if self.eat_keyword(kw::Struct) {
70 self.parse_struct().map(ItemKind::Struct)
71 } else if self.eat_keyword(kw::Event) {
72 self.parse_event().map(ItemKind::Event)
73 } else if self.is_contract_like() {
74 self.parse_contract().map(ItemKind::Contract)
75 } else if self.eat_keyword(kw::Enum) {
76 self.parse_enum().map(ItemKind::Enum)
77 } else if self.eat_keyword(kw::Type) {
78 self.parse_udvt().map(ItemKind::Udvt)
79 } else if self.eat_keyword(kw::Pragma) {
80 self.parse_pragma().map(ItemKind::Pragma)
81 } else if self.eat_keyword(kw::Import) {
82 self.parse_import().map(ItemKind::Import)
83 } else if self.eat_keyword(kw::Using) {
84 self.parse_using().map(ItemKind::Using)
85 } else if self.check_keyword(sym::error)
86 && self.look_ahead(1).is_ident()
87 && self.look_ahead(2).is_open_delim(Delimiter::Parenthesis)
88 {
89 self.bump(); self.parse_error().map(ItemKind::Error)
91 } else if self.is_variable_declaration() {
92 let flags = if self.in_contract { VarFlags::STATE_VAR } else { VarFlags::CONSTANT_VAR };
93 self.parse_variable_definition(flags).map(ItemKind::Variable)
94 } else {
95 return Ok(None);
96 };
97 kind.map(Some)
98 }
99
100 fn is_function_like(&self) -> bool {
102 (self.token.is_keyword(kw::Function)
103 && !self.look_ahead(1).is_open_delim(Delimiter::Parenthesis))
104 || self.token.is_keyword_any(&[
105 kw::Constructor,
106 kw::Fallback,
107 kw::Receive,
108 kw::Modifier,
109 ])
110 }
111
112 fn is_contract_like(&self) -> bool {
114 self.token.is_keyword_any(&[kw::Abstract, kw::Contract, kw::Interface, kw::Library])
115 }
116
117 pub(super) fn is_variable_declaration(&self) -> bool {
119 self.token.is_non_reserved_ident(false) || self.is_non_custom_variable_declaration()
121 }
122
123 pub(super) fn is_non_custom_variable_declaration(&self) -> bool {
124 self.token.is_keyword(kw::Mapping)
125 || (self.token.is_keyword(kw::Function)
126 && self.look_ahead(1).is_open_delim(Delimiter::Parenthesis))
127 || self.token.is_elementary_type()
128 }
129
130 fn parse_function(&mut self) -> PResult<'sess, ItemFunction<'ast>> {
137 let TokenRepr { span: lo, kind: TokenKind::Ident(kw) } = *self.token else {
138 unreachable!("parse_function called without function-like keyword");
139 };
140 self.bump(); let kind = match kw {
143 kw::Constructor => FunctionKind::Constructor,
144 kw::Function => FunctionKind::Function,
145 kw::Fallback => FunctionKind::Fallback,
146 kw::Receive => FunctionKind::Receive,
147 kw::Modifier => FunctionKind::Modifier,
148 _ => unreachable!("parse_function called without function-like keyword"),
149 };
150 let flags = FunctionFlags::from_kind(kind);
151 let header = self.parse_function_header(flags)?;
152 let (body_span, body) = self.parse_spanned(|this| {
153 Ok(if !flags.contains(FunctionFlags::ONLY_BLOCK) && this.eat(TokenKind::Semi) {
154 None
155 } else {
156 Some(this.parse_block()?)
157 })
158 })?;
159
160 if !self.in_contract && !kind.allowed_in_global() {
161 let msg = format!("{kind}s are not allowed in the global scope");
162 self.dcx().emit_err(lo.to(self.prev_token.span), msg);
163 }
164 Ok(ItemFunction { kind, header, body, body_span })
167 }
168
169 pub(super) fn parse_function_header(
171 &mut self,
172 flags: FunctionFlags,
173 ) -> PResult<'sess, FunctionHeader<'ast>> {
174 let lo = self.prev_token.span; let mut header = FunctionHeader::default();
177 let var_flags = if flags.contains(FunctionFlags::PARAM_NAME) {
178 VarFlags::FUNCTION_TY
179 } else {
180 VarFlags::FUNCTION
181 };
182
183 if flags.contains(FunctionFlags::NAME) {
184 let ident;
186 if flags == FunctionFlags::FUNCTION
187 && self.token.is_keyword_any(&[kw::Fallback, kw::Receive])
188 {
189 let kw_span = self.prev_token.span;
190 ident = self.parse_ident_any()?;
191 let msg = format!("function named `{ident}`");
192 let mut warn = self.dcx().warn(msg).span(ident.span).code(error_code!(3445));
193 if self.in_contract {
194 let help = format!(
195 "remove the `function` keyword if you intend this to be a contract's {ident} function"
196 );
197 warn = warn.span_help(kw_span, help);
198 }
199 warn.emit();
200 } else {
201 ident = self.parse_ident()?;
202 }
203 header.name = Some(ident);
204 } else if self.token.is_non_reserved_ident(false) {
205 let msg = "function names are not allowed here";
206 self.dcx().emit_err(self.token.span, msg);
207 self.bump();
208 }
209
210 if flags.contains(FunctionFlags::NO_PARENS)
211 && !self.token.is_open_delim(Delimiter::Parenthesis)
212 {
213 } else {
215 header.parameters = self.parse_parameter_list(true, var_flags)?;
216 }
217
218 let mut modifiers = Vec::new();
219 loop {
220 if !(flags == FunctionFlags::FUNCTION_TY && header.visibility.is_some())
224 && let Some(visibility) = self.parse_visibility()
225 {
226 let span = self.prev_token.span;
227 if let Some(prev) = header.visibility {
228 let msg = "visibility already specified";
229 self.dcx().emit_err_label(span, msg, prev.span, "previous definition");
230 } else {
231 let mut v = Some(visibility);
232 if !flags.contains(FunctionFlags::from_visibility(visibility)) {
233 let msg = visibility_error(visibility, flags.visibilities());
234 self.dcx().emit_err(span, msg);
235 v = flags.visibilities().into_iter().flatten().next();
237 }
238 header.visibility = v.map(|v| Spanned { span, data: v });
239 }
240 } else if let Some(state_mutability) = self.parse_state_mutability() {
241 let span = self.prev_token.span;
242 if let Some(prev) = header.state_mutability {
243 let msg = "state mutability already specified";
244 self.dcx().emit_err_label(span, msg, prev.span, "previous definition");
245 } else {
246 let mut sm = Some(state_mutability);
247 if !flags.contains(FunctionFlags::from_state_mutability(state_mutability)) {
248 let msg =
249 state_mutability_error(state_mutability, flags.state_mutabilities());
250 self.dcx().emit_err(span, msg);
251 sm = flags.state_mutabilities().into_iter().flatten().next();
253 }
254 header.state_mutability = sm.map(|sm| Spanned { span, data: sm });
255 }
256 } else if self.eat_keyword(kw::Virtual) {
257 let span = self.prev_token.span;
258 if !flags.contains(FunctionFlags::VIRTUAL) {
259 let msg = "`virtual` is not allowed here";
260 self.dcx().emit_err(span, msg);
261 } else if let Some(prev) = header.virtual_ {
262 let msg = "virtual already specified";
263 self.dcx().emit_err_label(span, msg, prev, "previous definition");
264 } else {
265 header.virtual_ = Some(span);
266 }
267 } else if self.eat_keyword(kw::Override) {
268 let o = self.parse_override()?;
269 let span = o.span;
270 if !flags.contains(FunctionFlags::OVERRIDE) {
271 let msg = "`override` is not allowed here";
272 self.dcx().emit_err(span, msg);
273 } else if let Some(prev) = &header.override_ {
274 let msg = "override already specified";
275 self.dcx().emit_err_label(span, msg, prev.span, "previous definition");
276 } else {
277 header.override_ = Some(o);
278 }
279 } else if flags.contains(FunctionFlags::MODIFIERS)
280 && self.token.is_non_reserved_ident(false)
281 {
282 modifiers.push(self.parse_modifier()?);
283 } else {
284 break;
285 }
286 }
287
288 header.modifiers = self.alloc_vec(modifiers);
289
290 if flags.contains(FunctionFlags::RETURNS) && self.eat_keyword(kw::Returns) {
291 header.returns = Some(self.parse_parameter_list(false, var_flags)?);
292 }
293
294 header.span = lo.to(self.prev_token.span);
295
296 Ok(header)
297 }
298
299 fn parse_struct(&mut self) -> PResult<'sess, ItemStruct<'ast>> {
301 let name = self.parse_ident()?;
302 let fields = self.parse_delim_seq(
303 Delimiter::Brace,
304 SeqSep::trailing_enforced(TokenKind::Semi),
305 true,
306 |this| this.parse_variable_definition(VarFlags::STRUCT),
307 )?;
308 Ok(ItemStruct { name, fields })
309 }
310
311 fn parse_event(&mut self) -> PResult<'sess, ItemEvent<'ast>> {
313 let name = self.parse_ident()?;
314 let parameters = self.parse_parameter_list(true, VarFlags::EVENT)?;
315 let anonymous = self.eat_keyword(kw::Anonymous);
316 self.expect_semi()?;
317 Ok(ItemEvent { name, parameters, anonymous })
318 }
319
320 fn parse_error(&mut self) -> PResult<'sess, ItemError<'ast>> {
322 let name = self.parse_ident()?;
323 let parameters = self.parse_parameter_list(true, VarFlags::ERROR)?;
324 self.expect_semi()?;
325 Ok(ItemError { name, parameters })
326 }
327
328 fn parse_contract(&mut self) -> PResult<'sess, ItemContract<'ast>> {
332 let TokenKind::Ident(kw) = self.token.kind else {
333 unreachable!("parse_contract called without contract-like keyword");
334 };
335 self.bump(); let kind = match kw {
338 kw::Abstract => {
339 self.expect_keyword(kw::Contract)?;
340 ContractKind::AbstractContract
341 }
342 kw::Contract => ContractKind::Contract,
343 kw::Interface => ContractKind::Interface,
344 kw::Library => ContractKind::Library,
345 _ => unreachable!("parse_contract called without contract-like keyword"),
346 };
347 let name = self.parse_ident()?;
348
349 let mut bases = None::<BoxSlice<'_, Modifier<'_>>>;
350 let mut layout = None::<StorageLayoutSpecifier<'_>>;
351 loop {
352 if self.eat_keyword(kw::Is) {
353 let new_bases = self.parse_inheritance()?;
354 if let Some(prev) = &bases {
355 let msg = "base contracts already specified";
356 let span = |bases: &[Modifier<'_>]| {
357 Span::join_first_last(bases.iter().map(|m| m.span()))
358 };
359 self.dcx().emit_err_label(
360 span(new_bases),
361 msg,
362 span(prev),
363 "previous definition",
364 );
365 } else if !new_bases.is_empty() {
366 bases = Some(new_bases);
367 }
368 } else if self.check_keyword(sym::layout) {
369 let new_layout = self.parse_storage_layout_specifier()?;
370 if let Some(prev) = &layout {
371 let msg = "storage layout already specified";
372 self.dcx().emit_err_label(
373 new_layout.span,
374 msg,
375 prev.span,
376 "previous definition",
377 );
378 } else {
379 layout = Some(new_layout);
380 }
381 } else {
382 break;
383 }
384 }
385
386 if let Some(layout) = &layout
387 && !kind.is_contract()
388 {
389 let msg = "storage layout is only allowed for contracts";
390 self.dcx().emit_err(layout.span, msg);
391 }
392
393 self.expect(TokenKind::OpenDelim(Delimiter::Brace))?;
394 let body =
395 self.in_contract(|this| this.parse_items(TokenKind::CloseDelim(Delimiter::Brace)))?;
396
397 Ok(ItemContract { kind, name, layout, bases: bases.unwrap_or_default(), body })
398 }
399
400 fn parse_enum(&mut self) -> PResult<'sess, ItemEnum<'ast>> {
402 let name = self.parse_ident()?;
403 let variants = self.parse_delim_comma_seq(Delimiter::Brace, true, Self::parse_ident)?;
404 Ok(ItemEnum { name, variants })
405 }
406
407 fn parse_udvt(&mut self) -> PResult<'sess, ItemUdvt<'ast>> {
409 let name = self.parse_ident()?;
410 self.expect_keyword(kw::Is)?;
411 let ty = self.parse_type()?;
412 self.expect_semi()?;
413 Ok(ItemUdvt { name, ty })
414 }
415
416 fn parse_pragma(&mut self) -> PResult<'sess, PragmaDirective<'ast>> {
418 let is_ident_or_strlit = |t: Token| t.is_ident() || t.is_str_lit();
419
420 let tokens = if self.check_keyword(sym::solidity)
421 || (self.token.is_ident()
422 && self.look_ahead_with(1, |t| t.is_op() || t.is_rational_lit()))
423 {
424 let ident = self.parse_ident_any()?;
426 let req = self.parse_semver_req()?;
427 PragmaTokens::Version(ident, req)
428 } else if (is_ident_or_strlit(self.token) && self.look_ahead(1).kind == TokenKind::Semi)
429 || (is_ident_or_strlit(self.token)
430 && self.look_ahead_with(1, is_ident_or_strlit)
431 && self.look_ahead(2).kind == TokenKind::Semi)
432 {
433 let k = self.parse_ident_or_strlit()?;
436 let v = if self.token.is_ident() || self.token.is_str_lit() {
437 Some(self.parse_ident_or_strlit()?)
438 } else {
439 None
440 };
441 PragmaTokens::Custom(k, v)
442 } else {
443 let mut tokens = Vec::new();
444 while !matches!(self.token.kind, TokenKind::Semi | TokenKind::Eof) {
445 tokens.push(self.token);
446 self.bump();
447 }
448 if !self.token.is_eof() && tokens.is_empty() {
449 let msg = "expected at least one token in pragma directive";
450 self.dcx().emit_err(self.prev_token.span, msg);
451 }
452 PragmaTokens::Verbatim(self.alloc_vec(tokens))
453 };
454 self.expect_semi()?;
455 Ok(PragmaDirective { tokens })
456 }
457
458 fn parse_ident_or_strlit(&mut self) -> PResult<'sess, IdentOrStrLit> {
459 if self.check_ident() {
460 self.parse_ident().map(IdentOrStrLit::Ident)
461 } else if self.check_str_lit() {
462 self.parse_str_lit().map(IdentOrStrLit::StrLit)
463 } else {
464 self.unexpected()
465 }
466 }
467
468 pub fn parse_semver_req(&mut self) -> PResult<'sess, SemverReq<'ast>> {
472 if self.check_noexpect(TokenKind::Semi) || self.check_noexpect(TokenKind::Eof) {
473 let msg = "empty version requirement";
474 let span = self.prev_token.span.to(self.token.span);
475 return Err(self.dcx().err(msg).span(span));
476 }
477 self.parse_semver_req_components_dis().map(|dis| SemverReq { dis })
478 }
479
480 fn parse_semver_req_components_dis(
482 &mut self,
483 ) -> PResult<'sess, BoxSlice<'ast, SemverReqCon<'ast>>> {
484 let mut dis = Vec::new();
486 loop {
487 dis.push(self.parse_semver_req_components_con()?);
488 if self.eat(TokenKind::OrOr) {
489 continue;
490 }
491 if self.check(TokenKind::Semi) || self.check(TokenKind::Eof) {
492 break;
493 }
494 debug_assert!(
497 matches!(
498 dis.last().map(|x| x.components.as_slice()),
499 Some([
500 ..,
501 SemverReqComponent { span: _, kind: SemverReqComponentKind::Range(..) }
502 ])
503 ),
504 "not a range: last={:?}",
505 dis.last()
506 );
507 return Err(self.dcx().err("ranges can only be combined using the || operator"));
508 }
509 Ok(self.alloc_vec(dis))
510 }
511
512 fn parse_semver_req_components_con(&mut self) -> PResult<'sess, SemverReqCon<'ast>> {
514 let mut components = Vec::new();
518 let lo = self.token.span;
519 let (op, v) = self.parse_semver_component()?;
520 if self.eat(TokenKind::BinOp(BinOpToken::Minus)) {
521 let _ = op;
524 let (_second_op, right) = self.parse_semver_component()?;
525 let kind = SemverReqComponentKind::Range(v, right);
526 let span = lo.to(self.prev_token.span);
527 components.push(SemverReqComponent { span, kind });
528 } else {
529 let span = lo.to(self.prev_token.span);
531 let kind = SemverReqComponentKind::Op(op, v);
532 components.push(SemverReqComponent { span, kind });
533 while !matches!(self.token.kind, TokenKind::OrOr | TokenKind::Eof | TokenKind::Semi) {
535 let (span, (op, v)) = self.parse_spanned(Self::parse_semver_component)?;
536 let kind = SemverReqComponentKind::Op(op, v);
537 components.push(SemverReqComponent { span, kind });
538 }
539 }
540 let span = lo.to(self.prev_token.span);
541 let components = self.alloc_vec(components);
542 Ok(SemverReqCon { span, components })
543 }
544
545 fn parse_semver_component(&mut self) -> PResult<'sess, (Option<SemverOp>, SemverVersion)> {
546 let op = self.parse_semver_op();
547 let v = self.parse_semver_version()?;
548 Ok((op, v))
549 }
550
551 fn parse_semver_op(&mut self) -> Option<SemverOp> {
552 let op = match self.token.kind {
554 TokenKind::Eq => SemverOp::Exact,
555 TokenKind::Gt => SemverOp::Greater,
556 TokenKind::Ge => SemverOp::GreaterEq,
557 TokenKind::Lt => SemverOp::Less,
558 TokenKind::Le => SemverOp::LessEq,
559 TokenKind::Tilde => SemverOp::Tilde,
560 TokenKind::BinOp(BinOpToken::Caret) => SemverOp::Caret,
561 _ => return None,
562 };
563 self.bump();
564 Some(op)
565 }
566
567 fn parse_semver_version(&mut self) -> PResult<'sess, SemverVersion> {
568 Ok(SemverVersionParser::new(self).parse())
569 }
570
571 fn parse_import(&mut self) -> PResult<'sess, ImportDirective<'ast>> {
573 let path;
574 let items = if self.eat(TokenKind::BinOp(BinOpToken::Star)) {
575 let alias = self.parse_as_alias()?;
577 self.expect_keyword(sym::from)?;
578 path = self.parse_str_lit()?;
579 ImportItems::Glob(alias)
580 } else if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
581 let list = self.parse_delim_comma_seq(Delimiter::Brace, false, |this| {
583 let name = this.parse_ident()?;
584 let alias = this.parse_as_alias_opt()?;
585 Ok((name, alias))
586 })?;
587 self.expect_keyword(sym::from)?;
588 path = self.parse_str_lit()?;
589 ImportItems::Aliases(list)
590 } else {
591 path = self.parse_str_lit()?;
593 let alias = self.parse_as_alias_opt()?;
594 ImportItems::Plain(alias)
595 };
596 if path.value.as_str().is_empty() {
597 let msg = "import path cannot be empty";
598 self.dcx().emit_err(path.span, msg);
599 }
600 self.expect_semi()?;
601 Ok(ImportDirective { path, items })
602 }
603
604 fn parse_as_alias_opt(&mut self) -> PResult<'sess, Option<Ident>> {
606 if self.eat_keyword(kw::As) { self.parse_ident().map(Some) } else { Ok(None) }
607 }
608
609 fn parse_as_alias(&mut self) -> PResult<'sess, Ident> {
611 self.expect_keyword(kw::As)?;
612 self.parse_ident()
613 }
614
615 fn parse_using(&mut self) -> PResult<'sess, UsingDirective<'ast>> {
617 let list = self.parse_using_list()?;
618 self.expect_keyword(kw::For)?;
619 let ty = if self.eat(TokenKind::BinOp(BinOpToken::Star)) {
620 None
621 } else {
622 Some(self.parse_type()?)
623 };
624 let global = self.eat_keyword(sym::global);
625 self.expect_semi()?;
626 Ok(UsingDirective { list, ty, global })
627 }
628
629 fn parse_using_list(&mut self) -> PResult<'sess, UsingList<'ast>> {
630 if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
631 self.parse_delim_comma_seq(Delimiter::Brace, false, |this| {
632 let path = this.parse_path()?;
633 let op = if this.eat_keyword(kw::As) {
634 Some(this.parse_user_definable_operator()?)
635 } else {
636 None
637 };
638 Ok((path, op))
639 })
640 .map(UsingList::Multiple)
641 } else {
642 self.parse_path().map(UsingList::Single)
643 }
644 }
645
646 fn parse_user_definable_operator(&mut self) -> PResult<'sess, UserDefinableOperator> {
647 use BinOpToken::*;
648 use TokenKind::*;
649 use UserDefinableOperator as Op;
650 macro_rules! user_op {
651 ($($tok1:tt $(($tok2:tt))? => $op:expr),* $(,)?) => {
652 match self.token.kind {
653 $($tok1 $(($tok2))? => $op,)*
654 _ => {
655 self.expected_tokens.extend_from_slice(&[$(ExpectedToken::Token($tok1 $(($tok2))?)),*]);
656 return self.unexpected();
657 }
658 }
659 };
660 }
661 let op = user_op! {
662 BinOp(And) => Op::BitAnd,
663 Tilde => Op::BitNot,
664 BinOp(Or) => Op::BitOr,
665 BinOp(Caret) => Op::BitXor,
666 BinOp(Plus) => Op::Add,
667 BinOp(Slash) => Op::Div,
668 BinOp(Percent) => Op::Rem,
669 BinOp(Star) => Op::Mul,
670 BinOp(Minus) => Op::Sub,
671 EqEq => Op::Eq,
672 Ge => Op::Ge,
673 Gt => Op::Gt,
674 Le => Op::Le,
675 Lt => Op::Lt,
676 Ne => Op::Ne,
677 };
678 self.bump();
679 Ok(op)
680 }
681
682 pub(super) fn parse_variable_definition(
689 &mut self,
690 flags: VarFlags,
691 ) -> PResult<'sess, VariableDefinition<'ast>> {
692 self.parse_variable_definition_with(flags, None)
693 }
694
695 pub(super) fn parse_variable_definition_with(
696 &mut self,
697 flags: VarFlags,
698 ty: Option<Type<'ast>>,
699 ) -> PResult<'sess, VariableDefinition<'ast>> {
700 let mut lo = self.token.span;
701 let ty = match ty {
702 Some(ty) => {
703 lo = lo.with_lo(ty.span.lo());
704 ty
705 }
706 None => self.parse_type()?,
707 };
708
709 if ty.is_function()
710 && flags == VarFlags::STATE_VAR
711 && self.check_noexpect(TokenKind::OpenDelim(Delimiter::Brace))
712 {
713 let msg = "expected a state variable declaration";
714 let note = "this style of fallback function has been removed; use the `fallback` or `receive` keywords instead";
715 self.dcx().emit_err_note(self.token.span, msg, note);
716 let _ = self.parse_block()?;
717 return Ok(VariableDefinition {
718 span: lo.to(self.prev_token.span),
719 ty,
720 visibility: None,
721 mutability: None,
722 data_location: None,
723 override_: None,
724 indexed: false,
725 name: None,
726 initializer: None,
727 });
728 }
729
730 let mut data_location = None;
731 let mut visibility = None;
732 let mut mutability = None;
733 let mut override_ = None;
734 let mut indexed = false;
735 loop {
736 if let Some(s) = self.parse_data_location() {
737 if !flags.contains(VarFlags::DATALOC) {
738 let msg = "data locations are not allowed here";
739 self.dcx().emit_err(self.prev_token.span, msg);
740 } else if data_location.is_some() {
741 let msg = "data location already specified";
742 self.dcx().emit_err(self.prev_token.span, msg);
743 } else {
744 data_location = Some(s);
745 }
746 } else if let Some(v) = self.parse_visibility() {
747 if !flags.contains(VarFlags::from_visibility(v)) {
748 let msg = visibility_error(v, flags.visibilities());
749 self.dcx().emit_err(self.prev_token.span, msg);
750 } else if visibility.is_some() {
751 let msg = "visibility already specified";
752 self.dcx().emit_err(self.prev_token.span, msg);
753 } else {
754 visibility = Some(v);
755 }
756 } else if let Some(m) = self.parse_variable_mutability() {
757 if flags != VarFlags::CONSTANT_VAR && !flags.contains(VarFlags::from_varmut(m)) {
759 let msg = varmut_error(m, flags.varmuts());
760 self.dcx().emit_err(self.prev_token.span, msg);
761 } else if mutability.is_some() {
762 let msg = "mutability already specified";
763 self.dcx().emit_err(self.prev_token.span, msg);
764 } else {
765 mutability = Some(m);
766 }
767 } else if self.eat_keyword(kw::Indexed) {
768 if !flags.contains(VarFlags::INDEXED) {
769 let msg = "`indexed` is not allowed here";
770 self.dcx().emit_err(self.prev_token.span, msg);
771 } else if indexed {
772 let msg = "`indexed` already specified";
773 self.dcx().emit_err(self.prev_token.span, msg);
774 } else {
775 indexed = true;
776 }
777 } else if self.eat_keyword(kw::Virtual) {
778 let msg = "`virtual` is not allowed here";
779 self.dcx().emit_err(self.prev_token.span, msg);
780 } else if self.eat_keyword(kw::Override) {
781 let o = self.parse_override()?;
782 if !flags.contains(VarFlags::OVERRIDE) {
783 let msg = "`override` is not allowed here";
784 self.dcx().emit_err(self.prev_token.span, msg);
785 } else if override_.is_some() {
786 let msg = "override already specified";
787 self.dcx().emit_err(self.prev_token.span, msg);
788 } else {
789 override_ = Some(o);
790 }
791 } else {
792 break;
793 }
794 }
795
796 let name = if flags.contains(VarFlags::NAME) {
797 self.parse_ident().map(Some)
798 } else {
799 self.parse_ident_opt()
800 }?;
801 if let Some(name) = &name
802 && flags.contains(VarFlags::NAME_WARN)
803 {
804 debug_assert!(!flags.contains(VarFlags::NAME));
805 let msg = "named function type parameters are deprecated";
806 self.dcx().warn(msg).code(error_code!(6162)).span(name.span).emit();
807 }
808
809 let initializer = if flags.contains(VarFlags::INITIALIZER) && self.eat(TokenKind::Eq) {
810 Some(self.parse_expr()?)
811 } else {
812 None
813 };
814
815 if flags.contains(VarFlags::SEMI) {
816 self.expect_semi()?;
817 }
818
819 let span = lo.to(self.prev_token.span);
820
821 if mutability == Some(VarMut::Constant) && initializer.is_none() {
822 let msg = "constant variable must be initialized";
823 self.dcx().emit_err(span, msg);
824 }
825 if flags == VarFlags::CONSTANT_VAR && mutability != Some(VarMut::Constant) {
826 let msg = "only constant variables are allowed at file level";
827 self.dcx().emit_err(span, msg);
828 }
829
830 Ok(VariableDefinition {
831 span,
832 ty,
833 data_location,
834 visibility,
835 mutability,
836 override_,
837 indexed,
838 name,
839 initializer,
840 })
841 }
842
843 fn parse_variable_mutability(&mut self) -> Option<VarMut> {
845 if self.eat_keyword(kw::Constant) {
846 Some(VarMut::Constant)
847 } else if self.eat_keyword(kw::Immutable) {
848 Some(VarMut::Immutable)
849 } else {
850 None
851 }
852 }
853
854 pub(super) fn parse_parameter_list(
856 &mut self,
857 allow_empty: bool,
858 flags: VarFlags,
859 ) -> PResult<'sess, ParameterList<'ast>> {
860 let lo = self.token.span;
861 let vars =
862 self.parse_paren_comma_seq(allow_empty, |this| this.parse_variable_definition(flags))?;
863 Ok(ParameterList { vars, span: lo.to(self.prev_token.span) })
864 }
865
866 fn parse_inheritance(&mut self) -> PResult<'sess, BoxSlice<'ast, Modifier<'ast>>> {
868 let mut list = SmallVec::<[_; 8]>::new();
869 loop {
870 list.push(self.parse_modifier()?);
871 if !self.eat(TokenKind::Comma) {
872 break;
873 }
874 }
875 Ok(self.alloc_smallvec(list))
876 }
877
878 fn parse_storage_layout_specifier(&mut self) -> PResult<'sess, StorageLayoutSpecifier<'ast>> {
880 let lo = self.token.span;
881 self.expect_keyword(sym::layout)?;
882 self.expect_keyword(sym::at)?;
883 let slot = self.parse_expr()?;
884 Ok(StorageLayoutSpecifier { span: lo.to(self.prev_token.span), slot })
885 }
886
887 fn parse_modifier(&mut self) -> PResult<'sess, Modifier<'ast>> {
889 let name = self.parse_path()?;
890 let arguments = if self.token.kind == TokenKind::OpenDelim(Delimiter::Parenthesis) {
891 self.parse_call_args()?
892 } else {
893 CallArgs::empty(name.span().shrink_to_hi())
894 };
895 Ok(Modifier { name, arguments })
896 }
897
898 fn parse_override(&mut self) -> PResult<'sess, Override<'ast>> {
902 debug_assert!(self.prev_token.is_keyword(kw::Override));
903 let lo = self.prev_token.span;
904 let paths = if self.token.is_open_delim(Delimiter::Parenthesis) {
905 self.parse_paren_comma_seq(false, Self::parse_path)?
906 } else {
907 Default::default()
908 };
909 let span = lo.to(self.prev_token.span);
910 Ok(Override { span, paths })
911 }
912
913 pub(super) fn parse_str_lit(&mut self) -> PResult<'sess, StrLit> {
916 match self.parse_str_lit_opt() {
917 Some(lit) => Ok(lit),
918 None => self.unexpected(),
919 }
920 }
921
922 pub(super) fn parse_str_lit_opt(&mut self) -> Option<StrLit> {
925 if !self.check_str_lit() {
926 return None;
927 }
928 let TokenRepr { kind: TokenKind::Literal(TokenLitKind::Str, symbol), span } = *self.token
929 else {
930 unreachable!()
931 };
932 self.bump();
933 Some(StrLit { span, value: symbol })
934 }
935
936 fn parse_data_location(&mut self) -> Option<DataLocation> {
938 if self.eat_keyword(kw::Storage) {
939 Some(DataLocation::Storage)
940 } else if self.eat_keyword(kw::Memory) {
941 Some(DataLocation::Memory)
942 } else if self.eat_keyword(kw::Calldata) {
943 Some(DataLocation::Calldata)
944 } else if self.check_keyword(sym::transient)
945 && !matches!(
946 self.look_ahead(1).kind,
947 TokenKind::Eq | TokenKind::Semi | TokenKind::CloseDelim(_) | TokenKind::Comma
948 )
949 {
950 self.bump(); Some(DataLocation::Transient)
952 } else {
953 None
954 }
955 }
956
957 pub(super) fn parse_visibility(&mut self) -> Option<Visibility> {
959 if self.eat_keyword(kw::Public) {
960 Some(Visibility::Public)
961 } else if self.eat_keyword(kw::Private) {
962 Some(Visibility::Private)
963 } else if self.eat_keyword(kw::Internal) {
964 Some(Visibility::Internal)
965 } else if self.eat_keyword(kw::External) {
966 Some(Visibility::External)
967 } else {
968 None
969 }
970 }
971
972 pub(super) fn parse_state_mutability(&mut self) -> Option<StateMutability> {
974 if self.eat_keyword(kw::Payable) {
975 Some(StateMutability::Payable)
976 } else if self.eat_keyword(kw::Pure) {
977 Some(StateMutability::Pure)
978 } else if self.eat_keyword(kw::View) {
979 Some(StateMutability::View)
980 } else {
981 None
982 }
983 }
984}
985
986struct SemverVersionParser<'p, 'sess, 'ast, 'cb> {
987 p: &'p mut Parser<'sess, 'ast, 'cb>,
988 bumps: u32,
989 pos_inside: u32,
990}
991
992impl<'p, 'sess, 'ast, 'cb> SemverVersionParser<'p, 'sess, 'ast, 'cb> {
993 fn new(p: &'p mut Parser<'sess, 'ast, 'cb>) -> Self {
994 Self { p, bumps: 0, pos_inside: 0 }
995 }
996
997 fn emit_err(&self, msg: impl Into<DiagMsg>) {
998 self.p.dcx().emit_err(self.current_span(), msg);
999 }
1000
1001 fn parse(mut self) -> SemverVersion {
1002 let lo = self.current_span();
1003 let major = self.parse_version_part();
1004 let mut minor = None;
1005 let mut patch = None;
1006 if self.eat_dot() {
1007 minor = Some(self.parse_version_part());
1008 if self.eat_dot() {
1009 patch = Some(self.parse_version_part());
1010 }
1011 }
1012 if self.pos_inside > 0 || self.bumps == 0 {
1013 self.emit_err("unexpected trailing characters");
1014 self.bump_token();
1015 }
1016 SemverVersion { span: lo.to(self.current_span()), major, minor, patch }
1017 }
1018
1019 fn eat_dot(&mut self) -> bool {
1020 let r = self.current_char() == Some('.');
1021 if r {
1022 self.bump_char();
1023 }
1024 r
1025 }
1026
1027 fn parse_version_part(&mut self) -> SemverVersionNumber {
1028 match self.current_char() {
1029 Some('*' | 'x' | 'X') => {
1030 self.bump_char();
1031 SemverVersionNumber::Wildcard
1032 }
1033 Some('0'..='9') => {
1034 let s = self.current_str().unwrap();
1035 let len = s.bytes().take_while(u8::is_ascii_digit).count();
1036 let result = s[..len].parse();
1037 self.bump_chars(len as u32);
1038 let Ok(n) = result else {
1039 self.emit_err("version number too large");
1040 return SemverVersionNumber::Wildcard;
1041 };
1042 SemverVersionNumber::Number(n)
1043 }
1044 _ => {
1045 self.emit_err("expected version number");
1046 self.bump_char();
1047 SemverVersionNumber::Wildcard
1048 }
1049 }
1050 }
1051
1052 fn current_char(&self) -> Option<char> {
1053 self.current_str()?.chars().next()
1054 }
1055
1056 fn current_str(&self) -> Option<&str> {
1057 self.current_token_str()?.get(self.pos_inside as usize..)
1058 }
1059
1060 fn current_token_str(&self) -> Option<&str> {
1061 Some(match &self.current_token().kind {
1062 TokenKind::Dot => ".",
1063 TokenKind::BinOp(BinOpToken::Star) => "*",
1064 TokenKind::Ident(s) | TokenKind::Literal(_, s) => s.as_str(),
1065 _ => return None,
1066 })
1067 }
1068
1069 fn current_token(&self) -> &Token {
1070 &self.p.token
1071 }
1072
1073 fn current_span(&self) -> Span {
1074 let mut s = self.current_token().span;
1075 if self.pos_inside > 0 {
1076 s = s.with_lo(s.lo() + self.pos_inside);
1077 }
1078 s
1079 }
1080
1081 fn bump_char(&mut self) {
1082 self.bump_chars(1);
1083 }
1084
1085 fn bump_chars(&mut self, n: u32) {
1086 if let Some(s) = self.current_token_str() {
1087 if self.pos_inside + n >= s.len() as u32 {
1088 self.bump_token();
1089 } else {
1090 self.pos_inside += n;
1091 }
1092 }
1093 }
1094
1095 fn bump_token(&mut self) {
1096 self.p.bump();
1097 self.bumps += 1;
1098 self.pos_inside = 0;
1099 }
1100}
1101
1102bitflags::bitflags! {
1103 #[derive(Clone, Copy, PartialEq, Eq)]
1105 pub(super) struct VarFlags: u16 {
1106 const DATALOC = 1 << 1;
1109 const INDEXED = 1 << 2;
1110
1111 const PRIVATE = 1 << 3;
1112 const INTERNAL = 1 << 4;
1113 const PUBLIC = 1 << 5;
1114 const EXTERNAL = 1 << 6; const VISIBILITY = Self::PRIVATE.bits()
1116 | Self::INTERNAL.bits()
1117 | Self::PUBLIC.bits()
1118 | Self::EXTERNAL.bits();
1119
1120 const CONSTANT = 1 << 7;
1121 const IMMUTABLE = 1 << 8;
1122
1123 const OVERRIDE = 1 << 9;
1124
1125 const NAME = 1 << 10;
1126 const NAME_WARN = 1 << 11;
1127
1128 const INITIALIZER = 1 << 12;
1129 const SEMI = 1 << 13;
1130
1131 const STRUCT = Self::NAME.bits();
1132 const ERROR = 0;
1133 const EVENT = Self::INDEXED.bits();
1134 const FUNCTION = Self::DATALOC.bits();
1135 const FUNCTION_TY = Self::DATALOC.bits() | Self::NAME_WARN.bits();
1136
1137 const STATE_VAR = Self::DATALOC.bits()
1139 | Self::PRIVATE.bits()
1140 | Self::INTERNAL.bits()
1141 | Self::PUBLIC.bits()
1142 | Self::CONSTANT.bits()
1143 | Self::IMMUTABLE.bits()
1144 | Self::OVERRIDE.bits()
1145 | Self::NAME.bits()
1146 | Self::INITIALIZER.bits()
1147 | Self::SEMI.bits();
1148
1149 const CONSTANT_VAR = Self::CONSTANT.bits()
1151 | Self::NAME.bits()
1152 | Self::INITIALIZER.bits()
1153 | Self::SEMI.bits();
1154
1155 const VAR = Self::DATALOC.bits() | Self::INITIALIZER.bits();
1157 }
1158
1159 #[derive(Clone, Copy, PartialEq, Eq)]
1161 pub(super) struct FunctionFlags: u16 {
1162 const NAME = 1 << 0;
1164 const PARAM_NAME = 1 << 1;
1166 const NO_PARENS = 1 << 2;
1168
1169 const PRIVATE = 1 << 3;
1171 const INTERNAL = 1 << 4;
1172 const PUBLIC = 1 << 5;
1173 const EXTERNAL = 1 << 6;
1174 const VISIBILITY = Self::PRIVATE.bits()
1175 | Self::INTERNAL.bits()
1176 | Self::PUBLIC.bits()
1177 | Self::EXTERNAL.bits();
1178
1179 const PURE = 1 << 7;
1181 const VIEW = 1 << 8;
1182 const PAYABLE = 1 << 9;
1183 const STATE_MUTABILITY = Self::PURE.bits()
1184 | Self::VIEW.bits()
1185 | Self::PAYABLE.bits();
1186
1187 const MODIFIERS = 1 << 10;
1188 const VIRTUAL = 1 << 11;
1189 const OVERRIDE = 1 << 12;
1190
1191 const RETURNS = 1 << 13;
1192 const ONLY_BLOCK = 1 << 14;
1194
1195 const CONSTRUCTOR = Self::MODIFIERS.bits()
1197 | Self::PAYABLE.bits()
1198 | Self::INTERNAL.bits()
1199 | Self::PUBLIC.bits()
1200 | Self::ONLY_BLOCK.bits();
1201
1202 const FUNCTION = Self::NAME.bits()
1204 | Self::VISIBILITY.bits()
1205 | Self::STATE_MUTABILITY.bits()
1206 | Self::MODIFIERS.bits()
1207 | Self::VIRTUAL.bits()
1208 | Self::OVERRIDE.bits()
1209 | Self::RETURNS.bits();
1210
1211 const MODIFIER = Self::NAME.bits()
1213 | Self::NO_PARENS.bits()
1214 | Self::VIRTUAL.bits()
1215 | Self::OVERRIDE.bits();
1216
1217 const FALLBACK = Self::EXTERNAL.bits()
1219 | Self::STATE_MUTABILITY.bits()
1220 | Self::MODIFIERS.bits()
1221 | Self::VIRTUAL.bits()
1222 | Self::OVERRIDE.bits()
1223 | Self::RETURNS.bits();
1224
1225 const RECEIVE = Self::EXTERNAL.bits()
1227 | Self::PAYABLE.bits()
1228 | Self::MODIFIERS.bits()
1229 | Self::VIRTUAL.bits()
1230 | Self::OVERRIDE.bits();
1231
1232 const FUNCTION_TY = Self::PARAM_NAME.bits()
1234 | Self::VISIBILITY.bits()
1235 | Self::STATE_MUTABILITY.bits()
1236 | Self::RETURNS.bits();
1237 }
1238}
1239
1240impl VarFlags {
1241 fn from_visibility(v: Visibility) -> Self {
1242 match v {
1243 Visibility::Private => Self::PRIVATE,
1244 Visibility::Internal => Self::INTERNAL,
1245 Visibility::Public => Self::PUBLIC,
1246 Visibility::External => Self::EXTERNAL,
1247 }
1248 }
1249
1250 fn into_visibility(self) -> Option<Visibility> {
1251 match self {
1252 Self::PRIVATE => Some(Visibility::Private),
1253 Self::INTERNAL => Some(Visibility::Internal),
1254 Self::PUBLIC => Some(Visibility::Public),
1255 Self::EXTERNAL => Some(Visibility::External),
1256 _ => None,
1257 }
1258 }
1259
1260 fn visibilities(self) -> Option<impl Iterator<Item = Visibility>> {
1261 self.supported(Self::VISIBILITY).map(|iter| iter.map(|x| x.into_visibility().unwrap()))
1262 }
1263
1264 fn from_varmut(v: VarMut) -> Self {
1265 match v {
1266 VarMut::Constant => Self::CONSTANT,
1267 VarMut::Immutable => Self::IMMUTABLE,
1268 }
1269 }
1270
1271 fn into_varmut(self) -> Option<VarMut> {
1272 match self {
1273 Self::CONSTANT => Some(VarMut::Constant),
1274 Self::IMMUTABLE => Some(VarMut::Immutable),
1275 _ => None,
1276 }
1277 }
1278
1279 fn varmuts(self) -> Option<impl Iterator<Item = VarMut>> {
1280 self.supported(Self::CONSTANT | Self::IMMUTABLE)
1281 .map(|iter| iter.map(|x| x.into_varmut().unwrap()))
1282 }
1283
1284 fn supported(self, what: Self) -> Option<impl Iterator<Item = Self>> {
1285 let s = self.intersection(what);
1286 if s.is_empty() { None } else { Some(s.iter()) }
1287 }
1288}
1289
1290impl FunctionFlags {
1291 fn from_kind(kind: FunctionKind) -> Self {
1292 match kind {
1293 FunctionKind::Constructor => Self::CONSTRUCTOR,
1294 FunctionKind::Function => Self::FUNCTION,
1295 FunctionKind::Modifier => Self::MODIFIER,
1296 FunctionKind::Receive => Self::RECEIVE,
1297 FunctionKind::Fallback => Self::FALLBACK,
1298 }
1299 }
1300
1301 fn from_visibility(visibility: Visibility) -> Self {
1302 match visibility {
1303 Visibility::Private => Self::PRIVATE,
1304 Visibility::Internal => Self::INTERNAL,
1305 Visibility::Public => Self::PUBLIC,
1306 Visibility::External => Self::EXTERNAL,
1307 }
1308 }
1309
1310 fn into_visibility(self) -> Option<Visibility> {
1311 match self {
1312 Self::PRIVATE => Some(Visibility::Private),
1313 Self::INTERNAL => Some(Visibility::Internal),
1314 Self::PUBLIC => Some(Visibility::Public),
1315 Self::EXTERNAL => Some(Visibility::External),
1316 _ => None,
1317 }
1318 }
1319
1320 fn visibilities(self) -> Option<impl Iterator<Item = Visibility>> {
1321 self.supported(Self::VISIBILITY).map(|iter| iter.map(|x| x.into_visibility().unwrap()))
1322 }
1323
1324 fn from_state_mutability(state_mutability: StateMutability) -> Self {
1325 match state_mutability {
1326 StateMutability::Pure => Self::PURE,
1327 StateMutability::View => Self::VIEW,
1328 StateMutability::Payable => Self::PAYABLE,
1329 StateMutability::NonPayable => unreachable!("NonPayable should not be parsed"),
1330 }
1331 }
1332
1333 fn into_state_mutability(self) -> Option<StateMutability> {
1334 match self {
1335 Self::PURE => Some(StateMutability::Pure),
1336 Self::VIEW => Some(StateMutability::View),
1337 Self::PAYABLE => Some(StateMutability::Payable),
1338 _ => None,
1339 }
1340 }
1341
1342 fn state_mutabilities(self) -> Option<impl Iterator<Item = StateMutability>> {
1343 self.supported(Self::STATE_MUTABILITY)
1344 .map(|iter| iter.map(|x| x.into_state_mutability().unwrap()))
1345 }
1346
1347 fn supported(self, what: Self) -> Option<impl Iterator<Item = Self>> {
1348 let s = self.intersection(what);
1349 if s.is_empty() { None } else { Some(s.iter()) }
1350 }
1351}
1352
1353fn visibility_error(v: Visibility, iter: Option<impl Iterator<Item = Visibility>>) -> String {
1354 common_flags_error(v, "visibility", iter)
1355}
1356
1357fn varmut_error(m: VarMut, iter: Option<impl Iterator<Item = VarMut>>) -> String {
1358 common_flags_error(m, "mutability", iter)
1359}
1360
1361fn state_mutability_error(
1362 m: StateMutability,
1363 iter: Option<impl Iterator<Item = StateMutability>>,
1364) -> String {
1365 common_flags_error(m, "state mutability", iter)
1366}
1367
1368fn common_flags_error<T: std::fmt::Display>(
1369 t: T,
1370 desc: &str,
1371 iter: Option<impl Iterator<Item = T>>,
1372) -> String {
1373 match iter {
1374 Some(iter) => format!("`{t}` not allowed here; allowed values: {}", iter.format(", ")),
1375 None => format!("{desc} is not allowed here"),
1376 }
1377}
1378
1379#[cfg(test)]
1380mod tests {
1381 use super::*;
1382 use solar_interface::{Result, Session, source_map::FileName};
1383
1384 fn session() -> Session {
1385 Session::builder().with_test_emitter().single_threaded().build()
1386 }
1387
1388 fn assert_version_matches(tests: &[(&str, &str, bool)]) {
1389 let sess = session();
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();
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();
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}