Lexing/parsing generic args.
This commit is contained in:
parent
b4094bf570
commit
3466908a80
@ -109,7 +109,7 @@ impl Function {
|
|||||||
Parameter::new(
|
Parameter::new(
|
||||||
"self",
|
"self",
|
||||||
SourceRange::new(0, 0),
|
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 {
|
pub struct TypeUse {
|
||||||
declared_name: String,
|
declared_name: String,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
|
generic_arguments: Vec<TypeUse>,
|
||||||
scope_id: Option<usize>,
|
scope_id: Option<usize>,
|
||||||
type_info: Option<TypeInfo>,
|
type_info: Option<TypeInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeUse {
|
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 {
|
Self {
|
||||||
declared_name: declared_name.into(),
|
declared_name: declared_name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
|
generic_arguments,
|
||||||
scope_id: None,
|
scope_id: None,
|
||||||
type_info: None,
|
type_info: None,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,10 +54,6 @@ impl<'a> Lexer<'a> {
|
|||||||
Token::new(self.position, self.position + 1, TokenKind::Modulo)
|
Token::new(self.position, self.position + 1, TokenKind::Modulo)
|
||||||
} else if chunk.starts_with("+") {
|
} else if chunk.starts_with("+") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Plus)
|
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("&") {
|
} else if chunk.starts_with("&") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Ampersand)
|
Token::new(self.position, self.position + 1, TokenKind::Ampersand)
|
||||||
} else if chunk.starts_with("^") {
|
} else if chunk.starts_with("^") {
|
||||||
@ -76,6 +72,10 @@ impl<'a> Lexer<'a> {
|
|||||||
Token::new(self.position, self.position + 1, TokenKind::LeftSquare)
|
Token::new(self.position, self.position + 1, TokenKind::LeftSquare)
|
||||||
} else if chunk.starts_with("]") {
|
} else if chunk.starts_with("]") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::RightSquare)
|
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 {
|
} else {
|
||||||
// more than one char token
|
// more than one char token
|
||||||
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
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> {
|
struct Parser<'a> {
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
lexer: Lexer<'a>,
|
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 {
|
fn peek_current(&self, token_kind: TokenKind) -> bool {
|
||||||
match &self.current {
|
match &self.current {
|
||||||
None => panic!("Unexpected end of input."),
|
None => panic!("Unexpected end of input."),
|
||||||
@ -488,9 +514,19 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
TokenKind::Identifier => {
|
TokenKind::Identifier => {
|
||||||
let identifier_token = self.expect_advance(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(
|
Ok(TypeUse::new(
|
||||||
self.token_text(&identifier_token),
|
self.token_text(&identifier_token),
|
||||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||||
|
generic_arguments,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => Err(vec![Diagnostic::new(
|
_ => 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(
|
fn public_class_member(
|
||||||
&mut self,
|
&mut self,
|
||||||
fields: &mut Vec<Field>,
|
fields: &mut Vec<Field>,
|
||||||
@ -747,8 +796,10 @@ impl<'a> Parser<'a> {
|
|||||||
while self.current.is_some() {
|
while self.current.is_some() {
|
||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::LeftShift => {
|
TokenKind::Lt => {
|
||||||
self.advance(); // left shift
|
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 rhs = self.additive_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -759,8 +810,10 @@ impl<'a> Parser<'a> {
|
|||||||
source_range,
|
source_range,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
TokenKind::RightShift => {
|
TokenKind::Gt => {
|
||||||
self.advance(); // right shift
|
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 rhs = self.additive_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -45,8 +45,6 @@ pub enum TokenKind {
|
|||||||
Star,
|
Star,
|
||||||
Slash,
|
Slash,
|
||||||
Modulo,
|
Modulo,
|
||||||
LeftShift,
|
|
||||||
RightShift,
|
|
||||||
Ampersand,
|
Ampersand,
|
||||||
Caret,
|
Caret,
|
||||||
Bar,
|
Bar,
|
||||||
@ -58,4 +56,6 @@ pub enum TokenKind {
|
|||||||
Ctor,
|
Ctor,
|
||||||
LeftSquare,
|
LeftSquare,
|
||||||
RightSquare,
|
RightSquare,
|
||||||
|
Lt,
|
||||||
|
Gt,
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user