vihaco_stdlib/program/
lower.rs1use super::{
7 operand::{StringOperand, Target},
8 program,
9};
10
11use vihaco_abi::{Lower, Syntax};
12use vihaco_module::loader::MetadataLoweringContext;
13
14pub trait LabelLookup {
19 fn label_address(&self, name: &str) -> eyre::Result<u32>;
20}
21
22pub trait FunctionLookup {
27 fn function_address(&self, name: &str) -> eyre::Result<u32>;
28 fn function_index(&self, name: &str) -> eyre::Result<u32>;
29}
30
31pub trait StringIntern {
36 fn intern_string(&mut self, value: &str) -> eyre::Result<u32>;
37}
38
39impl LabelLookup for MetadataLoweringContext {
40 fn label_address(&self, name: &str) -> eyre::Result<u32> {
41 MetadataLoweringContext::label_address(self, name)
42 }
43}
44
45impl FunctionLookup for MetadataLoweringContext {
46 fn function_address(&self, name: &str) -> eyre::Result<u32> {
47 MetadataLoweringContext::function_address(self, name)
48 }
49
50 fn function_index(&self, name: &str) -> eyre::Result<u32> {
51 MetadataLoweringContext::function_index(self, name)
52 }
53}
54
55impl StringIntern for MetadataLoweringContext {
56 fn intern_string(&mut self, value: &str) -> eyre::Result<u32> {
57 self.string_index(value)
58 }
59}
60
61fn label_target<C: LabelLookup + ?Sized>(target: Target, context: &C) -> eyre::Result<u32> {
62 match target {
63 Target::Resolved(address) => Ok(address),
64 Target::Symbol(name) => context.label_address(name.as_str()),
65 }
66}
67
68impl<C: LabelLookup + ?Sized> Lower<C> for program::Branch<Syntax> {
69 type Runtime = program::Branch;
70 fn lower(self, context: &mut C) -> eyre::Result<Self::Runtime> {
71 Ok(program::Branch(label_target(self.0, context)?))
72 }
73}
74
75impl<C: LabelLookup + ?Sized> Lower<C> for program::ConditionalBranch<Syntax> {
76 type Runtime = program::ConditionalBranch;
77 fn lower(self, context: &mut C) -> eyre::Result<Self::Runtime> {
78 Ok(program::ConditionalBranch(
79 label_target(self.0, context)?,
80 label_target(self.1, context)?,
81 ))
82 }
83}
84
85impl<C: FunctionLookup + ?Sized> Lower<C> for program::Call<Syntax> {
86 type Runtime = program::Call;
87 fn lower(self, context: &mut C) -> eyre::Result<Self::Runtime> {
88 let address = match self.1 {
89 Target::Resolved(address) => address,
90 Target::Symbol(name) => context.function_address(name.as_str())?,
91 };
92 Ok(program::Call(self.0, address))
93 }
94}
95
96impl<C: FunctionLookup + ?Sized> Lower<C> for program::ConstFunctionRef<Syntax> {
97 type Runtime = program::ConstFunctionRef;
98 fn lower(self, context: &mut C) -> eyre::Result<Self::Runtime> {
99 let index = match self.0 {
100 Target::Resolved(index) => index,
101 Target::Symbol(name) => context.function_index(name.as_str())?,
102 };
103 Ok(program::ConstFunctionRef(
104 vihaco_abi::word::encode_function_ref(index),
105 ))
106 }
107}
108
109impl<C: StringIntern + ?Sized> Lower<C> for program::ConstString<Syntax> {
110 type Runtime = program::ConstString;
111 fn lower(self, context: &mut C) -> eyre::Result<Self::Runtime> {
112 let index = match self.0 {
113 StringOperand::Resolved(index) => index,
114 StringOperand::Literal(value) => context.intern_string(value.as_str())?,
115 };
116 Ok(program::ConstString(vihaco_abi::word::encode_string_id(
117 index,
118 )))
119 }
120}
121
122macro_rules! lower_literal {
124 ($($instruction:ident => $convert:expr),* $(,)?) => {$(
125 impl<C: ?Sized> vihaco_abi::Lower<C> for program::$instruction<vihaco_abi::Syntax> {
126 type Runtime = program::$instruction;
127 fn lower(self, _: &mut C) -> eyre::Result<Self::Runtime> {
128 Ok(program::$instruction(($convert)(self.0)))
129 }
130 }
131 )*};
132}
133
134lower_literal! {
135 ConstI32 => vihaco_abi::word::Word::from,
136 ConstI64 => vihaco_abi::word::Word::from,
137 ConstF32 => vihaco_abi::word::Word::from,
138 ConstF64 => vihaco_abi::word::Word::from,
139 ConstU32 => vihaco_abi::word::encode_u32,
140 ConstBool => vihaco_abi::word::encode_bool,
141 ConstHeapRef => vihaco_abi::word::encode_heap_ref,
142}
143
144impl<I, V, Ty, Info> StringIntern for vihaco_module::module::LocalModule<I, V, Ty, Info> {
146 fn intern_string(&mut self, value: &str) -> eyre::Result<u32> {
147 if let Some(index) = self.strings.iter().position(|existing| existing == value) {
148 return Ok(u32::try_from(index)?);
149 }
150 let index = u32::try_from(self.strings.len())?;
151 self.strings.push(value.to_owned());
152 Ok(index)
153 }
154}