goscript_types/
operand.rs

1#![allow(dead_code)]
2use super::constant;
3use super::lookup::missing_method;
4use super::objects::{TCObjects, TypeKey};
5use super::typ;
6use super::typ::{fmt_type, BasicType, Type};
7use super::universe::{Builtin, Universe};
8use goscript_parser::ast;
9use goscript_parser::ast::*;
10use goscript_parser::objects::{FuncTypeKey, IdentKey, Objects as AstObjects};
11use goscript_parser::position;
12use goscript_parser::token::Token;
13use goscript_parser::visitor::{walk_expr, ExprVisitor};
14use std::fmt;
15use std::fmt::Display;
16use std::fmt::Write;
17
18/// An OperandMode specifies the (addressing) mode of an operand.
19#[derive(Clone, Debug, PartialEq)]
20pub enum OperandMode {
21    Invalid,                   // operand is invalid
22    NoValue,                   // operand represents no value (result of a function call w/o result)
23    Builtin(Builtin),          // operand is a built-in function
24    TypeExpr,                  // operand is a type
25    Constant(constant::Value), // operand is a constant; the operand's typ is a Basic type
26    Variable,                  // operand is an addressable variable
27    MapIndex, // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
28    Value,    // operand is a computed value
29    CommaOk,  // like value, but operand may be used in a comma,ok expression
30}
31
32impl OperandMode {
33    pub fn constant_val(&self) -> Option<&constant::Value> {
34        match self {
35            OperandMode::Constant(v) => Some(v),
36            _ => None,
37        }
38    }
39
40    pub fn builtin_id(&self) -> Option<Builtin> {
41        match self {
42            OperandMode::Builtin(id) => Some(*id),
43            _ => None,
44        }
45    }
46}
47
48impl fmt::Display for OperandMode {
49    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50        f.write_str(match self {
51            OperandMode::Invalid => "invalid operand",
52            OperandMode::NoValue => "no value",
53            OperandMode::Builtin(_) => "built-in",
54            OperandMode::TypeExpr => "type",
55            OperandMode::Constant(_) => "constant",
56            OperandMode::Variable => "variable",
57            OperandMode::MapIndex => "map index expression",
58            OperandMode::Value => "value",
59            OperandMode::CommaOk => "comma, ok expression",
60        })
61    }
62}
63
64/// An Operand represents an intermediate value during type checking.
65/// Operands have an (addressing) mode, the expression evaluating to
66/// the operand, the operand's type, a value for constants, and an id
67/// for built-in functions.
68#[derive(Clone, Debug)]
69pub struct Operand {
70    pub mode: OperandMode,
71    pub expr: Option<ast::Expr>,
72    pub typ: Option<TypeKey>,
73}
74
75impl Operand {
76    pub fn new() -> Operand {
77        Operand::with(OperandMode::Invalid, None, None)
78    }
79
80    pub fn with(mode: OperandMode, expr: Option<ast::Expr>, typ: Option<TypeKey>) -> Operand {
81        Operand {
82            mode: mode,
83            expr: expr,
84            typ: typ,
85        }
86    }
87
88    pub fn invalid(&self) -> bool {
89        self.mode == OperandMode::Invalid
90    }
91
92    pub fn pos(&self, ast_objs: &AstObjects) -> position::Pos {
93        if let Some(e) = &self.expr {
94            e.pos(ast_objs)
95        } else {
96            0
97        }
98    }
99
100    pub fn set_const(&mut self, t: &Token, u: &Universe) {
101        let bt = match t {
102            Token::INT(_) => BasicType::UntypedInt,
103            Token::FLOAT(_) => BasicType::UntypedFloat,
104            Token::IMAG(_) => BasicType::UntypedComplex,
105            Token::CHAR(_) => BasicType::UntypedRune,
106            Token::STRING(_) => BasicType::UntypedString,
107            _ => unreachable!(),
108        };
109        self.mode = OperandMode::Constant(constant::Value::with_literal(t));
110        self.typ = Some(u.types()[&bt]);
111    }
112
113    pub fn is_nil(&self, u: &Universe) -> bool {
114        match self.mode {
115            OperandMode::Value => self.typ == Some(u.types()[&BasicType::UntypedNil]),
116            _ => false,
117        }
118    }
119
120    /// assignable_to returns whether self is assignable to a variable of type 't'.
121    /// If the result is false and a non-None reason is provided, it may be set
122    /// to a more detailed explanation of the failure.
123    pub fn assignable_to(&self, t: TypeKey, reason: Option<&mut String>, objs: &TCObjects) -> bool {
124        let u = objs.universe();
125        if self.invalid() || t == u.types()[&BasicType::Invalid] {
126            return true; // avoid spurious errors
127        }
128
129        if typ::identical(self.typ.unwrap(), t, objs) {
130            return true;
131        }
132
133        let (k_left, k_right) = (t, self.typ.unwrap());
134        let t_left = &objs.types[k_left];
135        let t_right = &objs.types[k_right];
136        let ut_key_left = typ::underlying_type(k_left, objs);
137        let ut_key_right = typ::underlying_type(k_right, objs);
138        let ut_left = &objs.types[ut_key_left];
139        let ut_right = &objs.types[ut_key_right];
140
141        if ut_right.is_untyped(objs) {
142            match ut_left {
143                Type::Basic(detail) => {
144                    if self.is_nil(u) && detail.typ() == BasicType::UnsafePointer {
145                        return true;
146                    }
147                    if let OperandMode::Constant(val) = &self.mode {
148                        return val.representable(detail, None);
149                    }
150                    // The result of a comparison is an untyped boolean,
151                    // but may not be a constant.
152                    if detail.typ() == BasicType::Bool {
153                        return ut_right.try_as_basic().unwrap().typ() == BasicType::UntypedBool;
154                    }
155                }
156                Type::Interface(detail) => return self.is_nil(u) || detail.is_empty(),
157                Type::Pointer(_)
158                | Type::Signature(_)
159                | Type::Slice(_)
160                | Type::Map(_)
161                | Type::Chan(_) => return self.is_nil(u),
162                _ => {}
163            }
164        }
165
166        // 'right' is typed
167        // self's type 'right' and 'left' have identical underlying types
168        // and at least one of 'right' or 'left' is not a named type
169        if typ::identical(ut_key_right, ut_key_left, objs)
170            && (!t_right.is_named() || !t_left.is_named())
171        {
172            return true;
173        }
174
175        // 'left' is an interface and 'right' implements 'left'
176        if let Some(_) = ut_left.try_as_interface() {
177            if let Some((m, wrong_type)) = missing_method(k_right, ut_key_left, true, objs) {
178                if let Some(re) = reason {
179                    let msg = if wrong_type {
180                        "wrong type for method"
181                    } else {
182                        "missing method"
183                    };
184                    *re = format!("{} {}", msg, objs.lobjs[m].name());
185                }
186                return false;
187            }
188            return true;
189        }
190
191        // 'right' is a bidirectional channel value, 'left' is a channel
192        // type, they have identical element types,
193        // and at least one of 'right' or 'left' is not a named type
194        if let Some(cr) = ut_right.try_as_chan() {
195            if cr.dir() == typ::ChanDir::SendRecv {
196                if let Some(cl) = ut_left.try_as_chan() {
197                    if typ::identical(cr.elem(), cl.elem(), objs) {
198                        return !t_right.is_named() || !t_left.is_named();
199                    }
200                }
201            }
202        }
203
204        false
205    }
206
207    /// Operand string formats
208    /// (not all "untyped" cases can appear due to the type system)
209    ///
210    /// mode       format
211    ///
212    /// invalid    <expr> (               <mode>                    )
213    /// novalue    <expr> (               <mode>                    )
214    /// builtin    <expr> (               <mode>                    )
215    /// typexpr    <expr> (               <mode>                    )
216    ///
217    /// constant   <expr> (<untyped kind> <mode>                    )
218    /// constant   <expr> (               <mode>       of type <typ>)
219    /// constant   <expr> (<untyped kind> <mode> <val>              )
220    /// constant   <expr> (               <mode> <val> of type <typ>)
221    ///
222    /// variable   <expr> (<untyped kind> <mode>                    )
223    /// variable   <expr> (               <mode>       of type <typ>)
224    ///
225    /// mapindex   <expr> (<untyped kind> <mode>                    )
226    /// mapindex   <expr> (               <mode>       of type <typ>)
227    ///
228    /// value      <expr> (<untyped kind> <mode>                    )
229    /// value      <expr> (               <mode>       of type <typ>)
230    ///
231    /// commaok    <expr> (<untyped kind> <mode>                    )
232    /// commaok    <expr> (               <mode>       of type <typ>)
233    pub fn fmt(
234        &self,
235        f: &mut fmt::Formatter<'_>,
236        tc_objs: &TCObjects,
237        ast_objs: &AstObjects,
238    ) -> fmt::Result {
239        let universe = tc_objs.universe();
240        let mut has_expr = true;
241
242        // <expr> (
243        if let Some(expr) = &self.expr {
244            fmt_expr(&expr, f, ast_objs)?;
245        } else {
246            match &self.mode {
247                OperandMode::Builtin(bi) => {
248                    f.write_str(universe.builtins()[bi].name)?;
249                }
250                OperandMode::TypeExpr => {
251                    fmt_type(self.typ, f, tc_objs)?;
252                }
253                OperandMode::Constant(val) => {
254                    f.write_str(&val.to_string())?;
255                }
256                _ => has_expr = false,
257            }
258        }
259        if has_expr {
260            f.write_str(" (")?;
261        }
262
263        // <untyped kind>
264        let has_type = match self.mode {
265            OperandMode::Invalid
266            | OperandMode::NoValue
267            | OperandMode::Builtin(_)
268            | OperandMode::TypeExpr => false,
269            _ => {
270                let tval = &tc_objs.types[self.typ.unwrap()];
271                if tval.is_untyped(tc_objs) {
272                    f.write_str(tval.try_as_basic().unwrap().name())?;
273                    f.write_char(' ')?;
274                    false
275                } else {
276                    true
277                }
278            }
279        };
280
281        // <mode>
282        self.mode.fmt(f)?;
283
284        // <val>
285        if let OperandMode::Constant(val) = &self.mode {
286            if self.expr.is_some() {
287                f.write_char(' ')?;
288                f.write_str(&val.to_string())?;
289            }
290        }
291
292        // <typ>
293        if has_type {
294            if self.typ != Some(universe.types()[&BasicType::Invalid]) {
295                f.write_str(" of type ")?;
296                fmt_type(self.typ, f, tc_objs)?;
297            } else {
298                f.write_str(" with invalid type")?;
299            }
300        }
301
302        // )
303        if has_expr {
304            f.write_char(')')?;
305        }
306        Ok(())
307    }
308}
309
310/// fmt_expr formats the (possibly shortened) string representation for 'expr'.
311/// Shortened representations are suitable for user interfaces but may not
312/// necessarily follow Go syntax.
313pub fn fmt_expr(expr: &Expr, f: &mut fmt::Formatter<'_>, ast_objs: &AstObjects) -> fmt::Result {
314    // The AST preserves source-level parentheses so there is
315    // no need to introduce them here to correct for different
316    // operator precedences. (This assumes that the AST was
317    // generated by a Go parser.)
318    ExprFormater {
319        f: f,
320        ast_objs: ast_objs,
321    }
322    .visit_expr(expr)
323}
324
325struct ExprFormater<'a, 'b> {
326    f: &'a mut fmt::Formatter<'b>,
327    ast_objs: &'a AstObjects,
328}
329
330impl<'a, 'b> ExprVisitor for ExprFormater<'a, 'b> {
331    type Result = fmt::Result;
332
333    fn visit_expr(&mut self, expr: &Expr) -> Self::Result {
334        walk_expr(self, expr)
335    }
336
337    fn visit_expr_ident(&mut self, _: &Expr, ident: &IdentKey) -> Self::Result {
338        self.fmt_ident(ident)
339    }
340
341    fn visit_expr_ellipsis(&mut self, _: &Expr, els: &Option<Expr>) -> Self::Result {
342        self.f.write_str("...")?;
343        if let Some(e) = els {
344            self.visit_expr(e)?;
345        }
346        Ok(())
347    }
348
349    fn visit_expr_basic_lit(&mut self, _: &Expr, blit: &BasicLit) -> Self::Result {
350        blit.token.fmt(self.f)
351    }
352
353    fn visit_expr_func_lit(&mut self, this: &Expr, flit: &FuncLit) -> Self::Result {
354        self.f.write_char('(')?;
355        self.visit_expr_func_type(this, &flit.typ)?;
356        self.f.write_str(" literal)")
357    }
358
359    fn visit_expr_composit_lit(&mut self, _: &Expr, clit: &CompositeLit) -> Self::Result {
360        self.f.write_char('(')?;
361        match &clit.typ {
362            Some(t) => {
363                self.visit_expr(t)?;
364            }
365            None => {
366                self.f.write_str("(bad expr)")?;
367            }
368        }
369        self.f.write_str(" literal)")
370    }
371
372    fn visit_expr_paren(&mut self, _: &Expr, expr: &Expr) -> Self::Result {
373        self.f.write_char('(')?;
374        self.visit_expr(expr)?;
375        self.f.write_char(')')
376    }
377
378    fn visit_expr_selector(&mut self, this: &Expr, expr: &Expr, ident: &IdentKey) -> Self::Result {
379        self.visit_expr(expr)?;
380        self.f.write_char('.')?;
381        self.visit_expr_ident(this, ident)
382    }
383
384    fn visit_expr_index(&mut self, _: &Expr, expr: &Expr, index: &Expr) -> Self::Result {
385        self.visit_expr(expr)?;
386        self.f.write_char('[')?;
387        self.visit_expr(index)?;
388        self.f.write_char(']')
389    }
390
391    fn visit_expr_slice(
392        &mut self,
393        _: &Expr,
394        expr: &Expr,
395        low: &Option<Expr>,
396        high: &Option<Expr>,
397        max: &Option<Expr>,
398    ) -> Self::Result {
399        self.visit_expr(expr)?;
400        self.f.write_char('[')?;
401        if let Some(l) = low {
402            self.visit_expr(l)?;
403        }
404        self.f.write_char(':')?;
405        if let Some(h) = high {
406            self.visit_expr(h)?;
407        }
408        if let Some(m) = max {
409            self.f.write_char(':')?;
410            self.visit_expr(m)?;
411        }
412        self.f.write_char(']')
413    }
414
415    fn visit_expr_type_assert(
416        &mut self,
417        _: &Expr,
418        expr: &Expr,
419        typ: &Option<Expr>,
420    ) -> Self::Result {
421        self.visit_expr(expr)?;
422        self.f.write_str(".(")?;
423        match &typ {
424            Some(t) => {
425                self.visit_expr(t)?;
426            }
427            None => {
428                self.f.write_str("(bad expr)")?;
429            }
430        }
431        self.f.write_char(')')
432    }
433
434    fn visit_expr_call(
435        &mut self,
436        _: &Expr,
437        func: &Expr,
438        args: &Vec<Expr>,
439        ellipsis: bool,
440    ) -> Self::Result {
441        self.visit_expr(func)?;
442        self.f.write_char('(')?;
443        for (i, arg) in args.iter().enumerate() {
444            if i > 0 {
445                self.f.write_str(", ")?;
446            }
447            self.visit_expr(arg)?;
448        }
449        if ellipsis {
450            self.f.write_str("...")?;
451        }
452        self.f.write_char(')')
453    }
454
455    fn visit_expr_star(&mut self, _: &Expr, expr: &Expr) -> Self::Result {
456        self.f.write_char('*')?;
457        self.visit_expr(expr)
458    }
459
460    fn visit_expr_unary(&mut self, _: &Expr, expr: &Expr, op: &Token) -> Self::Result {
461        op.fmt(self.f)?;
462        self.visit_expr(expr)
463    }
464
465    fn visit_expr_binary(
466        &mut self,
467        _: &Expr,
468        left: &Expr,
469        op: &Token,
470        right: &Expr,
471    ) -> Self::Result {
472        self.visit_expr(left)?;
473        self.f.write_fmt(format_args!(" {} ", op))?;
474        self.visit_expr(right)
475    }
476
477    fn visit_expr_key_value(&mut self, _: &Expr, _: &Expr, _: &Expr) -> Self::Result {
478        self.f.write_str("(bad expr)")
479    }
480
481    fn visit_expr_array_type(&mut self, _: &Expr, len: &Option<Expr>, elm: &Expr) -> Self::Result {
482        self.f.write_char('[')?;
483        if let Some(l) = len {
484            self.visit_expr(l)?;
485        }
486        self.f.write_char(']')?;
487        self.visit_expr(elm)
488    }
489
490    fn visit_expr_struct_type(&mut self, _: &Expr, s: &StructType) -> Self::Result {
491        self.f.write_str("struct{")?;
492        self.fmt_fields(&s.fields, "; ", false)?;
493        self.f.write_char('}')
494    }
495
496    fn visit_expr_func_type(&mut self, _: &Expr, s: &FuncTypeKey) -> Self::Result {
497        self.f.write_str("func")?;
498        self.fmt_sig(&self.ast_objs.ftypes[*s])
499    }
500
501    fn visit_expr_interface_type(&mut self, _: &Expr, s: &InterfaceType) -> Self::Result {
502        self.f.write_str("interface{")?;
503        self.fmt_fields(&s.methods, "; ", true)?;
504        self.f.write_char('}')
505    }
506
507    fn visit_map_type(&mut self, _: &Expr, key: &Expr, val: &Expr, _: &Expr) -> Self::Result {
508        self.f.write_str("map[")?;
509        self.visit_expr(key)?;
510        self.f.write_char(']')?;
511        self.visit_expr(val)
512    }
513
514    fn visit_chan_type(&mut self, _: &Expr, chan: &Expr, dir: &ChanDir) -> Self::Result {
515        let s = match dir {
516            ChanDir::Send => "chan<- ",
517            ChanDir::Recv => "<-chan ",
518            ChanDir::SendRecv => "chan ",
519        };
520        self.f.write_str(s)?;
521        self.visit_expr(chan)
522    }
523
524    fn visit_bad_expr(&mut self, _: &Expr, _: &BadExpr) -> Self::Result {
525        self.f.write_str("(bad expr)")
526    }
527}
528
529impl<'a, 'b> ExprFormater<'a, 'b> {
530    fn fmt_sig(&mut self, sig: &FuncType) -> fmt::Result {
531        self.f.write_char('(')?;
532        self.fmt_fields(&sig.params, ", ", false)?;
533        self.f.write_char(')')?;
534        if let Some(re) = &sig.results {
535            self.f.write_char(' ')?;
536            if re.list.len() == 1 {
537                let field = &self.ast_objs.fields[re.list[0]];
538                if field.names.len() == 0 {
539                    self.visit_expr(&field.typ)?;
540                }
541            } else {
542                self.f.write_char('(')?;
543                self.fmt_fields(&re, ", ", false)?;
544                self.f.write_char(')')?;
545            }
546        }
547        Ok(())
548    }
549
550    fn fmt_fields(&mut self, fields: &FieldList, sep: &str, iface: bool) -> fmt::Result {
551        for (i, fkey) in fields.list.iter().enumerate() {
552            if i > 0 {
553                self.f.write_str(sep)?;
554            }
555            let field = &self.ast_objs.fields[*fkey];
556            for (i, name) in field.names.iter().enumerate() {
557                if i > 0 {
558                    self.f.write_str(", ")?;
559                    self.fmt_ident(name)?;
560                }
561            }
562            // types of interface methods consist of signatures only
563            if iface {
564                match &field.typ {
565                    Expr::Func(sig) => {
566                        self.fmt_sig(&self.ast_objs.ftypes[*sig])?;
567                    }
568                    _ => {}
569                }
570            } else {
571                // named fields are separated with a blank from the field type
572                if field.names.len() > 0 {
573                    self.f.write_char(' ')?;
574                }
575                self.visit_expr(&field.typ)?;
576            }
577        }
578        Ok(())
579    }
580
581    fn fmt_ident(&mut self, ident: &IdentKey) -> fmt::Result {
582        self.f.write_str(&self.ast_objs.idents[*ident].name)
583    }
584}