nifty_codegen/compile/
menu.rs1use std::mem::{offset_of, size_of};
5
6use cranelift_module::Module;
7use nifty_check::hir::{Block as Stmts, Menu, MenuEntry};
8use nifty_rt::{MenuDesc, MenuEntryDesc, MenuEntryKind, ShortcutDesc};
9use nifty_runtime::Shortcut;
10
11use super::ui::{Aliases, Frame, Ui};
12use super::{List, Result, Shared, put_str};
13use crate::emit::{Blob, Emitter, Target};
14
15pub(super) fn menu_bar<M: Module>(
17 emitter: &mut Emitter<M>,
18 shared: &mut Shared<'_>,
19) -> Result<(List, List)> {
20 let program = shared.program;
21 let mut ui = Ui { emitter, shared };
22 let frame = Frame::new(&program.menu_bar.locals);
23 let menus = ui.menus(&frame, &program.menu_bar.menus)?;
24 let locals = ui.frame_types(&frame)?;
25 Ok((menus, locals))
26}
27
28impl<M: Module> Ui<'_, '_, M> {
29 fn menus(&mut self, frame: &Frame<'_>, menus: &[Menu<Stmts>]) -> Result<List> {
30 let size = size_of::<MenuDesc>();
31 let mut blob = Blob::zeroed(menus.len() * size);
32 for (index, menu) in menus.iter().enumerate() {
33 let at = index * size;
34 let title = at + offset_of!(MenuDesc, title);
35 put_str(self.emitter, self.shared, &mut blob, title, &menu.title)?;
36 let entries = self.menu_entries(frame, &Aliases::new(), &menu.entries)?;
37 entries.put(&mut blob, at + offset_of!(MenuDesc, entries));
38 }
39 self.list(blob, menus.len())
40 }
41
42 pub(super) fn menu_entries(
44 &mut self,
45 frame: &Frame<'_>,
46 aliases: &Aliases,
47 entries: &[MenuEntry<Stmts>],
48 ) -> Result<List> {
49 let size = size_of::<MenuEntryDesc>();
50 let mut blob = Blob::zeroed(entries.len() * size);
51 for (index, entry) in entries.iter().enumerate() {
52 let at = index * size;
53 let title_at = at + offset_of!(MenuEntryDesc, title);
54 let kind = match entry {
55 MenuEntry::Item {
56 title,
57 shortcut,
58 action,
59 } => {
60 put_str(self.emitter, self.shared, &mut blob, title_at, title)?;
61 if let Some(shortcut) = shortcut {
62 put_shortcut(
63 &mut blob,
64 at + offset_of!(MenuEntryDesc, shortcut),
65 *shortcut,
66 );
67 }
68 let action = self.action(frame, aliases, action)?;
69 blob.put_pointer(
70 at + offset_of!(MenuEntryDesc, action),
71 Target::Function(action),
72 );
73 MenuEntryKind::Item
74 }
75 MenuEntry::Separator => MenuEntryKind::Separator,
76 MenuEntry::Submenu(submenu) => {
77 put_str(
78 self.emitter,
79 self.shared,
80 &mut blob,
81 title_at,
82 &submenu.title,
83 )?;
84 let entries = self.menu_entries(frame, aliases, &submenu.entries)?;
85 entries.put(&mut blob, at + offset_of!(MenuEntryDesc, entries));
86 MenuEntryKind::Submenu
87 }
88 };
89 blob.put_u8(at + offset_of!(MenuEntryDesc, kind), kind as u8);
90 }
91 self.list(blob, entries.len())
92 }
93}
94
95fn put_shortcut(blob: &mut Blob, at: usize, shortcut: Shortcut) {
96 blob.put_u8(at + offset_of!(ShortcutDesc, present), 1);
97 let at = at + offset_of!(ShortcutDesc, shortcut);
98 blob.put_u8(at + offset_of!(Shortcut, key), shortcut.key.code());
99 blob.put_u8(at + offset_of!(Shortcut, shift), u8::from(shortcut.shift));
100 blob.put_u8(at + offset_of!(Shortcut, alt), u8::from(shortcut.alt));
101}