Skip to content

Commit 13e1652

Browse files
committed
Implement select
1 parent 395f24d commit 13e1652

File tree

5 files changed

+170
-69
lines changed

5 files changed

+170
-69
lines changed

src/logic/ast.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ pub enum Instruction {
3737
to: Value,
3838
from: Value,
3939
},
40+
Select {
41+
result: Value,
42+
op: ConditionOp,
43+
x: Value,
44+
y: Value,
45+
if_true: Value,
46+
if_false: Value,
47+
},
4048
PackColor {
4149
result: Value,
4250
r: Value,

src/logic/grammar.lalrpop

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ match {
1919
"printchar",
2020
"format",
2121
"set",
22+
"select",
2223
"packcolor",
2324
"unpackcolor",
2425
"noop",
@@ -133,6 +134,12 @@ Instruction: Instruction = {
133134
"set" <to:Value> <from:Value> =>
134135
Instruction::Set { <> },
135136

137+
"select" <result:Value> <op:ConditionOp0> <x:Value> <y:Value> <if_true:Value> =>
138+
optional_args!(Instruction::Select { <>; if_false }),
139+
140+
"select" <result:Value> <op:ConditionOp2> <x:Value> <y:Value> <if_true:Value> <if_false:Value> =>
141+
Instruction::Select { <> },
142+
136143
"packcolor" <result:Value> <r:Value> <g:Value> <b:Value> <a:Value> =>
137144
Instruction::PackColor { <> },
138145

@@ -285,6 +292,7 @@ Symbol = {
285292
"printchar",
286293
"format",
287294
"set",
295+
"select",
288296
"packcolor",
289297
"unpackcolor",
290298
"noop",

src/logic/vm/instructions.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,21 @@ pub fn parse_instruction(
7070
to: lvar(to),
7171
from: lvar(from),
7272
}),
73+
ast::Instruction::Select {
74+
result,
75+
op,
76+
x,
77+
y,
78+
if_true,
79+
if_false,
80+
} => Box::new(Select {
81+
result: lvar(result),
82+
op,
83+
x: lvar(x),
84+
y: lvar(y),
85+
if_true: lvar(if_true),
86+
if_false: lvar(if_false),
87+
}),
7388
ast::Instruction::PackColor { result, r, g, b, a } => Box::new(PackColor {
7489
result: lvar(result),
7590
r: lvar(r),
@@ -235,7 +250,27 @@ struct Set {
235250

236251
impl SimpleInstruction for Set {
237252
fn execute(&self, state: &mut ProcessorState, _: &LogicVM) {
238-
self.to.set(state, self.from.get(state));
253+
self.to.set_from(state, &self.from);
254+
}
255+
}
256+
257+
struct Select {
258+
result: LVar,
259+
op: ConditionOp,
260+
x: LVar,
261+
y: LVar,
262+
if_true: LVar,
263+
if_false: LVar,
264+
}
265+
266+
impl SimpleInstruction for Select {
267+
fn execute(&self, state: &mut ProcessorState, _: &LogicVM) {
268+
let result = if Jump::test(self.op, &self.x, &self.y, state) {
269+
&self.if_true
270+
} else {
271+
&self.if_false
272+
};
273+
self.result.set_from(state, result);
239274
}
240275
}
241276

@@ -330,7 +365,14 @@ struct Jump {
330365
}
331366

332367
impl Jump {
333-
fn test(op: ConditionOp, x: LValue, y: LValue) -> bool {
368+
fn test(op: ConditionOp, x: &LVar, y: &LVar, state: &mut ProcessorState) -> bool {
369+
if matches!(op, ConditionOp::Always) {
370+
return true;
371+
}
372+
373+
let x = x.get(state);
374+
let y = y.get(state);
375+
334376
match op {
335377
ConditionOp::Equal => {
336378
if x.isobj() && y.isobj() {
@@ -351,14 +393,14 @@ impl Jump {
351393
ConditionOp::GreaterThan => x.num() > y.num(),
352394
ConditionOp::GreaterThanEq => x.num() >= y.num(),
353395
ConditionOp::StrictEqual => x == y,
354-
ConditionOp::Always => true,
396+
ConditionOp::Always => unreachable!(),
355397
}
356398
}
357399
}
358400

359401
impl SimpleInstruction for Jump {
360402
fn execute(&self, state: &mut ProcessorState, _: &LogicVM) {
361-
if Jump::test(self.op, self.x.get(state), self.y.get(state)) {
403+
if Self::test(self.op, &self.x, &self.y, state) {
362404
// we do the bounds check while parsing
363405
state.counter = self.target;
364406
}

src/logic/vm/mod.rs

Lines changed: 104 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,69 @@ mod tests {
421421
assert_eq!(processor.state.ipt, 2);
422422
}
423423

424+
const CONDITION_TESTS: &[(&str, &str, &str, bool)] = &[
425+
// equal
426+
("equal", "0", "0", true),
427+
("equal", "0", "null", true),
428+
("equal", "1", r#""""#, true),
429+
("equal", "1", r#""foo""#, true),
430+
("equal", r#""""#, r#""""#, true),
431+
("equal", r#""abc""#, r#""abc""#, true),
432+
("equal", "null", "null", true),
433+
("equal", "0", "0.0000009", true),
434+
("equal", "@pi", "3.1415927", true),
435+
("equal", "π", "3.1415927", true),
436+
("equal", "@e", "2.7182818", true),
437+
("equal", "0", "0.000001", false),
438+
("equal", "0", "1", false),
439+
("equal", "1", "null", false),
440+
("equal", r#""abc""#, r#""def""#, false),
441+
// notEqual
442+
("notEqual", "0", "0", false),
443+
("notEqual", "0", "null", false),
444+
("notEqual", "null", "null", false),
445+
("notEqual", "0", "0.0000009", false),
446+
("notEqual", "0", "0.000001", true),
447+
("notEqual", "0", "1", true),
448+
("notEqual", "1", "null", true),
449+
// lessThan
450+
("lessThan", "0", "1", true),
451+
("lessThan", "0", "0", false),
452+
("lessThan", "1", "0", false),
453+
// lessThanEq
454+
("lessThanEq", "0", "1", true),
455+
("lessThanEq", "0", "0", true),
456+
("lessThanEq", "1", "0", false),
457+
// greaterThan
458+
("greaterThan", "0", "1", false),
459+
("greaterThan", "0", "0", false),
460+
("greaterThan", "1", "0", true),
461+
// greaterThanEq
462+
("greaterThanEq", "0", "1", false),
463+
("greaterThanEq", "0", "0", true),
464+
("greaterThanEq", "1", "0", true),
465+
// strictEqual
466+
("strictEqual", "0", "0", true),
467+
("strictEqual", "0.5", "0.5", true),
468+
("strictEqual", "@pi", "3.1415927", true),
469+
("strictEqual", "null", "null", true),
470+
("strictEqual", r#""""#, r#""""#, true),
471+
("strictEqual", r#""abc""#, r#""abc""#, true),
472+
("strictEqual", "0", "null", false),
473+
("strictEqual", "1", r#""""#, false),
474+
("strictEqual", "1", r#""foo""#, false),
475+
("strictEqual", r#""abc""#, r#""def""#, false),
476+
("strictEqual", "0", "0.0000009", false),
477+
("strictEqual", "0", "0.000001", false),
478+
("strictEqual", "0", "1", false),
479+
("strictEqual", "1", "null", false),
480+
// always
481+
("always", "0", "0", true),
482+
("always", "0", "1", true),
483+
("always", "1", "0", true),
484+
("always", "1", "1", true),
485+
];
486+
424487
#[test]
425488
fn test_jump() {
426489
let mut code = r#"
@@ -447,71 +510,7 @@ mod tests {
447510
"#
448511
.to_string();
449512

450-
for (i, (cond, x, y, want_jump)) in [
451-
// equal
452-
("equal", "0", "0", true),
453-
("equal", "0", "null", true),
454-
("equal", "1", r#""""#, true),
455-
("equal", "1", r#""foo""#, true),
456-
("equal", r#""""#, r#""""#, true),
457-
("equal", r#""abc""#, r#""abc""#, true),
458-
("equal", "null", "null", true),
459-
("equal", "0", "0.0000009", true),
460-
("equal", "@pi", "3.1415927", true),
461-
("equal", "π", "3.1415927", true),
462-
("equal", "@e", "2.7182818", true),
463-
("equal", "0", "0.000001", false),
464-
("equal", "0", "1", false),
465-
("equal", "1", "null", false),
466-
("equal", r#""abc""#, r#""def""#, false),
467-
// notEqual
468-
("notEqual", "0", "0", false),
469-
("notEqual", "0", "null", false),
470-
("notEqual", "null", "null", false),
471-
("notEqual", "0", "0.0000009", false),
472-
("notEqual", "0", "0.000001", true),
473-
("notEqual", "0", "1", true),
474-
("notEqual", "1", "null", true),
475-
// lessThan
476-
("lessThan", "0", "1", true),
477-
("lessThan", "0", "0", false),
478-
("lessThan", "1", "0", false),
479-
// lessThanEq
480-
("lessThanEq", "0", "1", true),
481-
("lessThanEq", "0", "0", true),
482-
("lessThanEq", "1", "0", false),
483-
// greaterThan
484-
("greaterThan", "0", "1", false),
485-
("greaterThan", "0", "0", false),
486-
("greaterThan", "1", "0", true),
487-
// greaterThanEq
488-
("greaterThanEq", "0", "1", false),
489-
("greaterThanEq", "0", "0", true),
490-
("greaterThanEq", "1", "0", true),
491-
// strictEqual
492-
("strictEqual", "0", "0", true),
493-
("strictEqual", "0.5", "0.5", true),
494-
("strictEqual", "@pi", "3.1415927", true),
495-
("strictEqual", "null", "null", true),
496-
("strictEqual", r#""""#, r#""""#, true),
497-
("strictEqual", r#""abc""#, r#""abc""#, true),
498-
("strictEqual", "0", "null", false),
499-
("strictEqual", "1", r#""""#, false),
500-
("strictEqual", "1", r#""foo""#, false),
501-
("strictEqual", r#""abc""#, r#""def""#, false),
502-
("strictEqual", "0", "0.0000009", false),
503-
("strictEqual", "0", "0.000001", false),
504-
("strictEqual", "0", "1", false),
505-
("strictEqual", "1", "null", false),
506-
// always
507-
("always", "0", "0", true),
508-
("always", "0", "1", true),
509-
("always", "1", "0", true),
510-
("always", "1", "1", true),
511-
]
512-
.into_iter()
513-
.enumerate()
514-
{
513+
for (i, &(cond, x, y, want_jump)) in CONDITION_TESTS.iter().enumerate() {
515514
let err = format!("{cond} {x} {y}").replace('"', "'");
516515
if want_jump {
517516
code.push_str(&format!(
@@ -772,4 +771,44 @@ mod tests {
772771
LValue::Number(COLORS["royal"])
773772
);
774773
}
774+
775+
#[test]
776+
fn test_select() {
777+
for &(cond, x, y, want_true) in CONDITION_TESTS {
778+
let mut vm = single_processor_vm(
779+
BlockType::HyperProcessor,
780+
&format!(
781+
"
782+
set x {x}
783+
set y {y}
784+
set if_true 0xdeadbeef
785+
set if_false 0xbabecafe
786+
select got1 {cond} x y if_true if_false
787+
select got2 {cond} {x} {y} 0xdeadbeef 0xbabecafe
788+
stop
789+
"
790+
),
791+
);
792+
793+
run(&mut vm, 1, true);
794+
795+
let state = take_processor(&mut vm, 0).state;
796+
let want_value = if want_true {
797+
0xdeadbeefu64
798+
} else {
799+
0xbabecafeu64
800+
}
801+
.into();
802+
assert_eq!(
803+
state.variables["got1"].get(&state),
804+
want_value,
805+
"{cond} {x} {y} (variables)"
806+
);
807+
assert_eq!(
808+
state.variables["got2"].get(&state),
809+
want_value,
810+
"{cond} {x} {y} (constants)"
811+
);
812+
}
813+
}
775814
}

src/logic/vm/variables.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ impl LVar {
8686
_ => {}
8787
}
8888
}
89+
90+
pub fn set_from(&self, state: &mut ProcessorState, other: &LVar) {
91+
self.set(state, other.get(state));
92+
}
8993
}
9094

9195
fn constant<T>(value: T) -> LVar

0 commit comments

Comments
 (0)