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}