diff --git a/Cargo.lock b/Cargo.lock index 62809f1..0f36d89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,7 +288,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mindustry_logic_bang_lang" -version = "0.13.1" +version = "0.13.2" dependencies = [ "display_source", "lalrpop", diff --git a/Cargo.toml b/Cargo.toml index 9882fd0..72a2660 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindustry_logic_bang_lang" -version = "0.13.1" +version = "0.13.2" edition = "2021" authors = ["A4-Tacks "] diff --git a/examples/switch.mdtlbl b/examples/switch.mdtlbl index 4fe8110..0060dce 100644 --- a/examples/switch.mdtlbl +++ b/examples/switch.mdtlbl @@ -1,10 +1,17 @@ +#** +* 一种在常量时间内直接跳转至第不小于零的整数代码段的分支选择方式 +* +* case后面接的是id, 表明了第几段代码, 可以写多个 +* 如果不写的话, 则为上一段代码的id+1, 没有上一段代码的话则为0 +*# + i = 4; switch i { case 1 2: print "1 or 2\n"; print "foo"; break; - case 3: + case: # 省略 print "3\n"; break; case 5: diff --git a/src/syntax/def.lalrpop b/src/syntax/def.lalrpop index cce2194..bbc6809 100644 --- a/src/syntax/def.lalrpop +++ b/src/syntax/def.lalrpop @@ -759,7 +759,7 @@ pub Control: LogicLine = { )*> <( // cases "case" - + ":" )+> @@ -769,17 +769,23 @@ pub Control: LogicLine = { let (append, catchs, cases) = cases; let catchs_is_empty = catchs.is_empty(); + let mut next_case_num = 0; let case_num_max = cases .iter() .map( - |(nums, _)| *nums - .iter() - .max() - .unwrap() + |(nums, _)| { + let num = nums + .iter() + .max() + .copied() + .unwrap_or(next_case_num); + next_case_num = num + 1; + num + } ) .max() .unwrap(); - let mut cases_res = Vec::with_capacity(case_num_max); + let mut cases_res = Vec::with_capacity(case_num_max + 1); // 用于填充填充case的行, 如果有追加在末尾的行则将其封装并替换填充 let mut fill_line = append @@ -835,18 +841,22 @@ pub Control: LogicLine = { catch_lines.push(Expand(out_block).into()) } - for (nums, mut expand) in cases { + let mut next_ignored_num = 0; + for (mut nums, mut expand) in cases { if let Some(append) = &append { expand.push(append.clone()) } + if nums.is_empty() { nums.push(next_ignored_num) } for num in nums { for _ in cases_res.len()..=num { cases_res.push(fill_line.clone()) } - cases_res[num] = expand.clone().into() + cases_res[num] = expand.clone().into(); + next_ignored_num = num + 1; } } debug_assert_eq!(cases_res.len(), case_num_max + 1); + debug_assert_eq!(cases_res.len(), cases_res.capacity()); let (break_lab, continue_lab) = ctrl; if catchs_is_empty { diff --git a/src/syntax/tests.rs b/src/syntax/tests.rs index 7d0b891..24b26de 100644 --- a/src/syntax/tests.rs +++ b/src/syntax/tests.rs @@ -3594,3 +3594,76 @@ fn mul_consts_test() { "#).unwrap(), ); } + +#[test] +fn switch_ignored_id_test() { + let parser = TopLevelParser::new(); + + assert_eq!( + parse!(parser, r#" + switch x { + case: foo; + case: bar; + case: baz; + } + "#).unwrap(), + parse!(parser, r#" + switch x { + case 0: foo; + case 1: bar; + case 2: baz; + } + "#).unwrap(), + ); + + assert_eq!( + parse!(parser, r#" + switch x { + case 1: foo; + case: bar; + case: baz; + } + "#).unwrap(), + parse!(parser, r#" + switch x { + case 1: foo; + case 2: bar; + case 3: baz; + } + "#).unwrap(), + ); + + assert_eq!( + parse!(parser, r#" + switch x { + case: foo; + case 2: bar; + case: baz; + } + "#).unwrap(), + parse!(parser, r#" + switch x { + case 0: foo; + case 2: bar; + case 3: baz; + } + "#).unwrap(), + ); + + assert_eq!( + parse!(parser, r#" + switch x { + case 0 2 4: foo; + case: bar; + case: baz; + } + "#).unwrap(), + parse!(parser, r#" + switch x { + case 0 2 4: foo; + case 5: bar; + case 6: baz; + } + "#).unwrap(), + ); +}