* GjsContextPrivate::eval_with_scope: * @scope_object: an object to use as the global scope, or nullptr * @source: JavaScript program encoded in UTF-8 * @source_len: length of @source, or -1 if @source is 0-terminated * @filename: filename to use as the origin of @source * @retval: location for the return value of @source * * Executes @source with a local scope so that nothing from the sour
| 1651 | * Otherwise, the global definitions are just discarded. |
| 1652 | */ |
| 1653 | bool GjsContextPrivate::eval_with_scope(JS::HandleObject scope_object, |
| 1654 | const char* source, size_t source_len, |
| 1655 | const char* filename, |
| 1656 | JS::MutableHandleValue retval) { |
| 1657 | // log and clear exception if it's set (should not be, normally...) |
| 1658 | if (JS_IsExceptionPending(m_cx)) { |
| 1659 | g_warning("eval_with_scope() called with a pending exception"); |
| 1660 | return false; |
| 1661 | } |
| 1662 | |
| 1663 | JS::RootedObject eval_obj(m_cx, scope_object); |
| 1664 | if (!eval_obj) |
| 1665 | eval_obj = JS_NewPlainObject(m_cx); |
| 1666 | |
| 1667 | JS::SourceText<mozilla::Utf8Unit> buf; |
| 1668 | if (!buf.init(m_cx, source, source_len, JS::SourceOwnership::Borrowed)) |
| 1669 | return false; |
| 1670 | |
| 1671 | JS::EnvironmentChain scope_chain{m_cx, JS::SupportUnscopables::No}; |
| 1672 | if (!scope_chain.append(eval_obj)) { |
| 1673 | JS_ReportOutOfMemory(m_cx); |
| 1674 | return false; |
| 1675 | } |
| 1676 | |
| 1677 | JS::CompileOptions options(m_cx); |
| 1678 | options.setFileAndLine(filename, 1).setNonSyntacticScope(true); |
| 1679 | |
| 1680 | Gjs::AutoUnref<GFile> file{g_file_new_for_commandline_arg(filename)}; |
| 1681 | Gjs::AutoChar uri{g_file_get_uri(file)}; |
| 1682 | JS::RootedObject priv(m_cx, gjs_script_module_build_private(m_cx, uri)); |
| 1683 | if (!priv) |
| 1684 | return false; |
| 1685 | |
| 1686 | JS::RootedScript script(m_cx); |
| 1687 | script.set(JS::Compile(m_cx, options, buf)); |
| 1688 | if (!script) |
| 1689 | return false; |
| 1690 | |
| 1691 | JS::SetScriptPrivate(script, JS::ObjectValue(*priv)); |
| 1692 | if (!JS_ExecuteScript(m_cx, scope_chain, script, retval)) |
| 1693 | return false; |
| 1694 | |
| 1695 | schedule_gc_if_needed(); |
| 1696 | |
| 1697 | if (JS_IsExceptionPending(m_cx)) { |
| 1698 | g_warning( |
| 1699 | "JS::Evaluate() returned true but exception was pending; " |
| 1700 | "did somebody call gjs_throw() without returning false?"); |
| 1701 | return false; |
| 1702 | } |
| 1703 | |
| 1704 | gjs_debug(GJS_DEBUG_CONTEXT, "Script evaluation succeeded"); |
| 1705 | |
| 1706 | return true; |
| 1707 | } |
| 1708 | |
| 1709 | /** |
| 1710 | * GjsContextPrivate::call_function: |
no test coverage detected