Skip to content

Commit 4694414

Browse files
committed
Started implementing parsing for general purpose generics / compile-time arguments
1 parent cc2fc3f commit 4694414

File tree

6 files changed

+189
-78
lines changed

6 files changed

+189
-78
lines changed

Diff for: src/ast/datatype/generics.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use super::Type;
2+
use crate::ast::Expr;
3+
4+
#[derive(Clone, Debug)]
5+
pub enum CompileTimeArgument {
6+
Type(Type),
7+
Expr(Expr),
8+
}

Diff for: src/ast/datatype/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod c_integer;
22
mod description;
33
mod fixed_array;
44
mod function_pointer;
5+
mod generics;
56
mod kind;
67
mod nameless_enumeration;
78
mod nameless_structure;
@@ -12,6 +13,7 @@ pub use c_integer::*;
1213
pub use description::*;
1314
pub use fixed_array::*;
1415
pub use function_pointer::*;
16+
pub use generics::*;
1517
pub use kind::*;
1618
pub use nameless_enumeration::*;
1719
pub use nameless_structure::*;

Diff for: src/parser/error.rs

+27
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ pub enum ParseErrorKind {
7575
message: String,
7676
},
7777
CannotCallFunctionsAtGlobalScope,
78+
IncorrectNumberOfTypeParametersFor {
79+
name: String,
80+
got: usize,
81+
expected: usize,
82+
},
83+
ExpectedTypeParameterToBeType {
84+
name: String,
85+
word_for_nth: String,
86+
},
7887
Other {
7988
message: String,
8089
},
@@ -180,6 +189,24 @@ impl Display for ParseErrorKind {
180189
ParseErrorKind::CannotCallFunctionsAtGlobalScope => {
181190
write!(f, "Cannot call functions at global scope")?;
182191
}
192+
ParseErrorKind::IncorrectNumberOfTypeParametersFor {
193+
name,
194+
got,
195+
expected,
196+
} => {
197+
write!(
198+
f,
199+
"Incorrect number of type parameters for '{}' (got {}, expected {})",
200+
name, got, expected
201+
)?;
202+
}
203+
ParseErrorKind::ExpectedTypeParameterToBeType { name, word_for_nth } => {
204+
write!(
205+
f,
206+
"Expected {} type parameter to '{}' to be a type",
207+
word_for_nth, name
208+
)?;
209+
}
183210
ParseErrorKind::Other { message } | ParseErrorKind::Lexical { message } => {
184211
write!(f, "{}", message)?;
185212
}

Diff for: src/parser/parse_expr/primary/mod.rs

+44-27
Original file line numberDiff line numberDiff line change
@@ -66,37 +66,54 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
6666
TokenKind::StructKeyword | TokenKind::UnionKeyword | TokenKind::EnumKeyword => {
6767
self.parse_structure_literal()
6868
}
69-
TokenKind::Identifier(_) => match self.input.peek_nth(1).kind {
70-
TokenKind::Namespace => self.parse_enum_member_literal(),
71-
TokenKind::OpenAngle => self.parse_structure_literal(),
72-
TokenKind::OpenCurly => {
73-
let peek = &self.input.peek_nth(2).kind;
74-
75-
if peek.is_extend() || peek.is_colon() {
76-
self.parse_structure_literal()
77-
} else {
78-
let next_three =
79-
array_last::<3, 5, _>(self.input.peek_n()).map(|token| &token.kind);
80-
81-
match &next_three[..] {
82-
[TokenKind::Identifier(_), TokenKind::Colon, ..]
83-
| [TokenKind::Newline, TokenKind::Identifier(_), TokenKind::Colon, ..] => {
84-
self.parse_structure_literal()
69+
TokenKind::Identifier(_) => {
70+
// TODO: CLEANUP: This should be cleaned up once we have proper
71+
// namespaces and generic parsing that applies to all cases
72+
73+
match self.input.peek_nth(1).kind {
74+
TokenKind::Namespace => self.parse_enum_member_literal(),
75+
TokenKind::OpenAngle => {
76+
let name = self.input.eat_identifier().unwrap();
77+
let generics = self.parse_generics()?;
78+
79+
if !generics.is_empty() {
80+
todo!("generics in expressions not implemented yet");
81+
}
82+
83+
let ast_type = self.parse_type_from_parts(name, vec![], source)?;
84+
self.parse_structure_literal_with(ast_type)
85+
}
86+
TokenKind::OpenCurly => {
87+
let peek = &self.input.peek_nth(2).kind;
88+
89+
if peek.is_extend() || peek.is_colon() {
90+
self.parse_structure_literal()
91+
} else {
92+
let next_three =
93+
array_last::<3, 5, _>(self.input.peek_n()).map(|token| &token.kind);
94+
95+
match &next_three[..] {
96+
[TokenKind::Identifier(_), TokenKind::Colon, ..]
97+
| [TokenKind::Newline, TokenKind::Identifier(_), TokenKind::Colon, ..] => {
98+
self.parse_structure_literal()
99+
}
100+
_ => Ok(Expr::new(
101+
ExprKind::Variable(
102+
self.input.advance().kind.unwrap_identifier(),
103+
),
104+
source,
105+
)),
85106
}
86-
_ => Ok(Expr::new(
87-
ExprKind::Variable(self.input.advance().kind.unwrap_identifier()),
88-
source,
89-
)),
90107
}
91108
}
109+
TokenKind::OpenParen => self.parse_call(),
110+
TokenKind::DeclareAssign => self.parse_declare_assign(),
111+
_ => Ok(Expr::new(
112+
ExprKind::Variable(self.input.advance().kind.unwrap_identifier()),
113+
source,
114+
)),
92115
}
93-
TokenKind::OpenParen => self.parse_call(),
94-
TokenKind::DeclareAssign => self.parse_declare_assign(),
95-
_ => Ok(Expr::new(
96-
ExprKind::Variable(self.input.advance().kind.unwrap_identifier()),
97-
source,
98-
)),
99-
},
116+
}
100117
TokenKind::Not | TokenKind::BitComplement | TokenKind::Subtract => {
101118
let operator = match kind {
102119
TokenKind::Not => UnaryOperator::Not,

Diff for: src/parser/parse_expr/primary/structure_literal.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use super::Parser;
22
use crate::{
3-
ast::{ConformBehavior, Expr, ExprKind, FieldInitializer, FillBehavior, StructureLiteral},
3+
ast::{
4+
ConformBehavior, Expr, ExprKind, FieldInitializer, FillBehavior, StructureLiteral, Type,
5+
},
46
inflow::Inflow,
57
parser::error::ParseError,
68
token::{Token, TokenKind},
@@ -12,8 +14,14 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
1214
// ^
1315

1416
let ast_type = self.parse_type(None::<&str>, Some("for type of struct literal"))?;
15-
let source = ast_type.source;
17+
self.parse_structure_literal_with(ast_type)
18+
}
1619

20+
pub fn parse_structure_literal_with(&mut self, ast_type: Type) -> Result<Expr, ParseError> {
21+
// Type { x: VALUE, b: VALUE, c: VALUE, :d, :e, ..SPECIFIER }
22+
// ^
23+
24+
let source = ast_type.source;
1725
self.parse_token(TokenKind::OpenCurly, Some("to begin struct literal"))?;
1826
self.ignore_newlines();
1927

Diff for: src/parser/parse_type.rs

+98-49
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use super::{
33
Parser,
44
};
55
use crate::{
6-
ast::{FixedArray, Type, TypeKind},
6+
ast::{CompileTimeArgument, Type, TypeKind},
77
inflow::Inflow,
8+
source_files::Source,
89
token::{Token, TokenKind},
910
};
1011

@@ -28,6 +29,48 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
2829
});
2930
};
3031

32+
let generics = self.parse_generics()?;
33+
self.parse_type_from_parts(identifier, generics, source)
34+
}
35+
36+
pub fn parse_generics(&mut self) -> Result<Vec<CompileTimeArgument>, ParseError> {
37+
let mut generics = vec![];
38+
39+
if !self.input.eat(TokenKind::OpenAngle) {
40+
return Ok(generics);
41+
}
42+
43+
loop {
44+
if self.parse_type_parameters_close().is_some() {
45+
break;
46+
} else if self.input.peek_is(TokenKind::EndOfFile) {
47+
// TODO: Improve error message
48+
return Err(self.unexpected_token_is_next());
49+
}
50+
51+
if !generics.is_empty() && !self.input.eat(TokenKind::Comma) {
52+
// TODO: Improve error message
53+
return Err(self.unexpected_token_is_next());
54+
}
55+
56+
generics.push(if self.input.peek().could_start_type() {
57+
CompileTimeArgument::Type(
58+
self.parse_type(None::<&str>, Some("for compile time argument"))?,
59+
)
60+
} else {
61+
CompileTimeArgument::Expr(self.parse_expr()?)
62+
});
63+
}
64+
65+
Ok(generics)
66+
}
67+
68+
pub fn parse_type_from_parts(
69+
&mut self,
70+
identifier: String,
71+
generics: Vec<CompileTimeArgument>,
72+
source: Source,
73+
) -> Result<Type, ParseError> {
3174
let type_kind = match identifier.as_str() {
3275
"bool" => Ok(TypeKind::Boolean),
3376
"char" => Ok(TypeKind::char()),
@@ -52,39 +95,38 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
5295
"f32" | "float" => Ok(TypeKind::f32()),
5396
"f64" | "double" => Ok(TypeKind::f64()),
5497
"void" => Ok(TypeKind::Void),
55-
"ptr" => Ok(TypeKind::Pointer(Box::new(
56-
if self.input.eat(TokenKind::OpenAngle) {
57-
let inner = self.parse_type(None::<&str>, None::<&str>)?;
58-
self.parse_type_parameters_close()?;
59-
inner
98+
"ptr" => {
99+
if generics.len() == 1 {
100+
if let CompileTimeArgument::Type(inner) = generics.into_iter().next().unwrap() {
101+
Ok(TypeKind::Pointer(Box::new(inner)))
102+
} else {
103+
Err(ParseError {
104+
kind: ParseErrorKind::ExpectedTypeParameterToBeType {
105+
name: identifier,
106+
word_for_nth: "first".into(),
107+
},
108+
source,
109+
})
110+
}
60111
} else {
61-
TypeKind::Void.at(source)
62-
},
63-
))),
64-
"array" => {
65-
if !self.input.eat(TokenKind::OpenAngle) {
66-
return Err(ParseError {
67-
kind: ParseErrorKind::ExpectedTypeParameters,
112+
Err(ParseError {
113+
kind: ParseErrorKind::IncorrectNumberOfTypeParametersFor {
114+
name: identifier,
115+
expected: 1,
116+
got: generics.len(),
117+
},
68118
source,
69-
});
70-
}
71-
72-
let count = self.parse_expr()?;
73-
74-
if !self.input.eat(TokenKind::Comma) {
75-
return Err(ParseError {
76-
kind: ParseErrorKind::ExpectedCommaInTypeParameters,
77-
source: self.source_here(),
78-
});
119+
})
79120
}
121+
}
122+
"array" => {
123+
// TODO: Update fixed array type to use compile time arguments
124+
todo!("array<$N, $T> not updated yet to use compile time arguments");
80125

81-
let inner = self.parse_type(None::<&str>, None::<&str>)?;
82-
self.parse_type_parameters_close()?;
83-
84-
Ok(TypeKind::FixedArray(Box::new(FixedArray {
85-
ast_type: inner,
86-
count,
87-
})))
126+
// Ok(TypeKind::FixedArray(Box::new(FixedArray {
127+
// ast_type: inner,
128+
// count,
129+
// })))
88130
}
89131
identifier => Ok(TypeKind::Named(identifier.into())),
90132
}?;
@@ -96,14 +138,15 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
96138
/// This function may partially consume tokens, so be
97139
/// aware that any previously peeked tokens may no longer be in
98140
/// the same lookahead position after calling this function.
99-
fn parse_type_parameters_close(&mut self) -> Result<(), ParseError> {
100-
let closer = self.input.advance();
141+
fn parse_type_parameters_close(&mut self) -> Option<()> {
142+
let closer = self.input.peek();
143+
let source = closer.source;
101144

102145
/// Sub-function for properly handling trailing `=` signs
103146
/// resulting from partially consuming '>'-like tokens.
104147
fn merge_trailing_equals<I: Inflow<Token>>(
105148
parser: &mut Parser<I>,
106-
closer: &Token,
149+
closer: Token,
107150
column_offset: u32,
108151
) {
109152
if parser.input.eat(TokenKind::Assign) {
@@ -118,36 +161,42 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
118161
}
119162

120163
match &closer.kind {
121-
TokenKind::GreaterThan => Ok(()),
164+
TokenKind::GreaterThan => {
165+
self.input.advance();
166+
Some(())
167+
}
122168
TokenKind::RightShift => {
169+
self.input.advance();
123170
self.input
124-
.unadvance(TokenKind::GreaterThan.at(closer.source.shift_column(1)));
125-
Ok(())
171+
.unadvance(TokenKind::GreaterThan.at(source.shift_column(1)));
172+
Some(())
126173
}
127174
TokenKind::LogicalRightShift => {
175+
self.input.advance();
128176
self.input
129-
.unadvance(TokenKind::RightShift.at(closer.source.shift_column(1)));
130-
Ok(())
177+
.unadvance(TokenKind::RightShift.at(source.shift_column(1)));
178+
Some(())
131179
}
132180
TokenKind::RightShiftAssign => {
133-
merge_trailing_equals(self, &closer, 2);
134-
181+
let closer = self.input.advance();
182+
merge_trailing_equals(self, closer, 2);
135183
self.input
136-
.unadvance(TokenKind::GreaterThan.at(closer.source.shift_column(1)));
137-
Ok(())
184+
.unadvance(TokenKind::GreaterThan.at(source.shift_column(1)));
185+
Some(())
138186
}
139187
TokenKind::LogicalRightShiftAssign => {
140-
merge_trailing_equals(self, &closer, 3);
141-
188+
let closer = self.input.advance();
189+
merge_trailing_equals(self, closer, 3);
142190
self.input
143-
.unadvance(TokenKind::RightShift.at(closer.source.shift_column(1)));
144-
Ok(())
191+
.unadvance(TokenKind::RightShift.at(source.shift_column(1)));
192+
Some(())
145193
}
146194
TokenKind::GreaterThanEq => {
147-
merge_trailing_equals(self, &closer, 1);
148-
Ok(())
195+
let closer = self.input.advance();
196+
merge_trailing_equals(self, closer, 1);
197+
Some(())
149198
}
150-
_ => Err(self.unexpected_token(&closer)),
199+
_ => None,
151200
}
152201
}
153202
}

0 commit comments

Comments
 (0)