surfer_translation_types/
translator.rs

1//! Definition of the main [`Translator`] trait and the simplified version
2//! [`BasicTranslator`].
3use color_eyre::Result;
4use extism_convert::{FromBytes, Json, ToBytes};
5use num::BigUint;
6use serde::{Deserialize, Serialize};
7use std::sync::mpsc::Sender;
8
9use crate::result::TranslationResult;
10use crate::{
11    TranslationPreference, ValueKind, VariableEncoding, VariableInfo, VariableMeta, VariableValue,
12};
13
14#[derive(Debug, Clone, PartialEq)]
15pub enum TrueName {
16    /// The variable's true name is best represented as part of a line of code
17    /// for example if line 100 is
18    /// let x = a + b;
19    /// and the signal being queried is `a+b` then this would return
20    /// {line: 100, before: "let x = ", this: "a + b", after: ";"}
21    SourceCode {
22        line_number: usize,
23        before: String,
24        this: String,
25        after: String,
26    },
27}
28
29/// Provides a way for translators to "change" the name of variables in the variable list.
30/// Most translators should not produce VariableNameInfo since it is a global thing that
31/// is done on _all_ variables, not just those which have had the translator applied.
32///
33/// An example use case is translators for HDLs which want to translate from automatically
34/// generated subexpression back into names that a human can understand. In this use case,
35/// it is _very_ unlikely that the user wants to see the raw anonymous name that the compiler
36/// emitted, so performing this translation globally makes sense.
37#[derive(Clone, Debug)]
38pub struct VariableNameInfo {
39    /// A more human-undesrstandable name for a signal. This should only be used by translators
40    /// which
41    pub true_name: Option<TrueName>,
42    /// Translators can change the order that signals appear in the variable list using this
43    /// parameter. Before rendering, the variable will be sported by this number in descending
44    /// order, so variables that are predicted to be extra important to the
45    /// user should have a number > 0 while unimportant variables should be < 0
46    ///
47    /// Translators should only poke at this variable if they know something about the variable.
48    /// For example, an HDL translator that does not recognise a name should leave it at None
49    /// to give other translators the chance to set the priority
50    pub priority: Option<i32>,
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, FromBytes, ToBytes)]
54#[encoding(Json)]
55pub enum WaveSource {
56    File(String),
57    Data,
58    DragAndDrop(Option<String>),
59    Url(String),
60    Cxxrtl,
61}
62
63/// The most general translator trait.
64pub trait Translator<VarId, ScopeId, Message>: Send + Sync {
65    fn name(&self) -> String;
66
67    /// Notify the translator that the wave source has changed to the specified source
68    fn set_wave_source(&self, _wave_source: Option<WaveSource>) {}
69
70    fn translate(
71        &self,
72        variable: &VariableMeta<VarId, ScopeId>,
73        value: &VariableValue,
74    ) -> Result<TranslationResult>;
75
76    fn variable_info(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<VariableInfo>;
77
78    /// Return [`TranslationPreference`] based on if the translator can handle this variable.
79    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference>;
80
81    /// By default translators are stateless, but if they need to reload, they can
82    /// do by defining this method.
83    /// Long running translators should run the reloading in the background using `perform_work`
84    fn reload(&self, _sender: Sender<Message>) {}
85
86    /// Returns a `VariableNameInfo` about the specified variable which will be applied globally.
87    /// Most translators should simply return `None` here, see the
88    /// documentation `VariableNameInfo` for exceptions to this rule.
89    fn variable_name_info(
90        &self,
91        variable: &VariableMeta<VarId, ScopeId>,
92    ) -> Option<VariableNameInfo> {
93        // We could name this `_variable`, but that means the docs will make it look unused
94        // and LSPs will fill in the definition with that name too, so we'll mark it as unused
95        // like this
96        let _ = variable;
97        None
98    }
99}
100
101/// A translator that only produces non-hierarchical values
102pub trait BasicTranslator<VarId, ScopeId>: Send + Sync {
103    fn name(&self) -> String;
104
105    fn basic_translate(&self, num_bits: u64, value: &VariableValue) -> (String, ValueKind);
106
107    fn translates(&self, variable: &VariableMeta<VarId, ScopeId>) -> Result<TranslationPreference> {
108        translates_all_bit_types(variable)
109    }
110
111    fn variable_info(&self, _variable: &VariableMeta<VarId, ScopeId>) -> Result<VariableInfo> {
112        Ok(VariableInfo::Bits)
113    }
114}
115
116enum NumberParseResult {
117    Numerical(BigUint),
118    Unparsable(String, ValueKind),
119}
120
121/// Turn vector variable string into name and corresponding kind if it
122/// includes values other than 0 and 1. If only 0 and 1, return None.
123fn map_vector_variable(s: &str) -> NumberParseResult {
124    if let Some(val) = BigUint::parse_bytes(s.as_bytes(), 2) {
125        NumberParseResult::Numerical(val)
126    } else if s.contains('x') {
127        NumberParseResult::Unparsable("UNDEF".to_string(), ValueKind::Undef)
128    } else if s.contains('z') {
129        NumberParseResult::Unparsable("HIGHIMP".to_string(), ValueKind::HighImp)
130    } else if s.contains('-') {
131        NumberParseResult::Unparsable("DON'T CARE".to_string(), ValueKind::DontCare)
132    } else if s.contains('u') {
133        NumberParseResult::Unparsable("UNDEF".to_string(), ValueKind::Undef)
134    } else if s.contains('w') {
135        NumberParseResult::Unparsable("UNDEF WEAK".to_string(), ValueKind::Undef)
136    } else if s.contains('h') || s.contains('l') {
137        NumberParseResult::Unparsable("WEAK".to_string(), ValueKind::Weak)
138    } else {
139        NumberParseResult::Unparsable("UNKNOWN VALUES".to_string(), ValueKind::Undef)
140    }
141}
142
143impl VariableValue {
144    pub fn parse_biguint(self) -> Result<BigUint, (String, ValueKind)> {
145        match self {
146            VariableValue::BigUint(v) => Ok(v),
147            VariableValue::String(s) => match map_vector_variable(&s) {
148                NumberParseResult::Unparsable(v, k) => Err((v, k)),
149                NumberParseResult::Numerical(v) => Ok(v),
150            },
151        }
152    }
153}
154
155pub fn translates_all_bit_types<VarId, ScopeId>(
156    variable: &VariableMeta<VarId, ScopeId>,
157) -> Result<TranslationPreference> {
158    if variable.encoding == VariableEncoding::BitVector {
159        Ok(TranslationPreference::Yes)
160    } else {
161        Ok(TranslationPreference::No)
162    }
163}