Skip to content

Commit 68baab7

Browse files
committed
Implement format
1 parent 9e4adb2 commit 68baab7

File tree

5 files changed

+144
-11
lines changed

5 files changed

+144
-11
lines changed

src/logic/ast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub enum Instruction {
2929
PrintChar {
3030
value: Value,
3131
},
32+
Format {
33+
value: Value,
34+
},
3235
// operations
3336
Set {
3437
to: Value,

src/logic/grammar.lalrpop

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ match {
1717
"draw",
1818
"print",
1919
"printchar",
20+
"format",
2021
"set",
2122
"noop",
2223
"wait",
@@ -118,10 +119,13 @@ Instruction: Instruction = {
118119

119120
"print" <value:Value> =>
120121
Instruction::Print { <> },
121-
122+
122123
"printchar" <value:Value> =>
123124
Instruction::PrintChar { <> },
124125

126+
"format" <value:Value> =>
127+
Instruction::Format { <> },
128+
125129
// operations
126130

127131
"set" <to:Value> <from:Value> =>
@@ -271,6 +275,7 @@ Symbol = {
271275
"draw",
272276
"print",
273277
"printchar",
278+
"format",
274279
"set",
275280
"noop",
276281
"wait",

src/logic/vm/instructions.rs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub fn parse_instruction(
6060
ast::Instruction::Draw { .. } => Box::new(Noop),
6161
ast::Instruction::Print { value } => Box::new(Print { value: lvar(value) }),
6262
ast::Instruction::PrintChar { value } => Box::new(PrintChar { value: lvar(value) }),
63+
ast::Instruction::Format { value } => Box::new(Format { value: lvar(value) }),
6364

6465
// operations
6566
ast::Instruction::Set { to, from } => Box::new(Set {
@@ -143,10 +144,12 @@ impl Print {
143144

144145
impl SimpleInstruction for Print {
145146
fn execute(&self, state: &mut ProcessorState, _: &LogicVM) {
146-
if state.printbuffer.len() < MAX_TEXT_BUFFER {
147-
let value = self.value.get(state);
148-
state.append_printbuffer(&Print::to_string(&value));
147+
if state.printbuffer.len() >= MAX_TEXT_BUFFER {
148+
return;
149149
}
150+
151+
let value = self.value.get(state);
152+
state.append_printbuffer(&Print::to_string(&value));
150153
}
151154
}
152155

@@ -156,13 +159,53 @@ struct PrintChar {
156159

157160
impl SimpleInstruction for PrintChar {
158161
fn execute(&self, state: &mut ProcessorState, _: &LogicVM) {
159-
if state.printbuffer.len() < MAX_TEXT_BUFFER {
160-
// TODO: content emojis
161-
if let LValue::Number(c) = self.value.get(state) {
162-
// Java converts from float to char via int, not directly
163-
state.printbuffer.push(c.floor() as u32 as u16);
162+
if state.printbuffer.len() >= MAX_TEXT_BUFFER {
163+
return;
164+
}
165+
166+
// TODO: content emojis
167+
if let LValue::Number(c) = self.value.get(state) {
168+
// Java converts from float to char via int, not directly
169+
state.printbuffer.push(c.floor() as u32 as u16);
170+
}
171+
}
172+
}
173+
174+
struct Format {
175+
value: LVar,
176+
}
177+
178+
impl SimpleInstruction for Format {
179+
fn execute(&self, state: &mut ProcessorState, _: &LogicVM) {
180+
if state.printbuffer.len() >= MAX_TEXT_BUFFER {
181+
return;
182+
}
183+
184+
let mut placeholder_index = MAX_TEXT_BUFFER;
185+
let mut placeholder_number = 10;
186+
187+
for (i, vals) in state.printbuffer.windows(3).enumerate() {
188+
let &[left, c, right] = vals else {
189+
unreachable!()
190+
};
191+
if left == ('{' as u16) && right == ('}' as u16) {
192+
let n = (c as i32) - ('0' as i32);
193+
if (0..=9).contains(&n) && n < placeholder_number {
194+
placeholder_number = n;
195+
placeholder_index = i;
196+
}
164197
}
165198
}
199+
200+
if placeholder_index == MAX_TEXT_BUFFER {
201+
return;
202+
}
203+
204+
let value = self.value.get(state);
205+
state.printbuffer.splice(
206+
placeholder_index..placeholder_index + 3,
207+
ProcessorState::encode_utf16(&Print::to_string(&value)),
208+
);
166209
}
167210
}
168211

src/logic/vm/mod.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,4 +634,78 @@ mod tests {
634634
]
635635
);
636636
}
637+
638+
#[test]
639+
fn test_format() {
640+
let mut vm = single_processor_vm(
641+
BlockType::MicroProcessor,
642+
r#"
643+
print "{0} {2} {/} {3} {:} {10} {1}"
644+
noop
645+
646+
format 4
647+
noop
648+
649+
format "abcde"
650+
noop
651+
652+
format "aa"
653+
noop
654+
655+
format ""
656+
noop
657+
658+
format "ignored"
659+
stop
660+
"#,
661+
);
662+
663+
vm.do_tick(Duration::ZERO);
664+
665+
with_processor(&mut vm, 0, |p| {
666+
assert_eq!(
667+
p.state.decode_printbuffer(),
668+
r#"{0} {2} {/} {3} {:} {10} {1}"#
669+
);
670+
});
671+
672+
vm.do_tick(Duration::ZERO);
673+
674+
with_processor(&mut vm, 0, |p| {
675+
assert_eq!(
676+
p.state.decode_printbuffer(),
677+
r#"4 {2} {/} {3} {:} {10} {1}"#
678+
);
679+
});
680+
681+
vm.do_tick(Duration::ZERO);
682+
683+
with_processor(&mut vm, 0, |p| {
684+
assert_eq!(
685+
p.state.decode_printbuffer(),
686+
r#"4 {2} {/} {3} {:} {10} abcde"#
687+
);
688+
});
689+
690+
vm.do_tick(Duration::ZERO);
691+
692+
with_processor(&mut vm, 0, |p| {
693+
assert_eq!(
694+
p.state.decode_printbuffer(),
695+
r#"4 aa {/} {3} {:} {10} abcde"#
696+
);
697+
});
698+
699+
vm.do_tick(Duration::ZERO);
700+
701+
with_processor(&mut vm, 0, |p| {
702+
assert_eq!(p.state.decode_printbuffer(), r#"4 aa {/} {:} {10} abcde"#);
703+
});
704+
705+
vm.do_tick(Duration::ZERO);
706+
707+
with_processor(&mut vm, 0, |p| {
708+
assert_eq!(p.state.decode_printbuffer(), r#"4 aa {/} {:} {10} abcde"#);
709+
});
710+
}
637711
}

src/logic/vm/processor.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,20 @@ impl ProcessorState {
112112
self.time.get() * 60. / 1000.
113113
}
114114

115+
pub fn encode_utf16(value: &str) -> impl Iterator<Item = u16> {
116+
value.encode_utf16()
117+
}
118+
119+
pub fn decode_utf16(value: &[u16]) -> String {
120+
String::from_utf16_lossy(value)
121+
}
122+
115123
pub fn append_printbuffer(&mut self, value: &str) {
116-
self.printbuffer.extend(value.encode_utf16())
124+
self.printbuffer.extend(Self::encode_utf16(value))
117125
}
118126

119127
pub fn decode_printbuffer(&self) -> String {
120-
String::from_utf16_lossy(&self.printbuffer)
128+
Self::decode_utf16(&self.printbuffer)
121129
}
122130
}
123131

0 commit comments

Comments
 (0)