Skip to content

Commit

Permalink
feat(switch,parser): add parsing for input (#821)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtroo authored Mar 14, 2024
1 parent 0478ad1 commit 7cdbffb
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 0 deletions.
1 change: 1 addition & 0 deletions keyberon/src/action/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ impl OpCode {
/// Return a new OpCode for a boolean operation that ends (non-inclusive) at the specified
/// index.
pub fn new_bool(op: BooleanOperator, end_idx: u16) -> Self {
assert!(end_idx <= MAX_OPCODE_LEN);
Self((end_idx & MAX_OPCODE_LEN) + op.to_u16())
}

Expand Down
91 changes: 91 additions & 0 deletions parser/src/cfg/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@ pub fn parse_switch_case_bool(
Not,
KeyHistory,
KeyTiming,
Input,
InputHistory,
}
#[derive(Copy, Clone)]
enum InputType {
Real,
Virtual,
}
impl InputType {
fn to_row(self) -> u8 {
match self {
InputType::Real => 0,
InputType::Virtual => 1,
}
}
}
let op = l[0]
.atom(s.vars())
Expand All @@ -96,6 +111,8 @@ pub fn parse_switch_case_bool(
"not" => Some(AllowedListOps::Not),
"key-history" => Some(AllowedListOps::KeyHistory),
"key-timing" => Some(AllowedListOps::KeyTiming),
"input" => Some(AllowedListOps::Input),
"input-history" => Some(AllowedListOps::InputHistory),
_ => None,
})
.ok_or_else(|| {
Expand All @@ -120,6 +137,77 @@ pub fn parse_switch_case_bool(
ops.push(OpCode::new_key_history(osc.into(), key_recency));
Ok(())
}
AllowedListOps::Input => {
if l.len() != 3 {
bail_expr!(
op_expr,
"input must have 2 parameters: key-type(virtual|real), key"
);
}

let input_type = match l[1]
.atom(s.vars())
.ok_or_else(|| anyhow_expr!(op_expr, "key-type must be virtual|real"))?
{
"real" => InputType::Real,
"fake" | "virtual" => InputType::Virtual,
_ => bail_expr!(op_expr, "key-type must be virtual|real"),
};
let input = l[2]
.atom(s.vars())
.ok_or_else(|| anyhow_expr!(op_expr, "input key name must not be a list"))?;
let input = match input_type {
InputType::Real => u16::from(
str_to_oscode(input)
.ok_or_else(|| anyhow_expr!(op_expr, "invalid input key name"))?,
),
InputType::Virtual => {
let vk = s.fake_keys.get(input).ok_or_else(|| {
anyhow_expr!(op_expr, "virtual key name is not defined")
})?;
assert!(vk.0 < usize::from(KEY_MAX));
vk.0 as u16
}
};
let (op1, op2) = OpCode::new_active_input((input_type.to_row(), input));
ops.extend(&[op1, op2]);
Ok(())
}
AllowedListOps::InputHistory => {
if l.len() != 4 {
bail_expr!(op_expr, "input-history must have 3 parameters: key-type(virtual|real), key, key-recency");
}

let input_type = match l[1]
.atom(s.vars())
.ok_or_else(|| anyhow_expr!(op_expr, "key-type must be virtual|real"))?
{
"real" => InputType::Real,
"fake" | "virtual" => InputType::Virtual,
_ => bail_expr!(op_expr, "key-type must be virtual|real"),
};
let input = l[2]
.atom(s.vars())
.ok_or_else(|| anyhow_expr!(op_expr, "input key name must not be a list"))?;
let input = match input_type {
InputType::Real => u16::from(
str_to_oscode(input)
.ok_or_else(|| anyhow_expr!(op_expr, "invalid input key name"))?,
),
InputType::Virtual => {
let vk = s.fake_keys.get(input).ok_or_else(|| {
anyhow_expr!(op_expr, "virtual key name is not defined")
})?;
assert!(vk.0 < usize::from(KEY_MAX));
vk.0 as u16
}
};
let key_recency = parse_u8_with_range(&l[3], s, "key-recency", 1, 8)? - 1;
let (op1, op2) =
OpCode::new_historical_input((input_type.to_row(), input), key_recency);
ops.extend(&[op1, op2]);
Ok(())
}
AllowedListOps::KeyTiming => {
if l.len() != 4 {
bail_expr!(
Expand Down Expand Up @@ -165,6 +253,9 @@ pub fn parse_switch_case_bool(
for op in l.iter().skip(1) {
parse_switch_case_bool(depth + 1, op, ops, s)?;
}
if ops.len() > usize::from(MAX_OPCODE_LEN) {
bail_expr!(op_expr, "switch logic length has been exceeded");
}
ops[placeholder_index as usize] = OpCode::new_bool(op, ops.len() as u16);
Ok(())
}
Expand Down
31 changes: 31 additions & 0 deletions parser/src/cfg/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,8 @@ fn parse_switch() {
let source = r#"
(defvar var1 a)
(defsrc a)
(deffakekeys vk1 XX)
(deffakekeys vk2 XX)
(deflayer base
(switch
((and a b (or c d) (or e f))) XX break
Expand All @@ -791,6 +793,10 @@ fn parse_switch() {
(key-timing 7 lt 1000)
(key-timing 8 gt 20000)
)) $var1 fallthrough
((input virtual vk1)) $var1 break
((input real lctl)) $var1 break
((input-history virtual vk2 1)) $var1 break
((input-history real lsft 8)) $var1 break
)
)
"#;
Expand All @@ -804,6 +810,11 @@ fn parse_switch() {
DEF_LOCAL_KEYS,
)
.unwrap();
let (op1, op2) = OpCode::new_active_input((FAKE_KEY_ROW, 0));
let (op3, op4) = OpCode::new_active_input((NORMAL_KEY_ROW, u16::from(OsCode::KEY_LEFTCTRL)));
let (op5, op6) = OpCode::new_historical_input((FAKE_KEY_ROW, 1), 0);
let (op7, op8) =
OpCode::new_historical_input((NORMAL_KEY_ROW, u16::from(OsCode::KEY_LEFTSHIFT)), 7);
assert_eq!(
res.3[0][0][OsCode::KEY_A.as_u16() as usize],
Action::Switch(&Switch {
Expand Down Expand Up @@ -885,6 +896,26 @@ fn parse_switch() {
&Action::KeyCode(KeyCode::A),
BreakOrFallthrough::Fallthrough
),
(
&[op1, op2],
&Action::KeyCode(KeyCode::A),
BreakOrFallthrough::Break
),
(
&[op3, op4],
&Action::KeyCode(KeyCode::A),
BreakOrFallthrough::Break
),
(
&[op5, op6],
&Action::KeyCode(KeyCode::A),
BreakOrFallthrough::Break
),
(
&[op7, op8],
&Action::KeyCode(KeyCode::A),
BreakOrFallthrough::Break
),
]
})
);
Expand Down

0 comments on commit 7cdbffb

Please sign in to comment.