1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use crate::compiling::v1::assemble::prelude::*;
/// Compile a unary expression.
impl Assemble for ast::ExprUnary {
fn assemble(&self, c: &mut Compiler<'_>, needs: Needs) -> CompileResult<Asm> {
let span = self.span();
log::trace!("ExprUnary => {:?}", c.source.source(span));
// NB: special unary expressions.
if let ast::UnOp::BorrowRef { .. } = self.op {
return Err(CompileError::new(self, CompileErrorKind::UnsupportedRef));
}
if let (ast::UnOp::Neg, ast::Expr::Lit(expr_lit)) = (self.op, &self.expr) {
if let ast::Lit::Number(n) = &expr_lit.lit {
match n.resolve(&c.storage, &*c.source)? {
ast::Number::Float(n) => {
c.asm.push(Inst::float(-n), span);
}
ast::Number::Integer(int) => {
use num::ToPrimitive as _;
use std::ops::Neg as _;
let n = match int.neg().to_i64() {
Some(n) => n,
None => {
return Err(CompileError::new(
span,
ParseErrorKind::BadNumberOutOfBounds,
));
}
};
c.asm.push(Inst::integer(n), span);
}
}
return Ok(Asm::top(span));
}
}
self.expr.assemble(c, Needs::Value)?.apply(c)?;
match self.op {
ast::UnOp::Not { .. } => {
c.asm.push(Inst::Not, span);
}
ast::UnOp::Neg { .. } => {
c.asm.push(Inst::Neg, span);
}
op => {
return Err(CompileError::new(
span,
CompileErrorKind::UnsupportedUnaryOp { op },
));
}
}
// NB: we put it here to preserve the call in case it has side effects.
// But if we don't need the value, then pop it from the stack.
if !needs.value() {
c.asm.push(Inst::Pop, span);
}
Ok(Asm::top(span))
}
}