Skip to content

Commit d6b3649

Browse files
committed
Started working on support for C static_assert statement
1 parent 9d23714 commit d6b3649

File tree

8 files changed

+161
-10
lines changed

8 files changed

+161
-10
lines changed

src/ast/expr/kind.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub enum ExprKind {
3939
Break,
4040
Continue,
4141
IntegerPromote(Box<Expr>),
42+
StaticAssert(Box<Expr>, Option<String>),
4243
}
4344

4445
impl ExprKind {

src/ast/expr/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod struct_literal;
1212
mod unary;
1313
mod while_loop;
1414

15+
use super::{Stmt, StmtKind};
1516
use crate::source_files::Source;
1617
pub use array_access::*;
1718
pub use binary::*;
@@ -38,6 +39,11 @@ impl Expr {
3839
pub fn new(kind: ExprKind, source: Source) -> Self {
3940
Self { kind, source }
4041
}
42+
43+
pub fn stmt(self) -> Stmt {
44+
let source = self.source;
45+
return StmtKind::Expr(self).at(source);
46+
}
4147
}
4248

4349
// Make sure ExprKind doesn't accidentally become huge

src/c/lexer/error.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
1+
use std::fmt::Display;
2+
13
#[derive(Clone, Debug, PartialEq)]
24
pub enum LexError {
35
UniversalCharacterNameNotSupported,
46
UnrecognizedSymbol,
57
UnrepresentableInteger,
68
}
9+
10+
impl Display for LexError {
11+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12+
match self {
13+
LexError::UniversalCharacterNameNotSupported => {
14+
write!(f, "unsupported universal character name")
15+
}
16+
LexError::UnrecognizedSymbol => write!(f, "unrecognized symbol"),
17+
LexError::UnrepresentableInteger => write!(f, "unrepresentable integer literal"),
18+
}
19+
}
20+
}

src/c/parser/error.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{
2+
c::token::CTokenKind,
23
show::Show,
34
source_files::{Source, SourceFiles},
45
};
@@ -49,6 +50,7 @@ pub enum ParseErrorKind {
4950
UndeclaredVariable(String),
5051
UndeclaredType(String),
5152
CannotContainNulInNullTerminatedString,
53+
MiscGot(&'static str, CTokenKind),
5254
Misc(&'static str),
5355
}
5456

@@ -85,6 +87,9 @@ impl Display for ParseErrorKind {
8587
ParseErrorKind::CannotContainNulInNullTerminatedString => {
8688
write!(f, "Cannot contain NUL byte in C-String'")
8789
}
90+
ParseErrorKind::MiscGot(message, got) => {
91+
write!(f, "{}, got {}", message, got)
92+
}
8893
ParseErrorKind::Misc(message) => f.write_str(message),
8994
}
9095
}

src/c/parser/mod.rs

+47-8
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,36 @@ impl<'input, 'diagnostics> Parser<'input, 'diagnostics> {
895895
return Err(self.error("Expected 'static_assert' keyword to begin static assert"));
896896
}
897897

898-
todo!("parse_static_assert")
898+
if !self.eat_open_paren() {
899+
return Err(self.error("Expected '(' after 'static_assert' keyword"));
900+
}
901+
902+
let condition = self.parse_constant_expression()?;
903+
904+
let message = if self.eat_punctuator(Punctuator::Comma) {
905+
let token = self.input.advance();
906+
907+
let CTokenKind::StringLiteral(_encoding, string) = &token.kind else {
908+
return Err(ParseError::message(
909+
"Expected message for 'static_assert'",
910+
token.source,
911+
));
912+
};
913+
914+
Some(string.clone())
915+
} else {
916+
None
917+
};
918+
919+
if !self.eat_punctuator(Punctuator::CloseParen) {
920+
return Err(self.error("Expected ')' to close 'static_assert' statement"));
921+
}
922+
923+
if !self.eat_punctuator(Punctuator::Semicolon) {
924+
return Err(self.error("Expected ';' after 'static_assert' statement"));
925+
}
926+
927+
Ok(StaticAssertDeclaration { condition, message })
899928
}
900929

