Skip to content

Commit dc12c3a

Browse files
committed
(ctrl flow) fix: non-braced block and user-defined types
1 parent 26168a9 commit dc12c3a

File tree

6 files changed

+120
-54
lines changed

6 files changed

+120
-54
lines changed

src/parser/keyword/control_flow/keyword.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,17 @@ impl From<ControlFlowKeyword> for ControlFlowNode {
7676
match keyword {
7777
ControlFlowKeyword::Break | ControlFlowKeyword::Continue => Self::SemiColon(keyword),
7878
ControlFlowKeyword::Case | ControlFlowKeyword::Default | ControlFlowKeyword::Goto => {
79-
Self::ColonAst(keyword, None)
79+
Self::ColonAst(keyword, None, false)
8080
}
8181
ControlFlowKeyword::For
8282
| ControlFlowKeyword::While
8383
| ControlFlowKeyword::Switch
84-
| ControlFlowKeyword::If => Self::ParensBlock(keyword, None, None),
84+
| ControlFlowKeyword::If => {
85+
Self::ParensBlock(keyword, None, Box::from(Ast::Empty), false)
86+
}
8587
// block
8688
ControlFlowKeyword::Do | ControlFlowKeyword::Else | ControlFlowKeyword::Return => {
87-
Self::Ast(keyword, Box::from(Ast::Empty))
89+
Self::Ast(keyword, Box::from(Ast::Empty), false)
8890
}
8991
// special
9092
ControlFlowKeyword::Typedef => Self::ControlFlow(keyword, None),

src/parser/keyword/control_flow/node.rs

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,80 @@ use crate::parser::{repr_option, repr_vec};
1313
#[derive(Debug, PartialEq)]
1414
pub enum ControlFlowNode {
1515
/// Keyword expects a node: `return 3+4`
16-
Ast(ControlFlowKeyword, Box<Ast>),
16+
Ast(ControlFlowKeyword, Box<Ast>, bool),
1717
/// Keyword expects a colon and a node: `goto: label`
18-
ColonAst(ControlFlowKeyword, Option<Box<Ast>>),
18+
ColonAst(ControlFlowKeyword, Option<Box<Ast>>, bool),
1919
/// Keyword expects another control flow: `typedef struct`
2020
ControlFlow(ControlFlowKeyword, Option<Box<ControlFlowNode>>),
2121
/// Keyword expects an identifier and a braced block: `struct Blob {}`
2222
IdentBlock(ControlFlowKeyword, Option<String>, Option<BracedBlock>),
2323
/// Keyword expects a parenthesised block and a braced block: `switch (cond)
2424
/// {};`
25-
ParensBlock(ControlFlowKeyword, Option<ParensBlock>, Option<BracedBlock>),
25+
ParensBlock(ControlFlowKeyword, Option<ParensBlock>, Box<Ast>, bool),
2626
/// Keyword expects a semicolon: `break;`
2727
SemiColon(ControlFlowKeyword),
2828
}
2929

3030
impl ControlFlowNode {
31+
/// Sets the control flow to full
32+
pub fn fill(&mut self) {
33+
match self {
34+
Self::Ast(.., full) | Self::ColonAst(.., full) | Self::ParensBlock(.., full) => {
35+
*full = true;
36+
}
37+
Self::ControlFlow(..) | Self::IdentBlock(..) | Self::SemiColon(..) => (),
38+
}
39+
}
40+
41+
/// Function to return an [`Ast`], if exists
42+
pub const fn get_ast(&mut self) -> Option<&mut Box<Ast>> {
43+
match self {
44+
Self::ColonAst(_, Some(ast), false)
45+
| Self::ParensBlock(.., ast, false)
46+
| Self::Ast(_, ast, false) => Some(ast),
47+
Self::ControlFlow(..)
48+
| Self::IdentBlock(..)
49+
| Self::SemiColon(_)
50+
| Self::ParensBlock(.., true)
51+
| Self::ColonAst(.., true)
52+
| Self::ColonAst(_, None, false)
53+
| Self::Ast(.., true) => None,
54+
}
55+
}
56+
3157
/// Get keyword from node
3258
pub const fn get_keyword(&self) -> &ControlFlowKeyword {
3359
match self {
34-
Self::Ast(keyword, _)
35-
| Self::ColonAst(keyword, _)
60+
Self::Ast(keyword, ..)
61+
| Self::ColonAst(keyword, ..)
3662
| Self::ControlFlow(keyword, _)
37-
| Self::IdentBlock(keyword, _, _)
38-
| Self::ParensBlock(keyword, _, _)
63+
| Self::IdentBlock(keyword, ..)
64+
| Self::ParensBlock(keyword, ..)
3965
| Self::SemiColon(keyword) => keyword,
4066
}
4167
}
4268

69+
///Checks if the control flow is empty
70+
pub fn is_empty(&self) -> bool {
71+
match self {
72+
Self::Ast(_, node, full) => **node == Ast::Empty && !*full,
73+
Self::ColonAst(_, node, full) => node.is_none() && !*full,
74+
Self::ControlFlow(_, node) => node.is_none(),
75+
Self::IdentBlock(_, ident, node) => node.is_none() && ident.is_none(),
76+
Self::ParensBlock(_, parens, braced, full) => {
77+
parens.is_none() && **braced != Ast::Empty && !*full
78+
}
79+
Self::SemiColon(_) => true,
80+
}
81+
}
82+
4383
/// Checks if the control flow is full
4484
pub const fn is_full(&self) -> bool {
4585
match self {
46-
Self::Ast(..) | Self::ColonAst(..) => false,
86+
Self::Ast(.., full) | Self::ColonAst(.., full) => *full,
4787
Self::ControlFlow(_, node) => node.is_some(),
4888
Self::IdentBlock(_, ident, node) => node.is_some() && ident.is_some(),
49-
Self::ParensBlock(_, parens, braced) => parens.is_some() && braced.is_some(),
89+
Self::ParensBlock(_, parens, _, full) => parens.is_some() && *full,
5090
Self::SemiColon(_) => true,
5191
}
5292
}
@@ -56,16 +96,20 @@ impl ControlFlowNode {
5696
/// See [`Ast::push_block_as_leaf`] for more information.
5797
pub fn push_block_as_leaf(&mut self, node: Ast) -> Result<(), String> {
5898
match self {
59-
Self::Ast(_, ast) | Self::ColonAst(_, Some(ast)) => ast.push_block_as_leaf(node)?,
60-
Self::ColonAst(keyword, None) => return Err(format!("Missing colon after {keyword}.")),
99+
Self::Ast(_, ast, false)
100+
| Self::ColonAst(_, Some(ast), false)
101+
| Self::ParensBlock(_, Some(_), ast, false) => ast.push_block_as_leaf(node)?,
102+
Self::ColonAst(keyword, None, false) => {
103+
return Err(format!("Missing colon after {keyword}."));
104+
}
61105
Self::ControlFlow(keyword, old_ctrl @ None) => {
62106
if let Ast::ControlFlow(node_ctrl) = node {
63107
*old_ctrl = Some(Box::from(node_ctrl));
64108
} else {
65109
return Err(format!("{keyword} expected a keyword but found {node}",));
66110
}
67111
}
68-
Self::ParensBlock(keyword, old_parens @ None, None) => {
112+
Self::ParensBlock(keyword, old_parens @ None, _, false) => {
69113
if let Ast::ParensBlock(node_parens) = node {
70114
*old_parens = Some(node_parens);
71115
} else {
@@ -74,8 +118,7 @@ impl ControlFlowNode {
74118
));
75119
}
76120
}
77-
Self::ParensBlock(_, Some(_), old_block @ None)
78-
| Self::IdentBlock(_, Some(_), old_block @ None) => {
121+
Self::IdentBlock(_, Some(_), old_block @ None) => {
79122
if let Ast::BracedBlock(mut node_block) = node {
80123
node_block.full = true;
81124
*old_block = Some(node_block);
@@ -104,8 +147,10 @@ impl ControlFlowNode {
104147
}
105148
}
106149
}
107-
Self::ControlFlow(_, Some(_))
108-
| Self::ParensBlock(_, _, Some(_))
150+
Self::Ast(.., true)
151+
| Self::ColonAst(.., true)
152+
| Self::ControlFlow(_, Some(_))
153+
| Self::ParensBlock(..)
109154
| Self::IdentBlock(_, _, Some(_))
110155
| Self::SemiColon(_) => {
111156
panic!("Tried to push not on full block, but it is not pushable")
@@ -116,7 +161,7 @@ impl ControlFlowNode {
116161

117162
/// Tries to push a colon inside the control flow node.
118163
pub fn push_colon(&mut self) -> Result<(), String> {
119-
if let Self::ColonAst(_, node @ None) = self {
164+
if let Self::ColonAst(_, node @ None, false) = self {
120165
*node = Some(Box::from(Ast::Empty));
121166
Ok(())
122167
} else {
@@ -129,8 +174,9 @@ impl ControlFlowNode {
129174
/// See [`Ast::push_op`] for more information.
130175
pub fn push_op<T: fmt::Display + OperatorConversions>(&mut self, op: T) -> Result<(), String> {
131176
match self {
132-
Self::Ast(_, ast) | Self::ColonAst(_, Some(ast)) => ast.push_op(op),
133-
Self::ColonAst(..)
177+
Self::Ast(_, ast, false) | Self::ColonAst(_, Some(ast), false) => ast.push_op(op),
178+
Self::Ast(..)
179+
| Self::ColonAst(..)
134180
| Self::ControlFlow(..)
135181
| Self::IdentBlock(..)
136182
| Self::ParensBlock(..)
@@ -146,9 +192,16 @@ impl ControlFlowNode {
146192
impl fmt::Display for ControlFlowNode {
147193
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148194
match self {
149-
Self::Ast(keyword, ast) => write!(f, "({keyword} {ast})"),
150-
Self::ColonAst(keyword, ast) => {
151-
write!(f, "({keyword}: {})", repr_option(ast))
195+
Self::Ast(keyword, ast, full) => {
196+
write!(f, "({keyword} {ast}{})", if *full { ".." } else { "" })
197+
}
198+
Self::ColonAst(keyword, ast, full) => {
199+
write!(
200+
f,
201+
"({keyword}: {}{})",
202+
repr_option(ast),
203+
if *full { ".." } else { "" }
204+
)
152205
}
153206
Self::ControlFlow(keyword, ctrl) => {
154207
write!(f, "({keyword} {})", repr_option(ctrl))
@@ -159,12 +212,12 @@ impl fmt::Display for ControlFlowNode {
159212
repr_option(ident),
160213
repr_option(block)
161214
),
162-
Self::ParensBlock(keyword, parens_block, block) => {
215+
Self::ParensBlock(keyword, parens_block, ast, full) => {
163216
write!(
164217
f,
165-
"({keyword} {} {})",
218+
"({keyword} {} {ast}{})",
166219
repr_option(parens_block),
167-
repr_option(block)
220+
if *full { ".." } else { "" }
168221
)
169222
}
170223
Self::SemiColon(keyword) => write!(f, "({keyword})"),

src/parser/modifiers/ast.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,7 @@ impl Ast {
124124
full: true,
125125
}
126126
};
127-
*self = Self::ControlFlow(attr.to_control_flow(
128-
name.ok_or_else(|| {
129-
format!("Found block {braced_block} after {attr:?}. Missing type name.")
130-
})?,
131-
braced_block,
132-
));
127+
*self = Self::ControlFlow(attr.to_control_flow(name, braced_block));
133128
Ok(())
134129
} else {
135130
Err(format!(
@@ -209,10 +204,19 @@ impl Ast {
209204
#[expect(clippy::wildcard_enum_match_arm)]
210205
match self {
211206
Self::BracedBlock(BracedBlock { elts, full: false }) => {
212-
if let Some(Self::ControlFlow(ctrl)) = elts.last_mut()
207+
let last_mut = elts.last_mut();
208+
if let Some(Self::ControlFlow(ctrl)) = last_mut
213209
&& !ctrl.is_full()
214210
{
215211
ctrl.push_block_as_leaf(node)?;
212+
} else if let Some(Self::Leaf(Literal::Variable(var))) = last_mut
213+
&& let Some((keyword, name)) = var.get_typedef()?
214+
{
215+
if let Self::BracedBlock(block) = node {
216+
*self = Self::ControlFlow(keyword.to_control_flow(name, block));
217+
} else {
218+
panic!("see above: still block")
219+
}
216220
} else {
217221
elts.push(node);
218222
}

src/parser/modifiers/functions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ fn get_last_variable(current: &mut Ast) -> Option<&mut Ast> {
2727
// failure
2828
Ast::Empty
2929
| Ast::Leaf(_)
30-
| Ast::ControlFlow(_)
3130
| Ast::ParensBlock(_)
3231
| Ast::BracedBlock(BracedBlock { full: true, .. })
3332
| Ast::Ternary(Ternary { failure: None, .. })
@@ -49,6 +48,7 @@ fn get_last_variable(current: &mut Ast) -> Option<&mut Ast> {
4948
| Ast::BracedBlock(BracedBlock { elts: vec, .. }) => {
5049
vec.last_mut().and_then(get_last_variable)
5150
}
51+
Ast::ControlFlow(ctrl) => ctrl.get_ast().and_then(|ast| get_last_variable(ast)),
5252
}
5353
}
5454

src/parser/types/literal.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,27 +74,23 @@ impl Variable {
7474
/// `struct Name` is parsed as a variable attributes `struct` and `Name` and
7575
/// is waiting for the variable name. But if the next token is block, like
7676
/// in `struct Name {}`, it is meant as a control flow to define the type.
77-
pub fn get_typedef(&mut self) -> Result<Option<(&UserDefinedTypes, Option<String>)>, String> {
78-
match self.attrs.as_mut_slice() {
79-
[Attribute::Keyword(AttributeKeyword::UserDefinedTypes(user_type))] => {
80-
Ok(Some((user_type, None)))
77+
pub fn get_typedef(&mut self) -> Result<Option<(&UserDefinedTypes, String)>, String> {
78+
if self.attrs.len() == 1
79+
&& let Some(Attribute::Keyword(AttributeKeyword::UserDefinedTypes(user_type))) =
80+
self.attrs.last()
81+
{
82+
if let VariableName::UserDefined(name) = &mut self.name {
83+
Ok(Some((user_type, mem::take(name))))
84+
} else {
85+
Err(format!("Missing type name after {user_type:?}."))
8186
}
82-
[
83-
Attribute::Keyword(AttributeKeyword::UserDefinedTypes(user_type)),
84-
Attribute::User(name),
85-
] => Ok(Some((user_type, Some(mem::take(name))))),
86-
[
87-
Attribute::Keyword(AttributeKeyword::UserDefinedTypes(user_type)),
88-
attr,
89-
] => Err(format!(
90-
"{user_type:?} followed by {attr}. {attr} is not a valid type name."
91-
)),
92-
[..] => Ok(None),
87+
} else {
88+
Ok(None)
9389
}
9490
}
9591

9692
/// Adds an attribute to the variable
97-
pub fn push_attr(&mut self, attr: Attribute) -> Result<(), String> {
93+
fn push_attr(&mut self, attr: Attribute) -> Result<(), String> {
9894
match mem::take(&mut self.name) {
9995
VariableName::Empty => (),
10096
VariableName::Keyword(keyword) => {
@@ -126,7 +122,7 @@ impl Variable {
126122
Ok(())
127123
}
128124
VariableName::Keyword(keyword) => Err(format!(
129-
"Found 2 successive literals, found identifier {name} after function keuword {keyword}."
125+
"Found 2 successive literals, found identifier {name} after function keyword {keyword}."
130126
)),
131127
VariableName::UserDefined(old) => {
132128
self.attrs.push(Attribute::User(old));

tests/strings.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,23 @@ function_argument_priority:
183183
=>
184184
"[(main°((!(f°((x + y), (!u)))), (g°((f°((h°(x, y)), z)), t)), u))..]"
185185

186+
for_loops:
187+
"for(int i = 0; i < 9+1; i++) printf(\"i = %d\", i);"
188+
=>
189+
"[(for ([((int i) = 0), (i < (9 + 1)), (i++)..]) (printf°(\"i = %d\", i))), \u{2205} ..]"
190+
191+
structs:
192+
"struct A { int x };
193+
struct A a;"
194+
=>
195+
"[(struct A [(int x)]), (struct A a), \u{2205} ..]"
196+
186197
successive_ctrl_flow:
187198
"break;
188199
return 0*1;
189200
for(int x = 2; x<10;x++) x"
190201
=>
191-
"[(break), (return (0 * 1)), (for ([((int x) = 2), (x < 10), (x++)..]) [x])..]"
202+
"[(break), (return (0 * 1)), (for ([((int x) = 2), (x < 10), (x++)..]) x)..]"
192203
);
193204

194205
macro_rules! make_string_error_tests {

0 commit comments

Comments
 (0)