boa/syntax/ast/node/operator/unary_op/
mod.rs1use crate::{
2 exec::Executable,
3 gc::{Finalize, Trace},
4 syntax::ast::{node::Node, op},
5 Context, JsBigInt, JsResult, JsValue,
6};
7use std::fmt;
8
9use crate::builtins::Number;
10use crate::value::Numeric;
11#[cfg(feature = "deser")]
12use serde::{Deserialize, Serialize};
13
14#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
23#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
24pub struct UnaryOp {
25 op: op::UnaryOp,
26 target: Box<Node>,
27}
28
29impl UnaryOp {
30 pub(in crate::syntax) fn new<V>(op: op::UnaryOp, target: V) -> Self
32 where
33 V: Into<Node>,
34 {
35 Self {
36 op,
37 target: Box::new(target.into()),
38 }
39 }
40
41 pub fn op(&self) -> op::UnaryOp {
43 self.op
44 }
45
46 pub fn target(&self) -> &Node {
48 self.target.as_ref()
49 }
50}
51
52impl Executable for UnaryOp {
53 fn run(&self, context: &mut Context) -> JsResult<JsValue> {
54 Ok(match self.op() {
55 op::UnaryOp::Minus => self.target().run(context)?.neg(context)?,
56 op::UnaryOp::Plus => JsValue::new(self.target().run(context)?.to_number(context)?),
57 op::UnaryOp::IncrementPost => {
58 let x = self.target().run(context)?;
59 let ret = x.clone();
60 let result = x.to_number(context)? + 1.0;
61 context.set_value(self.target(), result.into())?;
62 ret
63 }
64 op::UnaryOp::IncrementPre => {
65 let result = self.target().run(context)?.to_number(context)? + 1.0;
66 context.set_value(self.target(), result.into())?
67 }
68 op::UnaryOp::DecrementPost => {
69 let x = self.target().run(context)?;
70 let ret = x.clone();
71 let result = x.to_number(context)? - 1.0;
72 context.set_value(self.target(), result.into())?;
73 ret
74 }
75 op::UnaryOp::DecrementPre => {
76 let result = self.target().run(context)?.to_number(context)? - 1.0;
77 context.set_value(self.target(), result.into())?
78 }
79 op::UnaryOp::Not => self.target().run(context)?.not(context)?.into(),
80 op::UnaryOp::Tilde => {
81 let expr = self.target().run(context)?;
82 let old_v = expr.to_numeric(context)?;
83 match old_v {
84 Numeric::Number(x) => JsValue::new(Number::not(x)),
85 Numeric::BigInt(x) => JsValue::new(JsBigInt::not(&x)),
86 }
87 }
88 op::UnaryOp::Void => {
89 self.target().run(context)?;
90 JsValue::undefined()
91 }
92 op::UnaryOp::Delete => match *self.target() {
93 Node::GetConstField(ref get_const_field) => {
94 let delete_status = get_const_field
95 .obj()
96 .run(context)?
97 .to_object(context)?
98 .__delete__(&get_const_field.field().into(), context)?;
99
100 if !delete_status && context.strict() {
101 return context.throw_type_error("Cannot delete property");
102 } else {
103 JsValue::new(delete_status)
104 }
105 }
106 Node::GetField(ref get_field) => {
107 let obj = get_field.obj().run(context)?;
108 let field = &get_field.field().run(context)?;
109 let res = obj
110 .to_object(context)?
111 .__delete__(&field.to_property_key(context)?, context)?;
112 return Ok(JsValue::new(res));
113 }
114 Node::Identifier(_) => JsValue::new(false),
115 Node::ArrayDecl(_)
116 | Node::Block(_)
117 | Node::Const(_)
118 | Node::FunctionDecl(_)
119 | Node::FunctionExpr(_)
120 | Node::New(_)
121 | Node::Object(_)
122 | Node::UnaryOp(_) => JsValue::new(true),
123 _ => return context.throw_syntax_error(format!("wrong delete argument {}", self)),
124 },
125 op::UnaryOp::TypeOf => JsValue::new(self.target().run(context)?.type_of()),
126 })
127 }
128}
129
130impl fmt::Display for UnaryOp {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 write!(f, "{}{}", self.op, self.target)
133 }
134}
135
136impl From<UnaryOp> for Node {
137 fn from(op: UnaryOp) -> Self {
138 Self::UnaryOp(op)
139 }
140}