Lexing/parsing generic args.
This commit is contained in:
parent
b4094bf570
commit
3466908a80
@ -109,7 +109,7 @@ impl Function {
|
||||
Parameter::new(
|
||||
"self",
|
||||
SourceRange::new(0, 0),
|
||||
TypeUse::new("Self", SourceRange::new(0, 0)),
|
||||
TypeUse::new("Self", SourceRange::new(0, 0), vec![]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -9,15 +9,21 @@ use std::rc::Rc;
|
||||
pub struct TypeUse {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
generic_arguments: Vec<TypeUse>,
|
||||
scope_id: Option<usize>,
|
||||
type_info: Option<TypeInfo>,
|
||||
}
|
||||
|
||||
impl TypeUse {
|
||||
pub fn new(declared_name: &str, declared_name_source_range: SourceRange) -> Self {
|
||||
pub fn new(
|
||||
declared_name: &str,
|
||||
declared_name_source_range: SourceRange,
|
||||
generic_arguments: Vec<TypeUse>,
|
||||
) -> Self {
|
||||
Self {
|
||||
declared_name: declared_name.into(),
|
||||
declared_name_source_range,
|
||||
generic_arguments,
|
||||
scope_id: None,
|
||||
type_info: None,
|
||||
}
|
||||
|
||||
@ -54,10 +54,6 @@ impl<'a> Lexer<'a> {
|
||||
Token::new(self.position, self.position + 1, TokenKind::Modulo)
|
||||
} else if chunk.starts_with("+") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::Plus)
|
||||
} else if chunk.starts_with("<<") {
|
||||
Token::new(self.position, self.position + 2, TokenKind::LeftShift)
|
||||
} else if chunk.starts_with(">>") {
|
||||
Token::new(self.position, self.position + 2, TokenKind::RightShift)
|
||||
} else if chunk.starts_with("&") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::Ampersand)
|
||||
} else if chunk.starts_with("^") {
|
||||
@ -76,6 +72,10 @@ impl<'a> Lexer<'a> {
|
||||
Token::new(self.position, self.position + 1, TokenKind::LeftSquare)
|
||||
} else if chunk.starts_with("]") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::RightSquare)
|
||||
} else if chunk.starts_with("<") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::Lt)
|
||||
} else if chunk.starts_with(">") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::Gt)
|
||||
} else {
|
||||
// more than one char token
|
||||
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
||||
|
||||
@ -56,6 +56,12 @@ macro_rules! matches_statement_first {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! matches_type_use_first {
|
||||
( $token_kind: expr ) => {
|
||||
matches!($token_kind, TokenKind::LeftSquare | TokenKind::Identifier)
|
||||
};
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
input: &'a str,
|
||||
lexer: Lexer<'a>,
|
||||
@ -163,6 +169,26 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_position_advance(
|
||||
&mut self,
|
||||
token_kind: TokenKind,
|
||||
start_position: usize,
|
||||
) -> Result<Token, Vec<Diagnostic>> {
|
||||
let matched = self.expect_advance(token_kind)?;
|
||||
if matched.start() == start_position {
|
||||
Ok(matched)
|
||||
} else {
|
||||
Err(vec![
|
||||
Diagnostic::new(
|
||||
&format!("Expected {:?} but found {:?}", token_kind, matched.kind()),
|
||||
matched.start(),
|
||||
matched.end(),
|
||||
)
|
||||
.with_reporter(file!(), line!()),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
fn peek_current(&self, token_kind: TokenKind) -> bool {
|
||||
match &self.current {
|
||||
None => panic!("Unexpected end of input."),
|
||||
@ -488,9 +514,19 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
TokenKind::Identifier => {
|
||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||
let generic_arguments =
|
||||
if self.current.is_some() && self.peek_current(TokenKind::Lt) {
|
||||
self.advance(); // <
|
||||
let generic_arguments = self.generic_arguments_list()?;
|
||||
self.expect_advance(TokenKind::Gt)?; // >
|
||||
generic_arguments
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
Ok(TypeUse::new(
|
||||
self.token_text(&identifier_token),
|
||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||
generic_arguments,
|
||||
))
|
||||
}
|
||||
_ => Err(vec![Diagnostic::new(
|
||||
@ -510,6 +546,19 @@ impl<'a> Parser<'a> {
|
||||
)])
|
||||
}
|
||||
|
||||
fn generic_arguments_list(&mut self) -> Result<Vec<TypeUse>, Vec<Diagnostic>> {
|
||||
let mut generic_arguments: Vec<TypeUse> = vec![];
|
||||
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
|
||||
generic_arguments.push(self.type_use()?);
|
||||
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
||||
self.advance(); // comma
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(generic_arguments)
|
||||
}
|
||||
|
||||
fn public_class_member(
|
||||
&mut self,
|
||||
fields: &mut Vec<Field>,
|
||||
@ -747,8 +796,10 @@ impl<'a> Parser<'a> {
|
||||
while self.current.is_some() {
|
||||
let current = self.get_current();
|
||||
match current.kind() {
|
||||
TokenKind::LeftShift => {
|
||||
self.advance(); // left shift
|
||||
TokenKind::Lt => {
|
||||
let second_lt_start = current.start() + 1;
|
||||
self.advance(); // first <
|
||||
self.expect_position_advance(TokenKind::Lt, second_lt_start)?; // second <
|
||||
let rhs = self.additive_expression()?;
|
||||
let source_range =
|
||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||
@ -759,8 +810,10 @@ impl<'a> Parser<'a> {
|
||||
source_range,
|
||||
));
|
||||
}
|
||||
TokenKind::RightShift => {
|
||||
self.advance(); // right shift
|
||||
TokenKind::Gt => {
|
||||
let second_gt_start = current.start() + 1;
|
||||
self.advance(); // first >
|
||||
self.expect_position_advance(TokenKind::Gt, second_gt_start)?; // second gt
|
||||
let rhs = self.additive_expression()?;
|
||||
let source_range =
|
||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||
@ -1170,6 +1223,16 @@ mod smoke_tests {
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_generic_arg() {
|
||||
smoke_test("fn main(args: Array<String>) end");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_generic_args() {
|
||||
smoke_test("fn main(foo: Array<Bar<Foo>>) end");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -45,8 +45,6 @@ pub enum TokenKind {
|
||||
Star,
|
||||
Slash,
|
||||
Modulo,
|
||||
LeftShift,
|
||||
RightShift,
|
||||
Ampersand,
|
||||
Caret,
|
||||
Bar,
|
||||
@ -58,4 +56,6 @@ pub enum TokenKind {
|
||||
Ctor,
|
||||
LeftSquare,
|
||||
RightSquare,
|
||||
Lt,
|
||||
Gt,
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user