forked from argotorg/fe
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodule.rs
More file actions
116 lines (105 loc) · 3.76 KB
/
Copy pathmodule.rs
File metadata and controls
116 lines (105 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use super::contracts::parse_contract_def;
use super::types::{parse_struct_def, parse_type_def};
use crate::ast::{Module, ModuleStmt, SimpleImportName};
use crate::node::{Node, Span};
use crate::{ParseFailed, ParseResult, Parser, TokenKind};
/// Parse a [`Module`].
pub fn parse_module(par: &mut Parser) -> ParseResult<Node<Module>> {
let mut body = vec![];
loop {
match par.peek() {
Some(TokenKind::Newline) => par.expect_newline("module")?,
Some(TokenKind::Dedent) => {
par.next()?;
break;
}
None => break,
Some(_) => {
let stmt = parse_module_stmt(par)?;
body.push(stmt);
}
}
}
let span = if body.is_empty() {
Span::zero()
} else {
body.first().unwrap().span + body.last()
};
Ok(Node::new(Module { body }, span))
}
/// Parse a [`ModuleStmt`].
pub fn parse_module_stmt(par: &mut Parser) -> ParseResult<Node<ModuleStmt>> {
match par.peek_or_err()? {
TokenKind::Import => parse_simple_import(par),
TokenKind::Name if par.peeked_text() == "from" => parse_from_import(par),
TokenKind::Contract => parse_contract_def(par),
TokenKind::Struct => parse_struct_def(par),
TokenKind::Type => parse_type_def(par),
TokenKind::Event => todo!("module-level event def"),
_ => {
let tok = par.next()?;
par.unexpected_token_error(
tok.span,
"failed to parse module",
vec!["Note: expected import, contract, struct, type, or event".into()],
);
Err(ParseFailed)
}
}
}
/// Parse an `import` statement. This does not yet support paths, just module
/// names. Note that `from x import y` style imports are handled in
/// [`parse_from_import`].
/// # Panics
/// Panics if the next token isn't `import`.
pub fn parse_simple_import(par: &mut Parser) -> ParseResult<Node<ModuleStmt>> {
let import_tok = par.assert(TokenKind::Import);
// TODO: only handles `import foo, bar as baz`
let mut names = vec![];
loop {
let name =
par.expect_with_notes(TokenKind::Name, "failed to parse import statement", || {
vec![
"Note: `import` must be followed by a module name or path".into(),
"Example: `import mymodule".into(),
]
})?;
let alias = if par.peek() == Some(TokenKind::As) {
par.next()?;
let tok = par.expect(TokenKind::Name, "failed to parse import statement")?;
Some(tok.into())
} else {
None
};
let span = name.span + alias.as_ref();
names.push(Node::new(
SimpleImportName {
path: vec![Node::new(name.text.to_string(), name.span)],
alias,
},
span,
));
match par.peek() {
Some(TokenKind::Comma) => {
par.next()?;
continue;
}
Some(TokenKind::Newline) | None => break,
Some(_) => {
let tok = par.next()?;
par.unexpected_token_error(tok.span, "failed to parse `import` statement", vec![]);
return Err(ParseFailed);
}
}
}
let span = import_tok.span + names.last();
Ok(Node::new(ModuleStmt::SimpleImport { names }, span))
}
/// Parse a `from x import y` style import statement.
/// # Panics
/// Always panics. Unimplemented.
pub fn parse_from_import(par: &mut Parser) -> ParseResult<Node<ModuleStmt>> {
let tok = par.assert(TokenKind::Name);
assert_eq!(tok.text, "from");
todo!("parse from .. import (not supported in rest of compiler yet)")
}