javascriptcore/base.rs
1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7use crate::{sys, JSContext, JSException, JSObject, JSString, JSValue};
8use std::ptr;
9
10/// Evaluates a string of JavaScript.
11///
12/// * `ctx`: The execution context to use.
13/// * `script`: A string containing the script to evaluate.
14/// * `this_object`: The optional object to use as `this`, or `None` to
15/// use the global object as `this`.
16/// * `source_url`: An optional string containing a URL for the script's
17/// source file. This is used by debuggers and when reporting
18/// exceptions. Pass `None` if you do not care to include source
19/// file information.
20/// * `starting_line_number`: An integer value specifying the script's
21/// starting line number in the file located at `source_url`. This
22/// is only used when reporting exceptions. The value is one-based,
23/// so the first line is line `1` and invalid values are clamped
24/// to `1`.
25///
26/// Returns either the [`JSValue`] that results from evaluating the script or
27/// the exception that occurred.
28///
29/// ```
30/// use javascriptcore::*;
31///
32/// let ctx = JSContext::default();
33/// let r = evaluate_script(&ctx, "2 + 2", None, "test.js", 1);
34/// assert_eq!(r.unwrap().as_number().unwrap(), 4.0);
35/// ```
36pub fn evaluate_script<S: Into<JSString>, U: Into<JSString>>(
37 ctx: &JSContext,
38 script: S,
39 this_object: Option<&JSObject>,
40 source_url: U,
41 starting_line_number: i32,
42) -> Result<JSValue, JSException> {
43 unsafe {
44 let mut exception: sys::JSValueRef = ptr::null_mut();
45 let result = sys::JSEvaluateScript(
46 ctx.raw,
47 script.into().raw,
48 this_object.map_or(ptr::null_mut(), |t| t.raw),
49 source_url.into().raw,
50 starting_line_number,
51 &mut exception,
52 );
53
54 if result.is_null() {
55 Err(JSValue::from_raw(ctx.raw, exception).into())
56 } else {
57 Ok(JSValue::from_raw(ctx.raw, result))
58 }
59 }
60}
61
62/// Checks for syntax errors in a string of JavaScript.
63///
64/// * `ctx`: The execution context to use.
65/// * `script`: A string containing the script to check for
66/// syntax errors.
67/// * `source_url`: An optional string containing a URL for the script's
68/// source file. This is only used when reporting exceptions. Pass
69/// `None` if you do not care to include source file information in
70/// exceptions.
71/// * `starting_line_number`: An integer value specifying the script's
72/// starting line number in the file located at `source_url`. This
73/// is only used when reporting exceptions. The value is one-based,
74/// so the first line is line `1` and invalid values are clamped
75/// to `1`.
76///
77/// Returns `Ok` if the script is syntactically correct, otherwise
78/// returns an [exception](JSException).
79///
80/// ```
81/// use javascriptcore::*;
82///
83/// let ctx = JSContext::default();
84/// let r = check_script_syntax(&ctx, "alert('abc');", "test.js", 1);
85/// assert!(r.is_ok());
86/// ```
87pub fn check_script_syntax<S: Into<JSString>, U: Into<JSString>>(
88 ctx: &JSContext,
89 script: S,
90 source_url: U,
91 starting_line_number: i32,
92) -> Result<(), JSException> {
93 unsafe {
94 let mut exception: sys::JSValueRef = ptr::null_mut();
95 let result = sys::JSCheckScriptSyntax(
96 ctx.raw,
97 script.into().raw,
98 source_url.into().raw,
99 starting_line_number,
100 &mut exception,
101 );
102
103 if result {
104 Ok(())
105 } else {
106 Err(JSValue::from_raw(ctx.raw, exception).into())
107 }
108 }
109}
110
111/// Performs a JavaScript garbage collection.
112///
113/// JavaScript values that are on the machine stack, in a register,
114/// protected by [`JSValue::protect()`], set as the global object of an
115/// execution context, or reachable from any such value will not
116/// be collected.
117///
118/// During JavaScript execution, you are not required to call this
119/// function; the JavaScript engine will garbage collect as needed.
120/// JavaScript values created within a context group are automatically
121/// destroyed when the last reference to the context group is released.
122///
123/// * `ctx`: The execution context to use.
124///
125/// ```
126/// use javascriptcore::*;
127///
128/// let ctx = JSContext::default();
129/// // ... Do things ...
130/// garbage_collect(&ctx);
131/// ```
132///
133/// # See also
134///
135/// * [`JSValue::protect()`]
136/// * [`JSValue::unprotect()`]
137pub fn garbage_collect(ctx: &JSContext) {
138 unsafe {
139 sys::JSGarbageCollect(ctx.raw);
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::{check_script_syntax, evaluate_script, garbage_collect};
146 use crate::JSContext;
147
148 #[test]
149 fn can_check_script_syntax() {
150 let ctx = JSContext::default();
151
152 let r = check_script_syntax(&ctx, "alert('abc');", "test.js", 1);
153 assert!(r.is_ok());
154
155 let f = check_script_syntax(&ctx, "alert('abc", "test.js", 1);
156 assert!(f.is_err());
157 }
158
159 #[test]
160 fn can_evaluate_script() {
161 let ctx = JSContext::default();
162
163 let r = evaluate_script(&ctx, "2 + 2", None, "test.js", 1);
164 assert_eq!(r.unwrap().as_number().unwrap(), 4.0);
165 }
166
167 #[test]
168 fn can_garbage_collect() {
169 let ctx = JSContext::default();
170 garbage_collect(&ctx);
171 }
172}