901930
fn parse_declaration(&mut self) -> Result<Declaration, ParseError> {
@@ -1067,12 +1096,18 @@ impl<'input, 'diagnostics> Parser<'input, 'diagnostics> {
10671096

10681097
let source = self.here();
10691098

1070-
if let Ok(declaration) = speculate!(self.input, self.parse_declaration()) {
1071-
statements.push(BlockItem {
1072-
kind: declaration.into(),
1073-
source,
1074-
});
1075-
continue;
1099+
match speculate!(self.input, self.parse_declaration()) {
1100+
Ok(declaration) => {
1101+
statements.push(BlockItem {
1102+
kind: declaration.into(),
1103+
source,
1104+
});
1105+
continue;
1106+
}
1107+
Err(error) if self.input.peek().is_static_assert_keyword() => {
1108+
return Err(error);
1109+
}
1110+
_ => (),
10761111
}
10771112

10781113
if let Ok(unlabeled_statement) =
@@ -1093,7 +1128,11 @@ impl<'input, 'diagnostics> Parser<'input, 'diagnostics> {
10931128
continue;
10941129
}
10951130

1096-
return Err(self.error("Expected '}' to end compound statement"));
1131+
return Err(ParseErrorKind::MiscGot(
1132+
"Expected '}' to end compound statement",
1133+
self.input.peek().kind.clone(),
1134+
)
1135+
.at(self.here()));
10971136
}
10981137

10991138
Ok(CompoundStatement { statements })

src/c/token.rs

+70
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::{encoding::Encoding, lexer::LexError, punctuator::Punctuator};
22
use crate::{inflow::InflowEnd, source_files::Source};
33
use derive_more::{Deref, IsVariant, Unwrap};
44
use num_bigint::BigInt;
5+
use std::fmt::Display;
56

67
#[derive(Clone, Debug, PartialEq, IsVariant, Unwrap)]
78
pub enum CTokenKind {
@@ -201,3 +202,72 @@ impl InflowEnd for CToken {
201202
matches!(&self.kind, CTokenKind::EndOfFile)
202203
}
203204
}
205+
206+
impl Display for CTokenKind {
207+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208+
match self {
209+
CTokenKind::EndOfFile => write!(f, "<end-of-file>"),
210+
CTokenKind::LexError(lex_error) => lex_error.fmt(f),
211+
CTokenKind::Identifier(identifier) => write!(f, "identifier '{}'", identifier),
212+
CTokenKind::Punctuator(punctuator) => write!(f, "'{}'", punctuator),
213+
CTokenKind::Integer(_) => write!(f, "integer literal"),
214+
CTokenKind::Float(_, _) => write!(f, "floating-point literal"),
215+
CTokenKind::CharacterConstant(_, _) => write!(f, "character literal"),
216+
CTokenKind::StringLiteral(_, _) => write!(f, "string literal"),
217+
CTokenKind::AlignasKeyword => write!(f, "'alignas' keyword"),
218+
CTokenKind::AlignofKeyword => write!(f, "'alignof' keyword"),
219+
CTokenKind::AutoKeyword => write!(f, "'auto' keyword"),
220+
CTokenKind::BoolKeyword => write!(f, "'bool' keyword"),
221+
CTokenKind::BreakKeyword => write!(f, "'break' keyword"),
222+
CTokenKind::CaseKeyword => write!(f, "'case' keyword"),
223+
CTokenKind::CharKeyword => write!(f, "'char' keyword"),
224+
CTokenKind::ConstKeyword => write!(f, "'const' keyword"),
225+
CTokenKind::ConstexprKeyword => write!(f, "'constexpr' keyword"),
226+
CTokenKind::ContinueKeyword => write!(f, "'continue' keyword"),
227+
CTokenKind::DefaultKeyword => write!(f, "'default' keyword"),
228+
CTokenKind::DoKeyword => write!(f, "'do' keyword"),
229+
CTokenKind::DoubleKeyword => write!(f, "'double' keyword"),
230+
CTokenKind::ElseKeyword => write!(f, "'else' keyword"),
231+
CTokenKind::EnumKeyword => write!(f, "'enum' keyword"),
232+
CTokenKind::ExternKeyword => write!(f, "'extern' keyword"),
233+
CTokenKind::FalseKeyword => write!(f, "'false' keyword"),
234+
CTokenKind::FloatKeyword => write!(f, "'float' keyword"),
235+
CTokenKind::ForKeyword => write!(f, "'for' keyword"),
236+
CTokenKind::GotoKeyword => write!(f, "'goto' keyword"),
237+
CTokenKind::IfKeyword => write!(f, "'if' keyword"),
238+
CTokenKind::InlineKeyword => write!(f, "'inline' keyword"),
239+
CTokenKind::IntKeyword => write!(f, "'int' keyword"),
240+
CTokenKind::LongKeyword => write!(f, "'long' keyword"),
241+
CTokenKind::NullptrKeyword => write!(f, "'nullptr' keyword"),
242+
CTokenKind::RegisterKeyword => write!(f, "'register' keyword"),
243+
CTokenKind::RestrictKeyword => write!(f, "'restrict' keyword"),
244+
CTokenKind::ReturnKeyword => write!(f, "'return' keyword"),
245+
CTokenKind::ShortKeyword => write!(f, "'short' keyword"),
246+
CTokenKind::SignedKeyword => write!(f, "'signed' keyword"),
247+
CTokenKind::SizeofKeyword => write!(f, "'sizeof' keyword"),
248+
CTokenKind::StaticKeyword => write!(f, "'static' keyword"),
249+
CTokenKind::StaticAssertKeyword => write!(f, "'static_assert' keyword"),
250+
CTokenKind::StructKeyword => write!(f, "'struct' keyword"),
251+
CTokenKind::SwitchKeyword => write!(f, "'switch' keyword"),
252+
CTokenKind::ThreadLocalKeyword => write!(f, "'thread_local' keyword"),
253+
CTokenKind::TrueKeyword => write!(f, "'true' keyword"),
254+
CTokenKind::TypedefKeyword => write!(f, "'typedef' keyword"),
255+
CTokenKind::TypeofKeyword => write!(f, "'typeof' keyword"),
256+
CTokenKind::TypeofUnqualKeyword => write!(f, "'typeof_unqual' keyword"),
257+
CTokenKind::UnionKeyword => write!(f, "'union' keyword"),
258+
CTokenKind::UnsignedKeyword => write!(f, "'unsigned' keyword"),
259+
CTokenKind::VoidKeyword => write!(f, "'void' keyword"),
260+
CTokenKind::VolatileKeyword => write!(f, "'volatile' keyword"),
261+
CTokenKind::WhileKeyword => write!(f, "'while' keyword"),
262+
CTokenKind::AtomicKeyword => write!(f, "'_Atomic' keyword"),
263+
CTokenKind::BitIntKeyword => write!(f, "'_BitInt' keyword"),
264+
CTokenKind::ComplexKeyword => write!(f, "'_Complex' keyword"),
265+
CTokenKind::Decimal128Keyword => write!(f, "'_Decimal128' keyword"),
266+
CTokenKind::Decimal32Keyword => write!(f, "'_Decimal32' keyword"),
267+
CTokenKind::Decimal64Keyword => write!(f, "'_Decimal64' keyword"),
268+
CTokenKind::GenericKeyword => write!(f, "'_Generic' keyword"),
269+
CTokenKind::ImaginaryKeyword => write!(f, "'_Imaginary' keyword"),
270+
CTokenKind::NoreturnKeyword => write!(f, "'_Noreturn' keyword"),
271+
}
272+
}
273+
}

src/c/translate/function.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
ast::{self, Func, FuncHead, Param, Params},
55
c::{
66
ast::{
7-
Attribute, BlockItem, BlockItemKind, CTypedef, CompoundStatement,
7+
Attribute, BlockItem, BlockItemKind, CTypedef, CompoundStatement, Declaration,
88
DeclarationSpecifiers, Declarator, ExprStatement, JumpStatement,
99
ParameterDeclarationCore, ParameterTypeList, StorageClassSpecifier, UnlabeledStatement,
1010
},
@@ -135,7 +135,16 @@ fn translate_block_item(
135135
block_item: &BlockItem,
136136
) -> Result<ast::Stmt, ParseError> {
137137
match &block_item.kind {
138-
BlockItemKind::Declaration(_) => todo!("translate_block_item declaration"),
138+
BlockItemKind::Declaration(declaration) => match declaration {
139+
Declaration::Common(_) => todo!("translate_block_item common declaration"),
140+
Declaration::StaticAssert(static_assert) => Ok(ast::ExprKind::StaticAssert(
141+
Box::new(translate_expr(ctx, &static_assert.condition.value)?),
142+
static_assert.message.clone(),
143+
)
144+
.at(block_item.source)
145+
.stmt()),
146+
Declaration::Attribute(_) => todo!("translate_block_item attribute declaration"),
147+
},
139148
BlockItemKind::UnlabeledStatement(unlabeled_statement) => {
140149
translate_unlabeled_statement(ctx, unlabeled_statement, block_item.source)
141150
}

src/resolve/expr/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,13 @@ pub fn resolve_expr(
512512

513513
return Ok(inner);
514514
}
515+
ast::ExprKind::StaticAssert(_condition, _message) => {
516+
todo!(
517+
"resolve_expr - static_assert - {:?} {:?}",
518+
_condition,
519+
_message
520+
)
521+
}
515522
}?;
516523

517524
match initialized {

0 commit comments

Comments
 (0)