diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..1df6c35b --- /dev/null +++ b/.clang-format @@ -0,0 +1,199 @@ +# Commented out parameters are those with the same value as base LLVM style. +# We can uncomment them if we want to change their value, or enforce the +# chosen value in case the base style changes (last sync: Clang 14.0). +--- +### General config, applies to all languages ### +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +# AlignArrayOfStructures: None +# AlignConsecutiveMacros: None +# AlignConsecutiveAssignments: None +# AlignConsecutiveBitFields: None +# AlignConsecutiveDeclarations: None +# AlignEscapedNewlines: Right +AlignOperands: DontAlign +AlignTrailingComments: false +# AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +# AllowShortEnumsOnASingleLine: true +# AllowShortBlocksOnASingleLine: Never +# AllowShortCaseLabelsOnASingleLine: false +# AllowShortFunctionsOnASingleLine: All +# AllowShortLambdasOnASingleLine: All +# AllowShortIfStatementsOnASingleLine: Never +# AllowShortLoopsOnASingleLine: false +# AlwaysBreakAfterDefinitionReturnType: None +# AlwaysBreakAfterReturnType: None +# AlwaysBreakBeforeMultilineStrings: false +# AlwaysBreakTemplateDeclarations: MultiLine +# AttributeMacros: +# - __capability +# BinPackArguments: true +# BinPackParameters: true +# BraceWrapping: +# AfterCaseLabel: false +# AfterClass: false +# AfterControlStatement: Never +# AfterEnum: false +# AfterFunction: false +# AfterNamespace: false +# AfterObjCDeclaration: false +# AfterStruct: false +# AfterUnion: false +# AfterExternBlock: false +# BeforeCatch: false +# BeforeElse: false +# BeforeLambdaBody: false +# BeforeWhile: false +# IndentBraces: false +# SplitEmptyFunction: true +# SplitEmptyRecord: true +# SplitEmptyNamespace: true +# BreakBeforeBinaryOperators: None +# BreakBeforeConceptDeclarations: true +# BreakBeforeBraces: Attach +# BreakBeforeInheritanceComma: false +# BreakInheritanceList: BeforeColon +# BreakBeforeTernaryOperators: true +# BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: AfterColon +# BreakStringLiterals: true +ColumnLimit: 0 +# CommentPragmas: '^ IWYU pragma:' +# QualifierAlignment: Leave +# CompactNamespaces: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +# DeriveLineEnding: true +# DerivePointerAlignment: false +# DisableFormat: false +# EmptyLineAfterAccessModifier: Never +# EmptyLineBeforeAccessModifier: LogicalBlock +# ExperimentalAutoDetectBinPacking: false +# PackConstructorInitializers: BinPack +ConstructorInitializerAllOnOneLineOrOnePerLine: true +# AllowAllConstructorInitializersOnNextLine: true +# FixNamespaceComments: true +# ForEachMacros: +# - foreach +# - Q_FOREACH +# - BOOST_FOREACH +# IfMacros: +# - KJ_IF_MAYBE +# IncludeBlocks: Preserve +IncludeCategories: + - Regex: '".*"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 +# IncludeIsMainRegex: '(Test)?$' +# IncludeIsMainSourceRegex: '' +# IndentAccessModifiers: false +IndentCaseLabels: true +# IndentCaseBlocks: false +# IndentGotoLabels: true +# IndentPPDirectives: None +# IndentExternBlock: AfterExternBlock +# IndentRequires: false +IndentWidth: 4 +# IndentWrappedFunctionNames: false +# InsertTrailingCommas: None +# JavaScriptQuotes: Leave +# JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +# LambdaBodyIndentation: Signature +# MacroBlockBegin: '' +# MacroBlockEnd: '' +# MaxEmptyLinesToKeep: 1 +# NamespaceIndentation: None +# PenaltyBreakAssignment: 2 +# PenaltyBreakBeforeFirstCallParameter: 19 +# PenaltyBreakComment: 300 +# PenaltyBreakFirstLessLess: 120 +# PenaltyBreakOpenParenthesis: 0 +# PenaltyBreakString: 1000 +# PenaltyBreakTemplateDeclaration: 10 +# PenaltyExcessCharacter: 1000000 +# PenaltyReturnTypeOnItsOwnLine: 60 +# PenaltyIndentedWhitespace: 0 +# PointerAlignment: Right +# PPIndentWidth: -1 +# ReferenceAlignment: Pointer +# ReflowComments: true +# RemoveBracesLLVM: false +# SeparateDefinitionBlocks: Leave +# ShortNamespaceLines: 1 +# SortIncludes: CaseSensitive +# SortJavaStaticImport: Before +# SortUsingDeclarations: true +# SpaceAfterCStyleCast: false +# SpaceAfterLogicalNot: false +# SpaceAfterTemplateKeyword: true +# SpaceBeforeAssignmentOperators: true +# SpaceBeforeCaseColon: false +# SpaceBeforeCpp11BracedList: false +# SpaceBeforeCtorInitializerColon: true +# SpaceBeforeInheritanceColon: true +# SpaceBeforeParens: ControlStatements +# SpaceBeforeParensOptions: +# AfterControlStatements: true +# AfterForeachMacros: true +# AfterFunctionDefinitionName: false +# AfterFunctionDeclarationName: false +# AfterIfMacros: true +# AfterOverloadedOperator: false +# BeforeNonEmptyParentheses: false +# SpaceAroundPointerQualifiers: Default +# SpaceBeforeRangeBasedForLoopColon: true +# SpaceInEmptyBlock: false +# SpaceInEmptyParentheses: false +# SpacesBeforeTrailingComments: 1 +# SpacesInAngles: Never +# SpacesInConditionalStatement: false +# SpacesInContainerLiterals: true +# SpacesInCStyleCastParentheses: false +## Godot TODO: We'll want to use a min of 1, but we need to see how to fix +## our comment capitalization at the same time. +SpacesInLineCommentPrefix: + Minimum: 0 + Maximum: -1 +# SpacesInParentheses: false +# SpacesInSquareBrackets: false +# SpaceBeforeSquareBrackets: false +# BitFieldColonSpacing: Both +# StatementAttributeLikeMacros: +# - Q_EMIT +# StatementMacros: +# - Q_UNUSED +# - QT_REQUIRE_VERSION +TabWidth: 4 +# UseCRLF: false +UseTab: Always +# WhitespaceSensitiveMacros: +# - STRINGIZE +# - PP_STRINGIZE +# - BOOST_PP_STRINGIZE +# - NS_SWIFT_NAME +# - CF_SWIFT_NAME +--- +### C++ specific config ### +Language: Cpp +Standard: c++17 +--- +### ObjC specific config ### +Language: ObjC +# ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +# ObjCBreakBeforeNestedBlockParam: true +# ObjCSpaceAfterProperty: false +# ObjCSpaceBeforeProtocolList: true +--- +### Java specific config ### +Language: Java +# BreakAfterJavaFieldAnnotations: false +JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax'] +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..659b9101 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,47 @@ +--- +Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,cppcoreguidelines-pro-type-member-init,modernize-redundant-void-arg,modernize-use-bool-literals,modernize-use-default-member-init,modernize-use-nullptr,readability-braces-around-statements,readability-redundant-member-init' +WarningsAsErrors: '' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +FormatStyle: none +CheckOptions: + - key: cert-dcl16-c.NewSuffixes + value: 'L;LL;LU;LLU' + - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField + value: '0' + - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors + value: '1' + - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic + value: '1' + - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays + value: '1' + - key: cppcoreguidelines-pro-type-member-init.UseAssignment + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-bool-literals.IgnoreMacros + value: '0' + - key: modernize-use-default-member-init.IgnoreMacros + value: '0' + - key: modernize-use-default-member-init.UseAssignment + value: '1' + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: readability-braces-around-statements.ShortStatementLines + value: '0' +... + diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..031582bc --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,180 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners. +# Owners can be @users, @org/teams or emails + +# Buildsystem + +.* @godotengine/buildsystem +.github/ @godotengine/buildsystem +*.py @godotengine/buildsystem +SConstruct @godotengine/buildsystem +SCsub @godotengine/buildsystem + +# Core + +/core/ @godotengine/core +/core/crypto/ @godotengine/network +/core/debugger/ @godotengine/debugger +/core/extension/ @godotengine/gdextension +/core/input/ @godotengine/input + +# Doc + +/doc/ @godotengine/documentation +doc_classes/* @godotengine/documentation + +# Drivers + +## Audio +/drivers/alsa/ @godotengine/audio +/drivers/alsamidi/ @godotengine/audio +/drivers/coreaudio/ @godotengine/audio +/drivers/coremidi/ @godotengine/audio +/drivers/pulseaudio/ @godotengine/audio +/drivers/wasapi/ @godotengine/audio +/drivers/winmidi/ @godotengine/audio +/drivers/xaudio2/ @godotengine/audio + +## Rendering +/drivers/dummy/ @godotengine/rendering +/drivers/gles3/ @godotengine/rendering +/drivers/spirv-reflect/ @godotengine/rendering +/drivers/vulkan/ @godotengine/rendering + +## OS +/drivers/unix/ @godotengine/_platforms +/drivers/windows/ @godotengine/windows + +## Misc +/drivers/png/ @godotengine/import + +# Editor + +/editor/*debugger* @godotengine/debugger +/editor/icons/ @godotengine/usability +/editor/import/ @godotengine/import +/editor/plugins/*2d_*.* @godotengine/2d-editor +/editor/plugins/*3d_*.* @godotengine/3d-editor +/editor/plugins/script_*.* @godotengine/script-editor +/editor/plugins/*shader*.* @godotengine/shaders +/editor/code_editor.* @godotengine/script-editor +/editor/*dock*.* @godotengine/docks +/editor/*shader*.* @godotengine/shaders + +# Main + +/main/ @godotengine/core + +# Misc + +/misc/ @godotengine/buildsystem + +# Modules + +## Audio (+ video) +/modules/minimp3/ @godotengine/audio +/modules/ogg/ @godotengine/audio +/modules/opus/ @godotengine/audio +/modules/theora/ @godotengine/audio +/modules/vorbis/ @godotengine/audio +/modules/webm/ @godotengine/audio + +## Import +/modules/basis_universal/ @godotengine/import +/modules/bmp/ @godotengine/import +/modules/cvtt/ @godotengine/import +/modules/dds/ @godotengine/import +/modules/etc/ @godotengine/import +/modules/fbx/ @godotengine/import +/modules/gltf/ @godotengine/import +/modules/hdr/ @godotengine/import +/modules/jpg/ @godotengine/import +/modules/pvr/ @godotengine/import +/modules/squish/ @godotengine/import +/modules/svg/ @godotengine/import +/modules/tga/ @godotengine/import +/modules/tinyexr/ @godotengine/import +/modules/webp/ @godotengine/import + +## Network +/modules/enet/ @godotengine/network +/modules/mbedtls/ @godotengine/network +/modules/upnp/ @godotengine/network +/modules/webrtc/ @godotengine/network +/modules/websocket/ @godotengine/network + +## Rendering +/modules/denoise/ @godotengine/rendering +/modules/glslang/ @godotengine/rendering +/modules/lightmapper_rd/ @godotengine/rendering +/modules/meshoptimizer/ @godotengine/rendering +/modules/vhacd/ @godotengine/rendering +/modules/xatlas_unwrap/ @godotengine/rendering + +## Scripting +/modules/gdscript/ @godotengine/gdscript +/modules/jsonrpc/ @godotengine/gdscript +/modules/mono/ @godotengine/dotnet + +## Text +/modules/freetype/ @godotengine/buildsystem +/modules/text_server_adv/ @godotengine/gui-nodes +/modules/text_server_fb/ @godotengine/gui-nodes + +## XR +/modules/camera/ @godotengine/xr +/modules/gdextension/xr/ @godotengine/xr +/modules/mobile_vr/ @godotengine/xr +/modules/webxr/ @godotengine/xr + +## Misc +/modules/bullet/ @godotengine/physics +/modules/csg/ @godotengine/3d-nodes +/modules/gdnavigation/ @godotengine/navigation +/modules/gridmap/ @godotengine/3d-nodes +/modules/opensimplex/ @godotengine/3d-nodes +/modules/regex/ @godotengine/core + +# Platform + +/platform/android/ @godotengine/android +/platform/ios/ @godotengine/ios +/platform/javascript/ @godotengine/html5 +/platform/linuxbsd/ @godotengine/linux-bsd +/platform/macos/ @godotengine/macos +/platform/uwp/ @godotengine/uwp +/platform/windows/ @godotengine/windows + +# Scene + +/scene/2d/ @godotengine/2d-nodes +/scene/3d/ @godotengine/3d-nodes +/scene/animation/ @godotengine/animation +/scene/audio/ @godotengine/audio +/scene/debugger/ @godotengine/debugger +/scene/gui/ @godotengine/gui-nodes +/scene/main/ @godotengine/core +/scene/resources/default_theme/ @godotengine/gui-nodes +/scene/resources/font.* @godotengine/gui-nodes +/scene/resources/text_line.* @godotengine/gui-nodes +/scene/resources/text_paragraph.* @godotengine/gui-nodes +/scene/resources/visual_shader*.* @godotengine/shaders + +# Servers + +/servers/audio* @godotengine/audio +/servers/camera* @godotengine/xr +/servers/display_server.* @godotengine/_platforms +/servers/navigation_server*.* @godotengine/navigation +/servers/physics* @godotengine/physics +/servers/rendering* @godotengine/rendering +/servers/text_server.* @godotengine/gui-nodes +/servers/xr* @godotengine/xr + +# Tests + +/tests/ @godotengine/tests + +# Thirdparty + +/thirdparty/ @godotengine/buildsystem diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..0b4abac1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,59 @@ +name: Bug report +description: Report a bug in Godot +body: + +- type: markdown + attributes: + value: | + - Read our [CONTRIBUTING.md guide](https://github.com/godotengine/godot/blob/master/CONTRIBUTING.md#reporting-bugs) on reporting bugs. + - Write a descriptive issue title above. + - Search [open](https://github.com/godotengine/godot/issues) and [closed](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. + - Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/stable/about/release_policy.html). + +- type: input + attributes: + label: Godot version + description: > + Specify the Git commit hash if using a development or non-official build. + If you use a custom build, please test if your issue is reproducible in official builds too. + placeholder: 3.3.stable, 4.0.dev (3041becc6) + validations: + required: true + +- type: input + attributes: + label: System information + description: | + Specify the OS version, and when relevant hardware information. + For graphics-related issues, specify the GPU model, driver version, and the rendering backend (GLES2, GLES3, Vulkan). + placeholder: Windows 10, GLES3, Intel HD Graphics 620 (27.20.100.9616) + validations: + required: true + +- type: textarea + attributes: + label: Issue description + description: | + Describe your issue briefly. What doesn't work, and how do you expect it to work instead? + You can include images or videos with drag and drop, and format code blocks or logs with ``` tags. + validations: + required: true + +- type: textarea + attributes: + label: Steps to reproduce + description: | + List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them. + If you include a minimal reproduction project below, you can detail how to use it here. + validations: + required: true + +- type: textarea + attributes: + label: Minimal reproduction project + description: | + A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`). + Required, unless the reproduction steps are trivial and don't require any project files to be followed. In this case, write "N/A" in the field. + Drag and drop a ZIP archive to upload it. **Do not select another field until the project is done uploading.** + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..f787bec0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: false + +contact_links: + - name: Godot proposals + url: https://github.com/godotengine/godot-proposals + about: Please submit feature proposals on the Godot proposals repository, not here. + + - name: Godot documentation repository + url: https://github.com/godotengine/godot-docs + about: Please report issues with documentation on the Godot documentation repository, not here. + + - name: Godot community channels + url: https://godotengine.org/community + about: Please ask for technical support on one of the other community channels, not here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..8dc712c7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ + diff --git a/.github/actions/godot-build/action.yml b/.github/actions/godot-build/action.yml index 564f40d9..377480b1 100644 --- a/.github/actions/godot-build/action.yml +++ b/.github/actions/godot-build/action.yml @@ -2,52 +2,35 @@ name: Build Godot description: Build Godot with the provided options. inputs: target: - description: The scons target (debug/editor/release). - default: editor - tools: - description: If tools are to be built. - default: false + description: Build target (editor, template_release, template_debug). + default: "editor" tests: - description: If tests are to be built. + description: Unit tests. default: false platform: - description: The Godot platform to build. + description: Target platform. required: false sconsflags: - default: '' + default: "" scons-cache: description: The scons cache path. - default: ${{ github.workspace }}/.scons-cache/ + default: "${{ github.workspace }}/.scons-cache/" scons-cache-limit: description: The scons cache size limit. + # actions/cache has 10 GiB limit, and GitHub runners have a 14 GiB disk. + # Limit to 7 GiB to avoid having the extracted cache fill the disk. default: 7168 - shell: - description: the shell to run this under - default: sh runs: - using: composite + using: "composite" steps: - - name: Scons Build - shell: sh - env: - SCONSFLAGS: ${{ inputs.sconsflags }} - SCONS_CACHE: ${{ inputs.scons-cache }} - SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }} - run: | - echo "Building with flags:" ${{ env.SCONSFLAGS }} - if [ "${{ inputs.target }}" != "editor" ]; then rm -rf editor; fi # Ensure we don't include editor code. - scons platform=${{ inputs.platform }} target=${{ inputs.target }} tools=${{ inputs.tools }} tests=${{ inputs.tests }} --jobs=2 ${{ env.SCONSFLAGS }} - ls -l bin/ - if: inputs.shell == 'sh' - - name: Scons Build - shell: msys2 {0} - env: - SCONSFLAGS: ${{ inputs.sconsflags }} - SCONS_CACHE: ${{ inputs.scons-cache }} - SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }} - run: | - echo "Building with flags:" ${{ env.SCONSFLAGS }} - if [ "${{ inputs.target }}" != "editor" ]; then rm -rf editor; rm -rf tools; fi # Ensure we don't include editor code. - scons platform=${{ inputs.platform }} target=${{ inputs.target }} tools=${{ inputs.tools }} tests=${{ inputs.tests }} --jobs=2 ${{ env.SCONSFLAGS }} - ls -l bin/ - if: inputs.shell == 'msys2 {0}' + - name: Scons Build + shell: sh + env: + SCONSFLAGS: ${{ inputs.sconsflags }} + SCONS_CACHE: ${{ inputs.scons-cache }} + SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }} + run: | + echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} + if [ "${{ inputs.target }}" != "editor" ]; then rm -rf editor; fi # Ensure we don't include editor code. + scons platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} + ls -l bin/ diff --git a/.github/actions/godot-cache/action.yml b/.github/actions/godot-cache/action.yml index 72ed281d..2d7afc85 100644 --- a/.github/actions/godot-cache/action.yml +++ b/.github/actions/godot-cache/action.yml @@ -3,19 +3,20 @@ description: Setup Godot build cache. inputs: cache-name: description: The cache base name (job name by default). - default: ${{github.job}} + default: "${{github.job}}" scons-cache: description: The scons cache path. - default: ${{github.workspace}}/.scons-cache/ + default: "${{github.workspace}}/.scons-cache/" runs: - using: composite + using: "composite" steps: - - name: Load .scons_cache directory - uses: actions/cache@v2 - with: - path: ${{inputs.scons-cache}} - key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} - restore-keys: | - ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} - ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}} - ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}} + # Upload cache on completion and check it out now + - name: Load .scons_cache directory + uses: actions/cache@v3 + with: + path: ${{inputs.scons-cache}} + key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} + restore-keys: | + ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}} + ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}} + ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}} diff --git a/.github/actions/godot-deps/action.yml b/.github/actions/godot-deps/action.yml index 1d7347bc..38731db5 100644 --- a/.github/actions/godot-deps/action.yml +++ b/.github/actions/godot-deps/action.yml @@ -3,32 +3,25 @@ description: Setup python, install the pip version of scons. inputs: python-version: description: The python version to use. - default: 3.x + default: "3.x" python-arch: description: The python architecture. - default: x64 - shell: - description: the shell to run this under - default: sh + default: "x64" runs: - using: composite + using: "composite" steps: - - name: Set up Python 3.x - uses: actions/setup-python@v2 - with: - python-version: ${{ inputs.python-version }} - architecture: ${{ inputs.python-arch }} - - name: Setup scons - shell: sh - run: | - python -c "import sys; print(sys.version)" - python -m pip install scons - scons --version - if: inputs.shell == 'sh' - - name: Setup scons - shell: msys2 {0} - run: | - python -c "import sys; print(sys.version)" - python -m pip install scons - scons --version - if: inputs.shell == 'msys2 {0}' + # Use python 3.x release (works cross platform) + - name: Set up Python 3.x + uses: actions/setup-python@v4 + with: + # Semantic version range syntax or exact version of a Python version + python-version: ${{ inputs.python-version }} + # Optional - x64 or x86 architecture, defaults to x64 + architecture: ${{ inputs.python-arch }} + + - name: Setup scons + shell: bash + run: | + python -c "import sys; print(sys.version)" + python -m pip install scons==4.4.0 + scons --version diff --git a/.github/actions/upload-artifact/action.yml b/.github/actions/upload-artifact/action.yml index 820273b1..ae0e634c 100644 --- a/.github/actions/upload-artifact/action.yml +++ b/.github/actions/upload-artifact/action.yml @@ -3,17 +3,17 @@ description: Upload the Godot artifact. inputs: name: description: The artifact name. - default: ${{ github.job }} + default: "${{ github.job }}" path: description: The path to upload. required: true - default: bin/* + default: "bin/*" runs: - using: composite + using: "composite" steps: - - name: Upload Godot Artifact - uses: actions/upload-artifact@v2 - with: - name: ${{ inputs.name }} - path: ${{ inputs.path }} - retention-days: 14 + - name: Upload Godot Artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.name }} + path: ${{ inputs.path }} + retention-days: 14 diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index 3506752c..42125db9 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -1,65 +1,69 @@ name: 🤖 Android Builds -'on': -- push -- pull_request +on: + workflow_call: + +# Global Settings env: - GODOT_BASE_BRANCH: "4.0" - SCONSFLAGS: verbose=yes warnings=extra debug_symbols=no module_text_server_fb_enabled=yes + # Used for the cache key. Add version suffix to force clean build. + GODOT_BASE_BRANCH: '4.0' + SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes + concurrency: group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-android cancel-in-progress: true + jobs: android-template: - runs-on: ubuntu-20.04 - name: Template (target=release, tools=no) + runs-on: "ubuntu-20.04" + name: Template (target=template_release) + steps: - - name: Checkout Godot - uses: actions/checkout@v2 - with: - repository: godotengine/godot - ref: ${{ env.GODOT_BASE_BRANCH }} - - name: Checkout ECMAScript - uses: actions/checkout@v2 - with: - path: ${{github.workspace}}/modules/javascript/ - - name: Make apt sources.list use the default Ubuntu repositories - run: | - # sudo rm -f /etc/apt/sources.list.d/* - # sudo cp -f misc/ci/sources.list /etc/apt/sources.list - sudo apt-get update - - name: Set up Java 11 - uses: actions/setup-java@v3 - with: - distribution: temurin - java-version: 11 - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache - continue-on-error: true - - name: Setup python and scons - uses: ./modules/javascript/.github/actions/godot-deps - with: - shell: sh - - name: Compilation (armv7) - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} android_arch=armv7 - platform: android - target: template_release - tools: false - shell: sh - - name: Compilation (arm64v8) - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} android_arch=arm64v8 - platform: android - target: template_release - tools: false - shell: sh - - name: Generate Godot templates - run: | - cd platform/android/java - ./gradlew generateGodotTemplates - cd ../../.. - ls -l bin/ - - name: Upload artifact - uses: ./.github/actions/upload-artifact + - name: Checkout Godot + uses: actions/checkout@v2 + with: + repository: godotengine/godot + ref: ${{ env.GODOT_BASE_BRANCH }} + + - name: Checkout ECMAScript + uses: actions/checkout@v2 + with: + path: ${{github.workspace}}/modules/javascript/ + + - name: Set up Java 11 + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11 + + - name: Setup Godot build cache + uses: ./.github/actions/godot-cache + continue-on-error: true + + - name: Setup python and scons + uses: ./.github/actions/godot-deps + + - name: Compilation (arm32) + uses: ./.github/actions/godot-build + with: + sconsflags: ${{ env.SCONSFLAGS }} arch=arm32 + platform: android + target: template_release + tests: false + + - name: Compilation (arm64) + uses: ./.github/actions/godot-build + with: + sconsflags: ${{ env.SCONSFLAGS }} arch=arm64 + platform: android + target: template_release + tests: false + + - name: Generate Godot templates + run: | + cd platform/android/java + ./gradlew generateGodotTemplates + cd ../../.. + ls -l bin/ + + - name: Upload artifact + uses: ./.github/actions/upload-artifact diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml index 43a3575f..78c05c78 100644 --- a/.github/workflows/ios_builds.yml +++ b/.github/workflows/ios_builds.yml @@ -1,41 +1,48 @@ name: 🍏 iOS Builds -'on': -- push -- pull_request +on: + workflow_call: + +# Global Settings env: - GODOT_BASE_BRANCH: "4.0" - SCONSFLAGS: verbose=yes warnings=extra debug_symbols=no module_text_server_fb_enabled=yes + # Used for the cache key. Add version suffix to force clean build. + GODOT_BASE_BRANCH: '4.0' + SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes + concurrency: group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-ios cancel-in-progress: true + jobs: ios-template: - runs-on: macos-latest - name: Template (target=release, tools=no) + runs-on: "macos-latest" + name: Template (target=template_release) + steps: - - name: Checkout Godot - uses: actions/checkout@v2 - with: - repository: godotengine/godot - ref: ${{ env.GODOT_BASE_BRANCH }} - - name: Checkout ECMAScript - uses: actions/checkout@v2 - with: - path: ${{github.workspace}}/modules/javascript/ - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache - continue-on-error: true - - name: Setup python and scons - uses: ./modules/javascript/.github/actions/godot-deps - with: - shell: sh - - name: Compilation (armv7) - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} - platform: ios - target: template_release - tools: false - shell: sh - - name: Upload artifact - uses: ./.github/actions/upload-artifact + - name: Checkout Godot + uses: actions/checkout@v2 + with: + repository: godotengine/godot + ref: ${{ env.GODOT_BASE_BRANCH }} + + - name: Checkout ECMAScript + uses: actions/checkout@v2 + with: + path: ${{github.workspace}}/modules/javascript/ + + - name: Setup Godot build cache + uses: ./.github/actions/godot-cache + continue-on-error: true + + - name: Setup python and scons + uses: ./.github/actions/godot-deps + + - name: Compilation (arm64) + uses: ./.github/actions/godot-build + with: + sconsflags: ${{ env.SCONSFLAGS }} + platform: ios + target: template_release + tests: false + + - name: Upload artifact + uses: ./.github/actions/upload-artifact diff --git a/.github/workflows/javascript_builds.yml b/.github/workflows/javascript_builds.yml deleted file mode 100644 index c7f2af2c..00000000 --- a/.github/workflows/javascript_builds.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: 🌐 JavaScript Builds -'on': -- push -- pull_request -env: - GODOT_BASE_BRANCH: "4.0" - SCONSFLAGS: verbose=yes warnings=extra debug_symbols=no - EM_VERSION: 3.1.18 - EM_CACHE_FOLDER: "emsdk-cache" - -concurrency: - group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-javascript - cancel-in-progress: true -jobs: - javascript-template: - runs-on: ubuntu-20.04 - name: Template (target=release, tools=no) - steps: - - name: Checkout Godot - uses: actions/checkout@v2 - with: - repository: godotengine/godot - ref: ${{ env.GODOT_BASE_BRANCH }} - - name: Checkout ECMAScript - uses: actions/checkout@v2 - with: - path: ${{github.workspace}}/modules/javascript/ - - name: Load Emscripten cache - id: javascript-template-emscripten-cache - uses: actions/cache@v2 - with: - path: ${{env.EM_CACHE_FOLDER}} - key: ${{env.EM_VERSION}}-${{github.job}} - - name: Set up Emscripten latest - uses: mymindstorm/setup-emsdk@v12 - with: - version: ${{env.EM_VERSION}} - actions-cache-folder: ${{env.EM_CACHE_FOLDER}} - - name: Verify Emscripten setup - run: | - emcc -v - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache - continue-on-error: true - - name: Setup python and scons - uses: ./modules/javascript/.github/actions/godot-deps - with: - shell: sh - - name: Compilation - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} - platform: web - target: template_release - tools: falsed - shell: sh - - name: Upload artifact - uses: ./.github/actions/upload-artifact diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 3b33ad58..d180139c 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -1,218 +1,157 @@ name: 🐧 Linux Builds -'on': -- push -- pull_request +on: + workflow_call: + +# Global Settings env: - GODOT_BASE_BRANCH: "4.0" - SCONSFLAGS: ' verbose=yes warnings=extra module_text_server_fb_enabled=yes ' + # Used for the cache key, and godot-cpp checkout. Add version suffix to force clean build. + GODOT_BASE_BRANCH: '4.0' + SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes DOTNET_NOLOGO: true DOTNET_CLI_TELEMETRY_OPTOUT: true concurrency: group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-linux cancel-in-progress: true + jobs: build-linux: - runs-on: ubuntu-20.04 + runs-on: "ubuntu-20.04" name: ${{ matrix.name }} strategy: fail-fast: false matrix: include: - - name: Editor w/ Mono (target=editor, tools=yes) - cache-name: linux-editor-mono - target: editor - tests: false # Disabled due freeze caused by mix Mono build and CI - tools: true - sconsflags: module_mono_enabled=yes - doc-test: true - bin: "./bin/godot.linuxbsd.editor.x86_64.mono" - build-mono: true - proj-conv: true - artifact: true - - name: Editor with doubles and GCC sanitizers (target=editor, tests=yes, dev_build=yes, precision=double, use_asan=yes, use_ubsan=yes, linker=gold) - cache-name: linux-editor-double-sanitizers - target: editor - tests: true - # Debug symbols disabled as they're huge on this build and we hit the 14 GB limit for runners. - sconsflags: dev_build=yes debug_symbols=no precision=double use_asan=yes use_ubsan=yes linker=gold - proj-test: true - # Can be turned off for PRs that intentionally break compat with godot-cpp, - # until both the upstream PR and the matching godot-cpp changes are merged. - godot-cpp-test: true - bin: "./bin/godot.linuxbsd.editor.dev.double.x86_64.san" - build-mono: false - # Skip 2GiB artifact speeding up action. - artifact: false - - name: Template w/ Mono (target=template_release) - cache-name: linux-template-mono - target: template_release - tests: false - sconsflags: module_mono_enabled=yes - build-mono: false - artifact: true + - name: Editor w/ Mono (target=editor) + cache-name: linux-editor-mono + target: editor + tests: false # Disabled due freeze caused by mix Mono build and CI + sconsflags: module_mono_enabled=yes + doc-test: true + bin: "./bin/godot.linuxbsd.editor.x86_64.mono" + build-mono: true + proj-conv: true + artifact: true - name: Minimal template (target=template_release, everything disabled) cache-name: linux-template-minimal target: template_release tests: false - sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no + sconsflags: modules_enabled_by_default=no disable_3d=yes disable_advanced_gui=yes deprecated=no steps: - - name: Checkout Godot - uses: actions/checkout@v2 - with: - repository: godotengine/godot - ref: ${{ env.GODOT_BASE_BRANCH }} - - name: Checkout ECMAScript - uses: actions/checkout@v2 - with: - path: ${{github.workspace}}/modules/javascript/ - # Need newer mesa for lavapipe to work properly. - - name: Linux dependencies for tests - if: ${{ matrix.proj-test }} - run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo add-apt-repository ppa:kisak/kisak-mesa - sudo apt-get install -qq mesa-vulkan-drivers - - name: Linux dependencies - shell: bash - run: | - # Azure repositories are not reliable, we need to prevent azure giving us packages. - # sudo rm -f /etc/apt/sources.list.d/* - # sudo cp -f misc/ci/sources.list /etc/apt/sources.list - sudo apt-get update - # The actual dependencies - sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \ - libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev \ - libdbus-1-dev libudev-dev libxi-dev libxrandr-dev yasm xvfb wget unzip - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache - with: - cache-name: ${{ matrix.cache-name }} - continue-on-error: true - - name: Setup python and scons - uses: ./modules/javascript/.github/actions/godot-deps - with: - shell: sh - - - name: Set up .NET Sdk - uses: actions/setup-dotnet@v2 - if: ${{ matrix.build-mono }} - with: - dotnet-version: '6.0.x' - - - name: Setup GCC problem matcher - uses: ammaraskar/gcc-problem-matcher@master - - - name: Compilation - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} - platform: linuxbsd - target: ${{ matrix.target }} - tools: ${{ matrix.tools }} - tests: ${{ matrix.tests }} - shell: sh - - - name: Generate C# glue - if: ${{ matrix.build-mono }} - run: | - ${{ matrix.bin }} --headless --generate-mono-glue ./modules/mono/glue || true - - - name: Build .NET solutions - if: ${{ matrix.build-mono }} - run: | - ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd - - # Execute unit tests for the editor - - name: Unit tests - if: ${{ matrix.tests }} - run: | - ${{ matrix.bin }} --version - ${{ matrix.bin }} --help - ${{ matrix.bin }} --test --headless - - # Check class reference - # - name: Check for class reference updates - # if: ${{ matrix.doc-test }} - # run: | - # echo "Running --doctool to see if this changes the public API without updating the documentation." - # echo -e "If a diff is shown, it means that your code/doc changes are incomplete and you should update the class reference with --doctool.\n\n" - # ${{ matrix.bin }} --doctool --headless 2>&1 > /dev/null || true - # git diff --color --exit-code && ! git ls-files --others --exclude-standard | sed -e 's/^/New doc file missing in PR: /' | grep 'xml$' - - # Test 3.x -> 4.x project converter - # - name: Test project converter - # if: ${{ matrix.proj-conv }} - # run: | - # mkdir converter_test - # cd converter_test - # touch project.godot - # ../${{ matrix.bin }} --headless --validate-conversion-3to4 - # cd .. - # rm converter_test -rf - - # # Download and extract zip archive with project, folder is renamed to be able to easy change used project - # - name: Download test project - # if: ${{ matrix.proj-test }} - # run: | - # wget https://github.com/godotengine/regression-test-project/archive/4.0.zip - # unzip 4.0.zip - # mv "regression-test-project-4.0" "test_project" - - # # Editor is quite complicated piece of software, so it is easy to introduce bug here - # - name: Open and close editor (Vulkan) - # if: ${{ matrix.proj-test }} - # run: | - # xvfb-run ${{ matrix.bin }} --audio-driver Dummy --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true - # misc/scripts/check_ci_log.py sanitizers_log.txt - - # - name: Open and close editor (GLES3) - # if: ${{ matrix.proj-test }} - # run: | - # DRI_PRIME=0 xvfb-run ${{ matrix.bin }} --audio-driver Dummy --rendering-driver opengl3 --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true - # misc/scripts/check_ci_log.py sanitizers_log.txt - - # # Run test project - # - name: Run project - # if: ${{ matrix.proj-test }} - # run: | - # xvfb-run ${{ matrix.bin }} 40 --audio-driver Dummy --path test_project 2>&1 | tee sanitizers_log.txt || true - # misc/scripts/check_ci_log.py sanitizers_log.txt - - # # Checkout godot-cpp - # - name: Checkout godot-cpp - # if: ${{ matrix.godot-cpp-test }} - # uses: actions/checkout@v3 - # with: - # repository: godotengine/godot-cpp - # submodules: 'recursive' - # path: 'godot-cpp' - - # # Dump GDExtension interface and API - # - name: Dump GDExtension interface and API for godot-cpp build - # if: ${{ matrix.godot-cpp-test }} - # run: | - # ${{ matrix.bin }} --headless --dump-gdextension-interface --dump-extension-api - # cp -f gdextension_interface.h godot-cpp/gdextension/ - # cp -f extension_api.json godot-cpp/gdextension/ - - # # Build godot-cpp test extension - # - name: Build godot-cpp test extension - # if: ${{ matrix.godot-cpp-test }} - # run: | - # cd godot-cpp/test - # scons target=template_debug dev_build=yes - # cd ../.. - - - name: Prepare artifact - if: ${{ matrix.artifact }} - run: | - strip bin/godot.* - chmod +x bin/godot.* + - name: Checkout Godot + uses: actions/checkout@v2 + with: + repository: godotengine/godot + ref: ${{ env.GODOT_BASE_BRANCH }} + + - name: Checkout ECMAScript + uses: actions/checkout@v2 + with: + path: ${{github.workspace}}/modules/javascript/ + + # Need newer mesa for lavapipe to work properly. + - name: Linux dependencies for tests + if: ${{ matrix.proj-test }} + run: | + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo add-apt-repository ppa:kisak/kisak-mesa + sudo apt-get install -qq mesa-vulkan-drivers + + - name: Setup Godot build cache + uses: ./.github/actions/godot-cache + with: + cache-name: ${{ matrix.cache-name }} + continue-on-error: true + + - name: Setup python and scons + uses: ./.github/actions/godot-deps + + - name: Set up .NET Sdk + uses: actions/setup-dotnet@v2 + if: ${{ matrix.build-mono }} + with: + dotnet-version: '6.0.x' + + - name: Setup GCC problem matcher + uses: ammaraskar/gcc-problem-matcher@master + + - name: Compilation + uses: ./.github/actions/godot-build + with: + sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} + platform: linuxbsd + target: ${{ matrix.target }} + tests: ${{ matrix.tests }} + + - name: Generate C# glue + if: ${{ matrix.build-mono }} + run: | + ${{ matrix.bin }} --headless --generate-mono-glue ./modules/mono/glue || true + + - name: Build .NET solutions + if: ${{ matrix.build-mono }} + run: | + ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd + + # Execute unit tests for the editor + - name: Unit tests + if: ${{ matrix.tests }} + run: | + ${{ matrix.bin }} --version + ${{ matrix.bin }} --help + ${{ matrix.bin }} --test --headless + + # Check class reference + - name: Check for class reference updates + if: ${{ matrix.doc-test }} + run: | + echo "Running --doctool to see if this changes the public API without updating the documentation." + echo -e "If a diff is shown, it means that your code/doc changes are incomplete and you should update the class reference with --doctool.\n\n" + ${{ matrix.bin }} --doctool --headless 2>&1 > /dev/null || true + git diff --color --exit-code && ! git ls-files --others --exclude-standard | sed -e 's/^/New doc file missing in PR: /' | grep 'xml$' + + # Test 3.x -> 4.x project converter + - name: Test project converter + if: ${{ matrix.proj-conv }} + run: | + mkdir converter_test + cd converter_test + touch project.godot + ../${{ matrix.bin }} --headless --validate-conversion-3to4 + cd .. + rm converter_test -rf + + # Download and extract zip archive with project, folder is renamed to be able to easy change used project + - name: Download test project + if: ${{ matrix.proj-test }} + run: | + wget https://github.com/godotengine/regression-test-project/archive/4.0.zip + unzip 4.0.zip + mv "regression-test-project-4.0" "test_project" + + # Editor is quite complicated piece of software, so it is easy to introduce bug here + - name: Open and close editor (Vulkan) + if: ${{ matrix.proj-test }} + run: | + xvfb-run ${{ matrix.bin }} --audio-driver Dummy --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true + misc/scripts/check_ci_log.py sanitizers_log.txt + + - name: Open and close editor (GLES3) + if: ${{ matrix.proj-test }} + run: | + DRI_PRIME=0 xvfb-run ${{ matrix.bin }} --audio-driver Dummy --rendering-driver opengl3 --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true + misc/scripts/check_ci_log.py sanitizers_log.txt + + # Run test project + - name: Run project + if: ${{ matrix.proj-test }} + run: | + xvfb-run ${{ matrix.bin }} 40 --audio-driver Dummy --path test_project 2>&1 | tee sanitizers_log.txt || true + misc/scripts/check_ci_log.py sanitizers_log.txt - name: Upload artifact uses: ./.github/actions/upload-artifact if: ${{ matrix.artifact }} with: - name: ${{ matrix.cache-name }} \ No newline at end of file + name: ${{ matrix.cache-name }} diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index 4ae295a6..7cb31994 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -1,79 +1,84 @@ name: 🍎 macOS Builds -'on': -- push -- pull_request +on: + workflow_call: + +# Global Settings env: - GODOT_BASE_BRANCH: "4.0" - SCONSFLAGS: verbose=yes warnings=extra module_text_server_fb_enabled=yes + # Used for the cache key. Add version suffix to force clean build. + GODOT_BASE_BRANCH: '4.0' + SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes + concurrency: group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-macos cancel-in-progress: true + jobs: build-macos: - runs-on: macos-latest + runs-on: "macos-latest" name: ${{ matrix.name }} strategy: fail-fast: false matrix: include: - - name: Editor (target=editor, tools=yes) - cache-name: macos-editor - target: editor - tools: true - tests: false - bin: ./bin/godot.osx.opt.tools.64 - - name: Template (target=release, tools=no) - cache-name: macos-template - target: template_release - tests: false - sconsflags: debug_symbols=no - tools: false + - name: Editor (target=editor, tests=yes) + cache-name: macos-editor + target: editor + tests: true + bin: "./bin/godot.macos.editor.x86_64" + + - name: Template (target=template_release) + cache-name: macos-template + target: template_release + tests: false + sconsflags: debug_symbols=no + steps: - - name: Checkout Godot - uses: actions/checkout@v2 - with: - repository: godotengine/godot - ref: ${{ env.GODOT_BASE_BRANCH }} - - name: Checkout ECMAScript - uses: actions/checkout@v2 - with: - path: ${{github.workspace}}/modules/javascript/ - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache - with: - cache-name: ${{ matrix.cache-name }} - continue-on-error: true - - name: Setup python and scons - uses: ./modules/javascript/.github/actions/godot-deps - with: - shell: sh - - name: Setup Vulkan SDK - run: | - sh misc/scripts/install_vulkan_sdk_macos.sh - - name: Compilation - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} - platform: macos - target: ${{ matrix.target }} - tests: ${{ matrix.tests }} - tools: ${{ matrix.tools }} - shell: sh + - name: Checkout Godot + uses: actions/checkout@v2 + with: + repository: godotengine/godot + ref: ${{ env.GODOT_BASE_BRANCH }} + + - name: Checkout ECMAScript + uses: actions/checkout@v2 + with: + path: ${{github.workspace}}/modules/javascript/ + + - name: Setup Godot build cache + uses: ./.github/actions/godot-cache + with: + cache-name: ${{ matrix.cache-name }} + continue-on-error: true + + - name: Setup python and scons + uses: ./.github/actions/godot-deps + + - name: Setup Vulkan SDK + run: | + sh misc/scripts/install_vulkan_sdk_macos.sh + + - name: Compilation + uses: ./.github/actions/godot-build + with: + sconsflags: ${{ env.SCONSFLAGS }} + platform: macos + target: ${{ matrix.target }} + tests: ${{ matrix.tests }} - # Execute unit tests for the editor - - name: Unit tests - if: ${{ matrix.tests }} - run: | - ${{ matrix.bin }} --version - ${{ matrix.bin }} --help - ${{ matrix.bin }} --test + # Execute unit tests for the editor + - name: Unit tests + if: ${{ matrix.tests }} + run: | + ${{ matrix.bin }} --version + ${{ matrix.bin }} --help + ${{ matrix.bin }} --test - - name: Prepare artifact - run: | - strip bin/godot.* - chmod +x bin/godot.* + - name: Prepare artifact + run: | + strip bin/godot.* + chmod +x bin/godot.* - - name: Upload artifact - uses: ./.github/actions/upload-artifact - with: - name: ${{ matrix.cache-name }} + - name: Upload artifact + uses: ./.github/actions/upload-artifact + with: + name: ${{ matrix.cache-name }} diff --git a/.github/workflows/on_tag.yml b/.github/workflows/on_tag.yml deleted file mode 100644 index 3fd76b41..00000000 --- a/.github/workflows/on_tag.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: 🚢 Publish release -'on': - push: - tags: - - '*' -jobs: - collect-template: - runs-on: ubuntu-latest - steps: - - name: download artifacts - uses: actions/github-script@v6 - if: startsWith(github.ref, 'refs/tags') - with: - script: |- - var total_slept = 0; - var downloaded_files = []; - var seen_completed_wfs = []; - var expected_to_see = 7; - while (total_slept < 7200000 && seen_completed_wfs.length < expected_to_see) { - var all_workflows = await github.rest.actions.listWorkflowRunsForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - }); - console.log("Expecting to download from " + expected_to_see + " workflows, currently at " + seen_completed_wfs.length + ". Have already downloaded " + downloaded_files.length + " files as " + downloaded_files); - for (const workflow of all_workflows.data.workflow_runs) { - if (workflow.head_sha == "${{ github.sha }}") { - console.log("found " + workflow.name + " " + workflow.status); - if (workflow.status == "completed") { - if (seen_completed_wfs.includes(workflow.name)) {continue;} - if (workflow.conclusion == "success") { - var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: workflow.id, - per_page: 100, - }); - for (const artifact of artifacts.data.artifacts) { - var fn = '${{github.workspace}}/' + artifact.name + '.zip'; - if (downloaded_files.includes(fn)) {continue;} - var download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: artifact.id, - archive_format: 'zip', - }); - var fs = require('fs'); - fs.writeFileSync(fn, Buffer.from(download.data)); - downloaded_files.push(fn); - } - seen_completed_wfs.push(workflow.name); - } - } - } - } - if (seen_completed_wfs.length < expected_to_see) { - console.log("sleeping " + 300000); - await new Promise(r => setTimeout(r, 300000)); - total_slept = total_slept + 300000; - console.log("done sleeping " + 300000); - } - } - console.log(downloaded_files); - - name: show dir - run: ls -R - - name: Upload binaries to release - uses: svenstaro/upload-release-action@v2 - if: startsWith(github.ref, 'refs/tags') - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: '*.zip' - tag: ${{ github.ref }} - overwrite: 'true' - file_glob: 'true' diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml new file mode 100644 index 00000000..be255b54 --- /dev/null +++ b/.github/workflows/runner.yml @@ -0,0 +1,41 @@ +name: 🔗 GHA +on: [push, pull_request] + +concurrency: + group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-runner + cancel-in-progress: true + +jobs: + static-checks: + name: 📊 Static checks + uses: ./.github/workflows/static_checks.yml + + android-build: + name: 🤖 Android + needs: static-checks + uses: ./.github/workflows/android_builds.yml + + ios-build: + name: 🍏 iOS + needs: static-checks + uses: ./.github/workflows/ios_builds.yml + + linux-build: + name: 🐧 Linux + needs: static-checks + uses: ./.github/workflows/linux_builds.yml + + macos-build: + name: 🍎 macOS + needs: static-checks + uses: ./.github/workflows/macos_builds.yml + + windows-build: + name: 🏁 Windows + needs: static-checks + uses: ./.github/workflows/windows_builds.yml + + web-build: + name: 🌐 Web + needs: static-checks + uses: ./.github/workflows/web_builds.yml diff --git a/.github/workflows/server_builds.yml b/.github/workflows/server_builds.yml deleted file mode 100644 index 04fd1e6d..00000000 --- a/.github/workflows/server_builds.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: ☁ Server Builds -'on': -- push -- pull_request -env: - GODOT_BASE_BRANCH: "4.0" - SCONSFLAGS: ' verbose=yes warnings=extra module_text_server_fb_enabled=yes ' - DOTNET_NOLOGO: true - DOTNET_CLI_TELEMETRY_OPTOUT: true - -concurrency: - group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-server - cancel-in-progress: true -jobs: - build-server: - runs-on: ubuntu-20.04 - name: ${{ matrix.name }} - strategy: - fail-fast: false - matrix: - include: - - name: Linux Headless w/ Mono (target=editor, tools=yes) - cache-name: server-editor-mono - target: editor - tests: false # Disabled due freeze caused by mix Mono build and CI - tools: true - sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no - bin: ./bin/godot.x11.opt.tools.64.mono - build-mono: true - artifact: true - - name: Linux Server w/ Mono (target=release, tools=no) - cache-name: server-template-mono - target: template_release - tests: false # Disabled due freeze caused by mix Mono build and CI - tools: false - sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no - build-mono: true - artifact: true - steps: - - name: Checkout Godot - uses: actions/checkout@v2 - with: - repository: godotengine/godot - ref: ${{ env.GODOT_BASE_BRANCH }} - - name: Checkout ECMAScript - uses: actions/checkout@v2 - with: - path: ${{github.workspace}}/modules/javascript/ - - name: Linux dependencies - shell: bash - run: | - # Azure repositories are not reliable, we need to prevent azure giving us packages. - # sudo rm -f /etc/apt/sources.list.d/* - # sudo cp -f misc/ci/sources.list /etc/apt/sources.list - sudo apt-get update - # The actual dependencies - sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \ - libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev \ - libdbus-1-dev libudev-dev libxi-dev libxrandr-dev yasm xvfb wget unzip - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache - with: - cache-name: ${{ matrix.cache-name }} - continue-on-error: true - - name: Setup python and scons - uses: ./modules/javascript/.github/actions/godot-deps - with: - shell: sh - - name: Compilation - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} - platform: linuxbsd - target: ${{ matrix.target }} - tools: ${{ matrix.tools }} - shell: sh diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml new file mode 100644 index 00000000..a004c269 --- /dev/null +++ b/.github/workflows/static_checks.yml @@ -0,0 +1,87 @@ +name: 📊 Static Checks +on: + workflow_call: + +concurrency: + group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static + cancel-in-progress: true + +jobs: + static-checks: + name: Code style, file formatting, and docs + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: Install APT dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: dos2unix libxml2-utils moreutils + + - name: Install Python dependencies and general setup + run: | + pip3 install black==22.3.0 pytest==7.1.2 mypy==0.971 + git config diff.wsErrorHighlight all + + - name: Get changed files + id: changed-files + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ "${{ github.event_name }}" == "pull_request" ]; then + files=$(gh pr diff ${{ github.event.pull_request.number }} --name-only) + elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then + files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true) + fi + echo "$files" >> changed.txt + cat changed.txt + files=$(echo "$files" | grep -v 'thirdparty' | xargs -I {} sh -c 'echo "./{}"' | tr '\n' ' ') + echo "CHANGED_FILES=$files" >> $GITHUB_ENV + + - name: File formatting checks (file_format.sh) + run: | + bash ./misc/scripts/file_format.sh changed.txt + + - name: Header guards formatting checks (header_guards.sh) + run: | + bash ./misc/scripts/header_guards.sh changed.txt + + - name: Python style checks via black (black_format.sh) + run: | + if grep -qE '\.py$|SConstruct|SCsub' changed.txt || [ -z "$(cat changed.txt)" ]; then + bash ./misc/scripts/black_format.sh + else + echo "Skipping Python formatting as no Python files were changed." + fi + + - name: Python scripts static analysis (mypy_check.sh) + run: | + if grep -qE '\.py$|SConstruct|SCsub' changed.txt || [ -z "$(cat changed.txt)" ]; then + bash ./misc/scripts/mypy_check.sh + else + echo "Skipping Python static analysis as no Python files were changed." + fi + + - name: Style checks via clang-format (clang_format.sh) + run: | + clang-format --version + bash ./misc/scripts/clang_format.sh changed.txt + + - name: Style checks via dotnet format (dotnet_format.sh) + run: | + if grep -q "modules/mono" changed.txt || [ -z "$(cat changed.txt)" ]; then + bash ./misc/scripts/dotnet_format.sh + else + echo "Skipping dotnet format as no C# files were changed." + fi + + - name: Spell checks via codespell + if: github.event_name == 'pull_request' && env.CHANGED_FILES != '' + uses: codespell-project/actions-codespell@v1 + with: + skip: "./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/project_converter_3_to_4.cpp,./misc/scripts/codespell.sh,./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json" + ignore_words_list: "curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,nd,numer,ot,te,vai" + path: ${{ env.CHANGED_FILES }} diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml new file mode 100644 index 00000000..12b32b8d --- /dev/null +++ b/.github/workflows/web_builds.yml @@ -0,0 +1,60 @@ +name: 🌐 Web Builds +on: + workflow_call: + +# Global Settings +env: + # Used for the cache key. Add version suffix to force clean build. + GODOT_BASE_BRANCH: '4.0' + SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no + EM_VERSION: 3.1.18 + EM_CACHE_FOLDER: "emsdk-cache" + +concurrency: + group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-web + cancel-in-progress: true + +jobs: + web-template: + runs-on: "ubuntu-20.04" + name: Template (target=template_release) + + steps: + - name: Checkout Godot + uses: actions/checkout@v2 + with: + repository: godotengine/godot + ref: ${{ env.GODOT_BASE_BRANCH }} + + - name: Checkout ECMAScript + uses: actions/checkout@v2 + with: + path: ${{github.workspace}}/modules/javascript/ + + - name: Set up Emscripten latest + uses: mymindstorm/setup-emsdk@v12 + with: + version: ${{env.EM_VERSION}} + actions-cache-folder: ${{env.EM_CACHE_FOLDER}} + + - name: Verify Emscripten setup + run: | + emcc -v + + - name: Setup Godot build cache + uses: ./.github/actions/godot-cache + continue-on-error: true + + - name: Setup python and scons + uses: ./.github/actions/godot-deps + + - name: Compilation + uses: ./.github/actions/godot-build + with: + sconsflags: ${{ env.SCONSFLAGS }} + platform: web + target: template_release + tests: false + + - name: Upload artifact + uses: ./.github/actions/upload-artifact diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index 68a7304a..67af76e3 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -1,82 +1,87 @@ name: 🏁 Windows Builds -'on': -- push -- pull_request +on: + workflow_call: + +# Global Settings +# SCONS_CACHE for windows must be set in the build environment env: - GODOT_BASE_BRANCH: "4.0" - SCONSFLAGS: ' use_mingw=yes debug_symbols=no verbose=yes warnings=extra module_text_server_fb_enabled=yes' + # Used for the cache key. Add version suffix to force clean build. + GODOT_BASE_BRANCH: '4.0' + SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes SCONS_CACHE_MSVC_CONFIG: true + concurrency: group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-windows cancel-in-progress: true + jobs: build-windows: - runs-on: windows-latest + # Windows 10 with latest image + runs-on: "windows-latest" name: ${{ matrix.name }} strategy: fail-fast: false matrix: include: - - name: Editor (target=editor, tools=yes) - cache-name: windows-editor - target: editor - tests: false - tools: true - bin: ./bin/godot.windows.opt.tools.64.exe - - name: Template (target=release, tools=no) - cache-name: windows-template - target: template_release - tools: false - tests: false - sconsflags: debug_symbols=no + - name: Editor (target=editor, tests=yes) + cache-name: windows-editor + target: editor + tests: true + # Skip debug symbols, they're way too big with MSVC. + sconsflags: debug_symbols=no vsproj=yes + bin: "./bin/godot.windows.editor.x86_64.exe" + + - name: Template (target=template_release) + cache-name: windows-template + target: template_release + tests: false + sconsflags: debug_symbols=no + steps: - - name: setup-msys2 - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW64 - update: true - install: mingw-w64-x86_64-gcc - - name: update mingw2 - run: pacman -Syu --needed --noconfirm mingw-w64-x86_64-python3-pip mingw-w64-x86_64-gcc - mingw-w64-i686-python3-pip mingw-w64-i686-gcc make - - name: update scons - run: pip3 install scons - - name: Checkout Godot - uses: actions/checkout@v2 - with: - repository: godotengine/godot - ref: ${{ env.GODOT_BASE_BRANCH }} - - name: Checkout ECMAScript - uses: actions/checkout@v2 - with: - path: ${{github.workspace}}/modules/javascript/ - - name: Setup Godot build cache - uses: ./.github/actions/godot-cache - with: - cache-name: ${{ matrix.cache-name }} - continue-on-error: true - - name: Setup python and scons - uses: ./modules/javascript/.github/actions/godot-deps - with: - shell: msys2 {0} + - name: Checkout Godot + uses: actions/checkout@v2 + with: + repository: godotengine/godot + ref: ${{ env.GODOT_BASE_BRANCH }} + + - name: Checkout ECMAScript + uses: actions/checkout@v2 + with: + path: ${{github.workspace}}/modules/javascript/ + + - name: Setup Godot build cache + uses: ./.github/actions/godot-cache + with: + cache-name: ${{ matrix.cache-name }} + continue-on-error: true + + - name: Setup python and scons + uses: ./.github/actions/godot-deps + + - name: Setup MSVC problem matcher + uses: ammaraskar/msvc-problem-matcher@master + + - name: Compilation + uses: ./.github/actions/godot-build + with: + sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} + platform: windows + target: ${{ matrix.target }} + tests: ${{ matrix.tests }} + + # Execute unit tests for the editor + - name: Unit tests + if: ${{ matrix.tests }} + run: | + ${{ matrix.bin }} --version + ${{ matrix.bin }} --help + ${{ matrix.bin }} --test - - name: Setup MSVC problem matcher - uses: ammaraskar/msvc-problem-matcher@master + - name: Prepare artifact + run: | + Remove-Item bin/* -Include *.exp,*.lib,*.pdb -Force - - name: Compilation - uses: ./modules/javascript/.github/actions/godot-build - with: - sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} - platform: windows - target: ${{ matrix.target }} - tests: ${{ matrix.tests }} - tools: ${{ matrix.tools }} - scons-cache-limit: 3072 - shell: msys2 {0} - - name: Upload artifact - uses: ./.github/actions/upload-artifact - with: - name: ${{ matrix.cache-name }} - defaults: - run: - shell: msys2 {0} + - name: Upload artifact + uses: ./.github/actions/upload-artifact + with: + name: ${{ matrix.cache-name }} diff --git a/.gitignore b/.gitignore index 6a7d3c7d..a3c7a391 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ *.os *.gen.cpp *.gen.json -.vscode \ No newline at end of file +.vscode diff --git a/README.md b/README.md index 3b3a3b0f..0261ca5d 100644 --- a/README.md +++ b/README.md @@ -1,133 +1,137 @@ -## JavaScript language binding for godot game engine +# JavaScript language binding for Godot game engine -This module implements JavaScript/TypeScript language support for the godot game engine. [QuickJS](https://bellard.org/quickjs/) is used as the JavaScript engine. +This module implements JavaScript/TypeScript language support for the Godot game engine using [QuickJS](https://bellard.org/quickjs/) as the JavaScript engine. ------ +## Features -### Features - Almost complete ES2020 support -- All godot api avaliable -- Operator overriding for builtin types (Vector3, Color, etc) -- TypeScript support -- [Using thirdpart libraries from npm](https://github.com/GodotExplorer/ECMAScriptDemos/tree/master/npm_module) +- All Godot API available +- Operator overriding for built-in types (Vector3, Color, etc) +- TypeScript support +- [Using third-party libraries from npm](https://github.com/GodotExplorer/ECMAScriptDemos/tree/master/npm_module) - Multi-thread support with Worker API -- Full code completion support for all godot APIs including signals and enumerations +- Full code completion support for all Godot APIs including signals and enumerations - Debug in Visual Studio Code with the [plugin](https://marketplace.visualstudio.com/items?itemName=geequlim.godot-javascript-debug) -### Download -You can try the pre-compiled binaries from the [release page](https://github.com/GodotExplorer/ECMAScript/releases) -You can also get the binaries with lastest commits from the [github build action result](https://github.com/GodotExplorer/ECMAScript/actions) +## Installation -### Compilation -* Clone the source code of [godot](https://github.com/godotengine/godot) -* Clone this module and put it into `godot/modules/` and make sure the folder name of this module is `javascript` -* [Recompile the godot engine](https://docs.godotengine.org/en/3.3/development/compiling/index.html) (Only MinGW is supported on Windows for now!) +No installation or setup necessary. The binaries for download are the complete, usable Godot editor and engine with JavaScript/TypeScript language support. + +## Download + +You can try the pre-compiled binaries from the [release page](https://github.com/GodotExplorer/ECMAScript/releases) or get the binaries with the latest commits from the [GitHub build action result](https://github.com/GodotExplorer/ECMAScript/actions). + +## Compilation + +1. Clone the source code of [godot](https://github.com/godotengine/godot) +2. Clone this module and put it into `godot/modules/` and make sure the folder name of this module is `javascript` +3. [Recompile the godot engine](https://docs.godotengine.org/en/3.3/development/compiling/index.html) **(Only MinGW is supported on Windows for now!)** ![Build Godot with ECMAScript](https://github.com/GodotExplorer/ECMAScript/workflows/Build%20Godot%20with%20ECMAScript/badge.svg) -### Usage +## Usage + +### How to export script class to Godot + +1. Define your JavaScript class and inherit from a Godot class, then export it as the **default** entry: -##### How to export script class to godot -1. Define your JavaScript class and inherit from a godot class then export it as the **default** entry ```js -// The default export entry is treated as an exported class to godot +// The default export entry is treated as an exported class to Godot export default class MySprite extends godot.Sprite { - // this is _init() in GDScript constructor() { super(); } - - _ready() { - - } - - _process(delta) { - - } + + _ready() {} + + _process(delta) {} } ``` + 2. Save the script with extension `.mjs` 3. Attach the script file to the node or resource object like you do with GDScript -##### How to export signals +### How to export signals ```js -export default class MySprite extends godot.Sprite {}; +export default class MySprite extends godot.Sprite {} // register game_over signal to MySprite class -godot.register_signal(MySprite, 'game_over'); +godot.register_signal(MySprite, "game_over"); ``` -##### How to export properties +### How to export properties + ```js export default class MySprite extends godot.Sprite { _process(delta) { // Yes! We can use operators in JavaScript like GDScript this.position += this.direction * delta; } -}; -// export 'direction' properties to MySprite godot inspector -godot.register_property(MySprite, 'direction', new godot.Vector2(1, 0)); +} +// export 'direction' properties to MySprite Godot inspector +godot.register_property(MySprite, "direction", new godot.Vector2(1, 0)); ``` -There are 2 ways of using the `godot.register_property`, the thrid param can either be -a default value for the property you're trying to export or an object giving a more detailed -description on how the editor should show it. +There are 2 ways of using the `godot.register_property`. The third parameter can either be a default value for the property you're trying to export or an object giving a more detailed description of how the editor should show it. ```js function register_property(target: GodotClass | godot.Object, name: string, value: any); function register_property(target: GodotClass | godot.Object, name: string, info: PropertyInfo); ``` -So calling the register_property like this: +So calling the `register_property` like this: + ```js -godot.register_property(MyClass, 'number_value', 3.14); +godot.register_property(MyClass, "number_value", 3.14); ``` Is the simplified version of: + ```js -godot.register_property(MyClass, 'number_value', { +godot.register_property(MyClass, "number_value", { type: godot.TYPE_REAL, hint: godot.PropertyHint.PROPERTY_HINT_NONE, hint_string: "", - default: 3.14 + default: 3.14, }); ``` For more detail on how to use it, [click here](https://github.com/Geequlim/ECMAScript/issues/24#issuecomment-655584829). -#### About the API - -All of godots api's are defined within the `godot` namespace. - -No API names have been renamed or changed so you shouldn't need to change your habits. - -GDScript | JavaScript ----- | --- -null | null -int | number -float | number -String | string -Array | Array -Dictionary | Object -NodePath | string -Object | godot.Object -Resource | godot.Resource -Vector2 | godot.Vector2 -Color | godot.Color -sin(v)| godot.sin(v) -print(v)| godot.print(v) -PI|godot.PI -Color.black | godot.Color.black -Control.CursorShape | godot.Control.CursorShape -Label.Align.ALIGN_LEFT | godot.Label.Align.ALIGN_LEFT - -##### API specification: +### About the API + +All of Godot's APIs are defined within the `godot` namespace. + +No API names have been renamed or changed, so you shouldn't need to change your habits. + +| GDScript | JavaScript | +| ---------------------- | ---------------------------- | +| null | null | +| int | number | +| float | number | +| String | string | +| Array | Array | +| Dictionary | Object | +| NodePath | string | +| Object | godot.Object | +| Resource | godot.Resource | +| Vector2 | godot.Vector2 | +| Color | godot.Color | +| sin(v) | godot.sin(v) | +| print(v) | godot.print(v) | +| PI | godot.PI | +| Color.black | godot.Color.black | +| Control.CursorShape | godot.Control.CursorShape | +| Label.Align.ALIGN_LEFT | godot.Label.Align.ALIGN_LEFT | + +#### API specification: + - Keys of Dictionary are converted to String in JavaScript -- Signals are defined as constants to its classes - ``` - godot.Control.resized === 'resized' // true - ``` +- Signals are defined as constants to their classes + ``` + godot.Control.resized === 'resized' // true + ``` - Additional functions - `godot.register_signal(cls, signal_name)` to register signals - `godot.register_property(cls, name, default_value)` to define and export properties @@ -141,49 +145,56 @@ Label.Align.ALIGN_LEFT | godot.Label.Align.ALIGN_LEFT - `require(module_id)` to load a CommonJS module or load a resource file - `$` is the alias of `Node.get_node` - Using signals in the ECMAScript way - - Allow passing functions for `godot.Object.connect`, `godot.Object.disconnect` and `godot.Object.is_connected` - ```js - this.panel.connect(godot.Control.resized, (size) => { - console.log('The size of the panel changed to:', size); - }); - ``` - - Using `await` to wait signals - ```js - await godot.yield(this.get_tree().create_timer(1), godot.SceneTreeTimer.timeout); - console.log('After one second to show'); - ``` + - Allow passing functions for `godot.Object.connect`, `godot.Object.disconnect`, and `godot.Object.is_connected` + ```js + this.panel.connect(godot.Control.resized, (size) => { + console.log("The size of the panel changed to:", size); + }); + ``` + - Using `await` to wait for signals + ```js + await godot.yield( + this.get_tree().create_timer(1), + godot.SceneTreeTimer.timeout + ); + console.log("After one second to show"); + ``` - Preload resources with ECMAScript import statement - ```js - import ICON from 'res://icon.png'; - ``` + ```js + import ICON from "res://icon.png"; + ``` - Multi-threading with minimal [Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Worker) (**This is an experimental feature**) - - Start a new thread with Worker - ```js - const worker = new Worker('worker.js'); // Run worker.js in a new thread context - worker.postMessage({type: 'load_dlc', value: 'dlc01.pck'}); - worker.onmessage = function(msg) { - console.log("[MainThread] received message from worker thread:", msg); - } - ``` - - Transfer value in different thread context with `godot.abandon_value` and `godot.adopt_value` - ```js - // In worker thread - let id = godot.abandon_value(object); - postMessage({ type: 'return_value', id: id }); - - // In the host thread - worker.onmessage = function(msg) { - if (typeof msg === 'object' && msg.type === 'return_value') { - let value_from_worker = godot.adopt_value(msg.id); - } - } - ``` - + + - Start a new thread with Worker + ```js + const worker = new Worker("worker.js"); // Run worker.js in a new thread context + worker.postMessage({ type: "load_dlc", value: "dlc01.pck" }); + worker.onmessage = function (msg) { + console.log("[MainThread] received message from worker thread:", msg); + }; + ``` + - Transfer value in different thread context with `godot.abandon_value` and `godot.adopt_value` + + ```js + // In worker thread + let id = godot.abandon_value(object); + postMessage({ type: "return_value", id: id }); + + // In the host thread + worker.onmessage = function (msg) { + if (typeof msg === "object" && msg.type === "return_value") { + let value_from_worker = godot.adopt_value(msg.id); + } + }; + ``` + ### TypeScript support -- Run the menu command `Project > Tools > JavaScript > Generate TypeScript Project` from the godot editor to generate a TypeScript project + +- Run the menu command `Project > Tools > JavaScript > Generate TypeScript Project` from the Godot editor to generate a TypeScript project - Run `tsc -w -p .` under your project folder in the terminal to compile scripts #### Code completion + - Code completion in TS will automatically work once the TypeScript project is generated by the above steps. - Code completion in VSCode is achieved by the property `"types": "./godot.d.ts"` in the generated package.json file of the TypeScript project. The `godot.d.ts` file can be generated alone via the `Project > Tools > ECMAScript > Generate TypeScript Declaration File` editor menu option and added to a `package.json` file manually to achieve this without a full TypeScript project. @@ -198,7 +209,6 @@ import { signal, property, tool, onready, node } from "./decorators"; @tool // make the script runnable in godot editor export default class InputLine extends godot.HBoxContainer { - // define a signal @signal static readonly OnTextChanged: string; @@ -210,10 +220,12 @@ export default class InputLine extends godot.HBoxContainer { // register offset property with the godot inspector with default value of Vector2(0, 0) @property({ default: godot.Vector2.ZERO }) offset: godot.Vector2; - + // register properties for godot editor inspector @property({ type: godot.VariantType.TYPE_STRING }) - get title() { return this._title; } + get title() { + return this._title; + } set title(v: string) { this._title = v; if (this._label) { @@ -223,7 +235,9 @@ export default class InputLine extends godot.HBoxContainer { private _title: string; @property({ default: "Input text here" }) - get hint() { return this._hint; } + get hint() { + return this._hint; + } set hint(v: string) { this._hint = v; if (this.edit) { @@ -233,11 +247,13 @@ export default class InputLine extends godot.HBoxContainer { } private _hint: string; - get label(): godot.Label { return this._label; } + get label(): godot.Label { + return this._label; + } protected _label: godot.Label; // call get_node('LineEdit') and assign the returned value to 'this.edit' automatically when the node is ready - @onready('LineEdit') + @onready("LineEdit") edit: godot.LineEdit; get text(): string { @@ -247,12 +263,12 @@ export default class InputLine extends godot.HBoxContainer { _ready() { // get first child with the type of godot.Label this._label = this.get_node(godot.Label); - + // Apply the inspector filled values with property setters this.title = this.title; this.hint = this.hint; - this.edit.connect(godot.LineEdit.text_changed, (text: string)=>{ + this.edit.connect(godot.LineEdit.text_changed, (text: string) => { this.emit_signal(InputLine.OnTextChanged, text); }); } @@ -260,15 +276,16 @@ export default class InputLine extends godot.HBoxContainer { ``` ## Demo + You can try demos in the [ECMAScriptDemos](https://github.com/Geequlim/ECMAScriptDemos) ## Developer notes -* This package is not compatible with MSVC, you will get build errors in quickjs. -* To update the github actions scripts we have the file `build_github_actions.py`. This script will copy the actions from the godot repo (usually at `../../`) and modify them to fix the requirements of quickjs and this repo. -** If you are updating this repo's compatibility, you should run that script (a brief description is at the top of the script) and it will re-create the actions `.yml` files for you. -* The script also build the `on_tag.yml` script which automates the github release publishing. -** The `on_tag.yml` functionality tries to sleep until all jobs with the same `sha` are completed. It should be fine to run whenever, but depending on how github actions culls long running jobs you might want to make sure that all/(most of) the builds look good before tagging. -* Linux ubsan asan build woes: -* The godot repo has ubsan and asan builds that we can't build from. Currently we skip them (get removed via the `build_github_actions.py` script). -* They should definitely be fixed & enabled at some point, **so please submit a PR if you have any ideas of how to do that!** +- This package is not compatible with MSVC, you will get build errors in quickjs. +- To update the github actions scripts we have the file `build_github_actions.py`. This script will copy the actions from the godot repo (usually at `../../`) and modify them to fix the requirements of quickjs and this repo. + \*\* If you are updating this repo's compatibility, you should run that script (a brief description is at the top of the script) and it will re-create the actions `.yml` files for you. +- The script also build the `on_tag.yml` script which automates the github release publishing. + \*\* The `on_tag.yml` functionality tries to sleep until all jobs with the same `sha` are completed. It should be fine to run whenever, but depending on how github actions culls long running jobs you might want to make sure that all/(most of) the builds look good before tagging. +- Linux ubsan asan build woes: +- The godot repo has ubsan and asan builds that we can't build from. Currently we skip them (get removed via the `build_github_actions.py` script). +- They should definitely be fixed & enabled at some point, **so please submit a PR if you have any ideas of how to do that!** diff --git a/SCsub b/SCsub index 795f1df1..1efe9a28 100644 --- a/SCsub +++ b/SCsub @@ -1,78 +1,100 @@ #!/usr/bin/env python import platform, os, sys -Import('env') -Import('env_modules') +Import("env") +Import("env_modules") env_module = env_modules.Clone() -JS_ENGINE = 'quickjs' -TOOLS = ('editor' == env_module['target']) #env.get('TOOLS'); +JS_ENGINE = "quickjs" +TOOLS = "editor" == env_module["target"] + def open_file(path, mode): - if platform.python_version() > '3': - return open(path, mode, encoding='utf8') - else: - return open(path, mode) + if platform.python_version() > "3": + return open(path, mode, encoding="utf8") + else: + return open(path, mode) + def dump_text_file_to_cpp(file): - source = open_file(file, 'r').read() - lines = source.split('\n') - source = "" - length = len(lines) - for i in range(length): - line = lines[i].replace('"', '\\"') - line = '\t"' + line + '\\n"' - if i < length -1: - line += "\n" - source += line - return source - -if JS_ENGINE == 'quickjs': - # generate builtin binding code - import generate_builtin_api - generate_builtin_api.generate_api_json(os.path.join(GetLaunchDir(), "modules", os.path.basename(os.getcwd()))) - import quickjs.builtin_binding_generator - quickjs.builtin_binding_generator.generate_builtin_bindings() - # build quickjs source - version = open('quickjs/quickjs/VERSION.txt', 'r').read().split('\n')[0] - env_module.Append(CPPDEFINES={"QUICKJS_CONFIG_VERSION": '"'+ version +'"'}) - env_module.Append(CPPDEFINES=["CONFIG_BIGNUM"]) - if 'release' not in (env_module['target'] or ''): - env_module.Append(CPPDEFINES={"DUMP_LEAKS": 1}) - env_module.Append(CPPDEFINES={"QUICKJS_WITH_DEBUGGER": 1}) - env_module.Append(CPPPATH=["quickjs/quickjs"]) - # env_module.Append(CXXFLAGS=["-std=c++20"]) - # env_module.Append(CCFLAGS=["-std=c++20"]) - if TOOLS: - env_module.add_source_files(env.modules_sources, 'tools/editor_tools.cpp') - env_module.add_source_files(env.modules_sources, 'quickjs/quickjs_builtin_binder.gen.cpp') - env_module.add_source_files(env.modules_sources, 'quickjs/*.cpp') - env_module.add_source_files(env.modules_sources, 'quickjs/quickjs/*.c') + source = open_file(file, "r").read() + lines = source.split("\n") + source = "" + length = len(lines) + for i in range(length): + line = lines[i].replace('"', '\\"') + line = '\t"' + line + '\\n"' + if i < length - 1: + line += "\n" + source += line + return source + + +if JS_ENGINE == "quickjs": + import generate_builtin_api + + generate_builtin_api.generate_api_json(os.path.join(GetLaunchDir(), "modules", os.path.basename(os.getcwd()))) + import thirdparty.quickjs.builtin_binding_generator + + thirdparty.quickjs.builtin_binding_generator.generate_builtin_bindings() + version = open("thirdparty/quickjs/quickjs/VERSION.txt", "r").read().split("\n")[0] + env_module.Append(CPPDEFINES={"QUICKJS_CONFIG_VERSION": '"' + version + '"'}) + env_module.Append(CPPDEFINES=["CONFIG_BIGNUM"]) + if "release" not in (env_module["target"] or ""): + env_module.Append(CPPDEFINES={"DUMP_LEAKS": 1}) + env_module.Append(CPPDEFINES={"QUICKJS_WITH_DEBUGGER": 1}) + env_module.Append(CPPPATH=["thirdparty/quickjs/quickjs"]) + env_module.Append(CPPPATH=["thirdparty/quickjs"]) + + if TOOLS: + env_module.add_source_files(env.modules_sources, "tools/editor_tools.cpp") + env_module.add_source_files(env.modules_sources, "thirdparty/quickjs/quickjs_builtin_binder.gen.cpp") + env_module.add_source_files(env.modules_sources, "thirdparty/quickjs/*.cpp") + env_module.add_source_files(env.modules_sources, "thirdparty/quickjs/quickjs/*.c") + # Binding script to run at engine initializing with open("misc/godot.binding_script.gen.cpp", "w") as f: - text = '/* THIS FILE IS GENERATED DO NOT EDIT */\n#include "../javascript_binder.h"\nString JavaScriptBinder::BINDING_SCRIPT_CONTENT = \n${source};' - f.write(text.replace('${source}', dump_text_file_to_cpp("misc/binding_script.js"))) + text = '/* THIS FILE IS GENERATED DO NOT EDIT */\n#include "../javascript_binder.h"\nString JavaScriptBinder::BINDING_SCRIPT_CONTENT = \n${source};' + f.write(text.replace("${source}", dump_text_file_to_cpp("misc/binding_script.js"))) sources = [ - 'register_types.cpp', - 'javascript_language.cpp', - 'javascript_instance.cpp', - 'javascript.cpp', - 'misc/godot.binding_script.gen.cpp', + "register_types.cpp", + "javascript_language.cpp", + "javascript_instance.cpp", + "javascript.cpp", + "misc/godot.binding_script.gen.cpp", ] if TOOLS: - base_text = '/* THIS FILE IS GENERATED DO NOT EDIT */\n#include "editor_tools.h"\nString JavaScriptPlugin::{} = \n{};' - tool_fns = {"tools/godot.d.ts.gen.cpp": ("BUILTIN_DECLARATION_TEXT", dump_text_file_to_cpp("misc/godot.d.ts")), - "tools/tsconfig.json.gen.cpp": ("TSCONFIG_CONTENT", dump_text_file_to_cpp("misc/tsconfig.json")), - "tools/decorators.ts.gen.cpp": ("TS_DECORATORS_CONTENT", dump_text_file_to_cpp("misc/decorators.ts")), - "tools/package.json.gen.cpp": ("PACKAGE_JSON_CONTENT", dump_text_file_to_cpp("misc/package.json")), - } - for fn, subs in tool_fns.items(): - with open_file(fn, "w") as fh: - fh.write(base_text.format(*subs)) - env_module.add_source_files(env.modules_sources, fn) + base_text = ( + '/* THIS FILE IS GENERATED DO NOT EDIT */\n#include "editor_tools.h"\nString JavaScriptPlugin::{} = \n{};' + ) + tool_fns = { + "tools/godot.d.ts.gen.cpp": ( + "BUILTIN_DECLARATION_TEXT", + dump_text_file_to_cpp("misc/godot.d.ts"), + ), + "tools/tsconfig.json.gen.cpp": ( + "TSCONFIG_CONTENT", + dump_text_file_to_cpp("misc/tsconfig.json"), + ), + "tools/decorators.ts.gen.cpp": ( + "TS_DECORATORS_CONTENT", + dump_text_file_to_cpp("misc/decorators.ts"), + ), + "tools/package.json.gen.cpp": ( + "PACKAGE_JSON_CONTENT", + dump_text_file_to_cpp("misc/package.json"), + ), + } + for fn, subs in tool_fns.items(): + with open_file(fn, "w") as fh: + fh.write(base_text.format(*subs)) + env_module.add_source_files(env.modules_sources, fn) env_module.Append(CPPPATH=["#modules/javascript"]) env_module.add_source_files(env.modules_sources, sources) + +if env.editor_build: + env_module.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/build_github_actions.py b/build_github_actions.py deleted file mode 100644 index bd28f338..00000000 --- a/build_github_actions.py +++ /dev/null @@ -1,345 +0,0 @@ -#!/usr/bin/env python -""" -run this every time you upgrade the godot-base version to generate new matching github workflows -You must be in this directory, and in the modules subfolder of godot (just as if you would install this project into godot) - -usage: -python build_github_actions.py --godot-version "4.0" --godot-github-folder ../../.github --js-github-folder .github - -""" - -import argparse -import yaml -import os -import subprocess -from dataclasses import dataclass, field -from typing import Dict, List, Any -import copy - -# https://stackoverflow.com/a/33300001 + some changes -def str_presenter(dumper, data): - if len(data.splitlines()) > 1 or "\n" in data: # check for multiline string - return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") - return dumper.represent_scalar("tag:yaml.org,2002:str", data) - - -yaml.add_representer(str, str_presenter) - -# to use with safe_dump: -yaml.representer.SafeRepresenter.add_representer(str, str_presenter) - -# END https://stackoverflow.com/a/33300001 - - -@dataclass -class BuildOpts: - SCONSFLAGS: str - GODOT_BASE_BRANCH: str - ENV: Dict[str, str] = field(default_factory=dict) - - def add_to_flags(self, toadd: str) -> None: - if not self.SCONSFLAGS.endswith(" "): - toadd = f" {toadd}" - self.SCONSFLAGS = f"{self.SCONSFLAGS} {toadd}" - - def get_fixed_flags(self) -> str: - todel = ["warnings=all", "werror=yes"] - for x in todel: - self.SCONSFLAGS = self.SCONSFLAGS.replace(x, "") - return self.SCONSFLAGS - - -def parseargs(): - parser = argparse.ArgumentParser() - parser.add_argument("--godot-version", required=True) - parser.add_argument("--godot-github-folder", required=True) - parser.add_argument("--js-github-folder", required=True) - return parser.parse_args() - - -def checkout_local_godot_install(tag: str): - cmd = ["git", "checkout", f"tags/{tag}"] - ret = subprocess.run(cmd, cwd="../../") - if ret.returncode != 0: - raise RuntimeError(f"godot not setup properly, could not checkout '{' '.join(cmd)}'") - - -def get_windows_mingw_checkout_steps() -> List[Dict[str, Any]]: - out = [ - { - "name": "setup-msys2", - "uses": "msys2/setup-msys2@v2", - "with": {"msystem": "MINGW64", "update": True, "install": "mingw-w64-x86_64-gcc"}, - }, - { - "name": "update mingw2", - "run": "pacman -Syu --needed --noconfirm mingw-w64-x86_64-python3-pip mingw-w64-x86_64-gcc mingw-w64-i686-python3-pip mingw-w64-i686-gcc make", - }, - { - "name": "update scons", - "run": "pip3 install scons", - }, - ] - return out - - -def get_js_checkout_steps() -> List[Dict[str, Any]]: - out = [ - { - "name": "Checkout Godot", - "uses": "actions/checkout@v2", - "with": {"repository": "godotengine/godot", "ref": "${{ env.GODOT_BASE_BRANCH }}"}, - }, - { - "name": "Checkout javascript", - "uses": "actions/checkout@v2", - "with": {"path": "${{github.workspace}}/modules/javascript/"}, - }, - ] - return out - - -def get_rid_of_ubsan_asan_linux(matrix_step: Dict[str, Any]) -> Dict[str, Any]: - for get_rid_of in ["use_ubsan=yes", "use_asan=yes"]: - matrix_step["name"] = matrix_step["name"].replace(get_rid_of, "").replace(" , ", " ").replace(", )", ")") - matrix_step["sconsflags"] = matrix_step["sconsflags"].replace(get_rid_of, "").replace(", )", ")") - return matrix_step - - -def fix_all_workflows( - js_github_folder: str, workflows: Dict[str, BuildOpts], wf_actions_that_require_shell: List[str] -) -> List[str]: - wf_names: List[str] = [] - for wf_base_fn, build_opts in workflows.items(): - full_fn = os.path.join(js_github_folder, "workflows", wf_base_fn) - data = yaml.safe_load(open(full_fn)) - wf_names.append(data["name"]) - - build_opts.add_to_flags(data["env"]["SCONSFLAGS"]) - data["env"]["SCONSFLAGS"] = build_opts.get_fixed_flags() - data["env"]["GODOT_BASE_BRANCH"] = build_opts.GODOT_BASE_BRANCH - for k, v in build_opts.ENV.items(): - data["env"][k] = v - - if True in data.keys(): - new_data = {"name": data["name"], "on": data[True]} - del data[True] - for k, v in data.items(): - if k in ("name", "on"): - continue - new_data[k] = v - data = new_data - assert len(data["jobs"]) == 1 - only_template_name = list(data["jobs"].keys())[0] - - new_steps = [] - if "windows" in wf_base_fn: - # quickjs can't build under msvc, must use mingw, install it here - new_steps += get_windows_mingw_checkout_steps() - data["jobs"][only_template_name]["defaults"] = {"run": {"shell": "msys2 {0}"}} - - elif "linux" in wf_base_fn: - for matrix_step in data["jobs"][only_template_name]["strategy"]["matrix"]["include"]: - # quickjs fails under ubsan & asan, don't include those flags - if "name" in matrix_step and "Editor and sanitizers" in matrix_step["name"]: - matrix_step = get_rid_of_ubsan_asan_linux(matrix_step) - - base_github_string = "./.github/" - for step in data["jobs"][only_template_name]["steps"]: - # replace godot checkout routine with this checkout routine - if "uses" in step and "checkout" in step["uses"]: - new_steps += get_js_checkout_steps() - elif ( - "uses" in step - and base_github_string in step["uses"] - and any(x in step["uses"] for x in wf_actions_that_require_shell) - ): - step["uses"] = step["uses"].replace(base_github_string, "./modules/javascript/.github/") - to_add = {"shell": "msys2 {0}" if "windows" in wf_base_fn else "sh"} - if "with" not in step: - step["with"] = to_add - else: - step["with"].update(to_add) - new_steps.append(step) - else: - new_steps.append(step) - - data["jobs"][only_template_name]["steps"] = new_steps - with open(full_fn, "w") as fh: - yaml.dump(data, fh, sort_keys=False, allow_unicode=True) - return wf_names - - -def fix_all_actions(js_github_folder: str, actions: List[str]) -> List[str]: - """ - This can be simplified once: - https://github.com/actions/runner/pull/1767 - is completed - """ - actions_that_require_shell_set = set() - for action_base_fn in actions: - full_action_fn = os.path.join(js_github_folder, action_base_fn) - data = yaml.safe_load(open(full_action_fn)) - new_steps = [] - for step in data["runs"]["steps"]: - if "shell" in step: - for shell in ["sh", "msys2 {0}"]: - cp_step = copy.deepcopy(step) - cp_step["shell"] = shell - cp_step["if"] = f"inputs.shell == '{shell}'" - new_steps.append(cp_step) - data["inputs"]["shell"] = {"description": "the shell to run this under", "default": "sh"} - actions_that_require_shell_set.add(action_base_fn) - else: - new_steps.append(step) - # new_steps.append(step) - # Uncomment this when github actions updated - # if "shell" in step: - # step["shell"] = "${{ inputs.shell }}" - # data["inputs"]["shell"] = {"description": "the shell to run this under", "default": "sh"} - # new_steps.append(step) - - # We ca - data["runs"]["steps"] = new_steps - with open(full_action_fn, "w") as fh: - yaml.dump(data, fh, sort_keys=False, allow_unicode=True) - return list(sorted([x.split("/")[1] for x in actions_that_require_shell_set])) - - -def add_publish_workflow(out_fn: str, wf_name_list: List[str]): - # "on": {"tag": "", "workflow_run": {"workflows": wf_name_list, "types": ["completed"]}}, - # run_id: ${{ github.event.workflow_run.id }}, - # var matchArtifact = artifacts.data.artifacts.filter((artifact) => { - # return artifact.name == "pr" - # })[0]; - - script_text = ( - """var total_slept = 0; -var downloaded_files = []; -var seen_completed_wfs = []; -var expected_to_see = """ - + str(len(wf_name_list)) - + """; -while (total_slept < 3600000 && seen_completed_wfs.length < expected_to_see) { - var all_workflows = await github.rest.actions.listWorkflowRunsForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - }); - console.log("Expecting to download from " + expected_to_see + " workflows, currently at " + seen_completed_wfs.length + ". Have already downloaded " + downloaded_files.length + " files as " + downloaded_files); - for (const workflow of all_workflows.data.workflow_runs) { - if (workflow.head_sha == "${{ github.sha }}") { - console.log("found " + workflow.name + " " + workflow.status); - if (workflow.status == "completed") { - if (seen_completed_wfs.includes(workflow.name)) {continue;} - if (workflow.conclusion == "success") { - var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: workflow.id, - per_page: 100, - }); - for (const artifact of artifacts.data.artifacts) { - var fn = '${{github.workspace}}/' + artifact.name + '.zip'; - if (downloaded_files.includes(fn)) {continue;} - var download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: artifact.id, - archive_format: 'zip', - }); - var fs = require('fs'); - fs.writeFileSync(fn, Buffer.from(download.data)); - downloaded_files.push(fn); - } - seen_completed_wfs.push(workflow.name); - } - } - } - } - if (seen_completed_wfs.length < expected_to_see) { - console.log("sleeping " + 300000); - await new Promise(r => setTimeout(r, 300000)); - total_slept = total_slept + 300000; - console.log("done sleeping " + 300000); - } -} -console.log(downloaded_files);""" - ) - - data = { - "name": "🚢 Publish release", - # You should tag as late as possible, don't want to sleep too long and get push job killed - "on": { - "push": {"tags": ["*"]}, - }, - "jobs": { - "collect-template": { - "runs-on": "ubuntu-latest", - "steps": [ - # {"name": "show dir", "run": "sleep 900"}, - { - "name": "download artifacts", - "uses": "actions/github-script@v6", - "if": "startsWith(github.ref, 'refs/tags')", - "with": {"script": script_text}, - }, - {"name": "show dir", "run": "ls -R"}, - { - "name": "Upload binaries to release", - "uses": "svenstaro/upload-release-action@v2", - "if": "startsWith(github.ref, 'refs/tags')", - "with": { - "repo_token": "${{ secrets.GITHUB_TOKEN }}", - "file": "*.zip", - "tag": "${{ github.ref }}", - "overwrite": "true", - "file_glob": "true", - }, - }, - ], - } - }, - } - - with open(out_fn, "w") as fh: - yaml.dump(data, fh, sort_keys=False, allow_unicode=True) - - -def main(): - args = parseargs() - assert os.path.isdir(args.godot_github_folder) - assert os.path.isdir(args.js_github_folder) - checkout_local_godot_install(args.godot_version) - - for x in ["actions", "workflows"]: - subprocess.call(["rm", "-rf", os.path.join(args.js_github_folder, x)]) - subprocess.call( - ["cp", "-r", os.path.join(args.godot_github_folder, x), os.path.join(args.js_github_folder, x)] - ) - - basic_flags = " " - actions = [ - "actions/godot-build/action.yml", - "actions/godot-cache/action.yml", - "actions/godot-deps/action.yml", - "actions/upload-artifact/action.yml", - ] - wf_actions_that_require_shell = fix_all_actions(args.js_github_folder, actions) - workflows = { - "android_builds.yml": BuildOpts(basic_flags, args.godot_version), - "ios_builds.yml": BuildOpts(basic_flags, args.godot_version), - "javascript_builds.yml": BuildOpts(basic_flags, args.godot_version), - "linux_builds.yml": BuildOpts(basic_flags, args.godot_version), - "macos_builds.yml": BuildOpts(basic_flags, args.godot_version), - "server_builds.yml": BuildOpts(basic_flags, args.godot_version), - "windows_builds.yml": BuildOpts(f"{basic_flags} use_mingw=yes", args.godot_version), - } - wf_names = fix_all_workflows(args.js_github_folder, workflows, wf_actions_that_require_shell) - subprocess.call(["rm", os.path.join(args.js_github_folder, "workflows", "static_checks.yml")]) - - out_publish_fn = os.path.join(args.js_github_folder, "workflows", "on_tag.yml") - add_publish_workflow(out_publish_fn, wf_names) - - -if __name__ == "__main__": - main() diff --git a/config.py b/config.py index 53bc8270..951e814f 100644 --- a/config.py +++ b/config.py @@ -1,5 +1,17 @@ def can_build(env, platform): - return True + return not (platform == "windows" and not env["use_mingw"]) + def configure(env): - pass + pass + + +def get_doc_classes(): + return [ + "JavaScript", + "JavaScriptModule", + ] + + +def get_doc_path(): + return "doc_classes" diff --git a/doc/class.xsd b/doc/class.xsd new file mode 100644 index 00000000..22821ac7 --- /dev/null +++ b/doc/class.xsd @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc_classes/JavaScript.xml b/doc_classes/JavaScript.xml new file mode 100644 index 00000000..ca3f4659 --- /dev/null +++ b/doc_classes/JavaScript.xml @@ -0,0 +1,11 @@ + + + + A JavaScript script resource for creating and managing JavaScript scripts in Godot. + + + The JavaScript class provides a way to create and manage JavaScript scripts within the Godot game engine. It inherits from the Script class and allows you to write game logic using JavaScript as the scripting language. + + + + diff --git a/doc_classes/JavaScriptModule.xml b/doc_classes/JavaScriptModule.xml new file mode 100644 index 00000000..c9f1c7f9 --- /dev/null +++ b/doc_classes/JavaScriptModule.xml @@ -0,0 +1,44 @@ + + + + A JavaScript module resource for managing JavaScript source code and bytecode. + + + The JavaScriptModule class provides methods to manage JavaScript source code and bytecode. It allows you to get and set both the source code and bytecode of a JavaScript module. + + + + + + + + Returns the bytecode of the JavaScript module as a PackedByteArray. + + + + + + Returns the source code of the JavaScript module as a String. + + + + + + + Sets the bytecode of the JavaScript module using a PackedByteArray. + + + + + + + Sets the source code of the JavaScript module using a String. + + + + + + The path to the JavaScript script file. + + + diff --git a/tools/editor_tools.cpp b/editor/editor_tools.cpp similarity index 80% rename from tools/editor_tools.cpp rename to editor/editor_tools.cpp index 1c705fa9..cc443f23 100644 --- a/tools/editor_tools.cpp +++ b/editor/editor_tools.cpp @@ -1,9 +1,42 @@ +/**************************************************************************/ +/* editor_tools.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #include "editor_tools.h" -#include "../javascript_language.h" #include "core/math/expression.h" #include "core/os/keyboard.h" +#include "editor/doc_tools.h" +#include "editor/editor_help.h" #include "editor/filesystem_dock.h" +#include "../javascript_language.h" + #define TS_IGNORE "//@ts-ignore\n" static HashMap> ts_ignore_errors; static HashMap> removed_members; @@ -62,7 +95,6 @@ void JavaScriptPlugin::_on_menu_item_pressed(int item) { } JavaScriptPlugin::JavaScriptPlugin(EditorNode *p_node) { - PopupMenu *menu = memnew(PopupMenu); add_tool_submenu_item(TTR("JavaScript"), menu); menu->add_item(TTR("Generate TypeScript Declaration File"), ITEM_GEN_DECLARE_FILE); @@ -318,32 +350,34 @@ String _export_class(const DocData::ClassDoc &class_doc) { String constants = ""; HashMap> enumerations; for (const DocData::ConstantDoc &const_doc : class_doc.constants) { - if (ignore_members.has(const_doc.name)) continue; + if (ignore_members.has(const_doc.name)) { + continue; + } - Dictionary dict; - dict["description"] = format_doc_text(const_doc.description, "\t\t "); - dict["name"] = format_property_name(const_doc.name); - dict["value"] = const_doc.value; + Dictionary new_dict; + new_dict["description"] = format_doc_text(const_doc.description, "\t\t "); + new_dict["name"] = format_property_name(const_doc.name); + new_dict["value"] = const_doc.value; String type = "number"; if (!const_doc.enumeration.is_empty()) { type = const_doc.enumeration + "." + const_doc.name; } else if (const_doc.value.find("(") != -1) { type = const_doc.value.split("(")[0]; } else if (const_doc.value.is_valid_int()) { - type = dict["value"]; + type = new_dict["value"]; } - dict["type"] = type; + new_dict["type"] = type; - String const_str = "\n" - "\t\t/** ${description} */\n" - "${TS_IGNORE}" - "\t\tconst ${name}: ${type};\n"; + String new_const_str = "\n" + "\t\t/** ${description} */\n" + "${TS_IGNORE}" + "\t\tconst ${name}: ${type};\n"; if (ts_ignore_errors.has(class_doc.name) && ts_ignore_errors[class_doc.name].has(const_doc.name)) { - const_str = const_str.replace("${TS_IGNORE}", "\t\t" TS_IGNORE); + new_const_str = new_const_str.replace("${TS_IGNORE}", "\t\t" TS_IGNORE); } else { - const_str = const_str.replace("${TS_IGNORE}", ""); + new_const_str = new_const_str.replace("${TS_IGNORE}", ""); } - constants += apply_pattern(const_str, dict); + constants += apply_pattern(new_const_str, new_dict); if (!const_doc.enumeration.is_empty()) { if (!enumerations.has(const_doc.enumeration)) { @@ -368,11 +402,11 @@ String _export_class(const DocData::ClassDoc &class_doc) { for (int i = 0; i < enums.size(); i++) { String const_str = "\t\t\t/** ${description} */\n" "\t\t\t${name} = ${value},\n"; - Dictionary dict; - dict["description"] = format_doc_text(enums[i]->description, "\t\t\t "); - dict["name"] = format_property_name(enums[i]->name); - dict["value"] = enums[i]->value; - enum_str += apply_pattern(const_str, dict); + Dictionary new_dict; + new_dict["description"] = format_doc_text(enums[i]->description, "\t\t\t "); + new_dict["name"] = format_property_name(enums[i]->name); + new_dict["value"] = enums[i]->value; + enum_str += apply_pattern(const_str, new_dict); } enum_str += "\t\t}\n"; enumerations_str += enum_str; @@ -382,7 +416,8 @@ String _export_class(const DocData::ClassDoc &class_doc) { Vector method_list = class_doc.methods; String properties = ""; for (const DocData::PropertyDoc &prop_doc : class_doc.properties) { - if (ignore_members.has(prop_doc.name)) continue; + if (ignore_members.has(prop_doc.name)) + continue; String prop_str = "\n" "\t\t/** ${description} */\n" @@ -394,12 +429,12 @@ String _export_class(const DocData::ClassDoc &class_doc) { prop_str = prop_str.replace("${TS_IGNORE}", ""); } - Dictionary dict; - dict["description"] = format_doc_text(prop_doc.description, "\t\t "); - dict["name"] = format_property_name(prop_doc.name); - dict["type"] = get_type_name(prop_doc.type); - dict["static"] = Engine::get_singleton()->has_singleton(class_doc.name) ? "static " : ""; - properties += apply_pattern(prop_str, dict); + Dictionary new_dict; + new_dict["description"] = format_doc_text(prop_doc.description, "\t\t "); + new_dict["name"] = format_property_name(prop_doc.name); + new_dict["type"] = get_type_name(prop_doc.type); + new_dict["static"] = Engine::get_singleton()->has_singleton(class_doc.name) ? "static " : ""; + properties += apply_pattern(prop_str, new_dict); if (!prop_doc.getter.is_empty()) { DocData::MethodDoc md; @@ -426,7 +461,8 @@ String _export_class(const DocData::ClassDoc &class_doc) { String signals = ""; for (int i = 0; i < class_doc.signals.size(); ++i) { const DocData::MethodDoc &signal = class_doc.signals[i]; - if (ignore_members.has(signal.name)) continue; + if (ignore_members.has(signal.name)) + continue; String signal_str = "\n" "\t\t/** ${description} */\n" @@ -437,10 +473,10 @@ String _export_class(const DocData::ClassDoc &class_doc) { } else { signal_str = signal_str.replace("${TS_IGNORE}", ""); } - Dictionary dict; - dict["description"] = format_doc_text(signal.description, "\t\t\t "); - dict["name"] = signal.name; - signals += apply_pattern(signal_str, dict); + Dictionary new_dict; + new_dict["description"] = format_doc_text(signal.description, "\t\t\t "); + new_dict["name"] = signal.name; + signals += apply_pattern(signal_str, new_dict); } dict["signals"] = signals; @@ -448,7 +484,8 @@ String _export_class(const DocData::ClassDoc &class_doc) { String methods = ""; for (int i = 0; i < method_list.size(); i++) { const DocData::MethodDoc &method_doc = method_list[i]; - if (ignore_members.has(method_doc.name)) continue; + if (ignore_members.has(method_doc.name)) + continue; if (method_doc.name == class_doc.name) { continue; @@ -570,18 +607,18 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) { "\tconst ${name}: ${type};\n"; for (int i = 0; i < class_doc.constants.size(); i++) { const DocData::ConstantDoc &const_doc = class_doc.constants[i]; - Dictionary dict; - dict["description"] = format_doc_text(const_doc.description, "\t "); - dict["name"] = format_property_name(const_doc.name); - dict["value"] = const_doc.value; + Dictionary new_dict; + new_dict["description"] = format_doc_text(const_doc.description, "\t "); + new_dict["name"] = format_property_name(const_doc.name); + new_dict["value"] = const_doc.value; if (const_doc.name == "NAN" || const_doc.name == "INF") { - dict["type"] = "number"; + new_dict["type"] = "number"; } else if (!const_doc.enumeration.is_empty()) { - dict["type"] = format_enum_name(const_doc.enumeration) + "." + const_doc.name; + new_dict["type"] = format_enum_name(const_doc.enumeration) + "." + const_doc.name; } else { - dict["type"] = dict["value"]; + new_dict["type"] = new_dict["value"]; } - constants += apply_pattern(const_str, dict); + constants += apply_pattern(const_str, new_dict); if (!const_doc.enumeration.is_empty()) { if (!enumerations.has(const_doc.enumeration)) { @@ -595,18 +632,18 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) { } class_enumerations.insert(GODOT_OBJECT_NAME, enumerations); - for (auto E : enumerations) { - String enum_str = "\tenum " + format_enum_name(E.key) + " {\n"; - const Vector &enums = E.value; + for (auto F : enumerations) { + String enum_str = "\tenum " + format_enum_name(F.key) + " {\n"; + const Vector &enums = F.value; for (int i = 0; i < enums.size(); i++) { - String const_str = "\t\t/** ${description} */\n" - "\t\t${name} = ${value},\n"; - Dictionary dict; - dict["description"] = format_doc_text(enums[i]->description, "\t\t\t "); - dict["name"] = format_property_name(enums[i]->name); - dict["value"] = enums[i]->value; - - enum_str += apply_pattern(const_str, dict); + String new_const_str = "\t\t/** ${description} */\n" + "\t\t${name} = ${value},\n"; + Dictionary new_dict; + new_dict["description"] = format_doc_text(enums[i]->description, "\t\t\t "); + new_dict["name"] = format_property_name(enums[i]->name); + new_dict["value"] = enums[i]->value; + + enum_str += apply_pattern(new_const_str, new_dict); } enum_str += "\t}\n"; enumerations_str += enum_str; @@ -643,7 +680,7 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) { void JavaScriptPlugin::_export_enumeration_binding_file(const String &p_path) { _export_typescript_declare_file(""); - String file_content = "// Tool generated file DO NOT modify mannually\n" + String file_content = "// Tool generated file DO NOT modify manually\n" "// Add this script as first autoload to your project to bind enumerations for release build of godot engine\n" "\n" "if (!godot.DEBUG_ENABLED) {\n" @@ -676,10 +713,10 @@ void JavaScriptPlugin::_export_enumeration_binding_file(const String &p_path) { } } enum_items_text += " }"; - Dictionary dict; - dict["name"] = format_enum_name(E.key); - dict["values"] = enum_items_text; - class_enums += apply_pattern("\n\t\t${name}: { value: ${values} }", dict); + Dictionary new_dict; + new_dict["name"] = format_enum_name(E.key); + new_dict["values"] = enum_items_text; + class_enums += apply_pattern("\n\t\t${name}: { value: ${values} }", new_dict); if (idx < enumeration.size() - 1) { class_enums += ", "; } else { @@ -688,14 +725,14 @@ void JavaScriptPlugin::_export_enumeration_binding_file(const String &p_path) { idx++; } static String class_template = "\tbind(${class}, {${enumerations}});\n"; - Dictionary dict; - dict["class"] = class_name; - dict["enumerations"] = class_enums; - enumerations += apply_pattern(class_template, dict); + Dictionary class_dict; + class_dict["class"] = class_name; + class_dict["enumerations"] = class_enums; + enumerations += apply_pattern(class_template, class_dict); } - Dictionary dict; - dict["enumerations"] = enumerations; - file_content = apply_pattern(file_content, dict); + Dictionary enum_dict; + enum_dict["enumerations"] = enumerations; + file_content = apply_pattern(file_content, enum_dict); dump_to_file(p_path, file_content); } diff --git a/generate_builtin_api.py b/generate_builtin_api.py index a4d71800..839d5560 100755 --- a/generate_builtin_api.py +++ b/generate_builtin_api.py @@ -3,445 +3,388 @@ import xml.etree.ElementTree as ET BUILTIN_CLASSES = [ - 'Vector2', - 'Rect2', - 'Color', - 'Vector3', - 'Basis', - 'Quaternion', - 'RID', - 'Transform2D', - 'Plane', - 'AABB', - "Transform3D", - "PackedByteArray", - "PackedInt32Array", - "PackedInt64Array", - "PackedFloat32Array", - "PackedFloat64Array", - "PackedStringArray", - "PackedVector2Array", - "PackedVector3Array", - "PackedColorArray", + "Vector2", + "Rect2", + "Color", + "Vector3", + "Basis", + "Quaternion", + "RID", + "Transform2D", + "Plane", + "AABB", + "Transform3D", + "PackedByteArray", + "PackedInt32Array", + "PackedInt64Array", + "PackedFloat32Array", + "PackedFloat64Array", + "PackedStringArray", + "PackedVector2Array", + "PackedVector3Array", + "PackedColorArray", ] MAX_CONSTRUCTOR_ARGC = { - 'Vector2': 2, - 'Rect2': 4, - 'Color': 4, - 'Vector3': 3, - 'Basis': 0, - 'Quaternion': 0, - 'RID': 0, - 'Transform2D': 0, - 'Plane': 0, - 'AABB': 0, - "Transform3D": 0, - "PackedByteArray": 0, - "PackedInt32Array": 0, - "PackedInt64Array": 0, - "PackedFloat32Array": 0, - "PackedFloat64Array": 0, - "PackedStringArray": 0, - "PackedVector2Array": 0, - "PackedVector3Array": 0, - "PackedColorArray": 0, + "Vector2": 2, + "Rect2": 4, + "Color": 4, + "Vector3": 3, + "Basis": 0, + "Quaternion": 0, + "RID": 0, + "Transform2D": 0, + "Plane": 0, + "AABB": 0, + "Transform3D": 0, + "PackedByteArray": 0, + "PackedInt32Array": 0, + "PackedInt64Array": 0, + "PackedFloat32Array": 0, + "PackedFloat64Array": 0, + "PackedStringArray": 0, + "PackedVector2Array": 0, + "PackedVector3Array": 0, + "PackedColorArray": 0, } TYPE_MAP = { - 'int': 'number', - 'float': 'number', - 'bool': 'boolean', - 'String': 'string', - 'NodePath': 'string', + "int": "number", + "float": "number", + "bool": "boolean", + "String": "string", + "NodePath": "string", } METHOD_OP_EQUALS = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "equals", - "native_method": "operator==", - "return": "boolean" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "equals", + "native_method": "operator==", + "return": "boolean", } METHOD_OP_ADD = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "add", - "native_method": "operator+", - "return": "${class_name}" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "add", + "native_method": "operator+", + "return": "${class_name}", } METHOD_OP_ADD_ASSIGN = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "add_assign", - "native_method": "operator+=", - "return": "this" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "add_assign", + "native_method": "operator+=", + "return": "this", } METHOD_OP_SUB = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "subtract", - "native_method": "operator-", - "return": "${class_name}" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "subtract", + "native_method": "operator-", + "return": "${class_name}", } METHOD_OP_SUB_ASSIGN = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "subtract_assign", - "native_method": "operator-=", - "return": "this" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "subtract_assign", + "native_method": "operator-=", + "return": "this", } METHOD_OP_MUL = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "multiply", - "native_method": "operator*", - "return": "${class_name}" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "multiply", + "native_method": "operator*", + "return": "${class_name}", } METHOD_OP_MUL_ASSIGN = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "multiply_assign", - "native_method": "operator*=", - "return": "this" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "multiply_assign", + "native_method": "operator*=", + "return": "this", } METHOD_OP_DIV = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "multiply", - "native_method": "operator/", - "return": "${class_name}" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "multiply", + "native_method": "operator/", + "return": "${class_name}", } METHOD_OP_DIV_ASSIGN = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "multiply_assign", - "native_method": "operator/=", - "return": "this" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "multiply_assign", + "native_method": "operator/=", + "return": "this", } METHOD_OP_NEG = { - "arguments": [], - "name": "negate", - "native_method": "operator-", - "return": "${class_name}" + "arguments": [], + "name": "negate", + "native_method": "operator-", + "return": "${class_name}", } METHOD_OP_LESS = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "less", - "native_method": "operator<", - "return": "boolean" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "less", + "native_method": "operator<", + "return": "boolean", } METHOD_OP_LESS_EQAUL = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "${class_name}" - } - ], - "name": "less_equal", - "native_method": "operator<=", - "return": "boolean" + "arguments": [{"default_value": None, "has_default_value": False, "type": "${class_name}"}], + "name": "less_equal", + "native_method": "operator<=", + "return": "boolean", } METHOD_PACKED_ARRAY_GET = { - "arguments": [ - { - "default_value": None, - "has_default_value": False, - "type": "number" - } - ], - "name": "get", - "native_method": "operator[]", - "return": "Variant" + "arguments": [{"default_value": None, "has_default_value": False, "type": "number"}], + "name": "get", + "native_method": "operator[]", + "return": "Variant", } IGNORED_PROPS = { - "Rect2": ['end', 'grow_side'], - "Color": ['h', 's', 'v', 'r8', 'g8', 'b8', 'a8'], - "Transform2D": ['xform', 'xform_inv'], - "Quaternion": ['get_euler'], - "Basis": ['is_equal_approx', 'get_euler', 'from_euler'], - "Plane": ['intersects_segment', 'intersects_ray', 'intersect_3'], - "AABB": ['end'], - "Transform3D": ['xform', 'xform_inv'], - "PackedByteArray": [ - 'compress', - 'decompress', - 'decompress_dynamic', - 'get_string_from_ascii', - 'get_string_from_utf8', - 'get_string_from_utf16', - 'get_string_from_utf32', - 'hex_encode', - 'to_float32_array', - 'to_float64_array', - 'to_int32_array', - 'to_int64_array', - 'has_encoded_var', - ], + "Rect2": ["end", "grow_side"], + "Color": ["h", "s", "v", "r8", "g8", "b8", "a8"], + "Transform2D": ["xform", "xform_inv"], + "Quaternion": ["get_euler"], + "Basis": ["is_equal_approx", "get_euler", "from_euler"], + "Plane": ["intersects_segment", "intersects_ray", "intersect_3"], + "AABB": ["end"], + "Transform3D": ["xform", "xform_inv"], + "PackedByteArray": [ + "compress", + "decompress", + "decompress_dynamic", + "get_string_from_ascii", + "get_string_from_utf8", + "get_string_from_utf16", + "get_string_from_utf32", + "hex_encode", + "to_float32_array", + "to_float64_array", + "to_int32_array", + "to_int64_array", + "has_encoded_var", + ], } PROPERTY_REMAP = { - "Transform2D": { - "x": "columns[0]", - "y": "columns[1]", - "origin": "columns[2]", - }, - "Basis": { - "x": "rows[0]", - "y": "rows[1]", - "z": "rows[2]", - }, - "Plane": { - "x": "normal.x", - "y": "normal.y", - "z": "normal.z", - } + "Transform2D": { + "x": "columns[0]", + "y": "columns[1]", + "origin": "columns[2]", + }, + "Basis": { + "x": "rows[0]", + "y": "rows[1]", + "z": "rows[2]", + }, + "Plane": { + "x": "normal.x", + "y": "normal.y", + "z": "normal.z", + }, } OPERATOR_METHODS = { - "Vector2": [ - METHOD_OP_NEG, - METHOD_OP_EQUALS, - METHOD_OP_LESS, - METHOD_OP_LESS_EQAUL, - METHOD_OP_ADD, - METHOD_OP_ADD_ASSIGN, - METHOD_OP_SUB, - METHOD_OP_SUB_ASSIGN, - METHOD_OP_MUL, - METHOD_OP_MUL_ASSIGN, - METHOD_OP_DIV, - METHOD_OP_DIV_ASSIGN, - ], - "Vector3": [ - METHOD_OP_NEG, - METHOD_OP_EQUALS, - METHOD_OP_LESS, - METHOD_OP_LESS_EQAUL, - METHOD_OP_ADD, - METHOD_OP_ADD_ASSIGN, - METHOD_OP_SUB, - METHOD_OP_SUB_ASSIGN, - METHOD_OP_MUL, - METHOD_OP_MUL_ASSIGN, - METHOD_OP_DIV, - METHOD_OP_DIV_ASSIGN, - ], - "Basis": [ - METHOD_OP_EQUALS, - METHOD_OP_ADD, - METHOD_OP_ADD_ASSIGN, - METHOD_OP_SUB, - METHOD_OP_SUB_ASSIGN, - METHOD_OP_MUL, - METHOD_OP_MUL_ASSIGN, - ], - "Quaternion": [ - METHOD_OP_NEG, - METHOD_OP_EQUALS, - METHOD_OP_ADD, - METHOD_OP_ADD_ASSIGN, - METHOD_OP_SUB, - METHOD_OP_SUB_ASSIGN, - ], - "Rect2": [ - METHOD_OP_EQUALS - ], - "Transform2D": [ - METHOD_OP_EQUALS, - METHOD_OP_MUL, - METHOD_OP_MUL_ASSIGN, - ], - "Color": [ - METHOD_OP_NEG, - METHOD_OP_EQUALS, - METHOD_OP_LESS, - METHOD_OP_ADD, - METHOD_OP_ADD_ASSIGN, - METHOD_OP_SUB, - METHOD_OP_SUB_ASSIGN, - METHOD_OP_MUL, - METHOD_OP_MUL_ASSIGN, - METHOD_OP_DIV, - METHOD_OP_DIV_ASSIGN, - ], - "RID": [ - METHOD_OP_EQUALS, - METHOD_OP_LESS, - METHOD_OP_LESS_EQAUL, - ], - "Plane": [ - METHOD_OP_NEG, - METHOD_OP_EQUALS, - ], - "AABB": [ - METHOD_OP_EQUALS, - ], - "Transform3D": [ - METHOD_OP_EQUALS, - METHOD_OP_MUL, - METHOD_OP_MUL_ASSIGN, - ] + "Vector2": [ + METHOD_OP_NEG, + METHOD_OP_EQUALS, + METHOD_OP_LESS, + METHOD_OP_LESS_EQAUL, + METHOD_OP_ADD, + METHOD_OP_ADD_ASSIGN, + METHOD_OP_SUB, + METHOD_OP_SUB_ASSIGN, + METHOD_OP_MUL, + METHOD_OP_MUL_ASSIGN, + METHOD_OP_DIV, + METHOD_OP_DIV_ASSIGN, + ], + "Vector3": [ + METHOD_OP_NEG, + METHOD_OP_EQUALS, + METHOD_OP_LESS, + METHOD_OP_LESS_EQAUL, + METHOD_OP_ADD, + METHOD_OP_ADD_ASSIGN, + METHOD_OP_SUB, + METHOD_OP_SUB_ASSIGN, + METHOD_OP_MUL, + METHOD_OP_MUL_ASSIGN, + METHOD_OP_DIV, + METHOD_OP_DIV_ASSIGN, + ], + "Basis": [ + METHOD_OP_EQUALS, + METHOD_OP_ADD, + METHOD_OP_ADD_ASSIGN, + METHOD_OP_SUB, + METHOD_OP_SUB_ASSIGN, + METHOD_OP_MUL, + METHOD_OP_MUL_ASSIGN, + ], + "Quaternion": [ + METHOD_OP_NEG, + METHOD_OP_EQUALS, + METHOD_OP_ADD, + METHOD_OP_ADD_ASSIGN, + METHOD_OP_SUB, + METHOD_OP_SUB_ASSIGN, + ], + "Rect2": [METHOD_OP_EQUALS], + "Transform2D": [ + METHOD_OP_EQUALS, + METHOD_OP_MUL, + METHOD_OP_MUL_ASSIGN, + ], + "Color": [ + METHOD_OP_NEG, + METHOD_OP_EQUALS, + METHOD_OP_LESS, + METHOD_OP_ADD, + METHOD_OP_ADD_ASSIGN, + METHOD_OP_SUB, + METHOD_OP_SUB_ASSIGN, + METHOD_OP_MUL, + METHOD_OP_MUL_ASSIGN, + METHOD_OP_DIV, + METHOD_OP_DIV_ASSIGN, + ], + "RID": [ + METHOD_OP_EQUALS, + METHOD_OP_LESS, + METHOD_OP_LESS_EQAUL, + ], + "Plane": [ + METHOD_OP_NEG, + METHOD_OP_EQUALS, + ], + "AABB": [ + METHOD_OP_EQUALS, + ], + "Transform3D": [ + METHOD_OP_EQUALS, + METHOD_OP_MUL, + METHOD_OP_MUL_ASSIGN, + ], } + def apply_pattern(template, values): - for key in values: - template = template.replace( '${' + key + '}', values[key]) - return template + for key in values: + template = template.replace("${" + key + "}", values[key]) + return template + def parse_class(cls): - class_name = cls.get('name') - ret = {'name': class_name} - members = [] - methods = [] - operators = [] - constants = [] - ret['properties'] = members - ret['methods'] = methods - ret['operators'] = operators - ret['constants'] = constants - ret['constructor_argc'] = MAX_CONSTRUCTOR_ARGC[class_name] - - for m in (cls.find("members") if cls.find("members") is not None else []): - m_dict = dict(m.attrib) - type = m_dict['type'] - name = m_dict['name'] - if (class_name in IGNORED_PROPS) and (name in IGNORED_PROPS[class_name]): - continue - if type in TYPE_MAP: - type = TYPE_MAP[type] - native_prop = name - if class_name in PROPERTY_REMAP: - if name in PROPERTY_REMAP[class_name]: - native_prop = PROPERTY_REMAP[class_name][name] - members.append({'name': name, 'type': type, 'native': native_prop}) - - for m in (cls.find("methods") if cls.find("methods") is not None else []): - m_dict = dict(m.attrib) - method_name = m_dict['name'] - if method_name == class_name: - continue# ignore constructors - if class_name in IGNORED_PROPS and method_name in IGNORED_PROPS[class_name]: - continue# ignored methods - if class_name == 'PackedByteArray' and method_name.startswith('encode_') or method_name.startswith('decode_'): - continue# ignore decode/encode methods - return_type = m.find("return").attrib["type"] if m.find("return") != None else "void" - if return_type in TYPE_MAP: - return_type = TYPE_MAP[return_type] - arguments = [] - for arg in m.iter('param'): - dictArg = dict(arg.attrib) - if "dictArg" in dictArg: dictArg.pop("index") - dictArg["default_value"] = dictArg["default"] if "default" in dictArg else None - if "default" in dictArg: dictArg.pop("default") - type = dictArg['type'] - if type in TYPE_MAP: - type = TYPE_MAP[type] - arguments.append({ - 'type': type, - 'default_value': dictArg['default_value'], - 'has_default_value': "default" in dictArg - }) - methods.append({ - 'name': method_name, - 'native_method': method_name, - 'return': return_type, - 'arguments': arguments, - }) - if class_name.startswith("Packed") and class_name.endswith("Array"): - methods.append(METHOD_PACKED_ARRAY_GET) - # add operator methods - if class_name in OPERATOR_METHODS: - for em in OPERATOR_METHODS[class_name]: - operators.append(em) - - for c in (cls.find("constants") if cls.find("constants") is not None else []): - const_name = c.get("name") - if class_name in IGNORED_PROPS and const_name in IGNORED_PROPS[class_name]: - continue - constants.append(dict(c.attrib)) - return json.loads(apply_pattern(json.dumps(ret), { - 'class_name': class_name, - })) + class_name = cls.get("name") + ret = {"name": class_name} + members = [] + methods = [] + operators = [] + constants = [] + ret["properties"] = members + ret["methods"] = methods + ret["operators"] = operators + ret["constants"] = constants + ret["constructor_argc"] = MAX_CONSTRUCTOR_ARGC[class_name] + + for m in cls.find("members") if cls.find("members") is not None else []: + m_dict = dict(m.attrib) + type = m_dict["type"] + name = m_dict["name"] + if (class_name in IGNORED_PROPS) and (name in IGNORED_PROPS[class_name]): + continue + if type in TYPE_MAP: + type = TYPE_MAP[type] + native_prop = name + if class_name in PROPERTY_REMAP: + if name in PROPERTY_REMAP[class_name]: + native_prop = PROPERTY_REMAP[class_name][name] + members.append({"name": name, "type": type, "native": native_prop}) + + for m in cls.find("methods") if cls.find("methods") is not None else []: + m_dict = dict(m.attrib) + method_name = m_dict["name"] + if method_name == class_name: + continue # ignore constructors + if class_name in IGNORED_PROPS and method_name in IGNORED_PROPS[class_name]: + continue # ignored methods + if class_name == "PackedByteArray" and method_name.startswith("encode_") or method_name.startswith("decode_"): + continue # ignore decode/encode methods + if class_name == "PackedByteArray" and method_name == "get_string_from_wchar": + continue + return_type = m.find("return").attrib["type"] if m.find("return") != None else "void" + if return_type in TYPE_MAP: + return_type = TYPE_MAP[return_type] + arguments = [] + for arg in m.iter("param"): + dictArg = dict(arg.attrib) + if "dictArg" in dictArg: + dictArg.pop("index") + dictArg["default_value"] = dictArg["default"] if "default" in dictArg else None + if "default" in dictArg: + dictArg.pop("default") + type = dictArg["type"] + if type in TYPE_MAP: + type = TYPE_MAP[type] + arguments.append( + { + "type": type, + "default_value": dictArg["default_value"], + "has_default_value": "default" in dictArg, + } + ) + methods.append( + { + "name": method_name, + "native_method": method_name, + "return": return_type, + "arguments": arguments, + } + ) + if class_name.startswith("Packed") and class_name.endswith("Array"): + methods.append(METHOD_PACKED_ARRAY_GET) + # add operator methods + if class_name in OPERATOR_METHODS: + for em in OPERATOR_METHODS[class_name]: + operators.append(em) + + for c in cls.find("constants") if cls.find("constants") is not None else []: + const_name = c.get("name") + if class_name in IGNORED_PROPS and const_name in IGNORED_PROPS[class_name]: + continue + constants.append(dict(c.attrib)) + return json.loads( + apply_pattern( + json.dumps(ret), + { + "class_name": class_name, + }, + ) + ) + def generate_api_json(MODULE_DIR): - DOCS_DIR = os.path.abspath(os.path.join(MODULE_DIR, "../../doc/classes")) - if not os.path.isdir(DOCS_DIR) and len(sys.argv) > 1: - DOCS_DIR = sys.argv[-1] - OUTPUT_FILE = os.path.join(MODULE_DIR, "builtin_api.gen.json") - - classes = [] - for cls in BUILTIN_CLASSES: - tree = ET.parse(open(os.path.join(DOCS_DIR, cls + '.xml'), 'r')) - data = tree.getroot() - classes.append(parse_class(data)) - json.dump(classes, open(OUTPUT_FILE, 'w'), ensure_ascii=False, indent=2, sort_keys=True) - + DOCS_DIR = os.path.abspath(os.path.join(MODULE_DIR, "../../doc/classes")) + if not os.path.isdir(DOCS_DIR) and len(sys.argv) > 1: + DOCS_DIR = sys.argv[-1] + OUTPUT_FILE = os.path.join(MODULE_DIR, "builtin_api.gen.json") + + classes = [] + for cls in BUILTIN_CLASSES: + tree = ET.parse(open(os.path.join(DOCS_DIR, cls + ".xml"), "r")) + data = tree.getroot() + classes.append(parse_class(data)) + json.dump(classes, open(OUTPUT_FILE, "w"), ensure_ascii=False, indent=2, sort_keys=True) + + if __name__ == "__main__": - generate_api_json() + generate_api_json(".") diff --git a/icons/JavaScript.svg b/icons/JavaScript.svg new file mode 100644 index 00000000..14e0906e --- /dev/null +++ b/icons/JavaScript.svg @@ -0,0 +1,3 @@ + + + diff --git a/icons/JavaScriptInternal.svg b/icons/JavaScriptInternal.svg new file mode 100644 index 00000000..d1d0e67c --- /dev/null +++ b/icons/JavaScriptInternal.svg @@ -0,0 +1,3 @@ + + + diff --git a/icons/README.md b/icons/README.md new file mode 100644 index 00000000..58e7cac5 --- /dev/null +++ b/icons/README.md @@ -0,0 +1 @@ +icon source https://commons.wikimedia.org/wiki/File:Unofficial_JavaScript_logo.svg diff --git a/javascript.cpp b/javascript.cpp index 411965e3..9c1c0940 100644 --- a/javascript.cpp +++ b/javascript.cpp @@ -1,3 +1,33 @@ +/**************************************************************************/ +/* javascript.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #include "javascript.h" #include "core/config/engine.h" #include "core/io/file_access_encrypted.h" @@ -35,7 +65,6 @@ StringName JavaScript::get_instance_base_type() const { } ScriptInstance *JavaScript::instance_create(Object *p_this) { - JavaScriptBinder *binder = JavaScriptLanguage::get_thread_binder(Thread::get_caller_id()); ERR_FAIL_NULL_V_MSG(binder, NULL, "Cannot create instance from this thread"); const JavaScriptClassInfo *cls = NULL; @@ -195,7 +224,6 @@ bool JavaScript::get_property_default_value(const StringName &p_property, Varian } void JavaScript::update_exports() { - #ifdef TOOLS_ENABLED if (!javascript_class) return; @@ -321,11 +349,11 @@ void JavaScriptModule::_bind_methods() { } JavaScriptModule::JavaScriptModule() { - set_source_code("module.exports = {};" ENDL); + set_source_code("module.exports = {};\n"); } -Ref ResourceFormatLoaderJavaScriptModule::load(const String &p_path, const String &p_original_path, Error *r_error) { - return load_static(p_path, p_original_path, r_error); +Ref ResourceFormatLoaderJavaScriptModule::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, ResourceFormatLoader::CacheMode p_cache_mode) { + return ResourceFormatLoaderJavaScriptModule::load_static(p_path, p_original_path, r_error); } void ResourceFormatLoaderJavaScriptModule::get_recognized_extensions(List *p_extensions) const { @@ -354,7 +382,8 @@ Ref ResourceFormatLoaderJavaScriptModule::load_static(const String &p_ module->set_script_path(p_path); if (p_path.ends_with("." EXT_JSMODULE) || p_path.ends_with("." EXT_JSCLASS) || p_path.ends_with("." EXT_JSON)) { String code = FileAccess::get_file_as_string(p_path, &err); - if (r_error) *r_error = err; + if (r_error) + *r_error = err; ERR_FAIL_COND_V_MSG(err != OK, Ref(), "Cannot load source code from file '" + p_path + "'."); module->set_source_code(code); } @@ -392,12 +421,13 @@ Ref ResourceFormatLoaderJavaScriptModule::load_static(const String &p_ } #endif - if (r_error) *r_error = err; + if (r_error) + *r_error = err; ERR_FAIL_COND_V(err != OK, Ref()); return module; } -Error ResourceFormatSaverJavaScriptModule::save(const String &p_path, const Ref &p_resource, uint32_t p_flags) { +Error ResourceFormatSaverJavaScriptModule::save(const Ref &p_resource, const String &p_path, uint32_t p_flags) { Ref module = p_resource; ERR_FAIL_COND_V(module.is_null(), ERR_INVALID_PARAMETER); String source = module->get_source_code(); diff --git a/javascript.h b/javascript.h index 1ffbf1a3..6a62530f 100644 --- a/javascript.h +++ b/javascript.h @@ -1,12 +1,43 @@ +/**************************************************************************/ +/* javascript.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #ifndef JAVASCRIPT_H #define JAVASCRIPT_H #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/object/script_language.h" -#include "javascript_binder.h" #include "scene/resources/text_file.h" +#include "javascript_binder.h" + #define EXT_JSCLASS "mjs" #define EXT_JSMODULE "js" #define EXT_JSON "json" @@ -125,7 +156,7 @@ class JavaScriptModule : public TextFile { class ResourceFormatLoaderJavaScriptModule : public ResourceFormatLoader { GDCLASS(ResourceFormatLoaderJavaScriptModule, ResourceFormatLoader) public: - virtual Ref load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual Ref load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, ResourceFormatLoader::CacheMode p_cache_mode = CACHE_MODE_REUSE) override; virtual void get_recognized_extensions(List *p_extensions) const override; virtual void get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const override; virtual bool handles_type(const String &p_type) const override; @@ -137,9 +168,9 @@ class ResourceFormatLoaderJavaScriptModule : public ResourceFormatLoader { class ResourceFormatSaverJavaScriptModule : public ResourceFormatSaver { GDCLASS(ResourceFormatSaverJavaScriptModule, ResourceFormatSaver) public: - virtual Error save(const String &p_path, const Ref &p_resource, uint32_t p_flags = 0); + virtual Error save(const Ref &p_resource, const String &p_path, uint32_t p_flags = 0) override; virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override; virtual bool recognize(const Ref &p_resource) const override; }; -#endif +#endif // JAVASCRIPT_H diff --git a/javascript_binder.h b/javascript_binder.h index ee296bbf..4bb88b3f 100644 --- a/javascript_binder.h +++ b/javascript_binder.h @@ -1,5 +1,35 @@ -#ifndef JAVASCRIPT_BINDING_HELPER_H -#define JAVASCRIPT_BINDING_HELPER_H +/**************************************************************************/ +/* javascript_binder.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef JAVASCRIPT_BINDER_H +#define JAVASCRIPT_BINDER_H #include "core/os/thread.h" #include "javascript_gc_handler.h" @@ -102,4 +132,4 @@ class JavaScriptBinder { #endif }; -#endif +#endif // JAVASCRIPT_BINDER_H diff --git a/javascript_callable.h b/javascript_callable.h index e8ceb011..c2f99b3f 100644 --- a/javascript_callable.h +++ b/javascript_callable.h @@ -1,3 +1,33 @@ +/**************************************************************************/ +/* javascript_callable.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #ifndef JAVASCRIPT_CALLABLE_H #define JAVASCRIPT_CALLABLE_H @@ -10,7 +40,8 @@ class JavaScriptCallable : public CallableCustom { public: JavaScriptCallable() {} - JavaScriptCallable(const JavaScriptGCHandler &p_function) : js_function(p_function) {} + JavaScriptCallable(const JavaScriptGCHandler &p_function) : + js_function(p_function) {} virtual ~JavaScriptCallable() {} }; diff --git a/javascript_gc_handler.h b/javascript_gc_handler.h index 0d88ffc4..8b111136 100644 --- a/javascript_gc_handler.h +++ b/javascript_gc_handler.h @@ -1,3 +1,33 @@ +/**************************************************************************/ +/* javascript_gc_handler.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #ifndef JAVASCRIPT_GC_HANDLER_H #define JAVASCRIPT_GC_HANDLER_H @@ -149,4 +179,4 @@ struct JavaScriptGCHandler { } }; -#endif +#endif // JAVASCRIPT_GC_HANDLER_H diff --git a/javascript_instance.cpp b/javascript_instance.cpp index af0e67b8..6b48beb9 100644 --- a/javascript_instance.cpp +++ b/javascript_instance.cpp @@ -1,3 +1,33 @@ +/**************************************************************************/ +/* javascript_instance.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #include "javascript_instance.h" #include "javascript.h" #include "javascript_language.h" diff --git a/javascript_instance.h b/javascript_instance.h index 01220a47..f013c1df 100644 --- a/javascript_instance.h +++ b/javascript_instance.h @@ -1,10 +1,41 @@ +/**************************************************************************/ +/* javascript_instance.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #ifndef JAVASCRIPT_INSTANCE_H #define JAVASCRIPT_INSTANCE_H -#include "javascript.h" -#include "javascript_binder.h" #include "core/object/script_language.h" + #include "core/variant/callable.h" +#include "javascript.h" +#include "javascript_binder.h" class JavaScriptInstance : public ScriptInstance { friend class JavaScript; @@ -39,4 +70,4 @@ class JavaScriptInstance : public ScriptInstance { ~JavaScriptInstance(); }; -#endif +#endif // JAVASCRIPT_INSTANCE_H diff --git a/javascript_language.cpp b/javascript_language.cpp index cd2fe07a..ae69e781 100644 --- a/javascript_language.cpp +++ b/javascript_language.cpp @@ -1,7 +1,41 @@ +/**************************************************************************/ +/* javascript_language.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #include "javascript_language.h" -#include "core/object/class_db.h" #include "core/io/file_access.h" -JavaScriptLanguage *JavaScriptLanguage::singleton = NULL; +#include "core/object/class_db.h" + +#include "javascript_binder.h" +#include "quickjs_binder.h" + +JavaScriptLanguage *JavaScriptLanguage::singleton = nullptr; namespace JavaScriptInstanceBindingCallbacks { @@ -188,7 +222,6 @@ void JavaScriptLanguage::get_reserved_words(List *p_words) const { const char **w = _reserved_words; while (*w) { - p_words->push_back(*w); w++; } @@ -196,19 +229,19 @@ void JavaScriptLanguage::get_reserved_words(List *p_words) const { bool JavaScriptLanguage::is_control_flow_keyword(String p_keyword) const { return p_keyword == "if" || - p_keyword == "else" || - p_keyword == "return" || - p_keyword == "do" || - p_keyword == "while" || - p_keyword == "for" || - p_keyword == "break" || - p_keyword == "continue" || - p_keyword == "switch" || - p_keyword == "case" || - p_keyword == "throw" || - p_keyword == "try" || - p_keyword == "catch" || - p_keyword == "finally"; + p_keyword == "else" || + p_keyword == "return" || + p_keyword == "do" || + p_keyword == "while" || + p_keyword == "for" || + p_keyword == "break" || + p_keyword == "continue" || + p_keyword == "switch" || + p_keyword == "case" || + p_keyword == "throw" || + p_keyword == "try" || + p_keyword == "catch" || + p_keyword == "finally"; } void JavaScriptLanguage::get_comment_delimiters(List *p_delimiters) const { @@ -236,38 +269,38 @@ Vector JavaScriptLanguage::get_built_in_template constexpr size_t len = 2; static const struct ScriptLanguage::ScriptTemplate TEMPLATES[len] = { { "Node", - "Default", - "Base template for Node with default Godot cycle methods", - "export default class %CLASS% extends " GODOT_OBJECT_NAME ".%BASE% {\n" - " \n" - " constructor() {\n" - " super();\n" - " }\n" - " \n" - " // Called when the node enters the scene tree for the first time.\n" - " _ready() {\n" - " \n" - " }\n" - " \n" - " // Called every frame. 'delta' is the elapsed time since the previous frame.\n" - " _process(delta) {\n" - " \n" - " }\n" - "}\n" }, + "Default", + "Base template for Node with default Godot cycle methods", + "export default class %CLASS% extends " GODOT_OBJECT_NAME ".%BASE% {\n" + " \n" + " constructor() {\n" + " super();\n" + " }\n" + " \n" + " // Called when the node enters the scene tree for the first time.\n" + " _ready() {\n" + " \n" + " }\n" + " \n" + " // Called every frame. 'delta' is the elapsed time since the previous frame.\n" + " _process(delta) {\n" + " \n" + " }\n" + "}\n" }, { "Object", - "Empty", - "Empty template suitable for all Objects", - "export default class %CLASS% extends " GODOT_OBJECT_NAME ".%BASE% {\n" - " \n" - " // Declare member variables here. Examples:\n" - " a = 2;\n" - " b = \"text\";\n" - " \n" - " constructor() {\n" - " super();\n" - " }\n" - " \n" - "}\n" }, + "Empty", + "Empty template suitable for all Objects", + "export default class %CLASS% extends " GODOT_OBJECT_NAME ".%BASE% {\n" + " \n" + " // Declare member variables here. Examples:\n" + " a = 2;\n" + " b = \"text\";\n" + " \n" + " constructor() {\n" + " super();\n" + " }\n" + " \n" + "}\n" }, }; for (int i = 0; i < len; i++) { @@ -350,7 +383,8 @@ String JavaScriptLanguage::globalize_relative_path(const String &p_relative, con break; } } - if (!base_dir.ends_with("/")) base_dir += "/"; + if (!base_dir.ends_with("/")) + base_dir += "/"; file = base_dir + file_path; } return file; diff --git a/javascript_language.h b/javascript_language.h index 8e28fcd9..cc0aa326 100644 --- a/javascript_language.h +++ b/javascript_language.h @@ -1,9 +1,40 @@ -#ifndef JAVASCRIPT_LANGUAGE_H +/**************************************************************************/ +/* javascript_language.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef JAVASCRIPT_LANGUAGE_H #define JAVASCRIPT_LANGUAGE_H #include "core/object/script_language.h" + #include "javascript.h" -#include "quickjs/quickjs_binder.h" +#include "javascript_binder.h" class CallableMiddleman : public Object { GDCLASS(CallableMiddleman, Object); @@ -45,7 +76,7 @@ class JavaScriptLanguage : public ScriptLanguage { _FORCE_INLINE_ virtual String get_name() const override { return "JavaScript"; } const GDExtensionInstanceBindingCallbacks *get_instance_binding_callbacks() const { return &instance_binding_callbacks; } #ifdef TOOLS_ENABLED - _FORCE_INLINE_ HashSet > &get_scripts() { return scripts; } + _FORCE_INLINE_ HashSet> &get_scripts() { return scripts; } #endif /* LANGUAGE FUNCTIONS */ @@ -122,4 +153,4 @@ class JavaScriptLanguage : public ScriptLanguage { virtual ~JavaScriptLanguage(); }; -#endif +#endif // JAVASCRIPT_LANGUAGE_H diff --git a/misc/binding_script.js b/misc/binding_script.js index ea58b032..d32a6844 100644 --- a/misc/binding_script.js +++ b/misc/binding_script.js @@ -1,8 +1,8 @@ // (function start_script_binding() { - + // const GodotAnonymousConnectionManager = new(class GodotAnonymousConnectionManager extends godot.RefCounted { // anonymous_connection_index = 0; - + // get_slot_id(emitter, signal, target) { // return `__${emitter.get_instance_id()}:${signal}:${target.get_instance_id()}__`; // } @@ -11,7 +11,7 @@ // return `__anonymous_slot:${this.anonymous_connection_index++}`; // } // })(); - + // const godot_object_connect = godot.Object.prototype.connect; // Object.defineProperty(godot.Object.prototype, 'connect', { // // Object.prototype.connect(signal_name, target, method, params, flags) @@ -19,7 +19,7 @@ // if (args.length < 2) throw new Error('2 or more arguments expected'); // let signal = args[0]; // if (typeof signal !== 'string' || !signal) throw new Error('signal name expected for argument #0'); - + // let offset = 0; // let target = null; // let method = null; @@ -27,7 +27,7 @@ // let target_caller = null; // let params = []; // let flags = 0; - + // if (typeof args[1] === 'function') { // offset = -1; // target = GodotAnonymousConnectionManager; @@ -52,7 +52,7 @@ // if (typeof p === 'number') // flags = p; // } - + // if (typeof method === 'string' && method.length) { // method_name = method; // } else if (typeof method === 'function') { @@ -69,14 +69,14 @@ // } else { // throw new Error('method name or function expected for signal method'); // } - + // // console.log("connect", this, signal, target, method_name, params, flags); // return godot_object_connect.apply(this, [signal, target, method_name, params, flags]); // }, // writable: false, // configurable: true // }); - + // const godot_object_disconnect = godot.Object.prototype.disconnect; // Object.defineProperty(godot.Object.prototype, 'disconnect', { // // Object.prototype.disconnect(signal_name, target, method) @@ -84,12 +84,12 @@ // if (args.length < 2) throw new Error('2 or more arguments expected'); // let signal = args[0]; // if (typeof signal !== 'string' || !signal) throw new Error('signal name expected for argument #0'); - + // let target = null; // let method_name = null; // let method = null; // let slot_id = undefined; - + // if (typeof args[1] === 'function') { // target = GodotAnonymousConnectionManager; // method = args[1]; @@ -102,7 +102,7 @@ // } else { // throw new Error('method name or function expected'); // } - + // if (typeof method === 'string' && method) { // method_name = method; // } else if (typeof method === 'function') { @@ -112,7 +112,7 @@ // } else { // throw new Error('method name or function expected'); // } - + // if (slot_id) { // if (typeof target[method_name] !== 'undefined') { // target[method_name] = undefined; @@ -126,7 +126,7 @@ // writable: false, // configurable: true // }); - + // const godot_object_is_connected = godot.Object.prototype.is_connected; // Object.defineProperty(godot.Object.prototype, 'is_connected', { // // Object.prototype.is_connected(signal_name, target, method) @@ -134,12 +134,12 @@ // if (args.length < 3) throw new Error('3 arguments expected'); // let signal = args[0]; // if (typeof signal !== 'string' || !signal) throw new Error('signal name expected for argument #1'); - + // let target = null; // let method = null; // let method_name = null; // let slot_id = undefined; - + // if (typeof args[1] === 'function') { // target = GodotAnonymousConnectionManager; // method = args[1]; @@ -152,7 +152,7 @@ // } else { // throw new Error('method name or function expected for argument #2'); // } - + // if (typeof method === 'string') { // method_name = method; // } else if (typeof method === 'function') { @@ -161,13 +161,13 @@ // } else { // throw new Error('method name or function expected'); // } - + // return godot_object_is_connected.apply(this, [signal, target, method_name]); // }, // writable: false, // configurable: true // }); - + // function godot_yield(target, signal) { // return new Promise(function(resolve, reject) { // function callback(...args) { @@ -181,13 +181,232 @@ // target.connect(signal, GodotAnonymousConnectionManager, callback, [], godot.Object.CONNECT_ONESHOT); // }); // } - + // Object.defineProperty(godot, 'yield', { // value: godot_yield, // writable: false, // configurable: true // }); +// get_slot_id(emitter, signal, target) { +// return `__${emitter.get_instance_id()}:${signal}:${target.get_instance_id()}__`; +// } + +// const godot_node_get_node = godot.Node.prototype.get_node; +// Object.defineProperty(godot.Node.prototype, 'get_node', { +// value: function(arg) { +// if (typeof arg === 'string') { +// return godot_node_get_node.call(this, arg); +// } else if (typeof arg === 'function') { +// for (let n of this.get_children()) { +// if (n instanceof arg) { +// return n; +// } +// } +// } +// return null; +// }, +// writable: false, +// configurable: true +// }); + +// Object.defineProperty(godot.Node.prototype, '$', { +// value: godot.Node.prototype.get_node, +// writable: false, +// configurable: true +// }); + +// const godot_vector2 = godot.Vector2; +// Object.defineProperty(godot_vector2, "Axis", { +// value: { +// AXIS_X: 0, +// AXIS_Y: 1, +// }, +// writable: false, +// configurable: false, +// }); + +// const godot_vector3 = godot.Vector3; +// Object.defineProperty(godot_vector3, "Axis", { +// value: { +// AXIS_X: 0, +// AXIS_Y: 1, +// AXIS_Z: 2, +// }, +// writable: false, +// configurable: false, +// }); + +// // iterator of Pool*Vector +// const pool_classes = [ godot.PackedByteArray, godot.PackedInt32Array, godot.PackedFloat32Array, godot.PackedStringArray, godot.PackedVector2Array, godot.PackedVector3Array, godot.PackedColorArray ]; +// for (const pool_class of pool_classes) { +// Object.defineProperty(pool_class.prototype, Symbol.iterator, {value: function iterator() { +// let next_index = 0; +// return { +// next: ()=> { +// if (next_index < this.size()) { +// return { value: this.get(next_index++), done: false } +// } else { +// return { done: true }; +// } +// }, +// }; +// }}); +// } + +// return godot.TOOLS_ENABLED ? { +// "removed": { +// "Rect2": ["end", "grow_margin"], +// "Color": ["h", "s", "v", "r8", "g8", "b8", "a8"], +// "Transform2D": ["xform", "xform_inv"], +// "Basis": ["is_equal_approx"], +// "Plane": ["intersects_segment", "intersects_ray", "intersect_3"], +// "AABB": ["end"], +// "Transform": ["xform", "xform_inv"], +// }, +// "added": { +// "Object": [ +// "/** Connect the `method` of `target` to the `signal`*/", +// "//@ts-ignore", +// "connect(signal: string, target: Object, method: Function, binds: any[] = [], flags: number = 0) : number;", +// "", +// "/** Connect the `method` to the `signal`. The caller of the method will be `null` */", +// "//@ts-ignore", +// "connect(signal: string, method: Function, binds: any[] = [], flags: number = 0) : number;", +// "", +// "/** Returns `true` if a connection exists for a given `signal`, `target`, and `method`. */", +// "is_connected(signal: string, target: Object, method: Function) : boolean;", +// "/** Returns `true` if a connection exists for a given `signal` and `method`. */", +// "is_connected(signal: string, method: Function) : boolean;", +// "", +// "/** Disconnects a `signal` from the `method` on the given `target`. */", +// "disconnect(signal: string, target: Object, method: Function) : void;", +// "/** Disconnects a `signal` from the `method` */", +// "disconnect(signal: string, method: Function) : void;" +// ], +// "Node": [ +// "/** Get first node with the class `cls` */", +// "get_node(cls: new()=>T): T;", +// "", +// "/** Get node with the path */", +// "$(path: string): godot.Node;", +// "/** Get first node with the class `cls` */", +// "$(cls: new()=>T): T;", +// ] +// }, +// } : undefined; +// })(); + +// const godot_object_disconnect = godot.Object.prototype.disconnect; +// Object.defineProperty(godot.Object.prototype, 'disconnect', { +// // Object.prototype.disconnect(signal_name, target, method) +// value: function disconnect(...args) { +// if (args.length < 2) throw new Error('2 or more arguments expected'); +// let signal = args[0]; +// if (typeof signal !== 'string' || !signal) throw new Error('signal name expected for argument #0'); + +// let target = null; +// let method_name = null; +// let method = null; +// let slot_id = undefined; + +// if (typeof args[1] === 'function') { +// target = GodotAnonymousConnectionManager; +// method = args[1]; +// } else if (args.length >= 3) { +// target = args[1] || GodotAnonymousConnectionManager; +// if (!(target instanceof godot.Object)) { +// new Error('godot.Object expected for signal target'); +// } +// method = args[2]; +// } else { +// throw new Error('method name or function expected'); +// } + +// if (typeof method === 'string' && method) { +// method_name = method; +// } else if (typeof method === 'function') { +// slot_id = GodotAnonymousConnectionManager.get_slot_id(this, signal, target); +// method_name = method[slot_id]; +// method[slot_id] = undefined; +// } else { +// throw new Error('method name or function expected'); +// } + +// if (slot_id) { +// if (typeof target[method_name] !== 'undefined') { +// target[method_name] = undefined; +// delete target[method_name]; +// } +// delete method[slot_id]; +// } +// // console.log("disconnect", this, signal, target, method_name); +// godot_object_disconnect.apply(this, [signal, target, method_name]); +// }, +// writable: false, +// configurable: true +// }); + +// const godot_object_is_connected = godot.Object.prototype.is_connected; +// Object.defineProperty(godot.Object.prototype, 'is_connected', { +// // Object.prototype.is_connected(signal_name, target, method) +// value: function godot_is_connected_override(...args) { +// if (args.length < 3) throw new Error('3 arguments expected'); +// let signal = args[0]; +// if (typeof signal !== 'string' || !signal) throw new Error('signal name expected for argument #1'); + +// let target = null; +// let method = null; +// let method_name = null; +// let slot_id = undefined; + +// if (typeof args[1] === 'function') { +// target = GodotAnonymousConnectionManager; +// method = args[1]; +// } else if (args.length >= 3) { +// target = args[1] || GodotAnonymousConnectionManager; +// if (!(target instanceof godot.Object)) { +// new Error('godot.Object expected for signal target'); +// } +// method = args[2]; +// } else { +// throw new Error('method name or function expected for argument #2'); +// } + +// if (typeof method === 'string') { +// method_name = method; +// } else if (typeof method === 'function') { +// slot_id = GodotAnonymousConnectionManager.get_slot_id(this, signal, target); +// method_name = method[slot_id]; +// } else { +// throw new Error('method name or function expected'); +// } + +// return godot_object_is_connected.apply(this, [signal, target, method_name]); +// }, +// writable: false, +// configurable: true +// }); + +// function godot_yield(target, signal) { +// return new Promise(function(resolve, reject) { +// function callback(...args) { +// const slot_id = GodotAnonymousConnectionManager.get_slot_id(target, signal, GodotAnonymousConnectionManager); +// const method_name = callback[slot_id]; +// GodotAnonymousConnectionManager[method_name] = undefined; +// delete GodotAnonymousConnectionManager[method_name]; +// delete callback[slot_id]; +// resolve(args); +// }; +// target.connect(signal, GodotAnonymousConnectionManager, callback, [], godot.Object.CONNECT_ONESHOT); +// }); +// } + +// Object.defineProperty(godot, 'yield', { +// value: godot_yield, +// writable: false, +// configurable: true +// }); // const godot_node_get_node = godot.Node.prototype.get_node; // Object.defineProperty(godot.Node.prototype, 'get_node', { diff --git a/misc/decorators.ts b/misc/decorators.ts index 6fb9ce7d..dc2bc9ff 100644 --- a/misc/decorators.ts +++ b/misc/decorators.ts @@ -1,6 +1,6 @@ /** * Expose as a godot class. - * An class object is created and attached automaticly when construct an instance from this class + * An class object is created and attached automatically when construct an instance from this class */ export function gdclass(target: new() => T) { const id = gdclass['internal_class_id'] = gdclass['internal_class_id'] ? gdclass['internal_class_id'] + 1 : 1; @@ -68,7 +68,7 @@ export function onready(path: string | (new()=>godot.Node) } /** - * Register the member as a node property + * Register the member as a node property * **Note: The value is null before current node is ready** * @param path The default path name of the node */ diff --git a/misc/godot.d.ts b/misc/godot.d.ts index 68d64b50..e4d3f8a2 100644 --- a/misc/godot.d.ts +++ b/misc/godot.d.ts @@ -18,7 +18,7 @@ declare module globalThis { * @param request_id The ID value returned by the call to `godot.requestAnimationFrame()` that requested the callback. */ function cancelAnimationFrame(request_id: FrameRequetID): void; - + /** * The Console API provides functionality to allow developers to perform debugging tasks, such as logging messages or the values of variables at set points in your code, or timing how long an operation takes to complete. */ @@ -29,19 +29,19 @@ declare module globalThis { * @param message A list of JavaScript objects to output. The string representations of each of these objects are appended together in the order listed and output. */ log(...message): void; - + /** * Outputs a warning message to the console. * @param message list of JavaScript objects to output. The string representations of each of these objects are appended together in the order listed and output. */ warn(...message): void; - + /** * Outputs an error message to the console. * @param message A list of JavaScript objects to output. The string representations of each of these objects are appended together in the order listed and output. */ error(...message): void; - + /** Outputs a stack trace to the console. * @param message A list of JavaScript objects to output. The string representations of each of these objects are appended together in the order listed and output. */ @@ -55,9 +55,9 @@ declare module globalThis { * A worker is an object created using a constructor of `Worker` that runs a named JavaScript file — this file contains the code that will run in the worker thread; * * Workers run in another global context that is different from the current context. - * + * * You can run whatever code you like inside the worker thread. All of the godot API are avaliable inside workers. - * + * * Data is sent between workers and the main thread via a system of messages — both sides send their messages using the `postMessage()` method, and respond to messages via the `onmessage` event handler (the message is contained within the Message event's data attribute.) The data is copied rather than shared. * * You can **transfer** value with `Worker.abandonValue` and `Worker.adoptValue`. After a value is abandoned you cannot using it anymore in the context. @@ -66,67 +66,67 @@ declare module globalThis { */ //@ts-ignore class Worker { - + /** * Creates a dedicated worker thread that executes the script at the specified file */ constructor(script: string); - + /** * The `onmessage` property of the Worker interface represents an event handler, that is a function to be called when the message event occurs. * It will be called when the worker's parent receives a message from the worker context by `postMessage` method. */ onmessage(message: any): void; - + /** * Sends a message to the worker's inner scope. This accepts a single parameter, which is the data to send to the worker. * @param message The object to deliver to the worker; this will be in the data field in the event delivered to the `onmessage` handler. - * @note The data cannot be instance of `godot.Object` or any other JavaScript object conains functions. + * @note The data cannot be instance of `godot.Object` or any other JavaScript object contains functions. */ postMessage(message: any): void; - + /** * Stop the worker thread */ terminate(): void; } - + /** **Worker context only** - * + * * Stop the worker thread of current context */ function close(): void; - + /** **Worker context only** - * + * * The message handler to handle messages send from the host context */ //@ts-ignore function onmessage(message: any): void; - + /** **Worker context only** - * + * * Sends a message to the host thread context that spawned it. * * @param {*} message The message to send */ function postMessage(message: any): void; - + /** **Worker context only** - * + * * Synchronously load and run one or more scripts in the worker thread. */ function importScripts(...scripts: string[]): void; - + /** **Worker context only** - * + * * The flag is `true` if current context is inside a worker thread. */ const INSIDE_WORKER: true | undefined; } declare module godot { - + type GodotClass = new() => godot.Object; interface PropertyInfo { @@ -140,7 +140,7 @@ declare module godot { /** Default value of the property */ default?: any; } - + /** * Export class to godot * @@ -163,77 +163,77 @@ declare module godot { * @param value The default value of the property */ function register_property(target: GodotClass | godot.Object, name: string, value: any); - + /** * The meta data of an script * @param target The script class * @param tool is tooled of this class */ function set_script_tooled(target: GodotClass, tool: boolean); - + /** * The meta data of an script * @param target The script class * @param icon The icon of the class */ function set_script_icon(target: GodotClass, icon: string); - + /** * Returns the internal type of the given `Variant` object, using the `godot.TYPE_*` */ function get_type(val: any): number; - + /** * Loads a resource from the filesystem located at `path`. - * + * * **Note:** Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing **Copy Path**. * ``` * // Load a scene called main located in the root of the project directory * const main = godot.load("res://main.tscn") * ```*/ function load(path: string): Resource; - + /** - * Returns the Object that corresponds to `instance_id`. All Objects have a unique instance ID. + * Returns the Object that corresponds to `instance_id`. All Objects have a unique instance ID. */ function instance_from_id(instance_id: number): Object; /** * Drop the `value` in the context. You should never touching an abandoned value anymore before it is adopted. - * + * * You can adopt the value in another thread context to transfer the `value` in threads. - * + * * A `non zero` ID is return if no error happen. * @param value The value to abandon in the context * @note You can only transfer values the godot `Variant` can represent. * @returns The ID of the abandoned value */ function abandon_value(value: any): number; - + /** * Adopt an abandoned value. * @param value_id The ID of the abandoned value */ function adopt_value(value_id: number): any; - + /** * Wait a signal of an object * @param target The owner of the signal to wait * @param signal The signal to wait */ function yield(target: godot.Object, signal: string): Promise; - + const E: 2.7182818284590452353602874714; const LN2: 0.6931471805599453094172321215; const SQRT2: 1.4142135623730950488016887242; const SQRT12: 0.7071067811865475244008443621048490; - + /** The flag is `true` if current binary is compiled with `target=debug` or `target=release_debug` */ const DEBUG_ENABLED: boolean; - + /** The flag is `true` if current binary is godot editor which is compiled with `tool=yes` */ const TOOLS_ENABLED: boolean; - + /** The flag is `true` if current binary enable debug method information */ const DEBUG_METHODS_ENABLED: boolean; } @@ -372,36 +372,36 @@ declare module godot { /** Enumerated value for the Y axis. */ const AXIS_Y: Axis.AXIS_Y; - /** Zero vector. + /** Zero vector. * @value `Vector2( 0, 0 )` */ const ZERO: Readonly; - /** One vector. + /** One vector. * @value `Vector2( 1, 1 )` */ const ONE: Readonly; - /** Infinity vector. + /** Infinity vector. * @value `Vector2( inf, inf )` */ const INF: Readonly; - /** Left unit vector. + /** Left unit vector. * @value `Vector2( -1, 0 )` */ const LEFT: Readonly; - /** Right unit vector. + /** Right unit vector. * @value `Vector2( 1, 0 )` */ const RIGHT: Readonly; - /** Up unit vector. + /** Up unit vector. * @value `Vector2( 0, -1 )` */ const UP: Readonly; - /** Down unit vector. + /** Down unit vector. * @value `Vector2( 0, 1 )` */ const DOWN: Readonly; } - + /** 2D axis-aligned bounding box. Rect2 consists of a position, a size, and several utility functions. It is typically used for fast overlap tests. */ class Rect2 { @@ -414,7 +414,7 @@ declare module godot { /** Size from position to end. */ size: Vector2; - + /** Ending corner. */ end: Vector2; @@ -589,43 +589,43 @@ declare module godot { const AXIS_Y: Axis.AXIS_Y; const AXIS_Z: Axis.AXIS_Z; - /** Zero vector. + /** Zero vector. * @value `Vector3( 0, 0, 0 )` */ const ZERO: Readonly; - /** One vector. + /** One vector. * @value `Vector3( 1, 1, 1 )` */ const ONE: Readonly; - /** Infinity vector. + /** Infinity vector. * @value `Vector3( inf, inf, inf )` */ const INF: Readonly; - /** Left unit vector. + /** Left unit vector. * @value `Vector3( -1, 0, 0 )` */ const LEFT: Readonly; - /** Right unit vector. + /** Right unit vector. * @value `Vector3( 1, 0, 0 )` */ const RIGHT: Readonly; - /** Up unit vector. + /** Up unit vector. * @value `Vector3( 0, 1, 0 )` */ const UP: Readonly; - /** Down unit vector. + /** Down unit vector. * @value `Vector3( 0, -1, 0 )` */ const DOWN: Readonly; - /** Forward unit vector. + /** Forward unit vector. * @value `Vector3( 0, 0, -1 )` */ const FORWARD: Readonly; - /** Back unit vector. + /** Back unit vector. * @value `Vector3( 0, 0, 1 )` */ const BACK: Readonly; } - + /** 3×3 matrix datatype. 3×3 matrix used for 3D rotation and scale. Contains 3 vector fields X, Y and Z as its columns, which can be interpreted as the local basis vectors of a transformation. Can also be accessed as array of 3D vectors. These vectors are orthogonal to each other, but are not necessarily normalized (due to scaling). Almost always used as an orthogonal basis for a `Transform`. @@ -717,7 +717,7 @@ declare module godot { /** @value `Basis( 1, 0, 0, 0, 1, 0, 0, 0, -1 )` */ const FLIP_Z: Readonly; } - + /** 3D transformation (3×4 matrix). Represents one or many transformations in 3D space such as translation, rotation, or scaling. It consists of a `basis` and an `origin`. It is similar to a 3×4 matrix. */ class Transform { @@ -774,19 +774,19 @@ declare module godot { } namespace Transform { - /** `Transform` with no translation, rotation or scaling applied. When applied to other data structures, `IDENTITY` performs no transformation. + /** `Transform` with no translation, rotation or scaling applied. When applied to other data structures, `IDENTITY` performs no transformation. * @value `Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )` */ const IDENTITY: Readonly; - /** `Transform` with mirroring applied perpendicular to the YZ plane. + /** `Transform` with mirroring applied perpendicular to the YZ plane. * @value `Transform( -1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )` */ const FLIP_X: Readonly; - /** `Transform` with mirroring applied perpendicular to the XZ plane. + /** `Transform` with mirroring applied perpendicular to the XZ plane. * @value `Transform( 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0 )` */ const FLIP_Y: Readonly; - /** `Transform` with mirroring applied perpendicular to the XY plane. + /** `Transform` with mirroring applied perpendicular to the XY plane. * @value `Transform( 1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0 )` */ const FLIP_Z: Readonly; } @@ -858,19 +858,19 @@ declare module godot { } namespace Transform2D { - /** `Transform2D` with no translation, rotation or scaling applied. When applied to other data structures, `IDENTITY` performs no transformation. + /** `Transform2D` with no translation, rotation or scaling applied. When applied to other data structures, `IDENTITY` performs no transformation. * @value `Transform2D( 1, 0, 0, 1, 0, 0 )` */ const IDENTITY: Readonly; - /** `Transform2D` with mirroring applied parallel to the X axis. + /** `Transform2D` with mirroring applied parallel to the X axis. * @value `Transform2D( -1, 0, 0, 1, 0, 0 )` */ const FLIP_X: Readonly; - /** `Transform2D` with mirroring applied parallel to the Y axis. + /** `Transform2D` with mirroring applied parallel to the Y axis. * @value `Transform2D( 1, 0, 0, -1, 0, 0 )` */ const FLIP_Y: Readonly; } - + /** Color in RGBA format with some support for ARGB format. A color is represented by red, green, and blue `(r, g, b)` components. Additionally, `a` represents the alpha component, often used for transparency. Values are in floating-point and usually range from 0 to 1. Some properties (such as `CanvasItem.modulate`) may accept values greater than 1. @@ -917,7 +917,7 @@ declare module godot { /** Returns a new color resulting from blending this color over another. If the color is opaque, the result is also opaque. The second color may have a range of alpha values. - + var bg = Color(0.0, 1.0, 0.0, 0.5) # Green with alpha of 50% var fg = Color(1.0, 0.0, 0.0, 0.5) # Red with alpha of 50% @@ -927,7 +927,7 @@ declare module godot { /** Returns the most contrasting color. - + var c = Color(0.3, 0.4, 0.9) var contrasted_color = c.contrasted() # Equivalent to RGBA(204, 229, 102, 255) @@ -936,7 +936,7 @@ declare module godot { /** Returns a new color resulting from making this color darker by the specified percentage (ratio from 0 to 1). - + var green = Color(0.0, 1.0, 0.0) var darkgreen = green.darkened(0.2) # 20% darker than regular green @@ -945,7 +945,7 @@ declare module godot { /** Constructs a color from an HSV profile. `h`, `s`, and `v` are values between 0 and 1. - + var c = Color.from_hsv(0.58, 0.5, 0.79, 0.8) # Equivalent to HSV(210, 50, 79, 0.8) or Color8(100, 151, 201, 0.8) */ @@ -955,7 +955,7 @@ declare module godot { The gray value is calculated as `(r + g + b) / 3`. - + var c = Color(0.2, 0.45, 0.82) var gray = c.gray() # A value of 0.466667 @@ -964,7 +964,7 @@ declare module godot { /** Returns the inverted color `(1 - r, 1 - g, 1 - b, a)`. - + var c = Color(0.3, 0.4, 0.9) var inverted_color = c.inverted() # A color of an RGBA(178, 153, 26, 255) @@ -976,7 +976,7 @@ declare module godot { /** Returns a new color resulting from making this color lighter by the specified percentage (ratio from 0 to 1). - + var green = Color(0.0, 1.0, 0.0) var lightgreen = green.lightened(0.2) # 20% lighter than regular green @@ -985,7 +985,7 @@ declare module godot { /** Returns the linear interpolation with another color. The interpolation factor `t` is between 0 and 1. - + var c1 = Color(1.0, 0.0, 0.0) var c2 = Color(0.0, 1.0, 0.0) @@ -995,7 +995,7 @@ declare module godot { /** Returns the color's 32-bit integer in ABGR format (each byte represents a component of the ABGR profile). ABGR is the reversed version of the default format. - + var c = Color(1, 0.5, 0.2) print(c.to_abgr32()) # Prints 4281565439 @@ -1004,7 +1004,7 @@ declare module godot { /** Returns the color's 64-bit integer in ABGR format (each word represents a component of the ABGR profile). ABGR is the reversed version of the default format. - + var c = Color(1, 0.5, 0.2) print(c.to_abgr64()) # Prints -225178692812801 @@ -1013,7 +1013,7 @@ declare module godot { /** Returns the color's 32-bit integer in ARGB format (each byte represents a component of the ARGB profile). ARGB is more compatible with DirectX. - + var c = Color(1, 0.5, 0.2) print(c.to_argb32()) # Prints 4294934323 @@ -1022,7 +1022,7 @@ declare module godot { /** Returns the color's 64-bit integer in ARGB format (each word represents a component of the ARGB profile). ARGB is more compatible with DirectX. - + var c = Color(1, 0.5, 0.2) print(c.to_argb64()) # Prints -2147470541 @@ -1033,7 +1033,7 @@ declare module godot { Setting `with_alpha` to `false` excludes alpha from the hexadecimal string. - + var c = Color(1, 1, 1, 0.5) var s1 = c.to_html() # Returns "7fffffff" @@ -1043,7 +1043,7 @@ declare module godot { /** Returns the color's 32-bit integer in RGBA format (each byte represents a component of the RGBA profile). RGBA is Godot's default format. - + var c = Color(1, 0.5, 0.2) print(c.to_rgba32()) # Prints 4286526463 @@ -1052,7 +1052,7 @@ declare module godot { /** Returns the color's 64-bit integer in RGBA format (each word represents a component of the RGBA profile). RGBA is Godot's default format. - + var c = Color(1, 0.5, 0.2) print(c.to_rgba64()) # Prints -140736629309441 @@ -1062,598 +1062,598 @@ declare module godot { } namespace Color { - /** + /** * @value `Color( 0.75, 0.75, 0.75, 1 )` */ const gray: Readonly - /** + /** * @value `Color( 0.94, 0.97, 1, 1 )` */ const aliceblue: Readonly - /** + /** * @value `Color( 0.98, 0.92, 0.84, 1 )` */ const antiquewhite: Readonly - /** + /** * @value `Color( 0, 1, 1, 1 )` */ const aqua: Readonly - /** + /** * @value `Color( 0.5, 1, 0.83, 1 )` */ const aquamarine: Readonly - /** + /** * @value `Color( 0.94, 1, 1, 1 )` */ const azure: Readonly - /** + /** * @value `Color( 0.96, 0.96, 0.86, 1 )` */ const beige: Readonly - /** + /** * @value `Color( 1, 0.89, 0.77, 1 )` */ const bisque: Readonly - /** + /** * @value `Color( 0, 0, 0, 1 )` */ const black: Readonly - /** + /** * @value `Color( 1, 0.92, 0.8, 1 )` */ const blanchedalmond: Readonly - /** + /** * @value `Color( 0, 0, 1, 1 )` */ const blue: Readonly - /** + /** * @value `Color( 0.54, 0.17, 0.89, 1 )` */ const blueviolet: Readonly - /** + /** * @value `Color( 0.65, 0.16, 0.16, 1 )` */ const brown: Readonly - /** + /** * @value `Color( 0.87, 0.72, 0.53, 1 )` */ const burlywood: Readonly - /** + /** * @value `Color( 0.37, 0.62, 0.63, 1 )` */ const cadetblue: Readonly - /** + /** * @value `Color( 0.5, 1, 0, 1 )` */ const chartreuse: Readonly - /** + /** * @value `Color( 0.82, 0.41, 0.12, 1 )` */ const chocolate: Readonly - /** + /** * @value `Color( 1, 0.5, 0.31, 1 )` */ const coral: Readonly - /** + /** * @value `Color( 0.39, 0.58, 0.93, 1 )` */ const cornflower: Readonly - /** + /** * @value `Color( 1, 0.97, 0.86, 1 )` */ const cornsilk: Readonly - /** + /** * @value `Color( 0.86, 0.08, 0.24, 1 )` */ const crimson: Readonly - /** + /** * @value `Color( 0, 1, 1, 1 )` */ const cyan: Readonly - /** + /** * @value `Color( 0, 0, 0.55, 1 )` */ const darkblue: Readonly - /** + /** * @value `Color( 0, 0.55, 0.55, 1 )` */ const darkcyan: Readonly - /** + /** * @value `Color( 0.72, 0.53, 0.04, 1 )` */ const darkgoldenrod: Readonly - /** + /** * @value `Color( 0.66, 0.66, 0.66, 1 )` */ const darkgray: Readonly - /** + /** * @value `Color( 0, 0.39, 0, 1 )` */ const darkgreen: Readonly - /** + /** * @value `Color( 0.74, 0.72, 0.42, 1 )` */ const darkkhaki: Readonly - /** + /** * @value `Color( 0.55, 0, 0.55, 1 )` */ const darkmagenta: Readonly - /** + /** * @value `Color( 0.33, 0.42, 0.18, 1 )` */ const darkolivegreen: Readonly - /** + /** * @value `Color( 1, 0.55, 0, 1 )` */ const darkorange: Readonly - /** + /** * @value `Color( 0.6, 0.2, 0.8, 1 )` */ const darkorchid: Readonly - /** + /** * @value `Color( 0.55, 0, 0, 1 )` */ const darkred: Readonly - /** + /** * @value `Color( 0.91, 0.59, 0.48, 1 )` */ const darksalmon: Readonly - /** + /** * @value `Color( 0.56, 0.74, 0.56, 1 )` */ const darkseagreen: Readonly - /** + /** * @value `Color( 0.28, 0.24, 0.55, 1 )` */ const darkslateblue: Readonly - /** + /** * @value `Color( 0.18, 0.31, 0.31, 1 )` */ const darkslategray: Readonly - /** + /** * @value `Color( 0, 0.81, 0.82, 1 )` */ const darkturquoise: Readonly - /** + /** * @value `Color( 0.58, 0, 0.83, 1 )` */ const darkviolet: Readonly - /** + /** * @value `Color( 1, 0.08, 0.58, 1 )` */ const deeppink: Readonly - /** + /** * @value `Color( 0, 0.75, 1, 1 )` */ const deepskyblue: Readonly - /** + /** * @value `Color( 0.41, 0.41, 0.41, 1 )` */ const dimgray: Readonly - /** + /** * @value `Color( 0.12, 0.56, 1, 1 )` */ const dodgerblue: Readonly - /** + /** * @value `Color( 0.7, 0.13, 0.13, 1 )` */ const firebrick: Readonly - /** + /** * @value `Color( 1, 0.98, 0.94, 1 )` */ const floralwhite: Readonly - /** + /** * @value `Color( 0.13, 0.55, 0.13, 1 )` */ const forestgreen: Readonly - /** + /** * @value `Color( 1, 0, 1, 1 )` */ const fuchsia: Readonly - /** + /** * @value `Color( 0.86, 0.86, 0.86, 1 )` */ const gainsboro: Readonly - /** + /** * @value `Color( 0.97, 0.97, 1, 1 )` */ const ghostwhite: Readonly - /** + /** * @value `Color( 1, 0.84, 0, 1 )` */ const gold: Readonly - /** + /** * @value `Color( 0.85, 0.65, 0.13, 1 )` */ const goldenrod: Readonly - /** + /** * @value `Color( 0, 1, 0, 1 )` */ const green: Readonly - /** + /** * @value `Color( 0.68, 1, 0.18, 1 )` */ const greenyellow: Readonly - /** + /** * @value `Color( 0.94, 1, 0.94, 1 )` */ const honeydew: Readonly - /** + /** * @value `Color( 1, 0.41, 0.71, 1 )` */ const hotpink: Readonly - /** + /** * @value `Color( 0.8, 0.36, 0.36, 1 )` */ const indianred: Readonly - /** + /** * @value `Color( 0.29, 0, 0.51, 1 )` */ const indigo: Readonly - /** + /** * @value `Color( 1, 1, 0.94, 1 )` */ const ivory: Readonly - /** + /** * @value `Color( 0.94, 0.9, 0.55, 1 )` */ const khaki: Readonly - /** + /** * @value `Color( 0.9, 0.9, 0.98, 1 )` */ const lavender: Readonly - /** + /** * @value `Color( 1, 0.94, 0.96, 1 )` */ const lavenderblush: Readonly - /** + /** * @value `Color( 0.49, 0.99, 0, 1 )` */ const lawngreen: Readonly - /** + /** * @value `Color( 1, 0.98, 0.8, 1 )` */ const lemonchiffon: Readonly - /** + /** * @value `Color( 0.68, 0.85, 0.9, 1 )` */ const lightblue: Readonly - /** + /** * @value `Color( 0.94, 0.5, 0.5, 1 )` */ const lightcoral: Readonly - /** + /** * @value `Color( 0.88, 1, 1, 1 )` */ const lightcyan: Readonly - /** + /** * @value `Color( 0.98, 0.98, 0.82, 1 )` */ const lightgoldenrod: Readonly - /** + /** * @value `Color( 0.83, 0.83, 0.83, 1 )` */ const lightgray: Readonly - /** + /** * @value `Color( 0.56, 0.93, 0.56, 1 )` */ const lightgreen: Readonly - /** + /** * @value `Color( 1, 0.71, 0.76, 1 )` */ const lightpink: Readonly - /** + /** * @value `Color( 1, 0.63, 0.48, 1 )` */ const lightsalmon: Readonly - /** + /** * @value `Color( 0.13, 0.7, 0.67, 1 )` */ const lightseagreen: Readonly - /** + /** * @value `Color( 0.53, 0.81, 0.98, 1 )` */ const lightskyblue: Readonly - /** + /** * @value `Color( 0.47, 0.53, 0.6, 1 )` */ const lightslategray: Readonly - /** + /** * @value `Color( 0.69, 0.77, 0.87, 1 )` */ const lightsteelblue: Readonly - /** + /** * @value `Color( 1, 1, 0.88, 1 )` */ const lightyellow: Readonly - /** + /** * @value `Color( 0, 1, 0, 1 )` */ const lime: Readonly - /** + /** * @value `Color( 0.2, 0.8, 0.2, 1 )` */ const limegreen: Readonly - /** + /** * @value `Color( 0.98, 0.94, 0.9, 1 )` */ const linen: Readonly - /** + /** * @value `Color( 1, 0, 1, 1 )` */ const magenta: Readonly - /** + /** * @value `Color( 0.69, 0.19, 0.38, 1 )` */ const maroon: Readonly - /** + /** * @value `Color( 0.4, 0.8, 0.67, 1 )` */ const mediumaquamarine: Readonly - /** + /** * @value `Color( 0, 0, 0.8, 1 )` */ const mediumblue: Readonly - /** + /** * @value `Color( 0.73, 0.33, 0.83, 1 )` */ const mediumorchid: Readonly - /** + /** * @value `Color( 0.58, 0.44, 0.86, 1 )` */ const mediumpurple: Readonly - /** + /** * @value `Color( 0.24, 0.7, 0.44, 1 )` */ const mediumseagreen: Readonly - /** + /** * @value `Color( 0.48, 0.41, 0.93, 1 )` */ const mediumslateblue: Readonly - /** + /** * @value `Color( 0, 0.98, 0.6, 1 )` */ const mediumspringgreen: Readonly - /** + /** * @value `Color( 0.28, 0.82, 0.8, 1 )` */ const mediumturquoise: Readonly - /** + /** * @value `Color( 0.78, 0.08, 0.52, 1 )` */ const mediumvioletred: Readonly - /** + /** * @value `Color( 0.1, 0.1, 0.44, 1 )` */ const midnightblue: Readonly - /** + /** * @value `Color( 0.96, 1, 0.98, 1 )` */ const mintcream: Readonly - /** + /** * @value `Color( 1, 0.89, 0.88, 1 )` */ const mistyrose: Readonly - /** + /** * @value `Color( 1, 0.89, 0.71, 1 )` */ const moccasin: Readonly - /** + /** * @value `Color( 1, 0.87, 0.68, 1 )` */ const navajowhite: Readonly - /** + /** * @value `Color( 0, 0, 0.5, 1 )` */ const navyblue: Readonly - /** + /** * @value `Color( 0.99, 0.96, 0.9, 1 )` */ const oldlace: Readonly - /** + /** * @value `Color( 0.5, 0.5, 0, 1 )` */ const olive: Readonly - /** + /** * @value `Color( 0.42, 0.56, 0.14, 1 )` */ const olivedrab: Readonly - /** + /** * @value `Color( 1, 0.65, 0, 1 )` */ const orange: Readonly - /** + /** * @value `Color( 1, 0.27, 0, 1 )` */ const orangered: Readonly - /** + /** * @value `Color( 0.85, 0.44, 0.84, 1 )` */ const orchid: Readonly - /** + /** * @value `Color( 0.93, 0.91, 0.67, 1 )` */ const palegoldenrod: Readonly - /** + /** * @value `Color( 0.6, 0.98, 0.6, 1 )` */ const palegreen: Readonly - /** + /** * @value `Color( 0.69, 0.93, 0.93, 1 )` */ const paleturquoise: Readonly - /** + /** * @value `Color( 0.86, 0.44, 0.58, 1 )` */ const palevioletred: Readonly - /** + /** * @value `Color( 1, 0.94, 0.84, 1 )` */ const papayawhip: Readonly - /** + /** * @value `Color( 1, 0.85, 0.73, 1 )` */ const peachpuff: Readonly - /** + /** * @value `Color( 0.8, 0.52, 0.25, 1 )` */ const peru: Readonly - /** + /** * @value `Color( 1, 0.75, 0.8, 1 )` */ const pink: Readonly - /** + /** * @value `Color( 0.87, 0.63, 0.87, 1 )` */ const plum: Readonly - /** + /** * @value `Color( 0.69, 0.88, 0.9, 1 )` */ const powderblue: Readonly - /** + /** * @value `Color( 0.63, 0.13, 0.94, 1 )` */ const purple: Readonly - /** + /** * @value `Color( 0.4, 0.2, 0.6, 1 )` */ const rebeccapurple: Readonly - /** + /** * @value `Color( 1, 0, 0, 1 )` */ const red: Readonly - /** + /** * @value `Color( 0.74, 0.56, 0.56, 1 )` */ const rosybrown: Readonly - /** + /** * @value `Color( 0.25, 0.41, 0.88, 1 )` */ const royalblue: Readonly - /** + /** * @value `Color( 0.55, 0.27, 0.07, 1 )` */ const saddlebrown: Readonly - /** + /** * @value `Color( 0.98, 0.5, 0.45, 1 )` */ const salmon: Readonly - /** + /** * @value `Color( 0.96, 0.64, 0.38, 1 )` */ const sandybrown: Readonly - /** + /** * @value `Color( 0.18, 0.55, 0.34, 1 )` */ const seagreen: Readonly - /** + /** * @value `Color( 1, 0.96, 0.93, 1 )` */ const seashell: Readonly - /** + /** * @value `Color( 0.63, 0.32, 0.18, 1 )` */ const sienna: Readonly - /** + /** * @value `Color( 0.75, 0.75, 0.75, 1 )` */ const silver: Readonly - /** + /** * @value `Color( 0.53, 0.81, 0.92, 1 )` */ const skyblue: Readonly - /** + /** * @value `Color( 0.42, 0.35, 0.8, 1 )` */ const slateblue: Readonly - /** + /** * @value `Color( 0.44, 0.5, 0.56, 1 )` */ const slategray: Readonly - /** + /** * @value `Color( 1, 0.98, 0.98, 1 )` */ const snow: Readonly - /** + /** * @value `Color( 0, 1, 0.5, 1 )` */ const springgreen: Readonly - /** + /** * @value `Color( 0.27, 0.51, 0.71, 1 )` */ const steelblue: Readonly - /** + /** * @value `Color( 0.82, 0.71, 0.55, 1 )` */ const tan: Readonly - /** + /** * @value `Color( 0, 0.5, 0.5, 1 )` */ const teal: Readonly - /** + /** * @value `Color( 0.85, 0.75, 0.85, 1 )` */ const thistle: Readonly - /** + /** * @value `Color( 1, 0.39, 0.28, 1 )` */ const tomato: Readonly - /** + /** * @value `Color( 1, 1, 1, 0 )` */ const transparent: Readonly - /** + /** * @value `Color( 0.25, 0.88, 0.82, 1 )` */ const turquoise: Readonly - /** + /** * @value `Color( 0.93, 0.51, 0.93, 1 )` */ const violet: Readonly - /** + /** * @value `Color( 0.5, 0.5, 0.5, 1 )` */ const webgray: Readonly - /** + /** * @value `Color( 0, 0.5, 0, 1 )` */ const webgreen: Readonly - /** + /** * @value `Color( 0.5, 0, 0, 1 )` */ const webmaroon: Readonly - /** + /** * @value `Color( 0.5, 0, 0.5, 1 )` */ const webpurple: Readonly - /** + /** * @value `Color( 0.96, 0.87, 0.7, 1 )` */ const wheat: Readonly - /** + /** * @value `Color( 1, 1, 1, 1 )` */ const white: Readonly - /** + /** * @value `Color( 0.96, 0.96, 0.96, 1 )` */ const whitesmoke: Readonly - /** + /** * @value `Color( 1, 1, 0, 1 )` */ const yellow: Readonly - /** + /** * @value `Color( 0.6, 0.8, 0.2, 1 )` */ const yellowgreen: Readonly } - + /** Handle for a `Resource`'s unique ID. The RID type is used to access the unique integer ID of a resource. They are opaque, which means they do not grant access to the associated resource by themselves. They are used by and with the low-level Server classes such as `VisualServer`. */ class RID { /** Returns the ID of the referenced resource. */ get_id() : number; } - + /** Plane in hessian form. Plane represents a normalized plane equation. Basically, "normal" is the normal of the plane (a,b,c normalized), and "d" is the distance from the origin to the plane (in the direction of "normal"). "Over" or "Above" the plane is considered the side of the plane towards where the normal is pointing. */ class Plane { @@ -1724,7 +1724,7 @@ declare module godot { /** @value `Plane( 0, 0, 1, 0 )` */ const PLANE_XY: Plane; } - + /** Quaternion. A unit quaternion used for representing 3D rotations. @@ -1799,7 +1799,7 @@ declare module godot { /** @value `Quaternion( 0, 0, 0, 1 )` */ const IDENTITY: Readonly; } - + /** Axis-Aligned Bounding Box. AABB consists of a position, a size, and several utility functions. It is typically used for fast overlap tests. */ class AABB { @@ -1880,20 +1880,20 @@ declare module godot { merge(p_with: AABB) : AABB; } - - + + /** A pooled `Array` of bytes. An `Array` specifically designed to hold bytes. Optimized for memory usage, does not fragment the memory. **Note:** This type is passed by value and not by reference. */ class PackedByteArray { - + constructor(source?: number[]); constructor(from: PackedByteArray); constructor(from: ArrayBuffer); constructor(from: DataView); [Symbol.iterator](): IterableIterator; - + /** Appends an element at the end of the array (alias of `push_back`). */ append(byte: number) : void; @@ -1935,7 +1935,7 @@ declare module godot { /** Changes the byte at the given index. */ set(idx: number, byte: number) : void; - + /** Get the `byte` at the given index */ get(idx: number): number; @@ -1944,7 +1944,7 @@ declare module godot { /** Returns the slice of the `PackedByteArray` between indices (inclusive) as a new `PackedByteArray`. Any negative index is considered to be from the end of the array. */ subarray(p_from: number, to: number) : PackedByteArray; - + /** Returns the content of the array as an `ArrayBuffer` */ get_buffer() : ArrayBuffer; } @@ -1988,7 +1988,7 @@ declare module godot { /** Changes the `Color` at the given index. */ set(idx: number, color: Color) : void; - + /** Get the `Color` at the given index */ get(idx: number): Color; @@ -2040,7 +2040,7 @@ declare module godot { /** Changes the int at the given index. */ set(idx: number, integer: number) : void; - + /** Get the `int` at the given index */ get(idx: number): number; @@ -2089,7 +2089,7 @@ declare module godot { /** Changes the float at the given index. */ set(idx: number, value: number) : void; - + /** Get the `number` at the given index */ get(idx: number): number; @@ -2140,7 +2140,7 @@ declare module godot { /** Changes the `String` at the given index. */ set(idx: number, p_string: string) : void; - + /** Get the `string` at the given index */ get(idx: number): string; @@ -2186,13 +2186,13 @@ declare module godot { /** Changes the `Vector2` at the given index. */ set(idx: number, vector2: Vector2) : void; - + /** Get the `Vector2` at the given index */ get(idx: number): Vector2; /** Returns the size of the array. */ size() : number; - + /** Returns the content of the array as an `ArrayBuffer` */ get_buffer() : ArrayBuffer; } @@ -2235,13 +2235,13 @@ declare module godot { /** Changes the `Vector3` at the given index. */ set(idx: number, vector3: Vector3) : void; - + /** Get the `Vector3` at the given index */ get(idx: number): Vector3; /** Returns the size of the array. */ size() : number; - + /** Returns the content of the array as an `ArrayBuffer` */ get_buffer() : ArrayBuffer; } diff --git a/misc/scripts/black_format.sh b/misc/scripts/black_format.sh new file mode 100755 index 00000000..3a64284e --- /dev/null +++ b/misc/scripts/black_format.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# This script runs black on all Python files in the repo. + +set -uo pipefail + +# Apply black. +echo -e "Formatting Python files..." +PY_FILES=$(git ls-files -- '*SConstruct' '*SCsub' '*.py' ':!:.git/*' ':!:thirdparty/*') +black -l 120 $PY_FILES + +diff=$(git diff --color) + +# If no diff has been generated all is OK, clean up, and exit. +if [ -z "$diff" ] ; then + printf "\e[1;32m*** Files in this commit comply with the black style rules.\e[0m\n" + exit 0 +fi + +# A diff has been created, notify the user, clean up, and exit. +printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" +# Perl commands replace trailing spaces with `·` and tabs with ``. +printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="" x length($2); sprintf("$1$tabs$3")/ge' + +printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\e[0m\n" +exit 1 diff --git a/misc/scripts/check_ci_log.py b/misc/scripts/check_ci_log.py new file mode 100644 index 00000000..1e5a12ee --- /dev/null +++ b/misc/scripts/check_ci_log.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys + +if len(sys.argv) < 2: + print("ERROR: You must run program with file name as argument.") + sys.exit(50) + +fname = sys.argv[1] + +fileread = open(fname.strip(), "r") +file_contents = fileread.read() + +# If find "ERROR: AddressSanitizer:", then happens invalid read or write +# This is critical bug, so we need to fix this as fast as possible + +if file_contents.find("ERROR: AddressSanitizer:") != -1: + print("FATAL ERROR: An incorrectly used memory was found.") + sys.exit(51) + +# There is also possible, that program crashed with or without backtrace. + +if ( + file_contents.find("Program crashed with signal") != -1 + or file_contents.find("Dumping the backtrace") != -1 + or file_contents.find("Segmentation fault (core dumped)") != -1 + or file_contents.find("Aborted (core dumped)") != -1 + or file_contents.find("terminate called without an active exception") != -1 +): + print("FATAL ERROR: Godot has been crashed.") + sys.exit(52) + +# Finding memory leaks in Godot is quite difficult, because we need to take into +# account leaks also in external libraries. They are usually provided without +# debugging symbols, so the leak report from it usually has only 2/3 lines, +# so searching for 5 element - "#4 0x" - should correctly detect the vast +# majority of memory leaks + +if file_contents.find("ERROR: LeakSanitizer:") != -1: + if file_contents.find("#4 0x") != -1: + print("ERROR: Memory leak was found") + sys.exit(53) + +# It may happen that Godot detects leaking nodes/resources and removes them, so +# this possibility should also be handled as a potential error, even if +# LeakSanitizer doesn't report anything + +if file_contents.find("ObjectDB instances leaked at exit") != -1: + print("ERROR: Memory leak was found") + sys.exit(54) + +# In test project may be put several assert functions which will control if +# project is executed with right parameters etc. which normally will not stop +# execution of project + +if file_contents.find("Assertion failed") != -1: + print("ERROR: Assertion failed in project, check execution log for more info") + sys.exit(55) + +# For now Godot leaks a lot of rendering stuff so for now we just show info +# about it and this needs to be re-enabled after fixing this memory leaks. + +if file_contents.find("were leaked") != -1 or file_contents.find("were never freed") != -1: + print("WARNING: Memory leak was found") + +sys.exit(0) diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh new file mode 100644 index 00000000..74a8e1a8 --- /dev/null +++ b/misc/scripts/clang_format.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# This script runs clang-format and fixes copyright headers on all relevant files in the repo. +# This is the primary script responsible for fixing style violations. + +set -uo pipefail + +if [ $# -eq 0 ]; then + # Loop through all code files tracked by Git. + files=$(git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \ + ':!:.git/*' ':!:thirdparty/*' ':!:*/thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' \ + ':!:*-so_wrap.*' ':!:tests/python_build/*') +else + # $1 should be a file listing file paths to process. Used in CI. + files=$(cat "$1" | grep -v "thirdparty/" | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$" | grep -v "platform/android/java/lib/src/com/google/" | grep -v "\-so_wrap\." | grep -v "tests/python_build/") +fi + +if [ ! -z "$files" ]; then + clang-format --Wno-error=unknown -i $files +fi + +# Fix copyright headers, but not all files get them. +for f in $files; do + if [[ "$f" == *"inc" ]]; then + continue + elif [[ "$f" == *"glsl" ]]; then + continue + elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView"* ]]; then + continue + elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper"* ]]; then + continue + elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix"* ]]; then + continue + fi + + python misc/scripts/copyright_headers.py "$f" +done + +diff=$(git diff --color) + +# If no diff has been generated all is OK, clean up, and exit. +if [ -z "$diff" ] ; then + printf "\e[1;32m*** Files in this commit comply with the clang-format style rules.\e[0m\n" + exit 0 +fi + +# A diff has been created, notify the user, clean up, and exit. +printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" +# Perl commands replace trailing spaces with `·` and tabs with ``. +printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="" x length($2); sprintf("$1$tabs$3")/ge' + +printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\e[0m\n" +exit 1 diff --git a/misc/scripts/clang_tidy.sh b/misc/scripts/clang_tidy.sh new file mode 100644 index 00000000..c4811b90 --- /dev/null +++ b/misc/scripts/clang_tidy.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# This script runs clang-tidy on all relevant files in the repo. +# This is more thorough than clang-format and thus slower; it should only be run manually. + +set -uo pipefail + +# Loops through all code files tracked by Git. +git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \ + ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' | +while read -r f; do + # Run clang-tidy. + clang-tidy --quiet --fix "$f" &> /dev/null + + # Run clang-format. This also fixes the output of clang-tidy. + clang-format --Wno-error=unknown -i "$f" +done + +diff=$(git diff --color) + +# If no diff has been generated all is OK, clean up, and exit. +if [ -z "$diff" ] ; then + printf "\e[1;32m*** Files in this commit comply with the clang-tidy style rules.\e[0m\n" + exit 0 +fi + +# A diff has been created, notify the user, clean up, and exit. +printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" +# Perl commands replace trailing spaces with `·` and tabs with ``. +printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="" x length($2); sprintf("$1$tabs$3")/ge' + +printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\e[0m\n" +exit 1 diff --git a/misc/scripts/codespell.sh b/misc/scripts/codespell.sh new file mode 100644 index 00000000..d15b6593 --- /dev/null +++ b/misc/scripts/codespell.sh @@ -0,0 +1,8 @@ +#!/bin/sh +SKIP_LIST="./.*,./**/.*,./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md," +SKIP_LIST+="./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/renames_map_3_to_4.cpp,./misc/scripts/codespell.sh," +SKIP_LIST+="./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json," + +IGNORE_LIST="curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,nd,numer,ot,te,vai" + +codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}" --builtin "clear,rare,en-GB_to_en-US" diff --git a/misc/scripts/copyright_headers.py b/misc/scripts/copyright_headers.py new file mode 100644 index 00000000..a5e2f0c0 --- /dev/null +++ b/misc/scripts/copyright_headers.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys + +header = """\ +/**************************************************************************/ +/* $filename */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ +""" + +fname = sys.argv[1] + +# Handle replacing $filename with actual filename and keep alignment +fsingle = fname.strip() +if fsingle.find("/") != -1: + fsingle = fsingle[fsingle.rfind("/") + 1 :] +rep_fl = "$filename" +rep_fi = fsingle +len_fl = len(rep_fl) +len_fi = len(rep_fi) +# Pad with spaces to keep alignment +if len_fi < len_fl: + for x in range(len_fl - len_fi): + rep_fi += " " +elif len_fl < len_fi: + for x in range(len_fi - len_fl): + rep_fl += " " +if header.find(rep_fl) != -1: + text = header.replace(rep_fl, rep_fi) +else: + text = header.replace("$filename", fsingle) +text += "\n" + +# We now have the proper header, so we want to ignore the one in the original file +# and potentially empty lines and badly formatted lines, while keeping comments that +# come after the header, and then keep everything non-header unchanged. +# To do so, we skip empty lines that may be at the top in a first pass. +# In a second pass, we skip all consecutive comment lines starting with "/*", +# then we can append the rest (step 2). + +fileread = open(fname.strip(), "r") +line = fileread.readline() +header_done = False + +while line.strip() == "": # Skip empty lines at the top + line = fileread.readline() + +if line.find("/**********") == -1: # Godot header starts this way + # Maybe starting with a non-Godot comment, abort header magic + header_done = True + +while not header_done: # Handle header now + if line.find("/*") != 0: # No more starting with a comment + header_done = True + if line.strip() != "": + text += line + line = fileread.readline() + +while line != "": # Dump everything until EOF + text += line + line = fileread.readline() + +fileread.close() + +# Write +filewrite = open(fname.strip(), "w") +filewrite.write(text) +filewrite.close() diff --git a/misc/scripts/dotnet_format.sh b/misc/scripts/dotnet_format.sh new file mode 100644 index 00000000..cac00f5c --- /dev/null +++ b/misc/scripts/dotnet_format.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# This script runs dotnet format on all relevant files in the repo. +# This is the primary script responsible for fixing style violations in C# files. + +set -uo pipefail + +# Create dummy generated files. +echo "" > modules/mono/SdkPackageVersions.props +mkdir -p modules/mono/glue/GodotSharp/GodotSharp/Generated +echo "" > modules/mono/glue/GodotSharp/GodotSharp/Generated/GeneratedIncludes.props +mkdir -p modules/mono/glue/GodotSharp/GodotSharpEditor/Generated +echo "" > modules/mono/glue/GodotSharp/GodotSharpEditor/Generated/GeneratedIncludes.props + +# Loops through all C# projects tracked by Git. +git ls-files -- '*.csproj' \ + ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' | +while read -r f; do + # Run dotnet format. + dotnet format "$f" +done + +diff=$(git diff --color) + +# If no diff has been generated all is OK, clean up, and exit. +if [ -z "$diff" ] ; then + printf "\e[1;32m*** Files in this commit comply with the dotnet format style rules.\e[0m\n" + exit 0 +fi + +# A diff has been created, notify the user, clean up, and exit. +printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" +# Perl commands replace trailing spaces with `·` and tabs with ``. +printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="" x length($2); sprintf("$1$tabs$3")/ge' + +printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\e[0m\n" +exit 1 diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh new file mode 100644 index 00000000..94a3affb --- /dev/null +++ b/misc/scripts/file_format.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash + +# This script ensures proper POSIX text file formatting and a few other things. +# This is supplementary to clang_format.sh and black_format.sh, but should be +# run before them. + +# We need dos2unix and isutf8. +if [ ! -x "$(command -v dos2unix)" -o ! -x "$(command -v isutf8)" ]; then + printf "Install 'dos2unix' and 'isutf8' (moreutils package) to use this script.\n" + exit 1 +fi + +set -uo pipefail + +if [ $# -eq 0 ]; then + # Loop through all code files tracked by Git. + mapfile -d '' files < <(git grep -zIl '') +else + # $1 should be a file listing file paths to process. Used in CI. + mapfile -d ' ' < <(cat "$1") +fi + +for f in "${files[@]}"; do + # Exclude some types of files. + if [[ "$f" == *"csproj" ]]; then + continue + elif [[ "$f" == *"sln" ]]; then + continue + elif [[ "$f" == *".bat" ]]; then + continue + elif [[ "$f" == *".out" ]]; then + # GDScript integration testing files. + continue + elif [[ "$f" == *"patch" ]]; then + continue + elif [[ "$f" == *"pot" ]]; then + continue + elif [[ "$f" == *"po" ]]; then + continue + elif [[ "$f" == "thirdparty/"* ]]; then + continue + elif [[ "$f" == *"/thirdparty/"* ]]; then + continue + elif [[ "$f" == "platform/android/java/lib/src/com/google"* ]]; then + continue + elif [[ "$f" == *"-so_wrap."* ]]; then + continue + elif [[ "$f" == *".test.txt" ]]; then + continue + fi + # Ensure that files are UTF-8 formatted. + isutf8 "$f" >> utf8-validation.txt 2>&1 + # Ensure that files have LF line endings and do not contain a BOM. + dos2unix "$f" 2> /dev/null + # Remove trailing space characters and ensures that files end + # with newline characters. -l option handles newlines conveniently. + perl -i -ple 's/\s*$//g' "$f" +done + +diff=$(git diff --color) + +if [ ! -s utf8-validation.txt ] && [ -z "$diff" ] ; then + # If no UTF-8 violations were collected (the file is empty) and + # no diff has been generated all is OK, clean up, and exit. + printf "\e[1;32m*** Files in this commit comply with the file formatting rules.\e[0m\n" + rm -f utf8-validation.txt + exit 0 +fi + +if [ -s utf8-validation.txt ] +then + # If the file has content and is not empty, violations + # detected, notify the user, clean up, and exit. + printf "\n\e[1;33m*** The following files contain invalid UTF-8 character sequences:\e[0m\n\n" + cat utf8-validation.txt +fi + +rm -f utf8-validation.txt + +if [ ! -z "$diff" ] +then + # A diff has been created, notify the user, clean up, and exit. + printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" + # Perl commands replace trailing spaces with `·` and tabs with ``. + printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="" x length($2); sprintf("$1$tabs$3")/ge' +fi + +printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\e[0m\n" +exit 1 diff --git a/misc/scripts/header_guards.sh b/misc/scripts/header_guards.sh new file mode 100644 index 00000000..1f8aa615 --- /dev/null +++ b/misc/scripts/header_guards.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +if [ ! -f "version.py" ]; then + echo "Warning: This script is intended to be run from the root of the Godot repository." + echo "Some of the paths checks may not work as intended from a different folder." +fi + +if [ $# -eq 0 ]; then + # Loop through all code files tracked by Git. + files=$(find -name "thirdparty" -prune -o -name "*.h" -print | sed "s@^\./@@g") +else + # $1 should be a file listing file paths to process. Used in CI. + files=$(cat "$1" | grep -v "thirdparty/" | grep -E "\.h$" | sed "s@^\./@@g") +fi + +files_invalid_guard="" + +for file in $files; do + # Skip *.gen.h and *-so_wrap.h, they're generated. + if [[ "$file" == *".gen.h" || "$file" == *"-so_wrap.h" ]]; then continue; fi + # Has important define before normal header guards. + if [[ "$file" == *"thread.h" || "$file" == *"platform_config.h" ]]; then continue; fi + # Obj-C files don't use header guards. + if grep -q "#import " "$file"; then continue; fi + + bname=$(basename $file .h) + + # Add custom prefix or suffix for generic filenames with a well-defined namespace. + + prefix= + if [[ "$file" == "modules/"*"/register_types.h" ]]; then + module=$(echo $file | sed "s@.*modules/\([^/]*\).*@\1@") + prefix="${module^^}_" + fi + if [[ "$file" == "platform/"*"/api/api.h" || "$file" == "platform/"*"/export/"* ]]; then + platform=$(echo $file | sed "s@.*platform/\([^/]*\).*@\1@") + prefix="${platform^^}_" + fi + if [[ "$file" == "modules/mono/utils/"* && "$bname" != *"mono"* ]]; then prefix="MONO_"; fi + if [[ "$file" == "servers/rendering/storage/utilities.h" ]]; then prefix="RENDERER_"; fi + + suffix= + if [[ "$file" == *"dummy"* && "$bname" != *"dummy"* ]]; then suffix="_DUMMY"; fi + if [[ "$file" == *"gles3"* && "$bname" != *"gles3"* ]]; then suffix="_GLES3"; fi + if [[ "$file" == *"renderer_rd"* && "$bname" != *"rd"* ]]; then suffix="_RD"; fi + if [[ "$file" == *"ustring.h" ]]; then suffix="_GODOT"; fi + + # ^^ is bash builtin for UPPERCASE. + guard="${prefix}${bname^^}${suffix}_H" + + # Replaces guards to use computed name. + # We also add some \n to make sure there's a proper separation. + sed -i $file -e "0,/ifndef/s/#ifndef.*/\n#ifndef $guard/" + sed -i $file -e "0,/define/s/#define.*/#define $guard\n/" + sed -i $file -e "$ s/#endif.*/\n#endif \/\/ $guard/" + # Removes redundant \n added before, if they weren't needed. + sed -i $file -e "/^$/N;/^\n$/D" + + # Check that first ifndef (should be header guard) is at the expected position. + # If not it can mean we have some code before the guard that should be after. + # "31" is the expected line with the copyright header. + first_ifndef=$(grep -n -m 1 "ifndef" $file | sed 's/\([0-9]*\).*/\1/') + if [[ "$first_ifndef" != "31" ]]; then + files_invalid_guard+="$file\n" + fi +done + +if [[ ! -z "$files_invalid_guard" ]]; then + echo -e "The following files were found to have potentially invalid header guard:\n" + echo -e "$files_invalid_guard" +fi + +diff=$(git diff --color) + +# If no diff has been generated all is OK, clean up, and exit. +if [ -z "$diff" ] ; then + printf "\e[1;32m*** Files in this commit comply with the header guards formatting rules.\e[0m\n" + exit 0 +fi + +# A diff has been created, notify the user, clean up, and exit. +printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" +# Perl commands replace trailing spaces with `·` and tabs with ``. +printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="" x length($2); sprintf("$1$tabs$3")/ge' + +printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i '\e[0m\n" +exit 1 diff --git a/misc/scripts/install_vulkan_sdk_macos.sh b/misc/scripts/install_vulkan_sdk_macos.sh new file mode 100644 index 00000000..17d567f2 --- /dev/null +++ b/misc/scripts/install_vulkan_sdk_macos.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env sh + +set -euo pipefail +IFS=$'\n\t' + +# Download and install the Vulkan SDK. +curl -L "https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.dmg" -o /tmp/vulkan-sdk.dmg +hdiutil attach /tmp/vulkan-sdk.dmg -mountpoint /Volumes/vulkan-sdk +/Volumes/vulkan-sdk/InstallVulkan.app/Contents/MacOS/InstallVulkan \ + --accept-licenses --default-answer --confirm-command install + +cnt=5 +until hdiutil detach -force /Volumes/vulkan-sdk +do + [[ cnt -eq "0" ]] && break + sleep 1 + ((cnt--)) +done + +rm -f /tmp/vulkan-sdk.dmg + +echo 'Vulkan SDK installed successfully! You can now build Godot by running "scons".' diff --git a/misc/scripts/make_icons.sh b/misc/scripts/make_icons.sh new file mode 100644 index 00000000..cbb92660 --- /dev/null +++ b/misc/scripts/make_icons.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# Generate .ico, .icns and .zip set of icons for Steam + +# Make icons with transparent backgrounds and all sizes +for s in 16 24 32 48 64 128 256 512 1024; do + convert -resize ${s}x$s -antialias \ + -background transparent \ + ../../icon.svg icon$s.png +done + +# 16px tga file for library +convert icon16.png icon16.tga + +# zip for Linux +zip godot-icons.zip icon*.png + +# ico for Windows +# Not including biggest ones or it blows up in size +icotool -c -o godot-icon.ico icon{16,24,32,48,64,128,256}.png + +# icns for macOS +# Only some sizes: https://iconhandbook.co.uk/reference/chart/osx/ +png2icns godot-icon.icns icon{16,32,128,256,512,1024}.png + +rm -f icon*.png diff --git a/misc/scripts/make_tarball.sh b/misc/scripts/make_tarball.sh new file mode 100644 index 00000000..9e02b80a --- /dev/null +++ b/misc/scripts/make_tarball.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +if [ ! -e "version.py" ]; then + echo "This script should be ran from the root folder of the Godot repository." + exit 1 +fi + +while getopts "h?sv:g:" opt; do + case "$opt" in + h|\?) + echo "Usage: $0 [OPTIONS...]" + echo + echo " -s script friendly file name (godot.tar.gz)" + echo " -v godot version for file name (e.g. 4.0-stable)" + echo " -g git treeish to archive (e.g. master)" + echo + exit 1 + ;; + s) + script_friendly_name=1 + ;; + v) + godot_version=$OPTARG + ;; + g) + git_treeish=$OPTARG + ;; + esac +done + +if [ ! -z "$git_treeish" ]; then + HEAD=$(git rev-parse $git_treeish) +else + HEAD=$(git rev-parse HEAD) +fi + +if [ ! -z "$script_friendly_name" ]; then + NAME=godot +else + if [ ! -z "$godot_version" ]; then + NAME=godot-$godot_version + else + NAME=godot-$HEAD + fi +fi + +CURDIR=$(pwd) +TMPDIR=$(mktemp -d -t godot-XXXXXX) + +echo "Generating tarball for revision $HEAD with folder name '$NAME'." +echo +echo "The tarball will be written to the parent folder:" +echo " $(dirname $CURDIR)/$NAME.tar.gz" + +git archive $HEAD --prefix=$NAME/ -o $TMPDIR/$NAME.tar + +# Adding custom .git/HEAD to tarball so that we can generate VERSION_HASH. +cd $TMPDIR +mkdir -p $NAME/.git +echo $HEAD > $NAME/.git/HEAD +tar -uf $NAME.tar $NAME + +cd $CURDIR +gzip -c $TMPDIR/$NAME.tar > ../$NAME.tar.gz + +rm -rf $TMPDIR diff --git a/misc/scripts/mypy.ini b/misc/scripts/mypy.ini new file mode 100644 index 00000000..c1ea695c --- /dev/null +++ b/misc/scripts/mypy.ini @@ -0,0 +1,11 @@ +[mypy] +ignore_missing_imports = true +disallow_any_generics = True +pretty = True +show_column_numbers = True +warn_redundant_casts = True +warn_return_any = True +warn_unreachable = True + +namespace_packages = True +explicit_package_bases = True diff --git a/misc/scripts/mypy_check.sh b/misc/scripts/mypy_check.sh new file mode 100644 index 00000000..2a06486d --- /dev/null +++ b/misc/scripts/mypy_check.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -uo pipefail + +echo -e "Python: mypy static analysis..." +mypy --config-file=./misc/scripts/mypy.ini . diff --git a/misc/scripts/pytest_builders.sh b/misc/scripts/pytest_builders.sh new file mode 100644 index 00000000..eb2ddbcd --- /dev/null +++ b/misc/scripts/pytest_builders.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -uo pipefail + +echo "Running Python checks for builder system" +pytest ./tests/python_build diff --git a/quickjs/builtin_binding_generator.py b/quickjs/builtin_binding_generator.py deleted file mode 100644 index 3d47b953..00000000 --- a/quickjs/builtin_binding_generator.py +++ /dev/null @@ -1,728 +0,0 @@ -#!/usr/bin/env python -import json, os - -DIR = os.path.abspath( os.path.dirname(__file__) ) -OUTPUT_FILE = os.path.join(DIR, "quickjs_builtin_binder.gen.cpp") -API = json.load(open(os.path.join(DIR, '..', 'builtin_api.gen.json'), 'r')) - -VariantTypes = { - "Variant": "Variant::NIL", - "boolean": "Variant::BOOL", - "number": "Variant::FLOAT", - "string": "Variant::STRING", - "Vector2": "Variant::VECTOR2", - "Vector3": "Variant::VECTOR3", - "Basis": "Variant::BASIS", - "Quaternion": "Variant::QUATERNION", - "Color": "Variant::COLOR", - "Rect2": "Variant::RECT2", - "RID": "Variant::RID", - "Transform2D": "Variant::TRANSFORM2D", - "Plane": "Variant::PLANE", - "AABB": "Variant::AABB", - "Transform3D": "Variant::TRANSFORM3D", - "PackedByteArray": "Variant::PACKED_BYTE_ARRAY", - "PackedInt32Array": "Variant::PACKED_INT32_ARRAY", - "PackedInt64Array": "Variant::PACKED_INT64_ARRAY", - "PackedFloat32Array": "Variant::PACKED_FLOAT32_ARRAY", - "PackedFloat64Array": "Variant::PACKED_FLOAT64_ARRAY", - "PackedStringArray": "Variant::PACKED_STRING_ARRAY", - "PackedVector2Array": "Variant::PACKED_VECTOR2_ARRAY", - "PackedVector3Array": "Variant::PACKED_VECTOR3_ARRAY", - "PackedColorArray": "Variant::PACKED_COLOR_ARRAY", -} - -JSToGodotTemplates = { - "number": 'QuickJSBinder::js_to_number(ctx, ${arg})', - "string": 'QuickJSBinder::js_to_string(ctx, ${arg})', - "boolean": 'QuickJSBinder::js_to_bool(ctx, ${arg})', - "Vector2": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getVector2()', - "Rect2": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getRect2()', - "Color": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getColor()', - "RID": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getRID()', - "AABB": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getAABB()', - "Plane": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPlane()', - "Quaternion": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getQuaternion()', - "Transform2D": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getTransform2D()', - "Vector3": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getVector3()', - "Basis": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getBasis()', - "Transform3D": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getTransform3D()', - "PackedByteArray": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedByteArray()', - "PackedInt32Array": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedInt32Array()', - "PackedInt64Array": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedInt64Array()', - "PackedFloat32Array": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedFloat32Array()', - "PackedFloat64Array": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedFloat64Array()', - "PackedStringArray": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedStringArray()', - "PackedVector2Array": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedVector2Array()', - "PackedVector3Array": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedVector3Array()', - "PackedColorArray": '*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedColorArray()', - "Variant": '(BINDING_DATA_FROM_JS(ctx, ${arg}))->get_value()', -} - -GodotTypeNames = { - "number": "real_t", - "string": "String", - "boolean": "bool", - "Vector2": "Vector2", - "Rect2": "Rect2", - "Color": "Color", - "RID": "RID", - "AABB": "AABB", - "Plane": "Plane", - "Quaternion": "Quaternion", - "Transform2D": "Transform2D", - "Vector3": "Vector3", - "Basis": "Basis", - "Transform3D": "Transform3D", - "PackedByteArray": "PackedByteArray", - "PackedInt32Array": "PackedInt32Array", - "PackedInt64Array": "PackedInt64Array", - "PackedFloat32Array": "PackedFloat32Array", - "PackedFloat64Array": "PackedFloat64Array", - "PackedStringArray": "PackedStringArray", - "PackedVector2Array": "PackedVector2Array", - "PackedVector3Array": "PackedVector3Array", - "PackedColorArray": "PackedColorArray", - "Variant": "Variant", -} - -GodotToJSTemplates = { - "number": 'QuickJSBinder::to_js_number(ctx, ${arg})', - "string": 'QuickJSBinder::to_js_string(ctx, ${arg})', - "boolean": 'QuickJSBinder::to_js_bool(ctx, ${arg})', - "Vector2": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Rect2": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Color": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "RID": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "AABB": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Plane": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Quaternion": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Transform2D": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Vector3": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Basis": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Transform3D": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedByteArray": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedInt32Array": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedInt64Array": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedFloat32Array": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedFloat64Array": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedStringArray": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedVector2Array": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedVector3Array": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "PackedColorArray": 'QuickJSBuiltinBinder::new_object_from(ctx, ${arg})', - "Variant": 'QuickJSBinder::variant_to_var(ctx, ${arg})', -} - -def apply_pattern(template, values): - for key in values: - template = template.replace( '${' + key + '}', values[key]) - return template - - -def generate_constructor(cls): - TemplateConstructorName = '${class}_constructor' - TemplateConstructorDeclare = 'static JSValue ${class}_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv);\n' - TemplateConstructor = ''' -static JSValue ${func}(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) { - ${class} tmp; - ${initializer} - JSValue proto = JS_GetProperty(ctx, new_target, QuickJSBinder::JS_ATOM_prototype); - JSValue obj = JS_NewObjectProtoClass(ctx, proto, QuickJSBinder::get_context_binder(ctx)->get_origin_class_id()); - QuickJSBuiltinBinder::bind_builtin_object(ctx, obj, ${type}, &tmp); - JS_FreeValue(ctx, proto); - return obj; - // return QuickJSBuiltinBinder::create_builtin_value(ctx, ${type}, &tmp); -} -''' - TemplateSimplePackedArrays = ''' - if (argc == 1) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!JS_IsArray(ctx, argv[0]), (JS_ThrowTypeError(ctx, "Array expected for argument #0 of ${class}(from)"))); -#endif - Variant arr = QuickJSBinder::var_to_variant(ctx, argv[0]); - tmp.operator=(arr); - } - ''' - TemplatePackedArrays = ''' - if (argc == 1) { - if (JS_IsArray(ctx, argv[0])) { - Variant arr = QuickJSBinder::var_to_variant(ctx, argv[0]); - tmp.operator=(arr); - } else if (JS_IsArrayBuffer(argv[0])) { - size_t size; - uint8_t *buffer = JS_GetArrayBuffer(ctx, &size, argv[0]); - if (size) { - if (size % sizeof(${element}) != 0) { - ERR_PRINT("Length of the ArrayBuffer does not match for ${class}"); - } - tmp.resize(size / sizeof(${element})); - memcpy(tmp.ptrw(), buffer, size / sizeof(${element}) * sizeof(${element})); - } - } else if (JS_IsDataView(argv[0])) { - JSValue byte_length = JS_GetPropertyStr(ctx, argv[0], "byteLength"); - uint64_t length = QuickJSBinder::js_to_uint64(ctx, byte_length); - JS_FreeValue(ctx, byte_length); - - JSValue byte_offset = JS_GetPropertyStr(ctx, argv[0], "byteOffset"); - uint64_t offset = QuickJSBinder::js_to_uint64(ctx, byte_offset); - JS_FreeValue(ctx, byte_offset); - - size_t size; - JSValue arraybuffer = JS_GetPropertyStr(ctx, argv[0], "buffer"); - uint8_t *buffer = JS_GetArrayBuffer(ctx, &size, arraybuffer); - JS_FreeValue(ctx, arraybuffer); - if (length) { - tmp.resize(length / sizeof(${element})); - memcpy(tmp.ptrw(), buffer + offset, length / sizeof(${element}) * sizeof(${element})); - } - } else { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(false, (JS_ThrowTypeError(ctx, "Array or ArrayBuffer expected for argument #0 of ${class}(from)"))); -#endif - } - } - ''' - ConstructorInitializers = { - "Vector2": ''' - if (argc == 2) { - tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.y = QuickJSBinder::js_to_number(ctx, argv[1]); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::VECTOR2) { - tmp = *bind->getVector2(); - } - } else { - tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.y = tmp.x; - } - } -''', - "Vector3": ''' - if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::VECTOR3) - tmp = *bind->getVector3(); - } else { - tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.z = tmp.y = tmp.x; - } - } else if (argc == 3) { - tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.y = QuickJSBinder::js_to_number(ctx, argv[1]); - tmp.z = QuickJSBinder::js_to_number(ctx, argv[2]); - } -''', - "Color": ''' - if (argc >= 3) { - tmp.r = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.g = QuickJSBinder::js_to_number(ctx, argv[1]); - tmp.b = QuickJSBinder::js_to_number(ctx, argv[2]); - tmp.a = (argc >= 4) ? QuickJSBinder::js_to_number(ctx, argv[3]) : 1.0f; - } else if (argc == 1) { - if (JS_IsNumber(argv[0])) { - tmp = Color::hex(QuickJSBinder::js_to_uint(ctx, argv[0])); - } else if (JS_IsString(argv[0])) { - tmp = Color::html(QuickJSBinder::js_to_string(ctx, argv[0])); - } else if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::COLOR) { - tmp = *bind->getColor(); - } - } - } -''', - "Rect2": ''' - if (argc == 4) { - tmp.position.x = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.position.y = QuickJSBinder::js_to_number(ctx, argv[1]); - tmp.size.x = QuickJSBinder::js_to_number(ctx, argv[2]); - tmp.size.y = QuickJSBinder::js_to_number(ctx, argv[3]); - } else if (argc == 2) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[0]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 0 of Rect2(position, size)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[1]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 1 of Rect2(position, size)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - tmp.position = *param0->getVector2(); - tmp.size = *param1->getVector2(); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::RECT2) - tmp = *bind->getRect2(); - } - } -''', - "AABB": ''' - if (argc == 2) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of AABB(position, size)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of AABB(position, size)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - tmp.position = *param0->getVector3(); - tmp.size = *param1->getVector3(); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::AABB) - tmp = *bind->getAABB(); - } - } -''', - "Plane": ''' - if (argc == 4) { - tmp.normal.x = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.normal.y = QuickJSBinder::js_to_number(ctx, argv[1]); - tmp.normal.z = QuickJSBinder::js_to_number(ctx, argv[2]); - tmp.d = QuickJSBinder::js_to_number(ctx, argv[3]); - } else if (argc == 3) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Plane(v1, v2, v3)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Plane(v1, v2, v3)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[2]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 2 of Plane(v1, v2, v3)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); - tmp = Plane(*param0->getVector3(), *param1->getVector3(), *param2->getVector3()); - } else if (argc == 2) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Plane(normal, d)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - tmp = Plane(*param0->getVector3(), QuickJSBinder::js_to_number(ctx, argv[1])); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::PLANE) - tmp = *bind->getPlane(); - } - } -''', - "Quaternion": ''' - if (argc == 4) { - tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); - tmp.y = QuickJSBinder::js_to_number(ctx, argv[1]); - tmp.z = QuickJSBinder::js_to_number(ctx, argv[2]); - tmp.w = QuickJSBinder::js_to_number(ctx, argv[3]); - } else if (argc == 2) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Quaternion(axis, angle)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - tmp = Quaternion(*param0->getVector3(), QuickJSBinder::js_to_number(ctx, argv[1])); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::QUATERNION) { - tmp = *bind->getQuaternion(); - } else if (bind->type == Variant::BASIS) { - tmp = *bind->getBasis(); - } else if (bind->type == Variant::VECTOR3) { - Basis basis; - basis.from_euler(*bind->getVector3()); - tmp = basis.get_rotation_quaternion(); - } - } - } -''', - "Transform2D": ''' - if (argc == 3) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[0]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 0 of Transform2D(x_axis, y_axis, origin)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[1]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 1 of Transform2D(x_axis, y_axis, origin)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[2]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 2 of Transform2D(x_axis, y_axis, origin)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); - tmp.columns[0].operator=(*param0->getVector2()); - tmp.columns[1].operator=(*param1->getVector2()); - tmp.columns[2].operator=(*param2->getVector2()); - } else if (argc == 2) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[1]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 1 of Transform2D(rotation, position)"))); -#endif - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - tmp.set_origin(*param1->getVector2()); - tmp.set_rotation(QuickJSBinder::js_to_number(ctx, argv[0])); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::TRANSFORM2D) - tmp = *bind->getTransform2D(); - else if (Variant::can_convert(bind->type, Variant::TRANSFORM2D)) { - tmp = bind->get_value(); - } - } - } -''', - "Basis": ''' - if (argc == 3) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Basis(x_axis, y_axis, z_axis)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Basis(x_axis, y_axis, z_axis)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[2]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 2 of Basis(x_axis, y_axis, z_axis)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); - tmp.rows[0].operator=(*param0->getVector3()); - tmp.rows[1].operator=(*param1->getVector3()); - tmp.rows[2].operator=(*param2->getVector3()); - } else if (argc == 2) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Basis(axis, phi)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - tmp.set_axis_angle(*param0->getVector3(), QuickJSBinder::js_to_number(ctx, argv[1])); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::VECTOR3) { - tmp.set_euler(*bind->getVector3()); - } else if (bind->type == Variant::QUATERNION) { - tmp.set_quaternion(*bind->getQuaternion()); - } else if (bind->type == Variant::BASIS) { - tmp.operator=(*bind->getBasis()); - } - } - } -''', - "Transform3D": ''' - if (argc == 4) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Transform3D(x_axis, y_axis, z_axis, origin)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Transform3D(x_axis, y_axis, z_axis, origin)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[2]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 2 of Transform3D(x_axis, y_axis, z_axis, origin)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[3]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 3 of Transform3D(x_axis, y_axis, z_axis, origin)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); - JavaScriptGCHandler *param3 = BINDING_DATA_FROM_JS(ctx, argv[3]); - - tmp.basis.rows[0].operator=(*param0->getVector3()); - tmp.basis.rows[1].operator=(*param1->getVector3()); - tmp.basis.rows[2].operator=(*param2->getVector3()); - tmp.origin.operator=(*param3->getVector3()); - } else if (argc == 2) { -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::BASIS, argv[0]), (JS_ThrowTypeError(ctx, "Basis expected for argument 0 of Transform3D(basis, origin)"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Transform3D(basis, origin)"))); -#endif - JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); - JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - tmp.basis.operator=(*param0->getBasis()); - tmp.origin.operator=(*param1->getVector3()); - } else if (argc == 1) { - if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { - if (bind->type == Variant::TRANSFORM3D) { - tmp.operator=(*bind->getTransform3D()); - } else if (Variant::can_convert(bind->type, Variant::TRANSFORM3D)) { - tmp.operator=(bind->get_value()); - } - } - } -''', - "PackedByteArray": apply_pattern(TemplatePackedArrays, {"class": "PackedByteArray", "type": "Variant::PACKED_BYTE_ARRAY", "element": "uint8_t"}), - "PackedInt32Array": apply_pattern(TemplatePackedArrays, {"class": "PackedInt32Array", "type": "Variant::PACKED_INT32_ARRAY", "element": "int32_t"}), - "PackedInt64Array": apply_pattern(TemplatePackedArrays, {"class": "PackedInt64Array", "type": "Variant::PACKED_INT64_ARRAY", "element": "int64_t"}), - "PackedFloat32Array": apply_pattern(TemplatePackedArrays, {"class": "PackedFloat32Array", "type": "Variant::PACKED32_FLOAT_ARRAY", "element": "real_t"}), - "PackedFloat64Array": apply_pattern(TemplatePackedArrays, {"class": "PackedFloat64Array", "type": "Variant::PACKED64_FLOAT_ARRAY", "element": "real_t"}), - "PackedVector2Array": apply_pattern(TemplatePackedArrays, {"class": "PackedVector2Array", "type": "Variant::PACKED_VECTOR2_ARRAY", "element": "Vector2"}), - "PackedVector3Array": apply_pattern(TemplatePackedArrays, {"class": "PackedVector3Array", "type": "Variant::PACKED_VECTOR3_ARRAY", "element": "Vector3"}), - "PackedColorArray": apply_pattern(TemplatePackedArrays, {"class": "PackedColorArray", "type": "Variant::PACKED_COLOR_ARRAY", "element": "Color"}), - "PackedStringArray": apply_pattern(TemplateSimplePackedArrays,{"class": "PackedStringArray", "type": "Variant::PACKED_STRING_ARRAY", "element": "String"}), - } - class_name = cls['name'] - constructor_name = apply_pattern(TemplateConstructorName, {"class": class_name}) - constructor_declare = apply_pattern(TemplateConstructorDeclare, {"class": class_name}) - - initializer = '' - if class_name in ConstructorInitializers: - initializer = ConstructorInitializers[class_name] - constructor = apply_pattern(TemplateConstructor, { - 'class': class_name, - 'type': VariantTypes[class_name], - 'func': constructor_name, - 'initializer': initializer - }) - return constructor_name, constructor_declare, constructor - -def generate_property_bindings(cls): - class_name = cls['name'] - TemplateDeclar = 'static void bind_${class}_properties(JSContext *octx);\n' - TemplateBind = '\tbind_${class}_properties(ctx);\n' - def generate_members(cls): - Template = ''' - JSCFunctionMagic *getter = [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) -> JSValue { - JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); - const ${class} *ptr = bind->get${class}(); - switch (magic) {\ -${getters} - } - return JS_UNDEFINED; - }; - - JSCFunctionMagic *setter = [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) -> JSValue { - JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); - ${class} *ptr = bind->get${class}();\ -${validation} - switch (magic) {\ -${setters} - } - return JS_DupValue(ctx, argv[0]); - }; -${bindings} - ''' - TemplateGetterItem = ''' - case ${index}: - return ${value};''' - TemplateSetterItem = ''' - case ${index}: -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[0]), (JS_ThrowTypeError(ctx, "${type_name} expected for ${class}.${name}"))); -#endif - ptr->${native} = ${value}; - break;''' - TemplateItemBinding = '\tbinder->get_builtin_binder().register_property(${type}, "${name}", getter, setter, ${index});\n' - getters = '' - setters = '' - bindings = '' - for i in range(len(cls['properties'])): - p = cls['properties'][i] - type = p['type'] - name = p['name'] - native_name = p['native'] - getters += apply_pattern(TemplateGetterItem, { - 'index': str(i), - 'value': apply_pattern(GodotToJSTemplates[type], { 'arg': apply_pattern('ptr->${native}', {'native': native_name}) }) - }) - setters += apply_pattern(TemplateSetterItem, { - 'index': str(i), - 'name': name, - 'native': native_name, - 'type': VariantTypes[type], - 'type_name': type, - 'class': class_name, - 'value': apply_pattern(JSToGodotTemplates[type], {'arg': 'argv[0]'}) - }) - bindings += apply_pattern(TemplateItemBinding, {'index': str(i), 'name': name, 'type': VariantTypes[class_name]}) - return apply_pattern(Template, { - 'class': class_name, - 'getters': getters, - 'setters': setters, - 'bindings': bindings, - 'validation': '' - }) - - def generate_methods(cls): - TemplateMethod = ''' - binder->get_builtin_binder().register_method( - ${type}, - "${name}", - [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); - ${class} *ptr = bind->get${class}();\ -${arg_declares} - ${call} - return ${return}; - }, - ${argc});''' - TemplateArgDeclare = ''' -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[${index}]), (JS_ThrowTypeError(ctx, "${type_name} expected for argument ${index} of ${class}.${name}"))); -#endif - const ${godot_type} &arg${index} = ${arg}; -''' - TemplateReturnValue = '${godot_type} ret = ' - bindings = '' - for m in cls['methods']: - args = '' - arg_declares = '' - for i in range(len(m['arguments'])): - arg = m['arguments'][i] - arg_type = arg['type'] - arg_declares += apply_pattern(TemplateArgDeclare, { - 'index': str(i), - 'type': VariantTypes[arg_type], - 'type_name': arg_type, - 'class': class_name, - 'name': m['name'], - 'arg': apply_pattern(JSToGodotTemplates[arg_type], {'arg': 'argv[' + str(i) +']'}), - 'godot_type': GodotTypeNames[arg_type], - }) - if i > 0: args += ', ' - args += 'arg' + str(i) - CallTemplate = ('' if m['return'] == 'void' else (apply_pattern(TemplateReturnValue, {"godot_type": GodotTypeNames[m['return']]}))) + 'ptr->${native_method}(${args});' - call = apply_pattern(CallTemplate, {'native_method': m['native_method'], 'args': args}) - bindings += apply_pattern(TemplateMethod, { - "class": class_name, - "type": VariantTypes[class_name], - "name": m['name'], - "call": call, - "arg_declares": arg_declares, - "argc": str(len(m['arguments'])), - "return": 'JS_UNDEFINED' if m['return'] == 'void' else apply_pattern(GodotToJSTemplates[m['return']], {'arg': 'ret'}), - }) - return bindings - - def generate_constants(cls): - ConstTemplate = '\tbinder->get_builtin_binder().register_constant(${type}, "${name}", ${value});\n' - bindings = '' - for c in cls['constants']: - bindings += apply_pattern(ConstTemplate, { - "name": c['name'], - "type": VariantTypes[class_name], - "value": c['value'] - }) - return bindings - - def genertate_operators(cls): - OperatorMap = { - 'operator+': '+', - 'operator-': '-', - 'operator*': '*', - 'operator/': '/', - 'operator==': '==', - 'operator<': '<' - } - TargetDeclareTemplate = ''' -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[1]), (JS_ThrowTypeError(ctx, "${target_class} expected for ${class}.${operator}"))); -#endif - JavaScriptGCHandler *bind1 = BINDING_DATA_FROM_JS(ctx, argv[1]); - ${target_class} *target = bind1->get${target_class}();\ -''' - OperatorTemplate = ''' - JS_SetPropertyStr(octx, base_operators, "${js_op}", - JS_NewCFunction(octx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0]); - ${class} *ptr = bind->get${class}();\ -${target_declare} - ${call} - return ${return}; - }, - "${name}", - ${argc}) - ); - ''' - TemplateReturnValue = '${godot_type} ret = ' - bindings = '''\ - Vector operators; - JSValue base_operators = JS_NewObject(octx); -''' - for o in cls['operators']: - op = o['native_method'] - if op in OperatorMap: - argc = len(o['arguments']) + 1 - js_op = OperatorMap[op] - if argc <= 1: - if op in ['operator-']: - js_op = 'neg' - - args = '' - target_declare = '' - if argc > 1: - arg_class = o['arguments'][0]['type'] - target_declare = apply_pattern(TargetDeclareTemplate, { - 'target_class': arg_class, - 'type': VariantTypes[arg_class], - 'class': class_name, - 'operator': o['native_method'], - }) - args = '*target' - CallTemplate = ('' if o['return'] == 'void' else apply_pattern(TemplateReturnValue, {'godot_type': GodotTypeNames[o['return']] })) + 'ptr->${op}(${args});' - call = apply_pattern(CallTemplate, {'op': op, 'args': args}) - bindings += apply_pattern(OperatorTemplate, { - 'type': VariantTypes[class_name], - 'class': class_name, - 'js_op': js_op, - 'call': call, - 'name': o['name'], - 'target_declare': target_declare, - "return": 'JS_UNDEFINED' if o['return'] == 'void' else apply_pattern(GodotToJSTemplates[o['return']], {'arg': 'ret'}), - 'argc': str(argc) - }) - bindings += apply_pattern(''' - operators.push_back(base_operators); - binder->get_builtin_binder().get_cross_type_operators(${type}, operators); - binder->get_builtin_binder().register_operators(${type}, operators); -''', {'type': VariantTypes[class_name]}) - return bindings - - TemplateBindDefine = ''' -static void bind_${class}_properties(JSContext *octx) { - QuickJSBinder *binder = QuickJSBinder::get_context_binder(octx); -${members} -${operators} -${constants} -${methods} -} -''' - class_name = cls['name'] - property_declare = apply_pattern(TemplateDeclar, {"class": class_name}) - property_defines = apply_pattern(TemplateBindDefine, { - "class": class_name, - "members": generate_members(cls) if len(cls['properties']) else '', - "methods": generate_methods(cls), - "constants": generate_constants(cls), - "operators": genertate_operators(cls), - }) - property_bind = apply_pattern(TemplateBind, {"class": class_name}) - return property_declare, property_defines, property_bind - - -def generate_class_bind_action(cls, constructor): - Template = '\tregister_builtin_class(${type}, "${class}", ${constructor}, ${argc});\n' - return apply_pattern(Template, { - 'class': cls['name'], - 'constructor': constructor, - 'type': VariantTypes[cls['name']], - 'argc': str(cls['constructor_argc']) - }) - - - -def generate_builtin_bindings(): - Template = '''\ -#include "core/variant/variant.h" -#include "quickjs_binder.h" -#include "quickjs_builtin_binder.h" - -#ifndef inf -#define inf INFINITY -#endif - -${declarations} - -void QuickJSBuiltinBinder::bind_builtin_classes_gen() { - -${bindings} -} - -${definitions} -''' - - declarations = '' - definitions = '' - bindings = '' - for cls in API: - constructor_name, constructor_declare, constructor = generate_constructor(cls) - declarations += constructor_declare - definitions += constructor - bindings += generate_class_bind_action(cls, constructor_name) - - property_declare, property_defines, property_bind= generate_property_bindings(cls) - declarations += property_declare - definitions += property_defines - bindings += property_bind - - output = apply_pattern(Template, { - 'declarations': declarations, - 'bindings': bindings, - 'definitions': definitions, - }) - file = open(OUTPUT_FILE, 'w') - file.write(output) - -if __name__ == "__main__": - generate_builtin_bindings() diff --git a/quickjs/quickjs_callable.cpp b/quickjs/quickjs_callable.cpp index 24799d7e..9e7e59a1 100644 --- a/quickjs/quickjs_callable.cpp +++ b/quickjs/quickjs_callable.cpp @@ -1,7 +1,38 @@ +/**************************************************************************/ +/* quickjs_callable.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #include "quickjs_callable.h" +#include "../../quickjs_binder.h" #include "../javascript_language.h" #include "quickjs/quickjs.h" -#include "quickjs_binder.h" +#include "../../quickjs_binder.h" bool QuickJSCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { const QuickJSCallable *a = static_cast(p_a); @@ -23,7 +54,8 @@ QuickJSCallable::QuickJSCallable(JSContext *ctx, const JSValue &p_value) { js_function.javascript_object = JS_VALUE_GET_PTR(v); } -QuickJSCallable::QuickJSCallable(const JavaScriptGCHandler &p_function) : JavaScriptCallable(p_function) { +QuickJSCallable::QuickJSCallable(const JavaScriptGCHandler &p_function) : + JavaScriptCallable(p_function) { JSValue js_func = JS_MKPTR(JS_TAG_OBJECT, p_function.javascript_object); JSContext *ctx = static_cast(p_function.context); ERR_FAIL_COND(JS_IsFunction(ctx, js_func)); diff --git a/quickjs/quickjs_callable.h b/quickjs/quickjs_callable.h index 061a370a..809b93b2 100644 --- a/quickjs/quickjs_callable.h +++ b/quickjs/quickjs_callable.h @@ -1,5 +1,36 @@ +/**************************************************************************/ +/* quickjs_callable.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + #ifndef QUICKJS_CALLABLE_H #define QUICKJS_CALLABLE_H + #include "../javascript_callable.h" #include "quickjs/quickjs.h" diff --git a/register_types.cpp b/register_types.cpp index 8b5781f2..709d46af 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -1,42 +1,43 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ +/**************************************************************************/ +/* register_types.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ #include "register_types.h" + #include "javascript.h" #include "javascript_language.h" #ifdef TOOLS_ENABLED #include "core/io/file_access_encrypted.h" #include "editor/editor_node.h" +#include "editor/editor_tools.h" #include "editor/export/editor_export.h" -#include "tools/editor_tools.h" void editor_init_callback(); class EditorExportJavaScript : public EditorExportPlugin { @@ -45,33 +46,13 @@ class EditorExportJavaScript : public EditorExportPlugin { public: virtual void _export_file(const String &p_path, const String &p_type, const HashSet &p_features) override { String script_key; - // int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED; const Ref &preset = get_export_preset(); - - // if (preset.is_valid()) { - // script_mode = preset->get_file_export_mode(p_path); - // } - - // if (script_mode == EditorExportPreset::MODE_SCRIPT_TEXT) - // return; - String extension = p_path.get_extension(); - if (extension != EXT_JSCLASS && extension != EXT_JSMODULE) + if (extension != EXT_JSCLASS && extension != EXT_JSMODULE) { return; - -// if (script_mode == EditorExportPreset::FileExportMode::MODE_SCRIPT_COMPILED) { -// #if 0 // Disable compile to bytecode as it is not battle tested on all platform -// Error err; -// String code = FileAccess::get_file_as_string(p_path, &err); -// ERR_FAIL_COND(err != OK); - -// Vector file; -// ERR_FAIL_COND(JavaScriptLanguage::get_singleton()->get_main_binder()->compile_to_bytecode(code, p_path, file) != OK); -// add_file(p_path.get_basename() + "." + extension + "b", file, true); -// #endif -// } + } } - virtual String _get_name() const override { return "JavaScript"; } + virtual String get_name() const override { return "JavaScript"; } }; #endif diff --git a/register_types.h b/register_types.h index c81b4a71..18785d49 100644 --- a/register_types.h +++ b/register_types.h @@ -1,38 +1,38 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ +/**************************************************************************/ +/* register_types.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ -#ifndef JAVASCRIPT_MODULE_H -#define JAVASCRIPT_MODULE_H +#ifndef JAVASCRIPT_REGISTER_TYPES_H +#define JAVASCRIPT_REGISTER_TYPES_H #include "modules/register_module_types.h" void initialize_javascript_module(ModuleInitializationLevel p_level); void uninitialize_javascript_module(ModuleInitializationLevel p_level); -#endif +#endif // JAVASCRIPT_REGISTER_TYPES_H diff --git a/tests/UnitTest.js b/tests/UnitTest.js.disabled similarity index 99% rename from tests/UnitTest.js rename to tests/UnitTest.js.disabled index 6954d6e7..c9699d38 100644 --- a/tests/UnitTest.js +++ b/tests/UnitTest.js.disabled @@ -97,4 +97,4 @@ async function run() { const logFunc = passed == count ? console.log : console.warn; logFunc(`Test complete: ${passed}/${count} passed`); } -const _ = run(); // QuickJS BUG ? 返回的是一个 Promise 对象,不赋给临时变量,会导致 Promise 对象无法被 GC +const _ = run(); // QuickJS BUG ? 返回的是一个 Promise 对象,不赋给临时变量,会导致 Promise 对象无法被 GC diff --git a/thirdparty/quickjs/builtin_binding_generator.py b/thirdparty/quickjs/builtin_binding_generator.py new file mode 100644 index 00000000..1e54ff7e --- /dev/null +++ b/thirdparty/quickjs/builtin_binding_generator.py @@ -0,0 +1,860 @@ +#!/usr/bin/env python +import json, os + +DIR = os.path.abspath(os.path.dirname(__file__)) +OUTPUT_FILE = os.path.join(DIR, "quickjs_builtin_binder.gen.cpp") +API = json.load(open(os.path.join(DIR, "../..", "builtin_api.gen.json"), "r")) + +VariantTypes = { + "Variant": "Variant::NIL", + "boolean": "Variant::BOOL", + "number": "Variant::FLOAT", + "string": "Variant::STRING", + "Vector2": "Variant::VECTOR2", + "Vector3": "Variant::VECTOR3", + "Basis": "Variant::BASIS", + "Quaternion": "Variant::QUATERNION", + "Color": "Variant::COLOR", + "Rect2": "Variant::RECT2", + "RID": "Variant::RID", + "Transform2D": "Variant::TRANSFORM2D", + "Plane": "Variant::PLANE", + "AABB": "Variant::AABB", + "Transform3D": "Variant::TRANSFORM3D", + "PackedByteArray": "Variant::PACKED_BYTE_ARRAY", + "PackedInt32Array": "Variant::PACKED_INT32_ARRAY", + "PackedInt64Array": "Variant::PACKED_INT64_ARRAY", + "PackedFloat32Array": "Variant::PACKED_FLOAT32_ARRAY", + "PackedFloat64Array": "Variant::PACKED_FLOAT64_ARRAY", + "PackedStringArray": "Variant::PACKED_STRING_ARRAY", + "PackedVector2Array": "Variant::PACKED_VECTOR2_ARRAY", + "PackedVector3Array": "Variant::PACKED_VECTOR3_ARRAY", + "PackedColorArray": "Variant::PACKED_COLOR_ARRAY", +} + +JSToGodotTemplates = { + "number": "QuickJSBinder::js_to_number(ctx, ${arg})", + "string": "QuickJSBinder::js_to_string(ctx, ${arg})", + "boolean": "QuickJSBinder::js_to_bool(ctx, ${arg})", + "Vector2": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getVector2()", + "Rect2": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getRect2()", + "Color": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getColor()", + "RID": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getRID()", + "AABB": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getAABB()", + "Plane": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPlane()", + "Quaternion": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getQuaternion()", + "Transform2D": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getTransform2D()", + "Vector3": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getVector3()", + "Basis": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getBasis()", + "Transform3D": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getTransform3D()", + "PackedByteArray": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedByteArray()", + "PackedInt32Array": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedInt32Array()", + "PackedInt64Array": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedInt64Array()", + "PackedFloat32Array": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedFloat32Array()", + "PackedFloat64Array": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedFloat64Array()", + "PackedStringArray": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedStringArray()", + "PackedVector2Array": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedVector2Array()", + "PackedVector3Array": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedVector3Array()", + "PackedColorArray": "*(BINDING_DATA_FROM_JS(ctx, ${arg}))->getPackedColorArray()", + "Variant": "(BINDING_DATA_FROM_JS(ctx, ${arg}))->get_value()", +} + +GodotTypeNames = { + "number": "real_t", + "string": "String", + "boolean": "bool", + "Vector2": "Vector2", + "Rect2": "Rect2", + "Color": "Color", + "RID": "RID", + "AABB": "AABB", + "Plane": "Plane", + "Quaternion": "Quaternion", + "Transform2D": "Transform2D", + "Vector3": "Vector3", + "Basis": "Basis", + "Transform3D": "Transform3D", + "PackedByteArray": "PackedByteArray", + "PackedInt32Array": "PackedInt32Array", + "PackedInt64Array": "PackedInt64Array", + "PackedFloat32Array": "PackedFloat32Array", + "PackedFloat64Array": "PackedFloat64Array", + "PackedStringArray": "PackedStringArray", + "PackedVector2Array": "PackedVector2Array", + "PackedVector3Array": "PackedVector3Array", + "PackedColorArray": "PackedColorArray", + "Variant": "Variant", +} + +GodotToJSTemplates = { + "number": "QuickJSBinder::to_js_number(ctx, ${arg})", + "string": "QuickJSBinder::to_js_string(ctx, ${arg})", + "boolean": "QuickJSBinder::to_js_bool(ctx, ${arg})", + "Vector2": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Rect2": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Color": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "RID": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "AABB": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Plane": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Quaternion": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Transform2D": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Vector3": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Basis": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Transform3D": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedByteArray": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedInt32Array": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedInt64Array": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedFloat32Array": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedFloat64Array": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedStringArray": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedVector2Array": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedVector3Array": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "PackedColorArray": "QuickJSBuiltinBinder::new_object_from(ctx, ${arg})", + "Variant": "QuickJSBinder::variant_to_var(ctx, ${arg})", +} + + +def apply_pattern(template, values): + for key in values: + template = template.replace("${" + key + "}", values[key]) + return template + + +def generate_constructor(cls): + TemplateConstructorName = "${class}_constructor" + TemplateConstructorDeclare = ( + "static JSValue ${class}_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv);\n" + ) + TemplateConstructor = """ +static JSValue ${func}(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) { + ${class} tmp; + ${initializer} + JSValue proto = JS_GetProperty(ctx, new_target, QuickJSBinder::JS_ATOM_prototype); + JSValue obj = JS_NewObjectProtoClass(ctx, proto, QuickJSBinder::get_context_binder(ctx)->get_origin_class_id()); + QuickJSBuiltinBinder::bind_builtin_object(ctx, obj, ${type}, &tmp); + JS_FreeValue(ctx, proto); + return obj; + // return QuickJSBuiltinBinder::create_builtin_value(ctx, ${type}, &tmp); +} +""" + TemplateSimplePackedArrays = """ + if (argc == 1) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!JS_IsArray(ctx, argv[0]), (JS_ThrowTypeError(ctx, "Array expected for argument #0 of ${class}(from)"))); +#endif + Variant arr = QuickJSBinder::var_to_variant(ctx, argv[0]); + tmp.operator=(arr); + } + """ + TemplatePackedArrays = """ + if (argc == 1) { + if (JS_IsArray(ctx, argv[0])) { + Variant arr = QuickJSBinder::var_to_variant(ctx, argv[0]); + tmp.operator=(arr); + } else if (JS_IsArrayBuffer(argv[0])) { + size_t size; + uint8_t *buffer = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (size) { + if (size % sizeof(${element}) != 0) { + ERR_PRINT("Length of the ArrayBuffer does not match for ${class}"); + } + tmp.resize(size / sizeof(${element})); + memcpy(tmp.ptrw(), buffer, size / sizeof(${element}) * sizeof(${element})); + } + } else if (JS_IsDataView(argv[0])) { + JSValue byte_length = JS_GetPropertyStr(ctx, argv[0], "byteLength"); + uint64_t length = QuickJSBinder::js_to_uint64(ctx, byte_length); + JS_FreeValue(ctx, byte_length); + + JSValue byte_offset = JS_GetPropertyStr(ctx, argv[0], "byteOffset"); + uint64_t offset = QuickJSBinder::js_to_uint64(ctx, byte_offset); + JS_FreeValue(ctx, byte_offset); + + size_t size; + JSValue arraybuffer = JS_GetPropertyStr(ctx, argv[0], "buffer"); + uint8_t *buffer = JS_GetArrayBuffer(ctx, &size, arraybuffer); + JS_FreeValue(ctx, arraybuffer); + if (length) { + tmp.resize(length / sizeof(${element})); + memcpy(tmp.ptrw(), buffer + offset, length / sizeof(${element}) * sizeof(${element})); + } + } else { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(false, (JS_ThrowTypeError(ctx, "Array or ArrayBuffer expected for argument #0 of ${class}(from)"))); +#endif + } + } + """ + ConstructorInitializers = { + "Vector2": """ + if (argc == 2) { + tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.y = QuickJSBinder::js_to_number(ctx, argv[1]); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::VECTOR2) { + tmp = *bind->getVector2(); + } + } else { + tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.y = tmp.x; + } + } +""", + "Vector3": """ + if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::VECTOR3) + tmp = *bind->getVector3(); + } else { + tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.z = tmp.y = tmp.x; + } + } else if (argc == 3) { + tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.y = QuickJSBinder::js_to_number(ctx, argv[1]); + tmp.z = QuickJSBinder::js_to_number(ctx, argv[2]); + } +""", + "Color": """ + if (argc >= 3) { + tmp.r = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.g = QuickJSBinder::js_to_number(ctx, argv[1]); + tmp.b = QuickJSBinder::js_to_number(ctx, argv[2]); + tmp.a = (argc >= 4) ? QuickJSBinder::js_to_number(ctx, argv[3]) : 1.0f; + } else if (argc == 1) { + if (JS_IsNumber(argv[0])) { + tmp = Color::hex(QuickJSBinder::js_to_uint(ctx, argv[0])); + } else if (JS_IsString(argv[0])) { + tmp = Color::html(QuickJSBinder::js_to_string(ctx, argv[0])); + } else if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::COLOR) { + tmp = *bind->getColor(); + } + } + } +""", + "Rect2": """ + if (argc == 4) { + tmp.position.x = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.position.y = QuickJSBinder::js_to_number(ctx, argv[1]); + tmp.size.x = QuickJSBinder::js_to_number(ctx, argv[2]); + tmp.size.y = QuickJSBinder::js_to_number(ctx, argv[3]); + } else if (argc == 2) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[0]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 0 of Rect2(position, size)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[1]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 1 of Rect2(position, size)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + tmp.position = *param0->getVector2(); + tmp.size = *param1->getVector2(); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::RECT2) + tmp = *bind->getRect2(); + } + } +""", + "AABB": """ + if (argc == 2) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of AABB(position, size)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of AABB(position, size)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + tmp.position = *param0->getVector3(); + tmp.size = *param1->getVector3(); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::AABB) + tmp = *bind->getAABB(); + } + } +""", + "Plane": """ + if (argc == 4) { + tmp.normal.x = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.normal.y = QuickJSBinder::js_to_number(ctx, argv[1]); + tmp.normal.z = QuickJSBinder::js_to_number(ctx, argv[2]); + tmp.d = QuickJSBinder::js_to_number(ctx, argv[3]); + } else if (argc == 3) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Plane(v1, v2, v3)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Plane(v1, v2, v3)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[2]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 2 of Plane(v1, v2, v3)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); + tmp = Plane(*param0->getVector3(), *param1->getVector3(), *param2->getVector3()); + } else if (argc == 2) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Plane(normal, d)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + tmp = Plane(*param0->getVector3(), QuickJSBinder::js_to_number(ctx, argv[1])); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::PLANE) + tmp = *bind->getPlane(); + } + } +""", + "Quaternion": """ + if (argc == 4) { + tmp.x = QuickJSBinder::js_to_number(ctx, argv[0]); + tmp.y = QuickJSBinder::js_to_number(ctx, argv[1]); + tmp.z = QuickJSBinder::js_to_number(ctx, argv[2]); + tmp.w = QuickJSBinder::js_to_number(ctx, argv[3]); + } else if (argc == 2) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Quaternion(axis, angle)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + tmp = Quaternion(*param0->getVector3(), QuickJSBinder::js_to_number(ctx, argv[1])); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::QUATERNION) { + tmp = *bind->getQuaternion(); + } else if (bind->type == Variant::BASIS) { + tmp = *bind->getBasis(); + } else if (bind->type == Variant::VECTOR3) { + Basis basis; + basis = basis.from_euler(*bind->getVector3()); + tmp = basis.get_rotation_quaternion(); + } + } + } +""", + "Transform2D": """ + if (argc == 3) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[0]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 0 of Transform2D(x_axis, y_axis, origin)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[1]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 1 of Transform2D(x_axis, y_axis, origin)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[2]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 2 of Transform2D(x_axis, y_axis, origin)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); + tmp.columns[0].operator=(*param0->getVector2()); + tmp.columns[1].operator=(*param1->getVector2()); + tmp.columns[2].operator=(*param2->getVector2()); + } else if (argc == 2) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR2, argv[1]), (JS_ThrowTypeError(ctx, "Vector2 expected for argument 1 of Transform2D(rotation, position)"))); +#endif + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + tmp.set_origin(*param1->getVector2()); + tmp.set_rotation(QuickJSBinder::js_to_number(ctx, argv[0])); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::TRANSFORM2D) + tmp = *bind->getTransform2D(); + else if (Variant::can_convert(bind->type, Variant::TRANSFORM2D)) { + tmp = bind->get_value(); + } + } + } +""", + "Basis": """ + if (argc == 3) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Basis(x_axis, y_axis, z_axis)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Basis(x_axis, y_axis, z_axis)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[2]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 2 of Basis(x_axis, y_axis, z_axis)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); + tmp.rows[0].operator=(*param0->getVector3()); + tmp.rows[1].operator=(*param1->getVector3()); + tmp.rows[2].operator=(*param2->getVector3()); + } else if (argc == 2) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Basis(axis, phi)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + tmp.set_axis_angle(*param0->getVector3(), QuickJSBinder::js_to_number(ctx, argv[1])); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::VECTOR3) { + tmp.set_euler(*bind->getVector3()); + } else if (bind->type == Variant::QUATERNION) { + tmp.set_quaternion(*bind->getQuaternion()); + } else if (bind->type == Variant::BASIS) { + tmp.operator=(*bind->getBasis()); + } + } + } +""", + "Transform3D": """ + if (argc == 4) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 0 of Transform3D(x_axis, y_axis, z_axis, origin)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Transform3D(x_axis, y_axis, z_axis, origin)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[2]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 2 of Transform3D(x_axis, y_axis, z_axis, origin)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[3]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 3 of Transform3D(x_axis, y_axis, z_axis, origin)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + JavaScriptGCHandler *param2 = BINDING_DATA_FROM_JS(ctx, argv[2]); + JavaScriptGCHandler *param3 = BINDING_DATA_FROM_JS(ctx, argv[3]); + + tmp.basis.rows[0].operator=(*param0->getVector3()); + tmp.basis.rows[1].operator=(*param1->getVector3()); + tmp.basis.rows[2].operator=(*param2->getVector3()); + tmp.origin.operator=(*param3->getVector3()); + } else if (argc == 2) { +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::BASIS, argv[0]), (JS_ThrowTypeError(ctx, "Basis expected for argument 0 of Transform3D(basis, origin)"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[1]), (JS_ThrowTypeError(ctx, "Vector3 expected for argument 1 of Transform3D(basis, origin)"))); +#endif + JavaScriptGCHandler *param0 = BINDING_DATA_FROM_JS(ctx, argv[0]); + JavaScriptGCHandler *param1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + tmp.basis.operator=(*param0->getBasis()); + tmp.origin.operator=(*param1->getVector3()); + } else if (argc == 1) { + if (JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0])) { + if (bind->type == Variant::TRANSFORM3D) { + tmp.operator=(*bind->getTransform3D()); + } else if (Variant::can_convert(bind->type, Variant::TRANSFORM3D)) { + tmp.operator=(bind->get_value()); + } + } + } +""", + "PackedByteArray": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedByteArray", + "type": "Variant::PACKED_BYTE_ARRAY", + "element": "uint8_t", + }, + ), + "PackedInt32Array": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedInt32Array", + "type": "Variant::PACKED_INT32_ARRAY", + "element": "int32_t", + }, + ), + "PackedInt64Array": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedInt64Array", + "type": "Variant::PACKED_INT64_ARRAY", + "element": "int64_t", + }, + ), + "PackedFloat32Array": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedFloat32Array", + "type": "Variant::PACKED32_FLOAT_ARRAY", + "element": "real_t", + }, + ), + "PackedFloat64Array": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedFloat64Array", + "type": "Variant::PACKED64_FLOAT_ARRAY", + "element": "real_t", + }, + ), + "PackedVector2Array": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedVector2Array", + "type": "Variant::PACKED_VECTOR2_ARRAY", + "element": "Vector2", + }, + ), + "PackedVector3Array": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedVector3Array", + "type": "Variant::PACKED_VECTOR3_ARRAY", + "element": "Vector3", + }, + ), + "PackedColorArray": apply_pattern( + TemplatePackedArrays, + { + "class": "PackedColorArray", + "type": "Variant::PACKED_COLOR_ARRAY", + "element": "Color", + }, + ), + "PackedStringArray": apply_pattern( + TemplateSimplePackedArrays, + { + "class": "PackedStringArray", + "type": "Variant::PACKED_STRING_ARRAY", + "element": "String", + }, + ), + } + class_name = cls["name"] + constructor_name = apply_pattern(TemplateConstructorName, {"class": class_name}) + constructor_declare = apply_pattern(TemplateConstructorDeclare, {"class": class_name}) + + initializer = "" + if class_name in ConstructorInitializers: + initializer = ConstructorInitializers[class_name] + constructor = apply_pattern( + TemplateConstructor, + { + "class": class_name, + "type": VariantTypes[class_name], + "func": constructor_name, + "initializer": initializer, + }, + ) + return constructor_name, constructor_declare, constructor + + +def generate_property_bindings(cls): + class_name = cls["name"] + TemplateDeclar = "static void bind_${class}_properties(JSContext *octx);\n" + TemplateBind = "\tbind_${class}_properties(ctx);\n" + + def generate_members(cls): + Template = """ + JSCFunctionMagic *getter = [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) -> JSValue { + JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); + const ${class} *ptr = bind->get${class}(); + switch (magic) {\ +${getters} + } + return JS_UNDEFINED; + }; + + JSCFunctionMagic *setter = [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) -> JSValue { + JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); + ${class} *ptr = bind->get${class}();\ +${validation} + switch (magic) {\ +${setters} + } + return JS_DupValue(ctx, argv[0]); + }; +${bindings} + """ + TemplateGetterItem = """ + case ${index}: + return ${value};""" + TemplateSetterItem = """ + case ${index}: +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[0]), (JS_ThrowTypeError(ctx, "${type_name} expected for ${class}.${name}"))); +#endif + ptr->${native} = ${value}; + break;""" + TemplateItemBinding = ( + '\tbinder->get_builtin_binder().register_property(${type}, "${name}", getter, setter, ${index});\n' + ) + getters = "" + setters = "" + bindings = "" + for i in range(len(cls["properties"])): + p = cls["properties"][i] + type = p["type"] + name = p["name"] + native_name = p["native"] + getters += apply_pattern( + TemplateGetterItem, + { + "index": str(i), + "value": apply_pattern( + GodotToJSTemplates[type], + {"arg": apply_pattern("ptr->${native}", {"native": native_name})}, + ), + }, + ) + setters += apply_pattern( + TemplateSetterItem, + { + "index": str(i), + "name": name, + "native": native_name, + "type": VariantTypes[type], + "type_name": type, + "class": class_name, + "value": apply_pattern(JSToGodotTemplates[type], {"arg": "argv[0]"}), + }, + ) + bindings += apply_pattern( + TemplateItemBinding, + {"index": str(i), "name": name, "type": VariantTypes[class_name]}, + ) + return apply_pattern( + Template, + { + "class": class_name, + "getters": getters, + "setters": setters, + "bindings": bindings, + "validation": "", + }, + ) + + def generate_methods(cls): + TemplateMethod = """ + binder->get_builtin_binder().register_method( + ${type}, + "${name}", + [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); + ${class} *ptr = bind->get${class}();\ + ${arg_declares} + ${call} + return ${return}; + }, + ${argc});""" + TemplateArgDeclare = """ + #ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[${index}]), JS_ThrowTypeError(ctx, "${type_name} expected for argument ${index} of ${class}.${name}")); + #endif + const ${godot_type} &arg${index} = ${arg}; + """ + TemplateReturnValue = "${godot_type} ret = " + bindings = "" + for m in cls["methods"]: + args = "" + arg_declares = "" + for i in range(len(m["arguments"])): + arg = m["arguments"][i] + arg_type = arg["type"] + arg_declares += apply_pattern( + TemplateArgDeclare, + { + "index": str(i), + "type": VariantTypes[arg_type], + "type_name": arg_type, + "class": class_name, + "name": m["name"], + "arg": apply_pattern( + JSToGodotTemplates[arg_type], + {"arg": "argv[" + str(i) + "]"}, + ), + "godot_type": GodotTypeNames[arg_type], + }, + ) + if i > 0: + args += ", " + args += "arg" + str(i) + CallTemplate = ( + "" + if m["return"] == "void" + else (apply_pattern(TemplateReturnValue, {"godot_type": GodotTypeNames[m["return"]]})) + ) + "ptr->${native_method}(${args});" + call = apply_pattern(CallTemplate, {"native_method": m["native_method"], "args": args}) + bindings += apply_pattern( + TemplateMethod, + { + "class": class_name, + "type": VariantTypes[class_name], + "name": m["name"], + "call": call, + "arg_declares": arg_declares, + "argc": str(len(m["arguments"])), + "return": "JS_UNDEFINED" + if m["return"] == "void" + else apply_pattern(GodotToJSTemplates[m["return"]], {"arg": "ret"}), + }, + ) + return bindings + + def generate_constants(cls): + ConstTemplate = '\tbinder->get_builtin_binder().register_constant(${type}, "${name}", ${value});\n' + bindings = "" + for c in cls["constants"]: + bindings += apply_pattern( + ConstTemplate, + { + "name": c["name"], + "type": VariantTypes[class_name], + "value": c["value"], + }, + ) + return bindings + + def genertate_operators(cls): + OperatorMap = { + "operator+": "+", + "operator-": "-", + "operator*": "*", + "operator/": "/", + "operator==": "==", + "operator<": "<", + } + TargetDeclareTemplate = """ +#ifdef DEBUG_METHODS_ENABLED + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[1]), (JS_ThrowTypeError(ctx, "${target_class} expected for ${class}.${operator}"))); +#endif + JavaScriptGCHandler *bind1 = BINDING_DATA_FROM_JS(ctx, argv[1]); + ${target_class} *target = bind1->get${target_class}();\ +""" + OperatorTemplate = """ + JS_SetPropertyStr(octx, base_operators, "${js_op}", + JS_NewCFunction(octx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0]); + ${class} *ptr = bind->get${class}();\ +${target_declare} + ${call} + return ${return}; + }, + "${name}", + ${argc}) + ); + """ + TemplateReturnValue = "${godot_type} ret = " + bindings = """\ + Vector operators; + JSValue base_operators = JS_NewObject(octx); +""" + for o in cls["operators"]: + op = o["native_method"] + if op in OperatorMap: + argc = len(o["arguments"]) + 1 + js_op = OperatorMap[op] + if argc <= 1: + if op in ["operator-"]: + js_op = "neg" + + args = "" + target_declare = "" + if argc > 1: + arg_class = o["arguments"][0]["type"] + target_declare = apply_pattern( + TargetDeclareTemplate, + { + "target_class": arg_class, + "type": VariantTypes[arg_class], + "class": class_name, + "operator": o["native_method"], + }, + ) + args = "*target" + CallTemplate = ( + "" + if o["return"] == "void" + else apply_pattern(TemplateReturnValue, {"godot_type": GodotTypeNames[o["return"]]}) + ) + "ptr->${op}(${args});" + call = apply_pattern(CallTemplate, {"op": op, "args": args}) + bindings += apply_pattern( + OperatorTemplate, + { + "type": VariantTypes[class_name], + "class": class_name, + "js_op": js_op, + "call": call, + "name": o["name"], + "target_declare": target_declare, + "return": "JS_UNDEFINED" + if o["return"] == "void" + else apply_pattern(GodotToJSTemplates[o["return"]], {"arg": "ret"}), + "argc": str(argc), + }, + ) + bindings += apply_pattern( + """ + operators.push_back(base_operators); + binder->get_builtin_binder().get_cross_type_operators(${type}, operators); + binder->get_builtin_binder().register_operators(${type}, operators); +""", + {"type": VariantTypes[class_name]}, + ) + return bindings + + TemplateBindDefine = """ +static void bind_${class}_properties(JSContext *octx) { + QuickJSBinder *binder = QuickJSBinder::get_context_binder(octx); +${members} +${operators} +${constants} +${methods} +} +""" + class_name = cls["name"] + property_declare = apply_pattern(TemplateDeclar, {"class": class_name}) + property_defines = apply_pattern( + TemplateBindDefine, + { + "class": class_name, + "members": generate_members(cls) if len(cls["properties"]) else "", + "methods": generate_methods(cls), + "constants": generate_constants(cls), + "operators": genertate_operators(cls), + }, + ) + property_bind = apply_pattern(TemplateBind, {"class": class_name}) + return property_declare, property_defines, property_bind + + +def generate_class_bind_action(cls, constructor): + Template = '\tregister_builtin_class(${type}, "${class}", ${constructor}, ${argc});\n' + return apply_pattern( + Template, + { + "class": cls["name"], + "constructor": constructor, + "type": VariantTypes[cls["name"]], + "argc": str(cls["constructor_argc"]), + }, + ) + + +def generate_builtin_bindings(): + Template = """\ +#include "core/variant/variant.h" + +#include "quickjs_builtin_binder.h" +#include "quickjs_worker.h" + +#ifndef inf +#define inf INFINITY +#endif + +${declarations} + +void QuickJSBuiltinBinder::bind_builtin_classes_gen() { + +${bindings} +} + +${definitions} +""" + + declarations = "" + definitions = "" + bindings = "" + for cls in API: + constructor_name, constructor_declare, constructor = generate_constructor(cls) + declarations += constructor_declare + definitions += constructor + bindings += generate_class_bind_action(cls, constructor_name) + + property_declare, property_defines, property_bind = generate_property_bindings(cls) + declarations += property_declare + definitions += property_defines + bindings += property_bind + + output = apply_pattern( + Template, + { + "declarations": declarations, + "bindings": bindings, + "definitions": definitions, + }, + ) + file = open(OUTPUT_FILE, "w") + file.write(output) + + +if __name__ == "__main__": + generate_builtin_bindings() diff --git a/quickjs/quickjs/VERSION.txt b/thirdparty/quickjs/quickjs/VERSION.txt similarity index 100% rename from quickjs/quickjs/VERSION.txt rename to thirdparty/quickjs/quickjs/VERSION.txt diff --git a/quickjs/quickjs/cutils.c b/thirdparty/quickjs/quickjs/cutils.c similarity index 99% rename from quickjs/quickjs/cutils.c rename to thirdparty/quickjs/quickjs/cutils.c index a02fb768..94dde37b 100644 --- a/quickjs/quickjs/cutils.c +++ b/thirdparty/quickjs/quickjs/cutils.c @@ -1,6 +1,6 @@ /* * C utilities - * + * * Copyright (c) 2017 Fabrice Bellard * Copyright (c) 2018 Charlie Gordon * @@ -166,13 +166,12 @@ int dbuf_putstr(DynBuf *s, const char *str) return dbuf_put(s, (const uint8_t *)str, strlen(str)); } -int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, - const char *fmt, ...) +int dbuf_printf(DynBuf *s, const char *fmt, ...) { va_list ap; char buf[128]; int len; - + va_start(ap, fmt); len = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); diff --git a/quickjs/quickjs/cutils.h b/thirdparty/quickjs/quickjs/cutils.h similarity index 84% rename from quickjs/quickjs/cutils.h rename to thirdparty/quickjs/quickjs/cutils.h index 31f7cd84..09be07a9 100644 --- a/quickjs/quickjs/cutils.h +++ b/thirdparty/quickjs/quickjs/cutils.h @@ -1,6 +1,6 @@ /* * C utilities - * + * * Copyright (c) 2017 Fabrice Bellard * Copyright (c) 2018 Charlie Gordon * @@ -31,11 +31,19 @@ /* set if CPU is big endian */ #undef WORDS_BIGENDIAN +#if defined(_MSC_VER) || !defined(__MINGW32__) +#define likely(x) (x) +#define unlikely(x) (x) +#define force_inline __forceinline +#define no_inline __declspec(noinline) +#define __maybe_unused __pragma(warning(suppress: 4100)) +#else #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #define force_inline inline __attribute__((always_inline)) #define no_inline __attribute__((noinline)) #define __maybe_unused __attribute__((unused)) +#endif #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -135,18 +143,35 @@ static inline int ctz64(uint64_t a) return __builtin_ctzll(a); } -struct __attribute__((packed)) packed_u64 { - uint64_t v; -}; - -struct __attribute__((packed)) packed_u32 { - uint32_t v; -}; - -struct __attribute__((packed)) packed_u16 { - uint16_t v; -}; - +#ifdef _MSC_VER +#pragma pack(push, 1) + struct packed_u64 { + uint64_t v; + }; +#pragma pack(pop) + +#pragma pack(push, 1) + struct packed_u32 { + uint32_t v; + }; +#pragma pack(pop) + +#pragma pack(push, 1) + struct packed_u16 { + uint16_t v; + }; + #pragma pack(pop) +#else + struct __attribute__((packed)) packed_u64 { + uint64_t v; + }; + struct __attribute__((packed)) packed_u32 { + uint32_t v; + }; + struct __attribute__((packed)) packed_u16 { + uint16_t v; + }; +#endif static inline uint64_t get_u64(const uint8_t *tab) { return ((const struct packed_u64 *)tab)->v; @@ -220,13 +245,13 @@ static inline uint32_t bswap32(uint32_t v) static inline uint64_t bswap64(uint64_t v) { - return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | - ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | - ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | - ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | - ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | - ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | - ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | + return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | + ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | + ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | + ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | + ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | + ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | + ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); } @@ -262,8 +287,9 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val) { return dbuf_put(s, (uint8_t *)&val, 8); } -int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, - const char *fmt, ...); + +int dbuf_printf(DynBuf *s, const char *fmt, ...); + void dbuf_free(DynBuf *s); static inline BOOL dbuf_error(DynBuf *s) { return s->error; diff --git a/quickjs/quickjs/libbf.c b/thirdparty/quickjs/quickjs/libbf.c similarity index 98% rename from quickjs/quickjs/libbf.c rename to thirdparty/quickjs/quickjs/libbf.c index 3bf257a1..f1cf45b5 100644 --- a/quickjs/quickjs/libbf.c +++ b/thirdparty/quickjs/quickjs/libbf.c @@ -1,6 +1,6 @@ /* * Tiny arbitrary precision floating point library - * + * * Copyright (c) 2017-2020 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -55,8 +55,8 @@ #define UDIV1NORM_THRESHOLD 3 #if LIMB_BITS == 64 -#define FMT_LIMB1 "%" PRIx64 -#define FMT_LIMB "%016" PRIx64 +#define FMT_LIMB1 "%" PRIx64 +#define FMT_LIMB "%016" PRIx64 #define PRId_LIMB PRId64 #define PRIu_LIMB PRIu64 @@ -194,7 +194,7 @@ void bf_init(bf_context_t *s, bf_t *r) int bf_resize(bf_t *r, limb_t len) { limb_t *tab; - + if (len != r->len) { tab = bf_realloc(r->ctx, r->tab, len * sizeof(limb_t)); if (!tab && len != 0) @@ -212,7 +212,7 @@ int bf_set_ui(bf_t *r, uint64_t a) if (a == 0) { r->expn = BF_EXP_ZERO; bf_resize(r, 0); /* cannot fail */ - } + } #if LIMB_BITS == 32 else if (a <= 0xffffffff) #else @@ -374,7 +374,7 @@ static inline limb_t scan_bit_nz(const bf_t *r, slimb_t bit_pos) { slimb_t pos; limb_t v; - + pos = bit_pos >> LIMB_LOG2_BITS; if (pos < 0) return 0; @@ -397,7 +397,7 @@ static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l, { int add_one, inexact; limb_t bit1, bit0; - + if (rnd_mode == BF_RNDF) { bit0 = 1; /* faithful rounding does not honor the INEXACT flag */ } else { @@ -408,7 +408,7 @@ static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l, /* get the bit at 'prec' */ bit1 = get_bit(r->tab, l, l * LIMB_BITS - 1 - prec); inexact = (bit1 | bit0) != 0; - + add_one = 0; switch(rnd_mode) { case BF_RNDZ: @@ -439,7 +439,7 @@ static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l, default: abort(); } - + if (inexact) *pret |= BF_ST_INEXACT; return add_one; @@ -449,7 +449,7 @@ static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags) { slimb_t i, l, e_max; int rnd_mode; - + rnd_mode = flags & BF_RND_MASK; if (prec == BF_PREC_INF || rnd_mode == BF_RNDN || @@ -492,7 +492,7 @@ static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l, e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1); e_min = -e_range + 3; e_max = e_range; - + if (flags & BF_FLAG_RADPNT_PREC) { /* 'prec' is the precision after the radix point */ if (prec1 != BF_PREC_INF) @@ -511,7 +511,7 @@ static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l, /* round to prec bits */ rnd_mode = flags & BF_RND_MASK; add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode); - + if (prec <= 0) { if (add_one) { bf_resize(r, 1); /* cannot fail */ @@ -524,12 +524,12 @@ static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l, } } else if (add_one) { limb_t carry; - + /* add one starting at digit 'prec - 1' */ bit_pos = l * LIMB_BITS - 1 - (prec - 1); pos = bit_pos >> LIMB_LOG2_BITS; carry = (limb_t)1 << (bit_pos & (LIMB_BITS - 1)); - + for(i = pos; i < l; i++) { v = r->tab[i] + carry; carry = (v < carry); @@ -548,7 +548,7 @@ static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l, r->expn++; } } - + /* check underflow */ if (unlikely(r->expn < e_min)) { if (flags & BF_FLAG_SUBNORMAL) { @@ -562,11 +562,11 @@ static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l, return ret; } } - + /* check overflow */ if (unlikely(r->expn > e_max)) return bf_set_overflow(r, r->sign, prec1, flags); - + /* keep the bits starting at 'prec - 1' */ bit_pos = l * LIMB_BITS - 1 - (prec - 1); i = bit_pos >> LIMB_LOG2_BITS; @@ -594,7 +594,7 @@ int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags) limb_t l, v, a; int shift, ret; slimb_t i; - + // bf_print_str("bf_renorm", r); l = r->len; while (l > 0 && r->tab[l - 1] == 0) @@ -633,7 +633,7 @@ int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k) BOOL is_rndn; slimb_t bit_pos, n; limb_t bit; - + if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN) return FALSE; if (rnd_mode == BF_RNDF) { @@ -647,7 +647,7 @@ int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k) bit_pos = a->len * LIMB_BITS - 1 - prec; n = k - prec; /* bit pattern for RNDN or RNDNA: 0111.. or 1000... - for other rounding modes: 000... or 111... + for other rounding modes: 000... or 111... */ bit = get_bit(a->tab, a->len, bit_pos); bit_pos--; @@ -739,7 +739,7 @@ int bf_cmpu(const bf_t *a, const bf_t *b) { slimb_t i; limb_t len, v1, v2; - + if (a->expn != b->expn) { if (a->expn < b->expn) return -1; @@ -764,7 +764,7 @@ int bf_cmpu(const bf_t *a, const bf_t *b) int bf_cmp_full(const bf_t *a, const bf_t *b) { int res; - + if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { if (a->expn == b->expn) res = 0; @@ -788,7 +788,7 @@ int bf_cmp_full(const bf_t *a, const bf_t *b) int bf_cmp(const bf_t *a, const bf_t *b) { int res; - + if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { res = 2; } else if (a->sign != b->sign) { @@ -807,7 +807,7 @@ int bf_cmp(const bf_t *a, const bf_t *b) /* Compute the number of bits 'n' matching the pattern: a= X1000..0 b= X0111..1 - + When computing a-b, the result will have at least n leading zero bits. @@ -922,7 +922,7 @@ static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, } else { cancelled_bits = 0; } - + /* add two extra bits for rounding */ precl = (cancelled_bits + prec + 2 + LIMB_BITS - 1) / LIMB_BITS; tot_len = bf_max(a->len, b->len + (d + LIMB_BITS - 1) / LIMB_BITS); @@ -940,7 +940,7 @@ static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, while (i < 0) { slimb_t ap, bp; BOOL inflag; - + ap = a_offset + i; bp = b_bit_offset + i * LIMB_BITS; inflag = FALSE; @@ -964,7 +964,7 @@ static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, if (ap < 0) i = bf_min(i, -a_offset); /* b_bit_offset + i * LIMB_BITS + LIMB_BITS >= 1 - equivalent to + equivalent to i >= ceil(-b_bit_offset + 1 - LIMB_BITS) / LIMB_BITS) */ if (bp + LIMB_BITS <= 0) @@ -1021,12 +1021,12 @@ static int __bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, return bf_add_internal(r, a, b, prec, flags, 1); } -limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, +limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, limb_t n, limb_t carry) { slimb_t i; limb_t k, a, v, k1; - + k = carry; for(i=0;i> shift. Return the remainder r (0 <= r < 2^shift). +/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). 1 <= shift <= LIMB_BITS - 1 */ -static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, +static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, int shift, limb_t high) { mp_size_t i; @@ -1127,7 +1127,7 @@ static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, } /* tabr[] = taba[] * b + l. Return the high carry */ -static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n, +static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n, limb_t b, limb_t l) { limb_t i; @@ -1147,7 +1147,7 @@ static limb_t mp_add_mul1(limb_t *tabr, const limb_t *taba, limb_t n, { limb_t i, l; dlimb_t t; - + l = 0; for(i = 0; i < n; i++) { t = (dlimb_t)taba[i] * (dlimb_t)b + l + tabr[i]; @@ -1158,12 +1158,12 @@ static limb_t mp_add_mul1(limb_t *tabr, const limb_t *taba, limb_t n, } /* size of the result : op1_size + op2_size. */ -static void mp_mul_basecase(limb_t *result, - const limb_t *op1, limb_t op1_size, - const limb_t *op2, limb_t op2_size) +static void mp_mul_basecase(limb_t *result, + const limb_t *op1, limb_t op1_size, + const limb_t *op2, limb_t op2_size) { limb_t i, r; - + result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0); for(i=1;i= FFT_MUL_THRESHOLD)) { @@ -1200,7 +1200,7 @@ static limb_t mp_sub_mul1(limb_t *tabr, const limb_t *taba, limb_t n, { limb_t i, l; dlimb_t t; - + l = 0; for(i = 0; i < n; i++) { t = tabr[i] - (dlimb_t)taba[i] * (dlimb_t)b - l; @@ -1264,15 +1264,15 @@ static limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n, return r; } -static int mp_divnorm_large(bf_context_t *s, - limb_t *tabq, limb_t *taba, limb_t na, +static int mp_divnorm_large(bf_context_t *s, + limb_t *tabq, limb_t *taba, limb_t na, const limb_t *tabb, limb_t nb); /* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb - 1] must be >= 1 << (LIMB_BITS - 1). na - nb must be >= 0. 'taba' is modified and contains the remainder (nb limbs). tabq[0..na-nb] contains the quotient with tabq[na - nb] <= 1. */ -static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, +static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, const limb_t *tabb, limb_t nb) { limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r; @@ -1287,7 +1287,7 @@ static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, if (bf_min(n, nb) >= DIVNORM_LARGE_THRESHOLD) { return mp_divnorm_large(s, tabq, taba, na, tabb, nb); } - + if (n >= UDIV1NORM_THRESHOLD) b1_inv = udiv1norm_init(b1); else @@ -1306,7 +1306,7 @@ static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, if (q) { mp_sub(taba + n, taba + n, tabb, nb, 0); } - + for(i = n - 1; i >= 0; i--) { if (unlikely(taba[i + nb] >= b1)) { q = -1; @@ -1345,14 +1345,14 @@ static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, /* compute r=B^(2*n)/a such as a*r < B^(2*n) < a*r + 2 with n >= 1. 'a' has n limbs with a[n-1] >= B/2 and 'r' has n+1 limbs with r[n] = 1. - + See Modern Computer Arithmetic by Richard P. Brent and Paul Zimmermann, algorithm 3.5 */ int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n) { mp_size_t l, h, k, i; limb_t *tabxh, *tabt, c, *tabu; - + if (n <= 2) { /* return ceil(B^(2*n)/a) - 1 */ /* XXX: could avoid allocation */ @@ -1430,8 +1430,8 @@ static int mp_cmp(const limb_t *taba, const limb_t *tabb, mp_size_t n) //#define DEBUG_DIVNORM_LARGE2 /* subquadratic divnorm */ -static int mp_divnorm_large(bf_context_t *s, - limb_t *tabq, limb_t *taba, limb_t na, +static int mp_divnorm_large(bf_context_t *s, + limb_t *tabq, limb_t *taba, limb_t na, const limb_t *tabb, limb_t nb) { limb_t *tabb_inv, nq, *tabt, i, n; @@ -1444,7 +1444,7 @@ static int mp_divnorm_large(bf_context_t *s, assert(nq >= 1); n = nq; if (nq < nb) - n++; + n++; tabb_inv = bf_malloc(s, sizeof(limb_t) * (n + 1)); tabt = bf_malloc(s, sizeof(limb_t) * 2 * (n + 1)); if (!tabb_inv || !tabt) @@ -1473,7 +1473,7 @@ static int mp_divnorm_large(bf_context_t *s, /* Q=A*B^-1 */ if (mp_mul(s, tabt, tabb_inv, n + 1, taba + na - (n + 1), n + 1)) goto fail; - + for(i = 0; i < nq + 1; i++) tabq[i] = tabt[i + 2 * (n + 1) - (nq + 1)]; #ifdef DEBUG_DIVNORM_LARGE @@ -1483,7 +1483,7 @@ static int mp_divnorm_large(bf_context_t *s, bf_free(s, tabt); bf_free(s, tabb_inv); tabb_inv = NULL; - + /* R=A-B*Q */ tabt = bf_malloc(s, sizeof(limb_t) * (na + 1)); if (!tabt) @@ -1554,10 +1554,10 @@ int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_t tmp, *r1 = NULL; limb_t a_len, b_len, precl; limb_t *a_tab, *b_tab; - + a_len = a->len; b_len = b->len; - + if ((flags & BF_RND_MASK) == BF_RNDF) { /* faithful rounding does not require using the full inputs */ precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS; @@ -1566,7 +1566,7 @@ int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, } a_tab = a->tab + a->len - a_len; b_tab = b->tab + b->len - b_len; - + #ifdef USE_FFT_MUL if (b_len >= FFT_MUL_THRESHOLD) { int mul_flags = 0; @@ -1622,7 +1622,7 @@ slimb_t bf_get_exp_min(const bf_t *a) slimb_t i; limb_t v; int k; - + for(i = 0; i < a->len; i++) { v = a->tab[i]; if (v != 0) { @@ -1655,7 +1655,7 @@ static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_context_t *s = r->ctx; int ret, r_sign; limb_t n, nb, precl; - + r_sign = a->sign ^ b->sign; if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) { if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { @@ -1688,11 +1688,11 @@ static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS; nb = b->len; n = bf_max(a->len, precl); - + { limb_t *taba, na; slimb_t d; - + na = n + nb; taba = bf_malloc(s, (na + 1) * sizeof(limb_t)); if (!taba) @@ -1721,8 +1721,8 @@ static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, return BF_ST_MEM_ERROR; } -/* division and remainder. - +/* division and remainder. + rnd_mode is the rounding mode for the quotient. The additional rounding mode BF_RND_EUCLIDIAN is supported. @@ -1736,11 +1736,11 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, bf_t b1_s, *b1 = &b1_s; int q_sign, ret; BOOL is_ceil, is_rndn; - + assert(q != a && q != b); assert(r != a && r != b); assert(q != r); - + if (a->len == 0 || b->len == 0) { bf_set_zero(q, 0); if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { @@ -1782,7 +1782,7 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, a1->tab = a->tab; a1->len = a->len; a1->sign = 0; - + b1->expn = b->expn; b1->tab = b->tab; b1->len = b->len; @@ -1828,7 +1828,7 @@ int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, { bf_t q_s, *q = &q_s; int ret; - + bf_init(r->ctx, q); ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode); bf_delete(q); @@ -1849,7 +1849,7 @@ int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, { bf_t q_s, *q = &q_s; int ret; - + bf_init(r->ctx, q); ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode); bf_get_limb(pq, q, BF_GET_INT_MOD); @@ -1887,7 +1887,7 @@ static const uint16_t sqrt_table[192] = { static limb_t mp_sqrtrem1(limb_t *pr, limb_t a) { limb_t s1, r1, s, r, q, u, num; - + /* use a table for the 16 -> 8 bit sqrt */ s1 = sqrt_table[(a >> (LIMB_BITS - 8)) - 64]; r1 = (a >> (LIMB_BITS - 16)) - s1 * s1; @@ -1895,7 +1895,7 @@ static limb_t mp_sqrtrem1(limb_t *pr, limb_t a) r1 -= 2 * s1 + 1; s1++; } - + /* one iteration to get a 32 -> 16 bit sqrt */ num = (r1 << 8) | ((a >> (LIMB_BITS - 32 + 8)) & 0xff); q = num / (2 * s1); /* q <= 2^8 */ @@ -1977,7 +1977,7 @@ static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n, limb_t *tmp_buf, limb_t *prh) { limb_t l, h, rh, ql, qh, c, i; - + if (n == 1) { *prh = mp_sqrtrem2(tabs, taba); return 0; @@ -1994,7 +1994,7 @@ static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n, mp_print_str_h("r1", taba + 2 * l, h, qh); mp_print_str_h("r2", taba + l, n, qh); #endif - + /* the remainder is in taba + 2 * l. Its high bit is in qh */ if (qh) { mp_sub(taba + 2 * l, taba + 2 * l, tabs + l, h, 0); @@ -2016,12 +2016,12 @@ static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n, mp_print_str_h("q", tabs, l, qh); mp_print_str_h("u", taba + l, h, rh); #endif - + mp_add_ui(tabs + l, qh, h); #ifdef DEBUG_SQRTREM mp_print_str_h("s2", tabs, n, sh); #endif - + /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */ /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */ if (qh) { @@ -2073,7 +2073,7 @@ int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n) int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a) { int ret; - + if (a->len == 0) { if (a->expn == BF_EXP_NAN) { bf_set_nan(r); @@ -2093,7 +2093,7 @@ int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a) ret = BF_ST_INVALID_OP; } else { bf_t rem_s, *rem; - + bf_sqrt(r, a, (a->expn + 1) / 2, BF_RNDZ); bf_rint(r, BF_RNDZ); /* see if the result is exact by computing the remainder */ @@ -2147,7 +2147,7 @@ int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) limb_t *a1; slimb_t n, n1; limb_t res; - + /* convert the mantissa to an integer with at least 2 * prec + 4 bits */ n = (2 * (prec + 2) + 2 * LIMB_BITS - 1) / (2 * LIMB_BITS); @@ -2192,7 +2192,7 @@ static no_inline int bf_op2(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, { bf_t tmp; int ret; - + if (r == a || r == b) { bf_init(r->ctx, &tmp); ret = func(&tmp, a, b, prec, flags); @@ -2250,7 +2250,7 @@ int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, { bf_t b; int ret; - + bf_init(r->ctx, &b); ret = bf_set_si(&b, b1); ret |= bf_add(r, a, &b, prec, flags); @@ -2262,7 +2262,7 @@ static int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec, bf_flags_t flags) { int ret, n_bits, i; - + assert(r != a); if (b == 0) return bf_set_ui(r, 1); @@ -2281,7 +2281,7 @@ static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b, { bf_t a; int ret; - + if (a1 == 10 && b <= LIMB_DIGITS) { /* use precomputed powers. We do not round at this point because we expect the caller to do it */ @@ -2326,7 +2326,7 @@ static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op) slimb_t l, i, a_bit_offset, b_bit_offset; limb_t v1, v2, v1_mask, v2_mask, r_mask; int ret; - + assert(r != a1 && r != b1); if (a1->expn <= 0) @@ -2338,7 +2338,7 @@ static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op) b_sign = 0; /* minus zero is considered as positive */ else b_sign = b1->sign; - + if (a_sign) { a = &a1_s; bf_init(r->ctx, a); @@ -2358,7 +2358,7 @@ static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op) } else { b = (bf_t *)b1; } - + r_sign = bf_logic_op1(a_sign, b_sign, op); if (op == BF_LOGIC_AND && r_sign == 0) { /* no need to compute extra zeros for and */ @@ -2435,13 +2435,13 @@ int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode) Float64Union u; int e, ret; uint64_t m; - + ret = 0; if (a->expn == BF_EXP_NAN) { u.u = 0x7ff8000000000000; /* quiet nan */ } else { bf_t b_s, *b = &b_s; - + bf_init(a->ctx, b); bf_set(b, a); if (bf_is_finite(b)) { @@ -2484,7 +2484,7 @@ int bf_set_float64(bf_t *a, double d) Float64Union u; uint64_t m; int shift, e, sgn; - + u.d = d; sgn = u.u >> 63; e = (u.u >> 52) & ((1 << 11) - 1); @@ -2555,7 +2555,7 @@ int bf_get_int32(int *pres, const bf_t *a, int flags) ret = BF_ST_INVALID_OP; if (a->sign) { v = (uint32_t)INT32_MAX + 1; - if (a->expn == 32 && + if (a->expn == 32 && (a->tab[a->len - 1] >> (LIMB_BITS - 32)) == v) { ret = 0; } @@ -2563,7 +2563,7 @@ int bf_get_int32(int *pres, const bf_t *a, int flags) v = INT32_MAX; } } else { - v = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); + v = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); if (a->sign) v = -v; ret = 0; @@ -2621,7 +2621,7 @@ int bf_get_int64(int64_t *pres, const bf_t *a, int flags) } } else { slimb_t bit_pos = a->len * LIMB_BITS - a->expn; - v = get_bits(a->tab, a->len, bit_pos); + v = get_bits(a->tab, a->len, bit_pos); #if LIMB_BITS == 32 v |= (uint64_t)get_bits(a->tab, a->len, bit_pos + 32) << 32; #endif @@ -2681,7 +2681,7 @@ static limb_t get_limb_radix(int radix) { int i, k; limb_t radixl; - + k = digits_per_limb_table[radix - 2]; radixl = radix; for(i = 1; i < k; i++) @@ -2700,7 +2700,7 @@ static int bf_integer_from_radix_rec(bf_t *r, const limb_t *tab, } else { bf_t T_s, *T = &T_s, *B; limb_t n1, n2; - + n2 = (((n0 * 2) >> (level + 1)) + 1) / 2; n1 = n - n2; // printf("level=%d n0=%ld n1=%ld n2=%ld\n", level, n0, n1, n2); @@ -2736,7 +2736,7 @@ static int bf_integer_from_radix(bf_t *r, const limb_t *tab, int pow_tab_len, i, ret; limb_t radixl; bf_t *pow_tab; - + radixl = get_limb_radix(radix); pow_tab_len = ceil_log2(n) + 2; /* XXX: check */ pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len); @@ -2885,7 +2885,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, slimb_t pos, expn, int_len, digit_count; BOOL has_decpt, is_bin_exp; bf_t a_s, *a; - + *pexponent = 0; p = str; if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 && @@ -2895,7 +2895,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, goto done; } is_neg = 0; - + if (p[0] == '+') { p++; p_start = p; @@ -2938,7 +2938,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, goto done; } } - + if (radix == 0) radix = 10; if (is_dec) { @@ -3029,7 +3029,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, goto done; } } - + /* reset the next limbs to zero (we prefer to reallocate in the renormalization) */ memset(a->tab, 0, (pos + 1) * sizeof(limb_t)); @@ -3087,7 +3087,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, } else if (radix_bits) { /* XXX: may overflow */ if (!is_bin_exp) - expn *= radix_bits; + expn *= radix_bits; a->expn = expn + (int_len * radix_bits); a->sign = is_neg; ret = bf_normalize_and_round(a, prec, flags); @@ -3126,9 +3126,9 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, return ret; } -/* +/* Return (status, n, exp). 'status' is the floating point status. 'n' - is the parsed number. + is the parsed number. If (flags & BF_ATOF_EXPONENT) and if the radix is not a power of two, the parsed number is equal to r * @@ -3343,7 +3343,7 @@ slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, const uint32_t *tab; limb_t b0, b1; dlimb_t t; - + if (is_inv) { tab = inv_log2_radix[radix - 2]; #if LIMB_BITS == 32 @@ -3377,7 +3377,7 @@ static int bf_integer_to_radix_rec(bf_t *pow_tab, { limb_t n1, n2, q_prec; int ret; - + assert(n >= 1); if (n == 1) { out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); @@ -3417,7 +3417,7 @@ static int bf_integer_to_radix_rec(bf_t *pow_tab, q_prec = n1 * radixl_bits; ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN); ret |= bf_rint(&Q, BF_RNDZ); - + ret |= bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ); ret |= bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ); @@ -3462,7 +3462,7 @@ static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl) limb_t r_len; bf_t *pow_tab; int i, pow_tab_len, ret; - + r_len = r->len; pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */ pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len); @@ -3492,7 +3492,7 @@ static int bf_convert_to_radix(bf_t *r, slimb_t *pE, slimb_t E, e, prec, extra_bits, ziv_extra_bits, prec0; bf_t B_s, *B = &B_s; int e_sign, ret, res; - + if (a->len == 0) { /* zero case */ *pE = 0; @@ -3507,7 +3507,7 @@ static int bf_convert_to_radix(bf_t *r, slimb_t *pE, } // bf_print_str("a", a); // printf("E=%ld P=%ld radix=%d\n", E, P, radix); - + for(;;) { e = P - E; e_sign = 0; @@ -3703,7 +3703,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, bf_context_t *ctx = a2->ctx; DynBuf s_s, *s = &s_s; int radix_bits; - + // bf_print_str("ftoa", a2); // printf("radix=%d\n", radix); dbuf_init2(s, ctx, bf_dbuf_realloc); @@ -3785,7 +3785,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, a->len = a2->len; a->expn = a2->expn; a->sign = 0; - + /* one more digit for the rounding */ n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE); n_digits = n + prec; @@ -3860,19 +3860,19 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, n = ceil_div(a1->expn, radix_bits); } else { bf_t a_s, *a = &a_s; - + /* make a positive number */ a->tab = a2->tab; a->len = a2->len; a->expn = a2->expn; a->sign = 0; - + if (fmt == BF_FTOA_FORMAT_FIXED) { n_digits = prec; n_max = n_digits; } else { slimb_t n_digits_max, n_digits_min; - + assert(prec != BF_PREC_INF); n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE); /* max number of digits for non exponential @@ -3881,7 +3881,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, n_max = n_digits + 4; if (fmt == BF_FTOA_FORMAT_FREE_MIN) { bf_t b_s, *b = &b_s; - + /* find the minimum number of digits by dichotomy. */ /* XXX: inefficient */ @@ -4020,7 +4020,7 @@ static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1, bf_t T1_s, *T1 = &T1_s; bf_t P1_s, *P1 = &P1_s; bf_t Q1_s, *Q1 = &Q1_s; - + m = n1 + ((n2 - n1) >> 1); bf_const_log2_rec(T, P, Q, n1, m, TRUE); bf_init(s, T1); @@ -4071,7 +4071,7 @@ static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g, if (a == (b - 1)) { bf_t T0, T1; - + bf_init(s, &T0); bf_init(s, &T1); bf_set_ui(G, 2 * b - 1); @@ -4092,7 +4092,7 @@ static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g, bf_delete(&T1); } else { bf_t P2, Q2, G2; - + bf_init(s, &P2); bf_init(s, &Q2); bf_init(s, &G2); @@ -4100,7 +4100,7 @@ static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g, c = (a + b) / 2; chud_bs(P, Q, G, a, c, 1, prec); chud_bs(&P2, &Q2, &G2, c, b, need_g, prec); - + /* Q = Q1 * Q2 */ /* G = G1 * G2 */ /* P = P1 * Q2 + P2 * G1 */ @@ -4136,11 +4136,11 @@ static void bf_const_pi_internal(bf_t *Q, limb_t prec) bf_init(s, &G); chud_bs(&P, Q, &G, 0, n, 0, BF_PREC_INF); - + bf_mul_ui(&G, Q, CHUD_A, prec1, BF_RNDN); bf_add(&P, &G, &P, prec1, BF_RNDN); bf_div(Q, Q, &P, prec1, BF_RNDF); - + bf_set_ui(&P, CHUD_C); bf_sqrt(&G, &P, prec1, BF_RNDF); bf_mul_ui(&G, &G, (uint64_t)CHUD_C / 12, prec1, BF_RNDF); @@ -4223,7 +4223,7 @@ static int bf_ziv_rounding(bf_t *r, const bf_t *a, { int rnd_mode, ret; slimb_t prec1, ziv_extra_bits; - + rnd_mode = flags & BF_RND_MASK; if (rnd_mode == BF_RNDF) { /* no need to iterate */ @@ -4282,7 +4282,7 @@ static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) bf_context_t *s = r->ctx; bf_t T_s, *T = &T_s; slimb_t n, K, l, i, prec1; - + assert(r != a); /* argument reduction: @@ -4315,14 +4315,14 @@ static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) /* reduce the range of T */ bf_mul_2exp(T, -K, BF_PREC_INF, BF_RNDZ); - + /* Taylor expansion around zero : - 1 + x + x^2/2 + ... + x^n/n! + 1 + x + x^2/2 + ... + x^n/n! = (1 + x * (1 + x/2 * (1 + ... (x/n)))) */ { bf_t U_s, *U = &U_s; - + bf_init(s, U); bf_set_ui(r, 1); for(i = l ; i >= 1; i--) { @@ -4334,7 +4334,7 @@ static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) bf_delete(U); } bf_delete(T); - + /* undo the range reduction */ for(i = 0; i < K; i++) { bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP); @@ -4354,7 +4354,7 @@ static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r, bf_t T_s, *T = &T_s; bf_t log2_s, *log2 = &log2_s; slimb_t e_min, e_max; - + if (a_high->expn <= 0) return 0; @@ -4362,7 +4362,7 @@ static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r, e_min = -e_max + 3; if (flags & BF_FLAG_SUBNORMAL) e_min -= (prec - 1); - + bf_init(s, T); bf_init(s, log2); bf_const_log2(log2, LIMB_BITS, BF_RNDU); @@ -4379,7 +4379,7 @@ static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r, bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD); if (bf_cmp_lt(a_high, T)) { int rnd_mode = flags & BF_RND_MASK; - + /* underflow */ bf_delete(T); bf_delete(log2); @@ -4419,12 +4419,12 @@ int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) ret = check_exp_underflow_overflow(s, r, a, a, prec, flags); if (ret) return ret; - if (a->expn < 0 && (-a->expn) >= (prec + 2)) { + if (a->expn < 0 && (-a->expn) >= (prec + 2)) { /* small argument case: result = 1 + epsilon * sign(x) */ bf_set_ui(r, 1); return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags); } - + return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL); } @@ -4435,7 +4435,7 @@ static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) bf_t U_s, *U = &U_s; bf_t V_s, *V = &V_s; slimb_t n, prec1, l, i, K; - + assert(r != a); bf_init(s, T); @@ -4448,7 +4448,7 @@ static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) T->expn = 0; /* U= ~ 2/3 */ bf_init(s, U); - bf_set_ui(U, 0xaaaaaaaa); + bf_set_ui(U, 0xaaaaaaaa); U->expn = 0; if (bf_cmp_lt(T, U)) { T->expn++; @@ -4461,18 +4461,18 @@ static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) /* XXX: precision analysis */ /* number of iterations for argument reduction 2 */ - K = bf_isqrt((prec + 1) / 2); + K = bf_isqrt((prec + 1) / 2); /* order of Taylor expansion */ - l = prec / (2 * K) + 1; + l = prec / (2 * K) + 1; /* precision of the intermediate computations */ prec1 = prec + K + 2 * l + 32; bf_init(s, U); bf_init(s, V); - + /* Note: cancellation occurs here, so we use more precision (XXX: reduce the precision by computing the exact cancellation) */ - bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN); + bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN); /* argument reduction 2 */ for(i = 0; i < K; i++) { @@ -4490,7 +4490,7 @@ static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) bf_init(s, Y2); /* compute ln(1+x) = ln((1+y)/(1-y)) with y=x/(2+x) - = y + y^3/3 + ... + y^(2*l + 1) / (2*l+1) + = y + y^3/3 + ... + y^(2*l + 1) / (2*l+1) with Y=Y^2 = y*(1+Y/3+Y^2/5+...) = y*(1+Y*(1/3+Y*(1/5 + ...))) */ @@ -4517,12 +4517,12 @@ static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) /* multiplication by 2 for the Taylor expansion and undo the argument reduction 2*/ bf_mul_2exp(r, K + 1, BF_PREC_INF, BF_RNDZ); - + /* undo the argument reduction 1 */ bf_const_log2(T, prec1, BF_RNDF); bf_mul_si(T, T, n, prec1, BF_RNDN); bf_add(r, r, T, prec1, BF_RNDN); - + bf_delete(T); return BF_ST_INEXACT; } @@ -4531,7 +4531,7 @@ int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) { bf_context_t *s = r->ctx; bf_t T_s, *T = &T_s; - + assert(r != a); if (a->len == 0) { if (a->expn == BF_EXP_NAN) { @@ -4596,7 +4596,7 @@ static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque) limb_t prec1; int ret; slimb_t y1; - + bf_get_limb(&y1, y, 0); if (y1 < 0) y1 = -y1; @@ -4621,7 +4621,7 @@ static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n) bf_t T_s, *T = &T_s; slimb_t e, i, er; limb_t v; - + /* x = m*2^e with m odd integer */ e = bf_get_exp_min(x); /* fast check on the exponent */ @@ -4661,7 +4661,7 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) BOOL y_is_int, y_is_odd; int r_sign, ret, rnd_mode; slimb_t y_emin; - + if (x->len == 0 || y->len == 0) { if (y->expn == BF_EXP_ZERO) { /* pow(x, 0) = 1 */ @@ -4735,7 +4735,7 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) bf_t al_s, *al = &al_s; bf_t ah_s, *ah = &ah_s; limb_t precl = LIMB_BITS; - + bf_init(s, al); bf_init(s, ah); /* compute bounds of log(abs(x)) * y with a low precision */ @@ -4751,7 +4751,7 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) if (ret) goto done; } - + if (y_is_int) { slimb_t T_bits, e; int_pow: @@ -4846,18 +4846,18 @@ static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) bf_t r_s, *r = &r_s; slimb_t K, prec1, i, l, mod, prec2; int is_neg; - + assert(c != a && s != a); bf_init(s1, T); bf_init(s1, U); bf_init(s1, r); - + /* XXX: precision analysis */ K = bf_isqrt(prec / 2); l = prec / (2 * K) + 1; prec1 = prec + 2 * K + l + 8; - + /* after the modulo reduction, -pi/4 <= T <= pi/4 */ if (a->expn <= -1) { /* abs(a) <= 0.25: no modulo reduction needed */ @@ -4880,13 +4880,13 @@ static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) } mod &= 3; } - + is_neg = T->sign; - + /* compute cosm1(x) = cos(x) - 1 */ bf_mul(T, T, T, prec1, BF_RNDN); bf_mul_2exp(T, -2 * K, BF_PREC_INF, BF_RNDZ); - + /* Taylor expansion: -x^2/2 + x^4/4! - x^6/6! + ... */ @@ -4965,7 +4965,7 @@ int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) return bf_add_epsilon(r, r, e, 1, prec, flags); } } - + return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL); } @@ -5008,7 +5008,7 @@ static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) bf_context_t *s = r->ctx; bf_t T_s, *T = &T_s; limb_t prec1; - + /* XXX: precision analysis */ prec1 = prec + 8; bf_init(s, T); @@ -5044,7 +5044,7 @@ int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) return bf_add_epsilon(r, r, e, a->sign, prec, flags); } } - + return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL); } @@ -5061,13 +5061,13 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, bf_t X2_s, *X2 = &X2_s; int cmp_1; slimb_t prec1, i, K, l; - + /* XXX: precision analysis */ K = bf_isqrt((prec + 1) / 2); l = prec / (2 * K) + 1; prec1 = prec + K + 2 * l + 32; // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1); - + bf_init(s, T); cmp_1 = (a->expn >= 1); /* a >= 1 */ if (cmp_1) { @@ -5093,8 +5093,8 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, bf_div(T, T, V, prec1, BF_RNDN); } - /* Taylor series: - x - x^3/3 + ... + (-1)^ l * y^(2*l + 1) / (2*l+1) + /* Taylor series: + x - x^3/3 + ... + (-1)^ l * y^(2*l + 1) / (2*l+1) */ bf_mul(X2, T, T, prec1, BF_RNDN); bf_set_ui(r, 0); @@ -5112,7 +5112,7 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, /* undo the argument reduction */ bf_mul_2exp(r, K, BF_PREC_INF, BF_RNDZ); - + bf_delete(U); bf_delete(V); bf_delete(X2); @@ -5131,7 +5131,7 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, T->sign = (i < 0); bf_add(r, T, r, prec1, BF_RNDN); } - + bf_delete(T); return BF_ST_INEXACT; } @@ -5141,7 +5141,7 @@ int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) bf_context_t *s = r->ctx; bf_t T_s, *T = &T_s; int res; - + if (a->len == 0) { if (a->expn == BF_EXP_NAN) { bf_set_nan(r); @@ -5156,7 +5156,7 @@ int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) return 0; } } - + bf_init(s, T); bf_set_ui(T, 1); res = bf_cmpu(a, T); @@ -5178,7 +5178,7 @@ int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags); } } - + return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE); } @@ -5189,7 +5189,7 @@ static int bf_atan2_internal(bf_t *r, const bf_t *y, limb_t prec, void *opaque) bf_t T_s, *T = &T_s; limb_t prec1; int ret; - + if (y->expn == BF_EXP_NAN || x->expn == BF_EXP_NAN) { bf_set_nan(r); return 0; @@ -5232,8 +5232,8 @@ static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) BOOL is_acos = (BOOL)(intptr_t)opaque; bf_t T_s, *T = &T_s; limb_t prec1, prec2; - - /* asin(x) = atan(x/sqrt(1-x^2)) + + /* asin(x) = atan(x/sqrt(1-x^2)) acos(x) = pi/2 - asin(x) */ prec1 = prec + 8; /* increase the precision in x^2 to compensate the cancellation in @@ -5283,7 +5283,7 @@ int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) bf_set_nan(r); return BF_ST_INVALID_OP; } - + /* small argument case: result = x+r(x) with r(x) = x^3/6 + O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */ if (a->expn < 0) { @@ -5328,7 +5328,7 @@ int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) bf_set_zero(r, 0); return 0; } - + return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE); } @@ -5561,8 +5561,8 @@ static inline limb_t fast_shr_dec(limb_t a, int shift) /* division and remainder by 10^shift */ #define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift] - -limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, + +limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, mp_size_t n, limb_t carry) { limb_t base = BF_DEC_BASE; @@ -5575,7 +5575,7 @@ limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, v = op1[i]; a = v + op2[i] + k - base; k = a <= v; - if (!k) + if (!k) a += base; res[i]=a; } @@ -5593,7 +5593,7 @@ limb_t mp_add_ui_dec(limb_t *tab, limb_t b, mp_size_t n) v = tab[i]; a = v + k - base; k = a <= v; - if (!k) + if (!k) a += base; tab[i] = a; if (k == 0) @@ -5602,7 +5602,7 @@ limb_t mp_add_ui_dec(limb_t *tab, limb_t b, mp_size_t n) return k; } -limb_t mp_sub_dec(limb_t *res, const limb_t *op1, const limb_t *op2, +limb_t mp_sub_dec(limb_t *res, const limb_t *op1, const limb_t *op2, mp_size_t n, limb_t carry) { limb_t base = BF_DEC_BASE; @@ -5626,7 +5626,7 @@ limb_t mp_sub_ui_dec(limb_t *tab, limb_t b, mp_size_t n) limb_t base = BF_DEC_BASE; mp_size_t i; limb_t k, v, a; - + k=b; for(i=0;i= UDIV1NORM_THRESHOLD) { shift = clz(b); @@ -5815,7 +5815,7 @@ static __maybe_unused void mp_print_str_h_dec(const char *str, #define DIV_STATIC_ALLOC_LEN 16 -/* return q = a / b and r = a % b. +/* return q = a / b and r = a % b. taba[na] must be allocated if tabb1[nb - 1] < B / 2. tabb1[nb - 1] must be != zero. na must be >= nb. 's' can be NULL if tabb1[nb - 1] @@ -5829,14 +5829,14 @@ static __maybe_unused void mp_print_str_h_dec(const char *str, */ /* XXX: optimize */ static int mp_div_dec(bf_context_t *s, limb_t *tabq, - limb_t *taba, mp_size_t na, + limb_t *taba, mp_size_t na, const limb_t *tabb1, mp_size_t nb) { limb_t base = BF_DEC_BASE; limb_t r, mult, t0, t1, a, c, q, v, *tabb; mp_size_t i, j; limb_t static_tabb[DIV_STATIC_ALLOC_LEN]; - + #ifdef DEBUG_DIV_SLOW mp_print_str_dec("a", taba, na); mp_print_str_dec("b", tabb1, nb); @@ -5934,7 +5934,7 @@ static int mp_div_dec(bf_context_t *s, limb_t *tabq, } /* divide by 10^shift */ -static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, +static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, limb_t shift, limb_t high) { mp_size_t i; @@ -5952,7 +5952,7 @@ static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, } /* multiply by 10^shift */ -static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, +static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, limb_t shift, limb_t low) { mp_size_t i; @@ -5998,7 +5998,7 @@ static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n, limb_t *tmp_buf) { limb_t l, h, rh, ql, qh, c, i; - + if (n == 1) return mp_sqrtrem2_dec(tabs, taba); #ifdef DEBUG_SQRTREM_DEC @@ -6012,7 +6012,7 @@ static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n, mp_print_str_h_dec("r1", taba + 2 * l, h, qh); mp_print_str_h_dec("r2", taba + l, n, qh); #endif - + /* the remainder is in taba + 2 * l. Its high bit is in qh */ if (qh) { mp_sub_dec(taba + 2 * l, taba + 2 * l, tabs + l, h, 0); @@ -6033,12 +6033,12 @@ static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n, mp_print_str_h_dec("q", tabs, l, qh); mp_print_str_h_dec("u", taba + l, h, rh); #endif - + mp_add_ui_dec(tabs + l, qh, h); #ifdef DEBUG_SQRTREM_DEC mp_print_str_dec("s2", tabs, n); #endif - + /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */ /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */ if (qh) { @@ -6332,7 +6332,7 @@ static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos) limb_t a0, a1; int shift; slimb_t i; - + i = floor_div(pos, LIMB_DIGITS); shift = pos - i * LIMB_DIGITS; if (i >= 0 && i < len) @@ -6360,7 +6360,7 @@ static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l, { int add_one, inexact; limb_t digit1, digit0; - + // bfdec_print_str("get_rnd_add", r); if (rnd_mode == BF_RNDF) { digit0 = 1; /* faithful rounding does not honor the INEXACT flag */ @@ -6372,7 +6372,7 @@ static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l, /* get the digit at 'prec' */ digit1 = get_digit(r->tab, l, l * LIMB_DIGITS - 1 - prec); inexact = (digit1 | digit0) != 0; - + add_one = 0; switch(rnd_mode) { case BF_RNDZ: @@ -6405,7 +6405,7 @@ static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l, default: abort(); } - + if (inexact) *pret |= BF_ST_INEXACT; return add_one; @@ -6425,7 +6425,7 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1); e_min = -e_range + 3; e_max = e_range; - + if (flags & BF_FLAG_RADPNT_PREC) { /* 'prec' is the precision after the decimal point */ if (prec1 != BF_PREC_INF) @@ -6440,12 +6440,12 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) } else { prec = prec1; } - + /* round to prec bits */ rnd_mode = flags & BF_RND_MASK; ret = 0; add_one = bfdec_get_rnd_add(&ret, r, l, prec, rnd_mode); - + if (prec <= 0) { if (add_one) { bfdec_resize(r, 1); /* cannot fail because r is non zero */ @@ -6458,7 +6458,7 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) } } else if (add_one) { limb_t carry; - + /* add one starting at digit 'prec - 1' */ bit_pos = l * LIMB_DIGITS - 1 - (prec - 1); pos = bit_pos / LIMB_DIGITS; @@ -6470,7 +6470,7 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) r->expn++; } } - + /* check underflow */ if (unlikely(r->expn < e_min)) { if (flags & BF_FLAG_SUBNORMAL) { @@ -6484,14 +6484,14 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) return ret; } } - + /* check overflow */ if (unlikely(r->expn > e_max)) { bfdec_set_inf(r, r->sign); ret |= BF_ST_OVERFLOW | BF_ST_INEXACT; return ret; } - + /* keep the bits starting at 'prec - 1' */ bit_pos = l * LIMB_DIGITS - 1 - (prec - 1); i = floor_div(bit_pos, LIMB_DIGITS); @@ -6528,7 +6528,7 @@ int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags) { limb_t l, v; int shift, ret; - + // bfdec_print_str("bf_renorm", r); l = r->len; while (l > 0 && r->tab[l - 1] == 0) @@ -6645,7 +6645,7 @@ static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, li limb_t *b1_tab; int b_shift; mp_size_t b1_len; - + d = a->expn - b->expn; /* XXX: not efficient in time and memory if the precision is @@ -6661,7 +6661,7 @@ static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, li r->tab[i] = 0; for(i = 0; i < a->len; i++) r->tab[a_offset + i] = a->tab[i]; - + b_shift = d % LIMB_DIGITS; if (b_shift == 0) { b1_len = b->len; @@ -6675,7 +6675,7 @@ static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, li mp_pow_dec[LIMB_DIGITS - b_shift]; } b_offset = r_len - (b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS); - + if (is_sub) { carry = mp_sub_dec(r->tab + b_offset, r->tab + b_offset, b1_tab, b1_len, 0); @@ -6771,12 +6771,12 @@ int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, bfdec_t tmp, *r1 = NULL; limb_t a_len, b_len; limb_t *a_tab, *b_tab; - + a_len = a->len; b_len = b->len; a_tab = a->tab; b_tab = b->tab; - + if (r == a || r == b) { bfdec_init(r->ctx, &tmp); r1 = r; @@ -6815,7 +6815,7 @@ int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec, { bfdec_t b; int ret; - + bfdec_init(r->ctx, &b); ret = bfdec_set_si(&b, b1); ret |= bfdec_add(r, a, &b, prec, flags); @@ -6828,7 +6828,7 @@ static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, { int ret, r_sign; limb_t n, nb, precl; - + r_sign = a->sign ^ b->sign; if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) { if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { @@ -6873,11 +6873,11 @@ static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS; } n = bf_max(a->len, precl); - + { limb_t *taba, na, i; slimb_t d; - + na = n + nb; taba = bf_malloc(r->ctx, (na + 1) * sizeof(limb_t)); if (!taba) @@ -6938,8 +6938,8 @@ static void bfdec_tdivremu(bf_context_t *s, bfdec_t *q, bfdec_t *r, } } -/* division and remainder. - +/* division and remainder. + rnd_mode is the rounding mode for the quotient. The additional rounding mode BF_RND_EUCLIDIAN is supported. @@ -6955,11 +6955,11 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, bfdec_t r1_s, *r1 = &r1_s; int q_sign, res; BOOL is_ceil, is_rndn; - + assert(q != a && q != b); assert(r != a && r != b); assert(q != r); - + if (a->len == 0 || b->len == 0) { bfdec_set_zero(q, 0); if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) { @@ -7001,7 +7001,7 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, a1->tab = a->tab; a1->len = a->len; a1->sign = 0; - + b1->expn = b->expn; b1->tab = b->tab; b1->len = b->len; @@ -7015,7 +7015,7 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, goto fail; // bfdec_print_str("q", q); // bfdec_print_str("r", r); - + if (r->len != 0) { if (is_rndn) { bfdec_init(s, r1); @@ -7056,7 +7056,7 @@ int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, { bfdec_t q_s, *q = &q_s; int ret; - + bfdec_init(r->ctx, q); ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode); bfdec_delete(q); @@ -7204,7 +7204,7 @@ int bfdec_get_int32(int *pres, const bfdec_t *a) int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b) { int ret, n_bits, i; - + assert(r != a); if (b == 0) return bfdec_set_ui(r, 1); @@ -7344,7 +7344,7 @@ static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = { typedef struct BFNTTState { bf_context_t *ctx; - + /* used for mul_mod_fast() */ limb_t ntt_mods_div[NB_MODS]; @@ -7384,16 +7384,16 @@ static inline limb_t sub_mod(limb_t a, limb_t b, limb_t m) return r; } -/* return (r0+r1*B) mod m - precondition: 0 <= r0+r1*B < 2^(64+NTT_MOD_LOG2_MIN) +/* return (r0+r1*B) mod m + precondition: 0 <= r0+r1*B < 2^(64+NTT_MOD_LOG2_MIN) */ -static inline limb_t mod_fast(dlimb_t r, +static inline limb_t mod_fast(dlimb_t r, limb_t m, limb_t m_inv) { limb_t a1, q, t0, r1, r0; - + a1 = r >> NTT_MOD_LOG2_MIN; - + q = ((dlimb_t)a1 * m_inv) >> LIMB_BITS; r = r - (dlimb_t)q * m - m * 2; r1 = r >> LIMB_BITS; @@ -7405,9 +7405,9 @@ static inline limb_t mod_fast(dlimb_t r, return r0; } -/* faster version using precomputed modulo inverse. +/* faster version using precomputed modulo inverse. precondition: 0 <= a * b < 2^(64+NTT_MOD_LOG2_MIN) */ -static inline limb_t mul_mod_fast(limb_t a, limb_t b, +static inline limb_t mul_mod_fast(limb_t a, limb_t b, limb_t m, limb_t m_inv) { dlimb_t r; @@ -7426,7 +7426,7 @@ static inline limb_t init_mul_mod_fast(limb_t m) /* Faster version used when the multiplier is constant. 0 <= a < 2^64, 0 <= b < m. */ -static inline limb_t mul_mod_fast2(limb_t a, limb_t b, +static inline limb_t mul_mod_fast2(limb_t a, limb_t b, limb_t m, limb_t b_inv) { limb_t r, q; @@ -7441,7 +7441,7 @@ static inline limb_t mul_mod_fast2(limb_t a, limb_t b, /* Faster version used when the multiplier is constant. 0 <= a < 2^64, 0 <= b < m. Let r = a * b mod m. The return value is 'r' or 'r + m'. */ -static inline limb_t mul_mod_fast3(limb_t a, limb_t b, +static inline limb_t mul_mod_fast3(limb_t a, limb_t b, limb_t m, limb_t b_inv) { limb_t r, q; @@ -7547,9 +7547,9 @@ static no_inline int ntt_fft(BFNTTState *s, __m256d m_inv, mf, m2f, c, a0, a1, b0, b1; limb_t m; int l; - + m = ntt_mods[m_idx]; - + m_inv = _mm256_set1_pd(1.0 / (double)m); mf = _mm256_set1_pd(m); m2f = _mm256_set1_pd(m * 2); @@ -7603,7 +7603,7 @@ static no_inline int ntt_fft(BFNTTState *s, tmp = tab_in; tab_in = tab_out; tab_out = tmp; - + nb_blocks = n / 4; fft_per_block = 4; @@ -7654,7 +7654,7 @@ static void ntt_vec_mul(BFNTTState *s, { limb_t i, c_inv, n, m; __m256d m_inv, mf, a, b, c; - + m = ntt_mods[m_idx]; c_inv = s->ntt_len_inv[m_idx][k_tot][0]; m_inv = _mm256_set1_pd(1.0 / (double)m); @@ -7676,7 +7676,7 @@ static no_inline void mul_trig(NTTLimb *buf, limb_t i, c2, c3, c4; __m256d c, c_mul, a0, mf, m_inv; assert(n >= 2); - + mf = _mm256_set1_pd(m); m_inv = _mm256_set1_pd(1.0 / (double)m); @@ -7725,7 +7725,7 @@ static no_inline int ntt_fft(BFNTTState *s, NTTLimb *out_buf, NTTLimb *in_buf, limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j, m, m2; NTTLimb *tab_in, *tab_out, *tmp, a0, a1, b0, b1, c, *trig, c_inv; int l; - + m = ntt_mods[m_idx]; m2 = 2 * m; n = (limb_t)1 << fft_len_log2; @@ -7765,7 +7765,7 @@ static no_inline int ntt_fft(BFNTTState *s, NTTLimb *out_buf, NTTLimb *in_buf, tab_out = tmp; } /* no twiddle in last step */ - tab_out = out_buf; + tab_out = out_buf; for(k = 0; k < stride_in; k++) { a0 = tab_in[k]; a1 = tab_in[k + stride_in]; @@ -7782,7 +7782,7 @@ static void ntt_vec_mul(BFNTTState *s, int k_tot, int m_idx) { limb_t i, norm, norm_inv, a, n, m, m_inv; - + m = ntt_mods[m_idx]; m_inv = s->ntt_mods_div[m_idx]; norm = s->ntt_len_inv[m_idx][k_tot][0]; @@ -7804,7 +7804,7 @@ static no_inline void mul_trig(NTTLimb *buf, limb_t n, limb_t c_mul, limb_t m, limb_t m_inv) { limb_t i, c0, c_mul_inv; - + c0 = 1; c_mul_inv = init_mul_mod_fast2(c_mul, m); for(i = 0; i < n; i++) { @@ -7820,7 +7820,7 @@ static no_inline NTTLimb *get_trig(BFNTTState *s, { NTTLimb *tab; limb_t i, n2, c, c_mul, m, c_mul_inv; - + if (k > NTT_TRIG_K_MAX) return NULL; @@ -7885,7 +7885,7 @@ static int ntt_fft_partial(BFNTTState *s, NTTLimb *buf1, { limb_t i, j, c_mul, c0, m, m_inv, strip_len, l; NTTLimb *buf2, *buf3; - + buf2 = NULL; buf3 = ntt_malloc(s, sizeof(NTTLimb) * n1); if (!buf3) @@ -7918,7 +7918,7 @@ static int ntt_fft_partial(BFNTTState *s, NTTLimb *buf1, mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv); c_mul = mul_mod_fast(c_mul, c0, m, m_inv); } - + for(i = 0; i < n1; i++) { for(l = 0; l < strip_len; l++) { buf1[i * n2 + (j + l)] = buf2[i + l *n1]; @@ -7942,7 +7942,7 @@ static int ntt_conv(BFNTTState *s, NTTLimb *buf1, NTTLimb *buf2, { limb_t n1, n2, i; int k1, k2; - + if (k <= NTT_TRIG_K_MAX) { k1 = k; } else { @@ -7952,7 +7952,7 @@ static int ntt_conv(BFNTTState *s, NTTLimb *buf1, NTTLimb *buf2, k2 = k - k1; n1 = (limb_t)1 << k1; n2 = (limb_t)1 << k2; - + if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 0, m_idx)) return -1; if (ntt_fft_partial(s, buf2, k1, k2, n1, n2, 0, m_idx)) @@ -7979,13 +7979,13 @@ static no_inline void limb_to_ntt(BFNTTState *s, dlimb_t a, b; int j, shift; limb_t base_mask1, a0, a1, a2, r, m, m_inv; - + #if 0 for(i = 0; i < a_len; i++) { printf("%" PRId64 ": " FMT_LIMB "\n", (int64_t)i, taba[i]); } -#endif +#endif memset(tabr, 0, sizeof(NTTLimb) * fft_len * nb_mods); shift = dpl & (LIMB_BITS - 1); if (shift == 0) @@ -8050,21 +8050,21 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, slimb_t i, len, pos; int j, k, l, shift, n_limb1, p; dlimb_t t; - + j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2; mods_cr_vec = s->ntt_mods_cr_vec + j; mf = s->ntt_mods_vec + NB_MODS - nb_mods; m_inv = s->ntt_mods_inv_vec + NB_MODS - nb_mods; - + shift = dpl & (LIMB_BITS - 1); if (shift == 0) base_mask1 = -1; else base_mask1 = ((limb_t)1 << shift) - 1; n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS; - for(j = 0; j < NB_MODS; j++) + for(j = 0; j < NB_MODS; j++) carry[j] = 0; - for(j = 0; j < NB_MODS; j++) + for(j = 0; j < NB_MODS; j++) u[j] = 0; /* avoid warnings */ memset(tabr, 0, sizeof(limb_t) * r_len); fft_len = (limb_t)1 << fft_len_log2; @@ -8086,7 +8086,7 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, } } y[j].v = ntt_mod1(y[j].v, mf[j]); - + for(p = 0; p < VEC_LEN; p++) { /* back to normal representation */ u[0] = (int64_t)y[nb_mods - 1].d[p]; @@ -8102,7 +8102,7 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, l++; } /* XXX: for nb_mods = 5, l should be 4 */ - + /* last step adds the carry */ r = (int64_t)y[0].d[p]; for(k = 0; k < l; k++) { @@ -8119,7 +8119,7 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, } printf("\n"); #endif - + /* write the digits */ pos = i * dpl; for(j = 0; j < n_limb1; j++) { @@ -8153,7 +8153,7 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, slimb_t i, len, pos; int j, k, l, shift, n_limb1; dlimb_t t; - + j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2; mods_cr = ntt_mods_cr + j; mods_cr_inv = s->ntt_mods_cr_inv + j; @@ -8164,9 +8164,9 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, else base_mask1 = ((limb_t)1 << shift) - 1; n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS; - for(j = 0; j < NB_MODS; j++) + for(j = 0; j < NB_MODS; j++) carry[j] = 0; - for(j = 0; j < NB_MODS; j++) + for(j = 0; j < NB_MODS; j++) u[j] = 0; /* avoid warnings */ memset(tabr, 0, sizeof(limb_t) * r_len); fft_len = (limb_t)1 << fft_len_log2; @@ -8184,12 +8184,12 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, m = mods[k]; /* Note: there is no overflow in the sub_mod() because the modulos are sorted by increasing order */ - y[k] = mul_mod_fast2(y[k] - y[j] + m, + y[k] = mul_mod_fast2(y[k] - y[j] + m, mods_cr[l], m, mods_cr_inv[l]); l++; } } - + /* back to normal representation */ u[0] = y[nb_mods - 1]; l = 1; @@ -8203,7 +8203,7 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, u[l] = r; l++; } - + /* last step adds the carry */ r = y[0]; for(k = 0; k < l; k++) { @@ -8220,7 +8220,7 @@ static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len, } printf("\n"); #endif - + /* write the digits */ pos = i * dpl; for(j = 0; j < n_limb1; j++) { @@ -8261,7 +8261,7 @@ static int ntt_static_init(bf_context_t *s1) memset(s, 0, sizeof(*s)); s1->ntt_state = s; s->ctx = s1; - + for(j = 0; j < NB_MODS; j++) { m = ntt_mods[j]; m_inv = init_mul_mod_fast(m); @@ -8310,7 +8310,7 @@ int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len) int dpl, fft_len_log2, n_bits, nb_mods, dpl_found, fft_len_log2_found; int int_bits, nb_mods_found; limb_t cost, min_cost; - + min_cost = -1; dpl_found = 0; nb_mods_found = 4; @@ -8366,11 +8366,11 @@ static no_inline int fft_mul(bf_context_t *s1, #if defined(USE_MUL_CHECK) limb_t ha, hb, hr, h_ref; #endif - + if (ntt_static_init(s1)) return -1; s = s1->ntt_state; - + /* find the optimal number of digits per limb (dpl) */ len = a_len + b_len; fft_len_log2 = bf_get_fft_size(&dpl, &nb_mods, len); @@ -8398,7 +8398,7 @@ static no_inline int fft_mul(bf_context_t *s1, return -1; limb_to_ntt(s, buf1, fft_len, a_tab, a_len, dpl, NB_MODS - nb_mods, nb_mods); - if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == + if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == FFT_MUL_R_OVERLAP_A) { if (!(mul_flags & FFT_MUL_R_NORESIZE)) bf_resize(res, 0); @@ -8448,7 +8448,7 @@ static no_inline int fft_mul(bf_context_t *s1, // printf("ha=0x" FMT_LIMB" hb=0x" FMT_LIMB " hr=0x" FMT_LIMB " expected=0x" FMT_LIMB "\n", ha, hb, hr, h_ref); exit(1); } -#endif +#endif return 0; fail: ntt_free(s, buf1); diff --git a/quickjs/quickjs/libbf.h b/thirdparty/quickjs/quickjs/libbf.h similarity index 98% rename from quickjs/quickjs/libbf.h rename to thirdparty/quickjs/quickjs/libbf.h index 6749b35c..3396e86e 100644 --- a/quickjs/quickjs/libbf.h +++ b/thirdparty/quickjs/quickjs/libbf.h @@ -1,6 +1,6 @@ /* * Tiny arbitrary precision floating point library - * + * * Copyright (c) 2017-2020 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -171,7 +171,7 @@ static inline bf_flags_t bf_set_exp_bits(int n) #define BF_ST_UNDERFLOW (1 << 3) #define BF_ST_INEXACT (1 << 4) /* indicate that a memory allocation error occured. NaN is returned */ -#define BF_ST_MEM_ERROR (1 << 5) +#define BF_ST_MEM_ERROR (1 << 5) #define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */ @@ -284,7 +284,7 @@ int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags) int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags); -int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, +int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags); int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); @@ -341,12 +341,12 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, /* fractional format: prec digits after the decimal point rounded with (flags & BF_RND_MASK) */ #define BF_FTOA_FORMAT_FRAC (1 << 16) -/* free format: - +/* free format: + For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum number of digits to represent 'a'. The precision and the rounding mode are ignored. - + For the non binary radices with bf_ftoa(): use as many digits as necessary so that bf_atof() return the same number when using precision 'prec', rounding to nearest and the subnormal @@ -373,7 +373,7 @@ char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec, bf_flags_t flags); /* modulo 2^n instead of saturation. NaN and infinity return 0 */ -#define BF_GET_INT_MOD (1 << 0) +#define BF_GET_INT_MOD (1 << 0) int bf_get_int32(int *pres, const bf_t *a, int flags); int bf_get_int64(int64_t *pres, const bf_t *a, int flags); int bf_get_uint64(uint64_t *pres, const bf_t *a); @@ -387,10 +387,10 @@ int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags); int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k); slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, int is_ceil1); -int mp_mul(bf_context_t *s, limb_t *result, - const limb_t *op1, limb_t op1_size, +int mp_mul(bf_context_t *s, limb_t *result, + const limb_t *op1, limb_t op1_size, const limb_t *op2, limb_t op2_size); -limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, +limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, limb_t n, limb_t carry); limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n); int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n); diff --git a/quickjs/quickjs/libregexp-opcode.h b/thirdparty/quickjs/quickjs/libregexp-opcode.h similarity index 99% rename from quickjs/quickjs/libregexp-opcode.h rename to thirdparty/quickjs/quickjs/libregexp-opcode.h index f90c23b3..cd3683f6 100644 --- a/quickjs/quickjs/libregexp-opcode.h +++ b/thirdparty/quickjs/quickjs/libregexp-opcode.h @@ -1,6 +1,6 @@ /* * Regular Expression Engine - * + * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/quickjs/quickjs/libregexp.c b/thirdparty/quickjs/quickjs/libregexp.c similarity index 99% rename from quickjs/quickjs/libregexp.c rename to thirdparty/quickjs/quickjs/libregexp.c index bbb5e9d7..1bac3e51 100644 --- a/quickjs/quickjs/libregexp.c +++ b/thirdparty/quickjs/quickjs/libregexp.c @@ -1,6 +1,6 @@ /* * Regular Expression Engine - * + * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -226,7 +226,7 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c) BOOL invert; const uint16_t *c_pt; int len, i; - + invert = c & 1; c_pt = char_range_table[c >> 1]; len = *c_pt++; @@ -276,7 +276,7 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, { int pos, len, opcode, bc_len, re_flags, i; uint32_t val; - + assert(buf_len >= RE_HEADER_LEN); re_flags= buf[0]; @@ -427,7 +427,16 @@ static void re_emit_op_u16(REParseState *s, int op, uint32_t val) dbuf_put_u16(&s->byte_code, val); } -static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s, const char *fmt, ...) +#include +#include + +#ifdef _MSC_VER +#define ATTRIBUTE_FORMAT_PRINTF _Printf_format_string_ +#else +#define ATTRIBUTE_FORMAT_PRINTF __attribute__((format(printf, 2, 3))) +#endif + +static int ATTRIBUTE_FORMAT_PRINTF re_parse_error(REParseState *s, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -448,7 +457,7 @@ static int parse_digits(const uint8_t **pp, BOOL allow_overflow) const uint8_t *p; uint64_t v; int c; - + p = *pp; v = 0; for(;;) { @@ -520,7 +529,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16) { int h, n, i; uint32_t c1; - + if (*p == '{' && allow_utf16) { p++; c = 0; @@ -714,7 +723,7 @@ static int get_class_atom(REParseState *s, CharRange *cr, const uint8_t *p; uint32_t c; int ret; - + p = *pp; c = *p; @@ -822,7 +831,7 @@ static int re_emit_range(REParseState *s, const CharRange *cr) { int len, i; uint32_t high; - + len = (unsigned)cr->len / 2; if (len >= 65535) return re_parse_error(s, "too many ranges"); @@ -863,7 +872,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) CharRange cr_s, *cr = &cr_s; CharRange cr1_s, *cr1 = &cr1_s; BOOL invert; - + cr_init(cr, s->mem_opaque, lre_realloc); p = *pp; p++; /* skip '[' */ @@ -953,12 +962,12 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len) uint32_t val, last; BOOL has_back_reference; uint8_t capture_bitmap[CAPTURE_COUNT_MAX]; - + ret = -2; /* not known yet */ pos = 0; has_back_reference = FALSE; memset(capture_bitmap, 0, sizeof(capture_bitmap)); - + while (pos < bc_buf_len) { opcode = bc_buf[pos]; len = reopcode_info[opcode].size; @@ -1035,7 +1044,7 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len) { int pos, opcode, len, count; uint32_t val; - + count = 0; pos = 0; while (pos < bc_buf_len) { @@ -1190,7 +1199,7 @@ static int find_group_name(REParseState *s, const char *name) const char *p, *buf_end; size_t len, name_len; int capture_index; - + name_len = strlen(name); p = (char *)s->group_names.buf; buf_end = (char *)s->group_names.buf + s->group_names.size; @@ -1213,7 +1222,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) int c, last_atom_start, quant_min, quant_max, last_capture_count; BOOL greedy, add_zero_advance_check, is_neg, is_backward_lookahead; CharRange cr_s, *cr = &cr_s; - + last_atom_start = -1; last_capture_count = 0; p = s->buf_ptr; @@ -1336,15 +1345,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) capture_index = s->capture_count++; re_emit_op_u8(s, REOP_save_start + is_backward_dir, capture_index); - + s->buf_ptr = p; if (re_parse_disjunction(s, is_backward_dir)) return -1; p = s->buf_ptr; - + re_emit_op_u8(s, REOP_save_start + 1 - is_backward_dir, capture_index); - + if (re_parse_expect(s, &p, ')')) return -1; } @@ -1360,7 +1369,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) { const uint8_t *p1; int dummy_res; - + p1 = p; if (p1[2] != '<') { /* annex B: we tolerate invalid group names in non @@ -1413,10 +1422,10 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) goto normal_char; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': - case '9': + case '9': { const uint8_t *q = ++p; - + c = parse_digits(&p, FALSE); if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) { if (!s->is_utf16) { @@ -1557,7 +1566,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } if (greedy) { int len, pos; - + if (quant_max > 0) { /* specific optimization for simple quantifiers */ if (dbuf_error(&s->byte_code)) @@ -1566,7 +1575,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) s->byte_code.size - last_atom_start); if (len > 0) { re_emit_op(s, REOP_match); - + if (dbuf_insert(&s->byte_code, last_atom_start, 17)) goto out_of_memory; pos = last_atom_start; @@ -1583,7 +1592,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) goto done; } } - + if (dbuf_error(&s->byte_code)) goto out_of_memory; add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start, @@ -1591,7 +1600,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } else { add_zero_advance_check = FALSE; } - + { int len, pos; len = s->byte_code.size - last_atom_start; @@ -1626,7 +1635,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) atom (only works if the atom has no side effect) */ s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos; - re_emit_goto(s, REOP_bne_char_pos, last_atom_start); + re_emit_goto(s, REOP_bne_char_pos, last_atom_start); } else { re_emit_goto(s, REOP_goto, last_atom_start); } @@ -1677,7 +1686,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) re_emit_op_u32(s, REOP_split_goto_first + greedy, len + 5); /* copy the atom */ dbuf_put_self(&s->byte_code, last_atom_start, len); - + re_emit_goto(s, REOP_loop, pos); re_emit_op(s, REOP_drop); } @@ -1729,7 +1738,7 @@ static int re_parse_alternative(REParseState *s, BOOL is_backward_dir) } return 0; } - + static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir) { int start, len, pos; @@ -1753,7 +1762,7 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir) if (re_parse_alternative(s, is_backward_dir)) return -1; - + /* patch the goto */ len = s->byte_code.size - (pos + 4); put_u32(s->byte_code.buf + pos, len); @@ -1766,7 +1775,7 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) { int stack_size, stack_size_max, pos, opcode, len; uint32_t val; - + stack_size = 0; stack_size_max = 0; bc_buf += RE_HEADER_LEN; @@ -1817,7 +1826,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, REParseState s_s, *s = &s_s; int stack_size; BOOL is_sticky; - + memset(s, 0, sizeof(*s)); s->mem_opaque = opaque; s->buf_ptr = (const uint8_t *)buf; @@ -1831,7 +1840,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, s->capture_count = 1; s->total_capture_count = -1; s->has_named_captures = -1; - + dbuf_init2(&s->byte_code, opaque, lre_realloc); dbuf_init2(&s->group_names, opaque, lre_realloc); @@ -1839,7 +1848,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */ dbuf_putc(&s->byte_code, 0); /* stack size */ dbuf_put_u32(&s->byte_code, 0); /* bytecode length */ - + if (!is_sticky) { /* iterate thru all positions (about the same as .*?( ... ) ) . We do it without an explicit loop so that lock step @@ -1861,7 +1870,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, } re_emit_op_u8(s, REOP_save_end, 0); - + re_emit_op(s, REOP_match); if (*s->buf_ptr != '\0') { @@ -1873,13 +1882,13 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, re_parse_out_of_memory(s); goto error; } - + stack_size = compute_stack_size(s->byte_code.buf, s->byte_code.size); if (stack_size < 0) { re_parse_error(s, "too many imbricated quantifiers"); goto error; } - + s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count; s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size; put_u32(s->byte_code.buf + 3, s->byte_code.size - RE_HEADER_LEN); @@ -1890,11 +1899,11 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, s->byte_code.buf[RE_HEADER_FLAGS] |= LRE_FLAG_NAMED_GROUPS; } dbuf_free(&s->group_names); - + #ifdef DUMP_REOP lre_dump_bytecode(s->byte_code.buf, s->byte_code.size); #endif - + error_msg[0] = '\0'; *plen = s->byte_code.size; return s->byte_code.buf; @@ -2025,7 +2034,7 @@ typedef struct { const uint8_t *cbuf; const uint8_t *cbuf_end; /* 0 = 8 bit chars, 1 = 16 bit chars, 2 = 16 bit chars, UTF-16 */ - int cbuf_type; + int cbuf_type; int capture_count; int stack_size_max; BOOL multi_line; @@ -2087,7 +2096,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, int cbuf_type; uint32_t val, c; const uint8_t *cbuf_end; - + cbuf_type = s->cbuf_type; cbuf_end = s->cbuf_end; @@ -2185,7 +2194,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, case REOP_split_next_first: { const uint8_t *pc1; - + val = get_u32(pc); pc += 4; if (opcode == REOP_split_next_first) { @@ -2211,7 +2220,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, if (ret < 0) return -1; break; - + case REOP_goto: val = get_u32(pc); pc += 4 + (int)val; @@ -2317,7 +2326,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, { const uint8_t *cptr1, *cptr1_end, *cptr1_start; uint32_t c1, c2; - + val = *pc++; if (val >= s->capture_count) goto no_match; @@ -2360,7 +2369,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, { int n; uint32_t low, high, idx_min, idx_max, idx; - + n = get_u16(pc); /* n must be >= 1 */ pc += 2; if (cptr >= cbuf_end) @@ -2400,7 +2409,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, { int n; uint32_t low, high, idx_min, idx_max, idx; - + n = get_u16(pc); /* n must be >= 1 */ pc += 2; if (cptr >= cbuf_end) @@ -2445,14 +2454,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, size_t q; intptr_t res; const uint8_t *pc1; - + next_pos = get_u32(pc); quant_min = get_u32(pc + 4); quant_max = get_u32(pc + 8); pc += 16; pc1 = pc; pc += (int)next_pos; - + q = 0; for(;;) { res = lre_exec_backtrack(s, capture, stack, stack_len, @@ -2495,7 +2504,7 @@ int lre_exec(uint8_t **capture, REExecContext s_s, *s = &s_s; int re_flags, i, alloca_size, ret; StackInt *stack_buf; - + re_flags = bc_buf[RE_HEADER_FLAGS]; s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0; s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0; @@ -2515,7 +2524,7 @@ int lre_exec(uint8_t **capture, s->state_stack = NULL; s->state_stack_len = 0; s->state_stack_size = 0; - + for(i = 0; i < s->capture_count * 2; i++) capture[i] = NULL; alloca_size = s->stack_size_max * sizeof(stack_buf[0]); @@ -2567,7 +2576,7 @@ int main(int argc, char **argv) uint8_t *capture[CAPTURE_COUNT_MAX * 2]; const char *input; int input_len, capture_count; - + if (argc < 3) { printf("usage: %s regexp input\n", argv[0]); exit(1); @@ -2581,7 +2590,7 @@ int main(int argc, char **argv) input = argv[2]; input_len = strlen(input); - + ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL); printf("ret=%d\n", ret); if (ret == 1) { diff --git a/quickjs/quickjs/libregexp.h b/thirdparty/quickjs/quickjs/libregexp.h similarity index 99% rename from quickjs/quickjs/libregexp.h rename to thirdparty/quickjs/quickjs/libregexp.h index 9aedb7e9..cbf339e4 100644 --- a/quickjs/quickjs/libregexp.h +++ b/thirdparty/quickjs/quickjs/libregexp.h @@ -1,6 +1,6 @@ /* * Regular Expression Engine - * + * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -53,7 +53,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16); LRE_BOOL lre_is_space(int c); /* must be provided by the user */ -LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size); +LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size); void *lre_realloc(void *opaque, void *ptr, size_t size); /* JS identifier test */ diff --git a/quickjs/quickjs/libunicode-table.h b/thirdparty/quickjs/quickjs/libunicode-table.h similarity index 100% rename from quickjs/quickjs/libunicode-table.h rename to thirdparty/quickjs/quickjs/libunicode-table.h diff --git a/quickjs/quickjs/libunicode.c b/thirdparty/quickjs/quickjs/libunicode.c similarity index 99% rename from quickjs/quickjs/libunicode.c rename to thirdparty/quickjs/quickjs/libunicode.c index 63c12a07..91d131ad 100644 --- a/quickjs/quickjs/libunicode.c +++ b/thirdparty/quickjs/quickjs/libunicode.c @@ -1,6 +1,6 @@ /* * Unicode utilities - * + * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -49,9 +49,9 @@ enum { }; /* conv_type: - 0 = to upper + 0 = to upper 1 = to lower - 2 = case folding (= to lower with modifications) + 2 = case folding (= to lower with modifications) */ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) { @@ -68,7 +68,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) } else { uint32_t v, code, data, type, len, a, is_lower; int idx, idx_min, idx_max; - + is_lower = (conv_type != 0); idx_min = 0; idx_max = countof(case_conv_table1) - 1; @@ -208,7 +208,7 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, uint32_t code, b, bit; int pos; const uint8_t *p; - + pos = get_index_pos(&code, c, index_table, index_table_len); if (pos < 0) return FALSE; /* outside the table */ @@ -241,7 +241,7 @@ BOOL lre_is_cased(uint32_t c) { uint32_t v, code, len; int idx, idx_min, idx_max; - + idx_min = 0; idx_max = countof(case_conv_table1) - 1; while (idx_min <= idx_max) { @@ -300,7 +300,7 @@ int cr_realloc(CharRange *cr, int size) { int new_size; uint32_t *new_buf; - + if (size > cr->size) { new_size = max_int(size, cr->size * 3 / 2); new_buf = cr->realloc_func(cr->mem_opaque, cr->points, @@ -327,7 +327,7 @@ static void cr_compress(CharRange *cr) { int i, j, k, len; uint32_t *pt; - + pt = cr->points; len = cr->len; i = 0; @@ -357,7 +357,7 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, { int a_idx, b_idx, is_in; uint32_t v; - + a_idx = 0; b_idx = 0; for(;;) { @@ -658,7 +658,7 @@ static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1) { uint32_t v, type, is_compat, code, len; int idx_min, idx_max, idx; - + idx_min = 0; idx_max = countof(unicode_decomp_table1) - 1; while (idx_min <= idx_max) { @@ -688,7 +688,7 @@ static int unicode_compose_pair(uint32_t c0, uint32_t c1) uint32_t code, len, type, v, idx1, d_idx, d_offset, ch; int idx_min, idx_max, idx, d; uint32_t pair[2]; - + idx_min = 0; idx_max = countof(unicode_comp_table) - 1; while (idx_min <= idx_max) { @@ -724,7 +724,7 @@ static int unicode_get_cc(uint32_t c) uint32_t code, n, type, cc, c1, b; int pos; const uint8_t *p; - + pos = get_index_pos(&code, c, unicode_cc_index, sizeof(unicode_cc_index) / 3); if (pos < 0) @@ -773,7 +773,7 @@ static int unicode_get_cc(uint32_t c) static void sort_cc(int *buf, int len) { int i, j, k, cc, cc1, start, ch1; - + for(i = 0; i < len; i++) { cc = unicode_get_cc(buf[i]); if (cc != 0) { @@ -812,7 +812,7 @@ static void to_nfd_rec(DynBuf *dbuf, uint32_t c, v; int i, l; uint32_t res[UNICODE_DECOMP_LEN_MAX]; - + for(i = 0; i < src_len; i++) { c = src[i]; if (c >= 0xac00 && c < 0xd7a4) { @@ -857,7 +857,7 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len; BOOL is_compat; DynBuf dbuf_s, *dbuf = &dbuf_s; - + is_compat = n_type >> 1; dbuf_init2(dbuf, opaque, realloc_func); @@ -885,15 +885,15 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, } buf = (int *)dbuf->buf; buf_len = dbuf->size / sizeof(int); - + sort_cc(buf, buf_len); - + if (buf_len <= 1 || (n_type & 1) != 0) { /* NFD / NFKD */ *pdst = (uint32_t *)buf; return buf_len; } - + i = 1; out_len = 1; while (i < buf_len) { @@ -930,7 +930,7 @@ static int unicode_find_name(const char *name_table, const char *name) const char *p, *r; int pos; size_t name_len, len; - + p = name_table; pos = 0; name_len = strlen(name); @@ -963,13 +963,13 @@ int unicode_script(CharRange *cr, CharRange cr1_s, *cr1; CharRange cr2_s, *cr2 = &cr2_s; BOOL is_common; - + script_idx = unicode_find_name(unicode_script_name_table, script_name); if (script_idx < 0) return -2; /* Note: we remove the "Unknown" Script */ script_idx += UNICODE_SCRIPT_Unknown + 1; - + is_common = (script_idx == UNICODE_SCRIPT_Common || script_idx == UNICODE_SCRIPT_Inherited); if (is_ext) { @@ -1236,7 +1236,7 @@ static int unicode_case1(CharRange *cr, int case_mask) } return 0; } - + typedef enum { POP_GC, POP_PROP, @@ -1256,7 +1256,7 @@ static int unicode_prop_ops(CharRange *cr, ...) CharRange stack[POP_STACK_LEN_MAX]; int stack_len, op, ret, i; uint32_t a; - + va_start(ap, cr); stack_len = 0; for(;;) { @@ -1342,7 +1342,7 @@ int unicode_general_category(CharRange *cr, const char *gc_name) { int gc_idx; uint32_t gc_mask; - + gc_idx = unicode_find_name(unicode_gc_name_table, gc_name); if (gc_idx < 0) return -2; @@ -1360,7 +1360,7 @@ int unicode_general_category(CharRange *cr, const char *gc_name) int unicode_prop(CharRange *cr, const char *prop_name) { int prop_idx, ret; - + prop_idx = unicode_find_name(unicode_prop_name_table, prop_name); if (prop_idx < 0) return -2; diff --git a/quickjs/quickjs/libunicode.h b/thirdparty/quickjs/quickjs/libunicode.h similarity index 99% rename from quickjs/quickjs/libunicode.h rename to thirdparty/quickjs/quickjs/libunicode.h index cfa600a5..0acc2095 100644 --- a/quickjs/quickjs/libunicode.h +++ b/thirdparty/quickjs/quickjs/libunicode.h @@ -1,6 +1,6 @@ /* * Unicode utilities - * + * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/quickjs/quickjs/list.h b/thirdparty/quickjs/quickjs/list.h similarity index 98% rename from quickjs/quickjs/list.h rename to thirdparty/quickjs/quickjs/list.h index 0a1bc5a4..c23193fe 100644 --- a/quickjs/quickjs/list.h +++ b/thirdparty/quickjs/quickjs/list.h @@ -1,6 +1,6 @@ /* * Linux klist like system - * + * * Copyright (c) 2016-2017 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -46,7 +46,7 @@ static inline void init_list_head(struct list_head *head) } /* insert 'el' between 'prev' and 'next' */ -static inline void __list_add(struct list_head *el, +static inline void __list_add(struct list_head *el, struct list_head *prev, struct list_head *next) { prev->next = el; diff --git a/quickjs/quickjs/quickjs-atom.h b/thirdparty/quickjs/quickjs/quickjs-atom.h similarity index 99% rename from quickjs/quickjs/quickjs-atom.h rename to thirdparty/quickjs/quickjs/quickjs-atom.h index a353ad44..5c998674 100644 --- a/quickjs/quickjs/quickjs-atom.h +++ b/thirdparty/quickjs/quickjs/quickjs-atom.h @@ -1,6 +1,6 @@ /* * QuickJS atom definitions - * + * * Copyright (c) 2017-2018 Fabrice Bellard * Copyright (c) 2017-2018 Charlie Gordon * @@ -201,7 +201,7 @@ DEF(RegExp, "RegExp") DEF(ArrayBuffer, "ArrayBuffer") DEF(SharedArrayBuffer, "SharedArrayBuffer") /* must keep same order as class IDs for typed arrays */ -DEF(Uint8ClampedArray, "Uint8ClampedArray") +DEF(Uint8ClampedArray, "Uint8ClampedArray") DEF(Int8Array, "Int8Array") DEF(Uint8Array, "Uint8Array") DEF(Int16Array, "Int16Array") @@ -268,5 +268,5 @@ DEF(Symbol_asyncIterator, "Symbol.asyncIterator") #ifdef CONFIG_BIGNUM DEF(Symbol_operatorSet, "Symbol.operatorSet") #endif - + #endif /* DEF */ diff --git a/quickjs/quickjs/quickjs-debugger.c b/thirdparty/quickjs/quickjs/quickjs-debugger.c similarity index 99% rename from quickjs/quickjs/quickjs-debugger.c rename to thirdparty/quickjs/quickjs/quickjs-debugger.c index c7493f31..f7557064 100644 --- a/quickjs/quickjs/quickjs-debugger.c +++ b/thirdparty/quickjs/quickjs/quickjs-debugger.c @@ -407,7 +407,7 @@ static void js_process_breakpoints(JSDebuggerInfo *info, JSValue message) { JSValue js_debugger_file_breakpoints(JSContext *ctx, const char* path) { JSDebuggerInfo *info = js_debugger_info(JS_GetRuntime(ctx)); JSValue path_data = JS_GetPropertyStr(ctx, info->breakpoints, path); - return path_data; + return path_data; } static int js_process_debugger_messages(JSDebuggerInfo *info, const uint8_t *cur_pc) { @@ -448,7 +448,7 @@ static int js_process_debugger_messages(JSDebuggerInfo *info, const uint8_t *cur if (!js_transport_read_fully(info, info->message_buffer, message_length)) goto done; - + info->message_buffer[message_length] = '\0'; JSValue message = JS_ParseJSON(ctx, info->message_buffer, message_length, ""); @@ -659,7 +659,7 @@ void js_debugger_check(JSContext* ctx, const uint8_t *cur_pc) { if (js_process_debugger_messages(info, cur_pc)) goto done; - fail: + fail: js_debugger_free(JS_GetRuntime(ctx), info); done: info->is_debugging = 0; @@ -730,4 +730,4 @@ int js_debugger_is_transport_connected(JSRuntime *rt) { void js_debugger_cooperate(JSContext *ctx) { js_debugger_info(JS_GetRuntime(ctx))->should_peek = 1; -} \ No newline at end of file +} diff --git a/quickjs/quickjs/quickjs-debugger.h b/thirdparty/quickjs/quickjs/quickjs-debugger.h similarity index 99% rename from quickjs/quickjs/quickjs-debugger.h rename to thirdparty/quickjs/quickjs/quickjs-debugger.h index eba243cf..d3b7787c 100644 --- a/quickjs/quickjs/quickjs-debugger.h +++ b/thirdparty/quickjs/quickjs/quickjs-debugger.h @@ -30,7 +30,7 @@ typedef struct JSDebuggerInfo { // JSContext that is used to for the JSON transport and debugger state. JSContext *ctx; JSContext *debugging_ctx; - + int attempted_connect; int attempted_wait; int peek_ticks; @@ -102,4 +102,4 @@ JSValue js_debugger_evaluate(JSContext *ctx, int stack_index, JSValue expression } #endif -#endif \ No newline at end of file +#endif diff --git a/quickjs/quickjs/quickjs-opcode.h b/thirdparty/quickjs/quickjs/quickjs-opcode.h similarity index 99% rename from quickjs/quickjs/quickjs-opcode.h rename to thirdparty/quickjs/quickjs/quickjs-opcode.h index 387363c3..ea91bd2c 100644 --- a/quickjs/quickjs/quickjs-opcode.h +++ b/thirdparty/quickjs/quickjs/quickjs-opcode.h @@ -1,6 +1,6 @@ /* * QuickJS opcode definitions - * + * * Copyright (c) 2017-2018 Fabrice Bellard * Copyright (c) 2017-2018 Charlie Gordon * @@ -165,14 +165,14 @@ DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */ DEF( get_arg, 3, 0, 1, arg) DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */ DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */ -DEF( get_var_ref, 3, 0, 1, var_ref) +DEF( get_var_ref, 3, 0, 1, var_ref) DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */ DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */ DEF(set_loc_uninitialized, 3, 0, 0, loc) DEF( get_loc_check, 3, 0, 1, loc) DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ DEF( put_loc_check_init, 3, 1, 0, loc) -DEF(get_var_ref_check, 3, 0, 1, var_ref) +DEF(get_var_ref_check, 3, 0, 1, var_ref) DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ DEF(put_var_ref_check_init, 3, 1, 0, var_ref) DEF( close_loc, 3, 0, 0, loc) @@ -262,7 +262,7 @@ DEF( mul_pow10, 1, 2, 1, none) DEF( math_mod, 1, 2, 1, none) #endif /* must be the last non short and non temporary opcode */ -DEF( nop, 1, 0, 0, none) +DEF( nop, 1, 0, 0, none) /* temporary opcodes: never emitted in the final bytecode */ @@ -285,7 +285,7 @@ def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ - + def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ #if SHORT_OPCODES diff --git a/quickjs/quickjs/quickjs.c b/thirdparty/quickjs/quickjs/quickjs.c similarity index 99% rename from quickjs/quickjs/quickjs.c rename to thirdparty/quickjs/quickjs/quickjs.c index 0e01ac1e..99b6be9e 100644 --- a/quickjs/quickjs/quickjs.c +++ b/thirdparty/quickjs/quickjs/quickjs.c @@ -1,6 +1,6 @@ /* * QuickJS Javascript Engine - * + * * Copyright (c) 2017-2020 Fabrice Bellard * Copyright (c) 2017-2020 Charlie Gordon * @@ -197,7 +197,7 @@ typedef enum JSErrorEnum { JS_URI_ERROR, JS_INTERNAL_ERROR, JS_AGGREGATE_ERROR, - + JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ } JSErrorEnum; @@ -260,7 +260,7 @@ struct JSRuntime { by the garbage collector) */ struct list_head gc_obj_list; /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */ - struct list_head gc_zero_ref_count_list; + struct list_head gc_zero_ref_count_list; struct list_head tmp_obj_list; /* used during GC */ JSGCPhaseEnum gc_phase : 8; size_t malloc_gc_threshold; @@ -282,7 +282,7 @@ struct JSRuntime { JSHostPromiseRejectionTracker *host_promise_rejection_tracker; void *host_promise_rejection_tracker_opaque; - + struct list_head job_list; /* list of JSJobEntry.link */ JSModuleNormalizeFunc *module_normalize_func; @@ -292,7 +292,7 @@ struct JSRuntime { BOOL can_block : 8; /* TRUE if Atomics.wait can block */ /* used to allocate, free and clone SharedArrayBuffers */ JSSharedArrayBufferFunctions sab_funcs; - + /* Shape hash table */ int shape_hash_bits; int shape_hash_size; @@ -337,7 +337,7 @@ typedef struct JSStackFrame { int arg_count; int js_mode; /* 0 or JS_MODE_MATH for C functions */ /* only used in generators. Current stack pointer value. NULL if - the function is running. */ + the function is running. */ JSValue *cur_sp; } JSStackFrame; @@ -371,9 +371,9 @@ typedef struct JSVarRef { /* 0 : the JSVarRef is on the stack. header.link is an element of JSStackFrame.var_ref_list. - 1 : the JSVarRef is detached. header.link has the normal meanning + 1 : the JSVarRef is detached. header.link has the normal meanning */ - uint8_t is_detached : 1; + uint8_t is_detached : 1; uint8_t is_arg : 1; uint16_t var_idx; /* index of the corresponding function variable on the stack */ @@ -793,7 +793,7 @@ struct JSModuleDef { BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */ /* true if evaluation yielded an exception. It is saved in eval_exception */ - BOOL eval_has_exception : 8; + BOOL eval_has_exception : 8; JSValue eval_exception; JSValue meta_obj; /* for import.meta */ }; @@ -861,7 +861,7 @@ struct JSObject { struct { int __gc_ref_count; /* corresponds to header.ref_count */ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ - + uint8_t extensible : 1; uint8_t free_mark : 1; /* only used when freeing objects with cycles */ uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */ @@ -921,7 +921,7 @@ struct JSObject { struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ } u1; union { - JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ + JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ void *ptr; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ int8_t *int8_ptr; /* JS_CLASS_INT8_ARRAY */ uint8_t *uint8_ptr; /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */ @@ -1620,7 +1620,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) init_list_head(&rt->gc_obj_list); init_list_head(&rt->gc_zero_ref_count_list); rt->gc_phase = JS_GC_PHASE_NONE; - + #ifdef DUMP_LEAKS init_list_head(&rt->string_list); #endif @@ -2278,7 +2278,7 @@ void JS_FreeContext(JSContext *ctx) if (--ctx->header.ref_count > 0) return; assert(ctx->header.ref_count == 0); - + #ifdef DUMP_ATOMS JS_DumpAtoms(ctx->rt); #endif @@ -3318,7 +3318,7 @@ static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1) const char *cstr; char *cstr2; size_t len, len1; - + str = JS_AtomToString(ctx, name); if (JS_IsException(str)) return JS_ATOM_NULL; @@ -3854,7 +3854,7 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) uint32_t c; StringBuffer b_s, *b = &b_s; size_t len1; - + p_start = (const uint8_t *)buf; p_end = p_start + buf_len; p = p_start; @@ -4346,7 +4346,7 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, sh->prop_size = prop_size; sh->prop_count = 0; sh->deleted_prop_count = 0; - + /* insert in the hash table */ sh->hash = shape_initial_hash(proto); sh->is_hashed = TRUE; @@ -4506,7 +4506,7 @@ static int compact_properties(JSContext *ctx, JSObject *p) uint32_t new_hash_size, i, j, new_hash_mask, new_size; JSShapeProperty *old_pr, *pr; JSProperty *prop, *new_prop; - + sh = p->shape; assert(!sh->is_hashed); @@ -4528,7 +4528,7 @@ static int compact_properties(JSContext *ctx, JSObject *p) list_del(&old_sh->header.link); memcpy(sh, old_sh, sizeof(JSShape)); list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); - + memset(prop_hash_end(sh) - new_hash_size, 0, sizeof(prop_hash_end(sh)[0]) * new_hash_size); @@ -4557,7 +4557,7 @@ static int compact_properties(JSContext *ctx, JSObject *p) p->shape = sh; js_free(ctx, get_alloc_from_shape(old_sh)); - + /* reduce the size of the object properties */ new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); if (new_prop) @@ -4684,7 +4684,7 @@ static __maybe_unused void JS_DumpShapes(JSRuntime *rt) struct list_head *el; JSObject *p; JSGCObjectHeader *gp; - + printf("JSShapes: {\n"); printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS"); for(i = 0; i < rt->shape_hash_size; i++) { @@ -5012,7 +5012,7 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, JSValue func_obj; JSObject *p; JSAtom name_atom; - + func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION); if (JS_IsException(func_obj)) return func_obj; @@ -5443,7 +5443,7 @@ static void free_zero_refcount(JSRuntime *rt) { struct list_head *el; JSGCObjectHeader *p; - + rt->gc_phase = JS_GC_PHASE_DECREF; for(;;) { el = rt->gc_zero_ref_count_list.next; @@ -5675,7 +5675,7 @@ static void gc_decref(JSRuntime *rt) { struct list_head *el, *el1; JSGCObjectHeader *p; - + init_list_head(&rt->tmp_obj_list); /* decrement the refcount of all the children of all the GC @@ -5722,7 +5722,7 @@ static void gc_scan(JSRuntime *rt) p->mark = 0; /* reset the mark for the next GC call */ mark_children(rt, p, gc_scan_incref_child); } - + /* restore the refcount of the objects to be deleted. */ list_for_each(el, &rt->tmp_obj_list) { p = list_entry(el, JSGCObjectHeader, link); @@ -5768,7 +5768,7 @@ static void gc_free_cycles(JSRuntime *rt) } } rt->gc_phase = JS_GC_PHASE_NONE; - + list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || @@ -6438,7 +6438,7 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func) JSProperty *pr; JSShapeProperty *prs; JSValueConst val; - + if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT) return NULL; prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name); @@ -6469,7 +6469,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, const char *str1; JSObject *p; BOOL backtrace_barrier; - + js_dbuf_init(ctx, &dbuf); if (filename) { dbuf_printf(&dbuf, " at %s", filename); @@ -7028,7 +7028,7 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, int ret; JSContext *realm; JSAutoInitFunc *func; - + realm = js_autoinit_get_realm(pr); func = js_autoinit_func_table[js_autoinit_get_id(pr)]; ret = func(realm, p, prop, pr->u.init.opaque); @@ -7287,7 +7287,7 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) JSProperty *pr; JSValue brand; JSAtom brand_atom; - + if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; @@ -7309,7 +7309,7 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) brand = JS_DupValue(ctx, pr->u.value); } brand_atom = js_symbol_to_atom(ctx, brand); - + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { JS_ThrowTypeErrorNotAnObject(ctx); JS_FreeAtom(ctx, brand_atom); @@ -7330,7 +7330,7 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) JSShapeProperty *prs; JSProperty *pr; JSValueConst brand; - + /* get the home object of 'func' */ if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) { not_obj: @@ -7352,7 +7352,7 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) /* safety check */ if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL)) goto not_obj; - + /* get the brand array of 'obj' */ if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) goto not_obj; @@ -7411,7 +7411,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, BOOL is_enumerable, num_sorted; uint32_t num_key; JSAtomKindEnum kind; - + /* clear pointer for consistency in case of failure */ *ptab = NULL; *plen = 0; @@ -9350,7 +9350,7 @@ static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj) JSShapeProperty *prs; JSValueConst val; JSString *p; - + prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name); if (!prs) return FALSE; @@ -9624,7 +9624,7 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags) JSValue obj1; JSObject *p; int res; - + obj1 = JS_ToObject(ctx, obj); if (JS_IsException(obj1)) return -1; @@ -9871,7 +9871,7 @@ static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) p = JS_VALUE_GET_OBJ(obj); return p->is_HTMLDDA; } - + static int JS_ToBoolFree(JSContext *ctx, JSValue val) { uint32_t tag = JS_VALUE_GET_TAG(val); @@ -9973,11 +9973,11 @@ static double js_strtod(const char *p, int radix, BOOL is_float) { double d; int c; - + if (!is_float || radix != 10) { uint64_t n_max, n; int int_exp, is_neg; - + is_neg = 0; if (*p == '-') { is_neg = 1; @@ -10025,7 +10025,7 @@ static double js_strtod(const char *p, int radix, BOOL is_float) /* accept _ between digits as a digit separator */ #define ATOD_ACCEPT_UNDERSCORES (1 << 5) /* allow a suffix to override the type */ -#define ATOD_ACCEPT_SUFFIX (1 << 6) +#define ATOD_ACCEPT_SUFFIX (1 << 6) /* default type */ #define ATOD_TYPE_MASK (3 << 7) #define ATOD_TYPE_FLOAT64 (0 << 7) @@ -10034,7 +10034,7 @@ static double js_strtod(const char *p, int radix, BOOL is_float) #define ATOD_TYPE_BIG_DECIMAL (3 << 7) /* assume bigint mode: floats are parsed as integers if no decimal point nor exponent */ -#define ATOD_MODE_BIGINT (1 << 9) +#define ATOD_MODE_BIGINT (1 << 9) /* accept -0x1 */ #define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) @@ -10064,7 +10064,7 @@ static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, bf_t *a; int ret; JSValue val; - + val = JS_NewBigFloat(ctx); if (JS_IsException(val)) return val; @@ -10090,7 +10090,7 @@ static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf, bfdec_t *a; int ret; JSValue val; - + val = JS_NewBigDecimal(ctx); if (JS_IsException(val)) return val; @@ -10124,11 +10124,11 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, int i, j, len; BOOL buf_allocated = FALSE; JSValue val; - + /* optional separator between digits */ sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; has_legacy_octal = FALSE; - + p = str; p_start = p; is_neg = 0; @@ -10333,7 +10333,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, val = JS_NewFloat64(ctx, d); } #endif - + done: if (buf_allocated) js_free_rt(ctx->rt, buf); @@ -10415,7 +10415,7 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, const char *str; const char *p; size_t len; - + str = JS_ToCStringLen(ctx, &len, val); JS_FreeValue(ctx, val); if (!str) @@ -11729,7 +11729,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) } printf(" }"); } - + if (js_class_has_bytecode(p->class_id)) { JSFunctionBytecode *b = p->u.func.function_bytecode; JSVarRef **var_refs; @@ -12021,7 +12021,7 @@ static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) uint32_t tag; JSBigDecimal *p; bfdec_t *r; - + tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_BIG_DECIMAL: @@ -12042,7 +12042,7 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) const char *str, *p; size_t len; int flags; - + str = JS_ToCStringLen(ctx, &len, val); JS_FreeValue(ctx, val); if (!str) @@ -12158,7 +12158,7 @@ static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val) } else { bf_t a_s, *a, *r; int ret; - JSValue res; + JSValue res; res = JS_NewBigInt(ctx); if (JS_IsException(res)) @@ -12260,7 +12260,7 @@ static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, { int64_t v; bf_t *a; - + if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) return val; /* fail safe */ a = JS_GetBigInt(val); @@ -12388,10 +12388,10 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, JSOverloadableOperatorEnum ovop; JSObject *p; JSValueConst args[2]; - + if (!ctx->allow_operator_overloading) return 0; - + opset2_obj = JS_UNDEFINED; opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset1_obj)) @@ -12420,7 +12420,7 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, } ovop = get_ovop_from_opcode(op); - + if (opset1->operator_counter == opset2->operator_counter) { p = opset1->self_ops[ovop]; } else if (opset1->operator_counter > opset2->operator_counter) { @@ -12445,7 +12445,7 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, } else { new_op1 = JS_DupValue(ctx, op1); } - + if (opset2->is_primitive) { if (is_numeric) { new_op2 = JS_ToNumeric(ctx, op2); @@ -12462,7 +12462,7 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, /* XXX: could apply JS_ToPrimitive() if primitive type so that the operator function does not get a value object */ - + method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) { args[0] = new_op2; @@ -12573,7 +12573,7 @@ static __exception int js_call_unary_op_fallback(JSContext *ctx, if (!ctx->allow_operator_overloading) return 0; - + opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset1_obj)) goto exception; @@ -12629,7 +12629,7 @@ static int js_unary_arith_bigint(JSContext *ctx, bf_t a_s, *r, *a; int ret, v; JSValue res; - + if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigint argument with unary +"); JS_FreeValue(ctx, op1); @@ -12681,7 +12681,7 @@ static int js_unary_arith_bigfloat(JSContext *ctx, bf_t a_s, *r, *a; int ret, v; JSValue res; - + if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); JS_FreeValue(ctx, op1); @@ -12730,7 +12730,7 @@ static int js_unary_arith_bigdecimal(JSContext *ctx, bfdec_t *r, *a; int ret, v; JSValue res; - + if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); JS_FreeValue(ctx, op1); @@ -12890,7 +12890,7 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) { JSValue op1, val; int ret; - + op1 = sp[-1]; if (JS_IsObject(op1)) { ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); @@ -12927,7 +12927,7 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, bf_t a_s, b_s, *r, *a, *b; int ret; JSValue res; - + res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); @@ -12988,7 +12988,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, bf_t a_s, b_s, *r, *a, *b; int ret; JSValue res; - + res = JS_NewBigInt(ctx); if (JS_IsException(res)) goto fail; @@ -13175,7 +13175,7 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, if (JS_IsException(res)) goto fail; r = JS_GetBigDecimal(res); - + a = JS_ToBigDecimal(ctx, op1); if (!a) goto fail; @@ -13602,7 +13602,7 @@ static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op, { bf_t a_s, b_s, *a, *b; int res; - + a = JS_ToBigFloat(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, op2); @@ -13664,7 +13664,7 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, } a = JS_ToBigDecimal(ctx, op1); b = JS_ToBigDecimal(ctx, op2); - + switch(op) { case OP_lt: res = bfdec_cmp_lt(a, b); /* if NaN return false */ @@ -14053,7 +14053,7 @@ static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, bf_t r_s, *r = &r_s; double d; int ret; - + /* always convert to Float64 */ bf_init(ctx->bf_ctx, r); ret = bf_mul_pow_radix(r, a, 10, exponent, @@ -14775,7 +14775,7 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) { JSObject *p; p = JS_VALUE_GET_OBJ(op1); - if (unlikely(p->is_HTMLDDA)) + if (unlikely(p->is_HTMLDDA)) atom = JS_ATOM_undefined; else if (JS_IsFunction(ctx, op1)) atom = JS_ATOM_function; @@ -15488,7 +15488,7 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) int is_array_iterator; JSValue *arrp; uint32_t i, count32, pos; - + if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { JS_ThrowInternalError(ctx, "invalid index for append"); return -1; @@ -15936,7 +15936,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, sf->prev_frame = prev_sf; rt->current_stack_frame = sf; ctx = p->u.cfunc.realm; /* change the current realm */ - + #ifdef CONFIG_BIGNUM /* we only propagate the bignum mode as some runtime functions test it */ @@ -16124,7 +16124,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, #define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id, #if SHORT_OPCODES #define def(id, size, n_pop, n_push, f) -#else +#else #define def(id, size, n_pop, n_push, f) && case_default, #endif #include "quickjs-opcode.h" @@ -16238,7 +16238,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; ctx = b->realm; /* set the current realm */ - + restart: for(;;) { int call_argc; @@ -16691,7 +16691,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JS_FreeValue(ctx, sp[-1]); sp -= 2; BREAK; - + CASE(OP_throw): JS_Throw(ctx, *--sp); goto exception; @@ -17529,7 +17529,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSAtom atom; JSValue val; - + atom = get_u32(pc); pc += 4; val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE); @@ -17538,7 +17538,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, *sp++ = val; } BREAK; - + CASE(OP_get_private_field): { JSValue val; @@ -17691,7 +17691,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { int class_flags; JSAtom atom; - + atom = get_u32(pc); class_flags = pc[4]; pc += 5; @@ -18669,7 +18669,7 @@ static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj) { JSObject *p; JSContext *realm; - + if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) return ctx; p = JS_VALUE_GET_OBJ(func_obj); @@ -18718,7 +18718,7 @@ static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, { JSValue proto, obj; JSContext *realm; - + if (JS_IsUndefined(ctor)) { proto = JS_DupValue(ctx, ctx->class_proto[class_id]); } else { @@ -18885,7 +18885,7 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) /* close the closure variables. */ close_var_refs(rt, sf); - + if (sf->arg_buf) { /* cannot free the function if it is running */ assert(sf->cur_sp != NULL); @@ -20011,7 +20011,7 @@ typedef struct JSFunctionDef { int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */ int home_object_var_idx; BOOL need_home_object; - + int scope_level; /* index into fd->scopes if the current lexical scope */ int scope_first; /* index into vd->vars of first lexically scoped variable */ int scope_size; /* allocated size of fd->scopes array */ @@ -20027,7 +20027,7 @@ typedef struct JSFunctionDef { int last_opcode_pos; /* -1 if no last opcode */ int last_opcode_line_num; BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */ - + LabelSlot *label_slots; int label_size; /* allocated size for label_slots[] */ int label_count; @@ -20242,7 +20242,7 @@ int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const JSContext *ctx = s->ctx; va_list ap; int backtrace_flags; - + va_start(ap, fmt); JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE); va_end(ap); @@ -20592,7 +20592,7 @@ static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, { char *buf, *new_buf; size_t size, new_size; - + buf = *pbuf; size = *psize; if (size >= (SIZE_MAX / 3) * 2) @@ -20622,7 +20622,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, char ident_buf[128], *buf; size_t ident_size, ident_pos; JSAtom atom; - + p = *pp; buf = ident_buf; ident_size = sizeof(ident_buf); @@ -20631,7 +20631,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, buf[ident_pos++] = '#'; for(;;) { p1 = p; - + if (c < 128) { buf[ident_pos++] = c; } else { @@ -20669,11 +20669,11 @@ static __exception int next_token(JSParseState *s) int c; BOOL ident_has_escape; JSAtom atom; - + if (js_check_stack_overflow(s->ctx->rt, 0)) { return js_parse_error(s, "stack overflow"); } - + free_token(s, &s->token); p = s->last_ptr = s->buf_ptr; @@ -20800,14 +20800,14 @@ static __exception int next_token(JSParseState *s) case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': + case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': + case 'Y': case 'Z': case '_': case '$': /* identifier */ @@ -20891,7 +20891,7 @@ static __exception int next_token(JSParseState *s) goto parse_number; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': - case '9': + case '9': /* number */ parse_number: { @@ -21149,7 +21149,7 @@ static __exception int next_token(JSParseState *s) case CP_LS: /* XXX: should avoid incrementing line_number, but needed to handle HTML comments */ - goto line_terminator; + goto line_terminator; default: if (lre_is_space(c)) { goto redo; @@ -21184,7 +21184,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) char ident_buf[128], *buf; size_t ident_size, ident_pos; JSAtom atom; - + p = *pp; buf = ident_buf; ident_size = sizeof(ident_buf); @@ -21216,11 +21216,11 @@ static __exception int json_next_token(JSParseState *s) const uint8_t *p; int c; JSAtom atom; - + if (js_check_stack_overflow(s->ctx->rt, 0)) { return js_parse_error(s, "stack overflow"); } - + free_token(s, &s->token); p = s->last_ptr = s->buf_ptr; @@ -21330,14 +21330,14 @@ static __exception int json_next_token(JSParseState *s) case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': + case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': + case 'Y': case 'Z': case '_': case '$': /* identifier : only pure ascii characters are accepted */ @@ -21364,7 +21364,7 @@ static __exception int json_next_token(JSParseState *s) goto parse_number; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': - case '9': + case '9': /* number */ parse_number: { @@ -21412,7 +21412,7 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) { const uint8_t *p; uint32_t c; - + /* skip spaces and comments */ p = *pp; for (;;) { @@ -21643,7 +21643,7 @@ static int emit_goto(JSParseState *s, int opcode, int label) static int cpool_add(JSParseState *s, JSValue val) { JSFunctionDef *fd = s->cur_func; - + if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]), &fd->cpool_size, fd->cpool_count + 1)) return -1; @@ -21993,7 +21993,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) { return js_parse_error(s, "invalid redefinition of a variable"); } - + if (fd->is_global_var) { JSHoistedDef *hf; hf = find_hoisted_def(fd, name); @@ -22002,7 +22002,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, return js_parse_error(s, "invalid redefinition of global identifier"); } } - + if (fd->is_eval && (fd->eval_type == JS_EVAL_TYPE_GLOBAL || fd->eval_type == JS_EVAL_TYPE_MODULE) && @@ -22271,7 +22271,7 @@ static int __exception js_parse_property_name(JSParseState *s, BOOL is_non_reserved_ident; JSAtom name; int prop_type; - + prop_type = PROP_TYPE_IDENT; if (allow_method) { if (token_is_pseudo_keyword(s, JS_ATOM_get) @@ -22496,7 +22496,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ if (level >= sizeof(state)) goto done; state[level++] = '`'; - } + } break; case TOK_EOF: goto done; @@ -22732,7 +22732,7 @@ static __exception int js_parse_class_default_ctor(JSParseState *s, int ret, line_num; JSParseFunctionEnum func_type; const uint8_t *saved_buf_end; - + js_parse_get_pos(s, &pos); if (has_super) { str = "(...a){super(...a);}"; @@ -22778,7 +22778,7 @@ static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd, static void emit_class_field_init(JSParseState *s) { int label_next; - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_class_fields_init); emit_u16(s, s->cur_func->scope_level); @@ -22786,13 +22786,13 @@ static void emit_class_field_init(JSParseState *s) /* no need to call the class field initializer if not defined */ emit_op(s, OP_dup); label_next = emit_goto(s, OP_if_false, -1); - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_this); emit_u16(s, 0); - + emit_op(s, OP_swap); - + emit_op(s, OP_call_method); emit_u16(s, 0); @@ -22817,29 +22817,29 @@ static __exception int emit_class_init_start(JSParseState *s, ClassFieldsDef *cf) { int label_add_brand; - + cf->fields_init_fd = js_parse_function_class_fields_init(s); if (!cf->fields_init_fd) return -1; s->cur_func = cf->fields_init_fd; - + /* XXX: would be better to add the code only if needed, maybe in a later pass */ emit_op(s, OP_push_false); /* will be patched later */ cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos; label_add_brand = emit_goto(s, OP_if_false, -1); - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_this); emit_u16(s, 0); - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_home_object); emit_u16(s, 0); - + emit_op(s, OP_add_brand); - + emit_label(s, label_add_brand); s->cur_func = s->cur_func->parent; @@ -22856,7 +22856,7 @@ static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf) } /* patch the start of the function to enable the OP_add_brand code */ cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true; - + cf->has_brand = TRUE; } return 0; @@ -22865,11 +22865,11 @@ static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf) static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf) { int cpool_idx; - + s->cur_func = cf->fields_init_fd; emit_op(s, OP_return_undef); s->cur_func = s->cur_func->parent; - + cpool_idx = cpool_add(s, JS_NULL); cf->fields_init_fd->parent_cpool_idx = cpool_idx; emit_op(s, OP_fclosure); @@ -22892,7 +22892,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, const uint8_t *class_start_ptr = s->token.ptr; const uint8_t *start_ptr; ClassFieldsDef class_fields[2]; - + /* classes are parsed and executed in strict mode */ saved_js_mode = fd->js_mode; fd->js_mode |= JS_MODE_STRICT; @@ -22956,7 +22956,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } else { class_name1 = class_name; } - + emit_op(s, OP_define_class); emit_atom(s, class_name1); emit_u8(s, class_flags); @@ -22968,7 +22968,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, cf->computed_fields_count = 0; cf->has_brand = FALSE; } - + ctor_fd = NULL; while (s->token.val != '}') { if (s->token.val == ';') { @@ -22998,7 +22998,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } is_private = prop_type & PROP_TYPE_PRIVATE; prop_type &= ~PROP_TYPE_PRIVATE; - + if ((name == JS_ATOM_constructor && !is_static && prop_type != PROP_TYPE_IDENT) || (name == JS_ATOM_prototype && is_static) || @@ -23044,7 +23044,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, if (is_set) { JSAtom setter_name; int ret; - + setter_name = get_private_setter_name(ctx, name); if (setter_name == JS_ATOM_NULL) goto fail; @@ -23070,7 +23070,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') { ClassFieldsDef *cf = &class_fields[is_static]; JSAtom field_var_name = JS_ATOM_NULL; - + /* class field */ /* XXX: spec: not consistent with method name checks */ @@ -23078,7 +23078,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, js_parse_error(s, "invalid field name"); goto fail; } - + if (is_private) { if (find_private_class_field(ctx, fd, name, fd->scope_level) >= 0) { @@ -23128,7 +23128,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_atom(s, name); emit_u16(s, s->cur_func->scope_level); } - + if (s->token.val == '=') { if (next_token(s)) goto fail; @@ -23155,7 +23155,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } else { JSParseFunctionEnum func_type; JSFunctionKindEnum func_kind; - + func_type = JS_PARSE_FUNC_METHOD; func_kind = JS_FUNC_NORMAL; if (prop_type == PROP_TYPE_STAR) { @@ -23247,7 +23247,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, { ClassFieldsDef *cf = &class_fields[0]; int var_idx; - + var_idx = define_var(s, fd, JS_ATOM_class_fields_init, JS_VAR_DEF_CONST); if (var_idx < 0) @@ -23274,7 +23274,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_u16(s, 0); emit_op(s, OP_drop); } - + if (class_name != JS_ATOM_NULL) { /* store the class name in the scoped class name variable (it is independent from the class statement variable @@ -23678,7 +23678,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope, default: break; } - + switch(opcode) { case OP_scope_get_var: /* val -- */ assert(special == PUT_LVALUE_NOKEEP || @@ -23732,7 +23732,7 @@ static __exception int js_define_var(JSParseState *s, JSAtom name, int tok) { JSFunctionDef *fd = s->cur_func; JSVarDefEnum var_def_type; - + if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) { return js_parse_error(s, "yield is a reserved identifier"); } @@ -24275,7 +24275,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen { FuncCallType call_type; int optional_chaining_label; - + call_type = FUNC_CALL_NORMAL; switch(s->token.val) { case TOK_NUMBER: @@ -24331,7 +24331,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen if (next_token(s)) return -1; break; - + case TOK_DIV_ASSIGN: s->buf_ptr -= 2; goto parse_regexp; @@ -24570,7 +24570,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen for(;;) { JSFunctionDef *fd = s->cur_func; BOOL has_optional_chain = FALSE; - + if (s->token.val == TOK_QUESTION_MARK_DOT) { /* optional chaining */ if (next_token(s)) @@ -25063,7 +25063,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND, FALSE); if (next_token(s)) - return -1; + return -1; } break; } @@ -25296,7 +25296,7 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op, static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted) { int label1; - + if (js_parse_logical_and_or(s, TOK_LOR, in_accepted)) return -1; if (s->token.val == TOK_DOUBLE_QUESTION_MARK) { @@ -25304,12 +25304,12 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted) for(;;) { if (next_token(s)) return -1; - + emit_op(s, OP_dup); emit_op(s, OP_is_undefined_or_null); emit_goto(s, OP_if_false, label1); emit_op(s, OP_drop); - + if (js_parse_expr_binary(s, 8, in_accepted)) return -1; if (s->token.val != TOK_DOUBLE_QUESTION_MARK) @@ -25528,7 +25528,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE); } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) { int label, label1, depth_lvalue, label2; - + if (next_token(s)) return -1; if (get_lvalue(s, &opcode, &scope, &name, &label, @@ -25541,7 +25541,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false, -1); emit_op(s, OP_drop); - + if (js_parse_assign_expr(s, in_accepted)) { JS_FreeAtom(s->ctx, name); return -1; @@ -25550,7 +25550,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) if (opcode == OP_get_ref_value && name == name0) { set_object_name(s, name); } - + switch(depth_lvalue) { case 1: emit_op(s, OP_insert2); @@ -25570,7 +25570,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH, FALSE); label2 = emit_goto(s, OP_goto, -1); - + emit_label(s, label1); /* remove the lvalue stack entries */ @@ -26870,7 +26870,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, if (js_parse_expect_semi(s)) goto fail; break; - + case TOK_ENUM: case TOK_EXPORT: case TOK_EXTENDS: @@ -27187,7 +27187,7 @@ static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name) { struct list_head *el; JSModuleDef *m; - + /* first look at the loaded modules */ list_for_each(el, &ctx->loaded_modules) { m = list_entry(el, JSModuleDef, link); @@ -27252,7 +27252,7 @@ static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx, { const char *base_cname, *cname; JSModuleDef *m; - + base_cname = JS_AtomToCString(ctx, base_module_name); if (!base_cname) return NULL; @@ -27567,7 +27567,7 @@ static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, { JSModuleDef *m = opaque; JSValue val, this_val = JS_MKPTR(JS_TAG_OBJECT, p); - + val = js_get_module_ns(ctx, m); if (JS_IsException(val)) return -1; @@ -27798,7 +27798,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) BOOL is_c_module; int i; JSVarRef *var_ref; - + if (m->func_created) return 0; @@ -27822,7 +27822,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) m->func_created = TRUE; /* do it on the dependencies */ - + for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; if (js_create_module_function(ctx, rme->module) < 0) @@ -27830,9 +27830,9 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) } return 0; -} +} + - /* Prepare a module to be executed by resolving all the imported variables. */ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) @@ -28038,7 +28038,7 @@ static JSValue js_import_meta(JSContext *ctx) { JSAtom filename; JSModuleDef *m; - + filename = JS_GetScriptOrModuleName(ctx, 0); if (filename == JS_ATOM_NULL) goto fail; @@ -28061,11 +28061,11 @@ JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, { JSModuleDef *m; JSValue ret, func_obj; - + m = js_host_resolve_imported_module(ctx, basename, filename); if (!m) return NULL; - + if (js_resolve_module(ctx, m) < 0) { js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); return NULL; @@ -28101,7 +28101,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx, filename = JS_ToCString(ctx, specifier); if (!filename) goto exception; - + m = JS_RunModule(ctx, basename, filename); JS_FreeCString(ctx, filename); if (!m) @@ -28143,7 +28143,7 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) JS_FreeAtom(ctx, basename); if (JS_IsException(basename_val)) return basename_val; - + promise = JS_NewPromiseCapability(ctx, resolving_funcs); if (JS_IsException(promise)) { JS_FreeValue(ctx, basename_val); @@ -28154,7 +28154,7 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) args[1] = resolving_funcs[1]; args[2] = basename_val; args[3] = specifier; - + JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args); JS_FreeValue(ctx, basename_val); @@ -28564,7 +28564,7 @@ static __exception int js_parse_source_element(JSParseState *s) { JSFunctionDef *fd = s->cur_func; int tok; - + if (s->token.val == TOK_FUNCTION || (token_is_pseudo_keyword(s, JS_ATOM_async) && peek_token(s, TRUE) == TOK_FUNCTION)) { @@ -28653,7 +28653,7 @@ static void free_bytecode_atoms(JSRuntime *rt, int pos, len, op; JSAtom atom; const JSOpCode *oi; - + pos = 0; while (pos < bc_len) { op = bc_buf[pos]; @@ -28661,7 +28661,7 @@ static void free_bytecode_atoms(JSRuntime *rt, oi = &short_opcode_info(op); else oi = &opcode_info[op]; - + len = oi->size; switch(oi->fmt) { case OP_FMT_atom: @@ -29899,7 +29899,7 @@ static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx) { /* if the field is not initialized, the error is catched when accessing it */ - if (is_ref) + if (is_ref) dbuf_putc(bc, OP_get_var_ref); else dbuf_putc(bc, OP_get_loc); @@ -29914,7 +29914,7 @@ static int resolve_scope_private_field1(JSContext *ctx, int idx, var_kind; JSFunctionDef *fd; BOOL is_ref; - + fd = s; is_ref = FALSE; for(;;) { @@ -30898,7 +30898,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_set_class_name: /* only used during parsing */ break; - + default: no_change: dbuf_put(&bc_out, bc_buf + pos, len); @@ -32427,7 +32427,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->realm = JS_DupContext(ctx); add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); - + #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1) if (!(fd->js_mode & JS_MODE_STRIP)) { js_dump_function_bytecode(ctx, b); @@ -32642,7 +32642,7 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd, static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) { JSFunctionDef *fd; - + fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE, s->filename, 0); if (!fd) @@ -32650,7 +32650,7 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) fd->func_name = JS_ATOM_NULL; fd->has_prototype = FALSE; fd->has_home_object = TRUE; - + fd->has_arguments_binding = FALSE; fd->has_this_binding = TRUE; fd->is_derived_class_constructor = FALSE; @@ -32658,7 +32658,7 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) fd->super_call_allowed = FALSE; fd->super_allowed = fd->has_home_object; fd->arguments_allowed = FALSE; - + fd->func_kind = JS_FUNC_NORMAL; fd->func_type = JS_PARSE_FUNC_METHOD; return fd; @@ -32832,7 +32832,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) { emit_class_field_init(s); } - + /* parse arguments */ fd->has_simple_parameter_list = TRUE; has_opt_arg = FALSE; @@ -33089,7 +33089,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, /* it is considered as defined at the top level (needed for annex B.3.3.4 and B.3.3.5 checks) */ - hf->scope_level = 0; + hf->scope_level = 0; hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0); /* store directly into global var, bypass lexical scope */ emit_op(s, OP_dup); @@ -33490,13 +33490,13 @@ static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s, js_free(ctx, s->hash_table); s->hash_table = new_hash_table; s->hash_size = new_hash_size; - + for(i = 0; i < s->hash_size; i++) { s->hash_table[i] = -1; } for(i = 0; i < s->object_count; i++) { e = &s->object_tab[i]; - h = js_object_list_get_hash(e->obj, s->hash_size); + h = js_object_list_get_hash(e->obj, s->hash_size); e->hash_next = s->hash_table[h]; s->hash_table[h] = i; } @@ -33509,7 +33509,7 @@ static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj) { JSObjectListEntry *e; uint32_t h, new_hash_size; - + if (js_resize_array(ctx, (void *)&s->object_tab, sizeof(s->object_tab[0]), &s->object_size, s->object_count + 1)) @@ -33522,7 +33522,7 @@ static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj) return -1; } e = &s->object_tab[s->object_count++]; - h = js_object_list_get_hash(obj, s->hash_size); + h = js_object_list_get_hash(obj, s->hash_size); e->obj = obj; e->hash_next = s->hash_table[h]; s->hash_table[h] = s->object_count - 1; @@ -33538,7 +33538,7 @@ static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj) /* must test empty size because there is no hash table */ if (s->object_count == 0) return -1; - h = js_object_list_get_hash(obj, s->hash_size); + h = js_object_list_get_hash(obj, s->hash_size); p = s->hash_table[h]; while (p != -1) { e = &s->object_tab[p]; @@ -33942,7 +33942,7 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) int bpos, d; uint8_t v8; size_t i0; - + /* little endian BCD */ i = 0; while (i < a->len && a->tab[i] == 0) @@ -33962,7 +33962,7 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) return -1; } bc_put_leb128(s, len); - + bpos = 0; v8 = 0; i0 = i; @@ -34000,7 +34000,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj); uint32_t flags; int idx, i; - + bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE); flags = idx = 0; bc_set_flags(&flags, &idx, b->has_prototype, 1); @@ -34018,7 +34018,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_put_u16(s, flags); bc_put_u8(s, b->js_mode); bc_put_atom(s, b->func_name); - + bc_put_leb128(s, b->arg_count); bc_put_leb128(s, b->var_count); bc_put_leb128(s, b->defined_arg_count); @@ -34045,7 +34045,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) } else { bc_put_leb128(s, 0); } - + for(i = 0; i < b->closure_var_count; i++) { JSClosureVar *cv = &b->closure_var[i]; bc_put_atom(s, cv->var_name); @@ -34059,17 +34059,17 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) assert(idx <= 8); bc_put_u8(s, flags); } - + if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len)) goto fail; - + if (b->has_debug) { bc_put_atom(s, b->debug.filename); bc_put_leb128(s, b->debug.line_num); bc_put_leb128(s, b->debug.pc2line_len); dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); } - + for(i = 0; i < b->cpool_count; i++) { if (JS_WriteObjectRec(s, b->cpool[i])) goto fail; @@ -34083,16 +34083,16 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) { JSModuleDef *m = JS_VALUE_GET_PTR(obj); int i; - + bc_put_u8(s, BC_TAG_MODULE); bc_put_atom(s, m->module_name); - + bc_put_leb128(s, m->req_module_entries_count); for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; bc_put_atom(s, rme->module_name); } - + bc_put_leb128(s, m->export_entries_count); for(i = 0; i < m->export_entries_count; i++) { JSExportEntry *me = &m->export_entries[i]; @@ -34105,13 +34105,13 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) } bc_put_atom(s, me->export_name); } - + bc_put_leb128(s, m->star_export_entries_count); for(i = 0; i < m->star_export_entries_count; i++) { JSStarExportEntry *se = &m->star_export_entries[i]; bc_put_leb128(s, se->req_module_idx); } - + bc_put_leb128(s, m->import_entries_count); for(i = 0; i < m->import_entries_count; i++) { JSImportEntry *mi = &m->import_entries[i]; @@ -34119,7 +34119,7 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) bc_put_atom(s, mi->import_name); bc_put_leb128(s, mi->req_module_idx); } - + if (JS_WriteObjectRec(s, m->func_obj)) goto fail; return 0; @@ -34134,7 +34134,7 @@ static int JS_WriteArray(BCWriterState *s, JSValueConst obj) JSValue val; int ret; BOOL is_template; - + if (s->allow_bytecode && !p->extensible) { /* not extensible array: we consider it is a template when we are saving bytecode */ @@ -34308,7 +34308,7 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) { JSObject *p = JS_VALUE_GET_OBJ(obj); int ret, idx; - + if (s->allow_reference) { idx = js_object_list_find(s->ctx, &s->object_list, p); if (idx >= 0) { @@ -34449,7 +34449,7 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, s->first_atom = 1; js_dbuf_init(ctx, &s->dbuf); js_object_list_init(&s->object_list); - + if (JS_WriteObjectRec(s, obj)) goto fail; if (JS_WriteObjectAtoms(s)) @@ -34497,7 +34497,7 @@ typedef struct BCReaderState { JSObject **objects; int objects_count; int objects_size; - + #ifdef DUMP_READ_OBJECT const uint8_t *ptr_last; int level; @@ -34782,7 +34782,7 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) limb_t v; bf_t *a; int bpos, d; - + p = js_new_bf(s->ctx); if (!p) goto fail; @@ -34994,11 +34994,11 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) b = js_mallocz(ctx, function_size); if (!b) return JS_EXCEPTION; - + memcpy(b, &bc, offsetof(JSFunctionBytecode, debug)); b->header.ref_count = 1; add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); - + obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); #ifdef DUMP_READ_OBJECT @@ -35115,7 +35115,7 @@ static JSValue JS_ReadModule(BCReaderState *s) JSAtom module_name; int i; uint8_t v8; - + if (bc_get_atom(s, &module_name)) goto fail; #ifdef DUMP_READ_OBJECT @@ -35216,7 +35216,7 @@ static JSValue JS_ReadObjectTag(BCReaderState *s) JSAtom atom; JSValue val; int ret; - + obj = JS_NewObject(ctx); if (BC_add_object_ref(s, obj)) goto fail; @@ -35296,7 +35296,7 @@ static JSValue JS_ReadTypedArray(BCReaderState *s) uint8_t array_tag; JSValueConst args[3]; uint32_t offset, len, idx; - + if (bc_get_u8(s, &array_tag)) return JS_EXCEPTION; if (array_tag >= JS_TYPED_ARRAY_COUNT) @@ -35341,7 +35341,7 @@ static JSValue JS_ReadArrayBuffer(BCReaderState *s) JSContext *ctx = s->ctx; uint32_t byte_length; JSValue obj; - + if (bc_get_leb128(s, &byte_length)) return JS_EXCEPTION; if (unlikely(s->buf_end - s->ptr < byte_length)) { @@ -35367,7 +35367,7 @@ static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s) uint8_t *data_ptr; JSValue obj; uint64_t u64; - + if (bc_get_leb128(s, &byte_length)) return JS_EXCEPTION; if (bc_get_u64(s, &u64)) @@ -35874,7 +35874,7 @@ static void JS_SetConstructor2(JSContext *ctx, set_cycle_flag(ctx, proto); } -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, +void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, JSValueConst proto) { JS_SetConstructor2(ctx, func_obj, proto, @@ -36691,7 +36691,7 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, if (!res) { return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false"); } - + p = JS_VALUE_GET_OBJ(obj); flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK; if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags)) @@ -36732,7 +36732,7 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, JSPropertyEnum *props; uint32_t len, i; int flags, res; - + if (!JS_IsObject(obj)) return JS_TRUE; @@ -36761,7 +36761,7 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, if (res < 0) return JS_EXCEPTION; res ^= 1; -done: +done: js_free_prop_enum(ctx, props, len); return JS_NewBool(ctx, res); @@ -36784,14 +36784,14 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, obj = JS_NewObject(ctx); if (JS_IsException(obj)) return obj; - + iter = JS_GetIterator(ctx, iterable, FALSE); if (JS_IsException(iter)) goto fail; next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); if (JS_IsException(next_method)) goto fail; - + for(;;) { JSValue key, value, item; item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); @@ -36801,7 +36801,7 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, item); break; } - + key = JS_UNDEFINED; value = JS_UNDEFINED; if (!JS_IsObject(item)) { @@ -37185,7 +37185,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, string_buffer_init(ctx, b, 0); string_buffer_putc8(b, '('); - + if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) { string_buffer_puts8(b, "async "); } @@ -37512,7 +37512,7 @@ static JSValue iterator_to_array(JSContext *ctx, JSValueConst items) JSValue v, r = JS_UNDEFINED; int64_t k; BOOL done; - + iter = JS_GetIterator(ctx, items, FALSE); if (JS_IsException(iter)) goto exception; @@ -37558,7 +37558,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, if (!JS_IsObject(proto)) { JSContext *realm; JSValueConst proto1; - + JS_FreeValue(ctx, proto); realm = JS_GetFunctionRealm(ctx, new_target); if (!realm) @@ -37646,7 +37646,7 @@ static JSValue js_aggregate_error_constructor(JSContext *ctx, JSValueConst errors) { JSValue obj; - + obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[JS_AGGREGATE_ERROR], JS_CLASS_ERROR); @@ -37885,7 +37885,7 @@ static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj, JSValue ctor, ret, species; int res; JSContext *realm; - + res = JS_IsArray(ctx, obj); if (res < 0) return JS_EXCEPTION; @@ -38050,7 +38050,7 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, this_arg = JS_UNDEFINED; if (argc > 1) this_arg = argv[1]; - + if (check_function(ctx, func)) goto exception; @@ -39763,7 +39763,7 @@ static int js_string_define_own_property(JSContext *ctx, uint32_t idx; JSObject *p; JSString *p1, *p2; - + if (__JS_AtomIsTaggedInt(prop)) { idx = __JS_AtomToUInt32(prop); p = JS_VALUE_GET_OBJ(this_obj); @@ -39930,7 +39930,7 @@ static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val, goto exception; if (js_get_length64(ctx, &n, raw) < 0) goto exception; - + for (i = 0; i < n; i++) { val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i)); if (JS_IsException(val)) @@ -40283,7 +40283,7 @@ static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp) { int ret; JSValue flags; - + ret = js_is_regexp(ctx, regexp); if (ret < 0) return -1; @@ -40555,7 +40555,7 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, } if (JS_IsException(repl_str)) goto exception; - + string_buffer_concat(b, sp, endOfLastMatch, pos); string_buffer_concat_value_free(b, repl_str); endOfLastMatch = pos + searchp->len; @@ -41233,7 +41233,7 @@ static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val, static struct { const char *tag, *attr; } const defs[] = { { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL }, { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL }, - { "a", "href" }, { "small", NULL }, { "strike", NULL }, + { "a", "href" }, { "small", NULL }, { "strike", NULL }, { "sub", NULL }, { "sup", NULL }, }; @@ -42033,7 +42033,7 @@ static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val) if (p->len == 0) { empty_regex: return JS_NewString(ctx, "(?:)"); - } + } string_buffer_init2(ctx, b, p->len, p->is_wide_char); /* Escape '/' and newline sequences as needed */ @@ -42092,7 +42092,7 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas else return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP); } - + flags = lre_get_flags(re->bytecode->u.str8); return JS_NewBool(ctx, (flags & mask) != 0); } @@ -42619,7 +42619,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, JSString *strp; int64_t lastIndex; JSRegExpStringIteratorData *it; - + if (!JS_IsObject(R)) return JS_ThrowTypeErrorNotAnObject(ctx); @@ -42627,7 +42627,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, flags = JS_UNDEFINED; matcher = JS_UNDEFINED; iter = JS_UNDEFINED; - + S = JS_ToString(ctx, argv[0]); if (JS_IsException(S)) goto exception; @@ -42648,7 +42648,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex, JS_NewInt64(ctx, lastIndex)) < 0) goto exception; - + iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR); if (JS_IsException(iter)) goto exception; @@ -42786,7 +42786,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, str = JS_ToString(ctx, argv[0]); if (JS_IsException(str)) goto exception; - + sp = JS_VALUE_GET_STRING(str); rp = NULL; functionalReplace = JS_IsFunction(ctx, rep); @@ -43061,7 +43061,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, while (q < size) { if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0) goto exception; - JS_FreeValue(ctx, z); + JS_FreeValue(ctx, z); z = JS_RegExpExec(ctx, splitter, str); if (JS_IsException(z)) goto exception; @@ -43115,7 +43115,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, ctor); JS_FreeValue(ctx, splitter); JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, z); + JS_FreeValue(ctx, z); return A; } @@ -43200,7 +43200,7 @@ static JSValue json_parse_value(JSParseState *s) { JSValue prop_val; JSAtom prop_name; - + if (json_next_token(s)) goto fail; val = JS_NewObject(ctx); @@ -43343,7 +43343,7 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, const char *filename) { - return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); + return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); } static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, @@ -43536,7 +43536,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, int64_t i, len; int cl, ret; BOOL has_content; - + indent1 = JS_UNDEFINED; sep = JS_UNDEFINED; sep1 = JS_UNDEFINED; @@ -43711,7 +43711,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, JS_FreeValue(ctx, val); return 0; } - + exception: JS_FreeValue(ctx, val); JS_FreeValue(ctx, tab); @@ -43829,7 +43829,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0) goto exception; val = JS_DupValue(ctx, obj); - + val = js_json_check(ctx, jsc, wrapper, val, jsc->empty); if (JS_IsException(val)) goto exception; @@ -44085,7 +44085,7 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod, JS_ThrowStackOverflow(ctx); return NULL; } - + /* 's' should never be NULL */ if (s->is_revoked) { JS_ThrowTypeErrorRevokedProxy(ctx); @@ -44484,7 +44484,7 @@ static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc JS_FreeValue(ctx, trap_result_obj); if (res < 0) return -1; - + if (target_desc_ret) { /* convert result_desc.flags to defineProperty flags */ flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE; @@ -44849,7 +44849,7 @@ static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj, if (flags & JS_CALL_FLAG_CONSTRUCTOR) return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv); - + s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply); if (!s) return JS_EXCEPTION; @@ -45434,7 +45434,7 @@ static void reset_weak_ref(JSRuntime *rt, JSObject *p) { JSMapRecord *mr, *mr_next; JSMapState *s; - + /* first pass to remove the records from the WeakMap/WeakSet lists */ for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) { @@ -45444,7 +45444,7 @@ static void reset_weak_ref(JSRuntime *rt, JSObject *p) list_del(&mr->hash_link); list_del(&mr->link); } - + /* second pass to free the values to avoid modifying the weak reference list while traversing it. */ for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) { @@ -46443,7 +46443,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, JSValueConst resolve_element_env = func_data[4]; JSValue ret, obj; int is_zero, index; - + if (JS_ToInt32(ctx, &index, func_data[1])) return JS_EXCEPTION; if (alreadyCalled) @@ -46452,7 +46452,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, if (resolve_type == PROMISE_MAGIC_allSettled) { JSValue str; - + obj = JS_NewObject(ctx); if (JS_IsException(obj)) return JS_EXCEPTION; @@ -46477,7 +46477,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, if (JS_DefinePropertyValueUint32(ctx, values, index, obj, JS_PROP_C_W_E) < 0) return JS_EXCEPTION; - + is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1); if (is_zero < 0) return JS_EXCEPTION; @@ -46510,7 +46510,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, JSValueConst then_args[2], resolve_element_data[5]; BOOL done; int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any); - + if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); @@ -46546,7 +46546,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, JS_NewInt32(ctx, 1), JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0) goto fail_reject; - + index = 0; for(;;) { /* XXX: conformance: should close the iterator if error on 'done' @@ -46556,7 +46556,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, goto fail_reject; if (done) break; - next_promise = JS_Call(ctx, promise_resolve, + next_promise = JS_Call(ctx, promise_resolve, this_val, 1, (JSValueConst *)&item); JS_FreeValue(ctx, item); if (JS_IsException(next_promise)) { @@ -46576,7 +46576,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, next_promise); goto fail_reject1; } - + if (magic == PROMISE_MAGIC_allSettled) { reject_element = JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1, @@ -48071,13 +48071,13 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, int p, i, c, sgn; JSString *sp; BOOL is_local; - + rv = JS_NAN; s = JS_ToString(ctx, argv[0]); if (JS_IsException(s)) return JS_EXCEPTION; - + sp = JS_VALUE_GET_STRING(s); p = 0; if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) { @@ -48405,7 +48405,7 @@ static void js_operator_set_finalizer(JSRuntime *rt, JSValue val) JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); int i, j; JSBinaryOperatorDefEntry *ent; - + if (opset) { for(i = 0; i < JS_OVOP_COUNT; i++) { if (opset->self_ops[i]) @@ -48437,7 +48437,7 @@ static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); int i, j; JSBinaryOperatorDefEntry *ent; - + if (opset) { for(i = 0; i < JS_OVOP_COUNT; i++) { if (opset->self_ops[i]) @@ -48537,7 +48537,7 @@ static JSValue js_operators_create_internal(JSContext *ctx, } op_count = opset1->operator_counter; JS_FreeValue(ctx, prop); - + /* we assume there are few entries */ new_tab = js_realloc(ctx, def->tab, (def->count + 1) * sizeof(def->tab[0])); @@ -48548,7 +48548,7 @@ static JSValue js_operators_create_internal(JSContext *ctx, ent = def->tab + def->count - 1; memset(ent, 0, sizeof(def->tab[0])); ent->operator_index = op_count; - + for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]); @@ -48585,7 +48585,7 @@ static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst t const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW }; JSOverloadableOperatorEnum op; int i; - + opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT], JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset_obj)) @@ -48715,7 +48715,7 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) case JS_TAG_BIG_FLOAT: { bf_t *a, a_s; - + a = JS_ToBigFloat(ctx, &a_s, val); if (!bf_is_finite(a)) { JS_FreeValue(ctx, val); @@ -48828,7 +48828,7 @@ static JSValue js_bigint_div(JSContext *ctx, bf_t a_s, b_s, *a, *b, *r, *q; int status; JSValue q_val, r_val; - + q_val = JS_NewBigInt(ctx); if (JS_IsException(q_val)) return JS_EXCEPTION; @@ -48879,7 +48879,7 @@ static JSValue js_bigint_sqrt(JSContext *ctx, bf_t a_s, *a, *r, *rem; int status; JSValue r_val, rem_val; - + r_val = JS_NewBigInt(ctx); if (JS_IsException(r_val)) return JS_EXCEPTION; @@ -48957,7 +48957,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx, uint64_t bits; bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s; JSValue res; - + if (JS_ToIndex(ctx, &bits, argv[0])) return JS_EXCEPTION; res = JS_NewBigInt(ctx); @@ -49024,7 +49024,7 @@ void JS_AddIntrinsicBigInt(JSContext *ctx) rt->bigint_ops.unary_arith = js_unary_arith_bigint; rt->bigint_ops.binary_arith = js_binary_arith_bigint; rt->bigint_ops.compare = js_compare_bigfloat; - + ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT], js_bigint_proto_funcs, @@ -49448,7 +49448,7 @@ static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val, { JSValueConst val = argv[0]; JSBigFloat *p; - + if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) return JS_FALSE; p = JS_VALUE_GET_PTR(val); @@ -49460,7 +49460,7 @@ static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val, { JSValueConst val = argv[0]; JSBigFloat *p; - + if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) return JS_FALSE; p = JS_VALUE_GET_PTR(val); @@ -49915,7 +49915,7 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx) JSRuntime *rt = ctx->rt; JSValue obj1; JSValueConst obj2; - + rt->bigfloat_ops.to_string = js_bigfloat_to_string; rt->bigfloat_ops.from_string = js_string_to_bigfloat; rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat; @@ -49923,7 +49923,7 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx) rt->bigfloat_ops.compare = js_compare_bigfloat; rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64; rt->bigfloat_ops.mul_pow10 = js_mul_pow10; - + ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT], js_bigfloat_proto_funcs, @@ -50098,7 +50098,7 @@ static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj) const char *str; size_t size; int rnd_mode; - + str = JS_ToCStringLen(ctx, &size, obj); if (!str) return -1; @@ -50138,7 +50138,7 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, int64_t val; BOOL has_prec; int rnd_mode; - + if (!JS_IsObject(obj)) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; @@ -50151,7 +50151,7 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, if (rnd_mode < 0) return -1; fe->flags = rnd_mode; - + prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits); if (JS_IsException(prop)) return -1; @@ -50206,7 +50206,7 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, op_count = 1; else op_count = 2; - + op1 = JS_ToNumeric(ctx, argv[0]); if (JS_IsException(op1)) return op1; @@ -51164,7 +51164,7 @@ JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, } return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); } - + static JSValue js_typed_array_get_toStringTag(JSContext *ctx, JSValueConst this_val) { @@ -51584,7 +51584,7 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, if (typed_array_is_detached(ctx, p)) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - + shift = typed_array_size_log2(p->class_id); switch(shift) { case 0: @@ -51737,7 +51737,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, #ifdef CONFIG_BIGNUM if (tag == JS_TAG_BIG_INT) { JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]); - + if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) { if (bf_get_int64(&v64, &p1->num, 0) != 0) goto done; @@ -52368,7 +52368,7 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, uint32_t *array_idx; void *array_tmp; size_t i, j; - + /* XXX: a stable sort would use less memory */ array_idx = js_malloc(ctx, len * sizeof(array_idx[0])); if (!array_idx) @@ -53182,7 +53182,7 @@ static JSValue js_atomics_op(JSContext *ctx, } switch(op | (size_log2 << 3)) { - + #ifdef CONFIG_BIGNUM #define OP(op_name, func_name) \ case ATOMICS_OP_ ## op_name | (0 << 3): \ @@ -53231,7 +53231,7 @@ static JSValue js_atomics_op(JSContext *ctx, a = atomic_load((_Atomic(uint64_t) *)ptr); break; #endif - + case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3): { uint8_t v1 = v; @@ -53406,7 +53406,7 @@ static JSValue js_atomics_wait(JSContext *ctx, return JS_EXCEPTION; } else #endif - { + { if (JS_ToInt32(ctx, &v32, argv[2])) return JS_EXCEPTION; v = v32; diff --git a/quickjs/quickjs/quickjs.h b/thirdparty/quickjs/quickjs/quickjs.h similarity index 99% rename from quickjs/quickjs/quickjs.h rename to thirdparty/quickjs/quickjs/quickjs.h index 2dd9f53d..6d130152 100644 --- a/quickjs/quickjs/quickjs.h +++ b/thirdparty/quickjs/quickjs/quickjs.h @@ -32,6 +32,12 @@ extern "C" { #endif +#ifdef _MSC_VER +#define INLINE_FUNC __forceinline +#else +#define INLINE_FUNC inline +#endif + #if defined(__GNUC__) || defined(__clang__) #define js_likely(x) __builtin_expect(!!(x), 1) #define js_unlikely(x) __builtin_expect(!!(x), 0) @@ -40,7 +46,7 @@ extern "C" { #else #define js_likely(x) (x) #define js_unlikely(x) (x) -#define js_force_inline inline +#define js_force_inline INLINE_FUNC #define __js_printf_like(a, b) #endif @@ -126,7 +132,7 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) { return 0; } - + #elif defined(JS_NAN_BOXING) typedef uint64_t JSValue; @@ -191,7 +197,7 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) tag = JS_VALUE_GET_TAG(v); return tag == (JS_NAN >> 32); } - + #else /* !JS_NAN_BOXING */ typedef union JSValueUnion { @@ -948,7 +954,7 @@ static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *fun { return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic); } -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, +void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, JSValueConst proto); /* C property definition */ diff --git a/quickjs/quickjs_binder.cpp b/thirdparty/quickjs/quickjs_binder.cpp similarity index 98% rename from quickjs/quickjs_binder.cpp rename to thirdparty/quickjs/quickjs_binder.cpp index 7af69266..518b7632 100644 --- a/quickjs/quickjs_binder.cpp +++ b/thirdparty/quickjs/quickjs_binder.cpp @@ -1,7 +1,3 @@ -#include "quickjs_binder.h" -#include "../javascript.h" -#include "../javascript_instance.h" -#include "../javascript_language.h" #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/core_bind.h" @@ -10,12 +6,19 @@ #include "core/io/json.h" #include "core/math/expression.h" #include "core/os/os.h" -#include "quickjs_binder.h" -#include "quickjs_worker.h" + #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" #endif + +#include "javascript.h" +#include "javascript_instance.h" +#include "javascript_language.h" +#include "quickjs_binder.h" #include "quickjs_callable.h" +#include "quickjs_worker.h" + + #include SafeNumeric QuickJSBinder::global_context_id; @@ -262,7 +265,7 @@ JSValue QuickJSBinder::variant_to_var(JSContext *ctx, const Variant p_var) { return js_arr; } case Variant::DICTIONARY: { - Dictionary dict = p_var; + Dictionary dict = static_cast(p_var); JSValue obj = JS_NewObject(ctx); Array keys = dict.keys(); for (int i = 0; i < keys.size(); i++) { @@ -335,7 +338,6 @@ Variant QuickJSBinder::var_to_variant(JSContext *ctx, JSValue p_val) { JSValue QuickJSBinder::godot_builtin_function(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic) { Variant ret; - Callable::CallError err; String err_msg; #if 0 // TODO: builtin functions Expression::BuiltinFunc func = (Expression::BuiltinFunc)magic; @@ -1207,31 +1209,6 @@ void QuickJSBinder::add_godot_globals() { } } -QuickJSBinder::QuickJSBinder() { - context_id = QuickJSBinder::global_context_id.increment(); - internal_godot_method_id = 0; - internal_godot_indexed_property_id = 0; - godot_allocator.js_malloc = QuickJSBinder::js_binder_malloc; - godot_allocator.js_free = QuickJSBinder::js_binder_free; - godot_allocator.js_realloc = QuickJSBinder::js_binder_realloc; - godot_allocator.js_malloc_usable_size = NULL; - godot_object_class = NULL; - godot_reference_class = NULL; - - if (class_remap.is_empty()) { -#if 0 - class_remap.insert(File::get_class_static(), "File"); - class_remap.insert(_Directory::get_class_static(), "Directory"); - class_remap.insert(_Thread::get_class_static(), ""); - class_remap.insert(_Mutex::get_class_static(), ""); - class_remap.insert(_Semaphore::get_class_static(), ""); -#endif - } -} - -QuickJSBinder::~QuickJSBinder() { -} - void QuickJSBinder::initialize() { thread_id = Thread::get_caller_id(); { diff --git a/quickjs/quickjs_binder.h b/thirdparty/quickjs/quickjs_binder.h similarity index 95% rename from quickjs/quickjs_binder.h rename to thirdparty/quickjs/quickjs_binder.h index 1be30191..1d003dd1 100644 --- a/quickjs/quickjs_binder.h +++ b/thirdparty/quickjs/quickjs_binder.h @@ -1,29 +1,29 @@ #ifndef QUICKJS_BINDING_HELPER_H #define QUICKJS_BINDING_HELPER_H -#include "../javascript_binder.h" +#include "core/io/resource.h" +#include "core/os/memory.h" +#include "core/os/thread.h" +#include "core/variant/callable.h" + +#include "../../javascript_binder.h" #include "./quickjs/quickjs.h" +#include "quickjs_builtin_binder.h" #ifdef QUICKJS_WITH_DEBUGGER #include "quickjs_debugger.h" #endif -#include "core/os/memory.h" -#include "core/os/thread.h" -#include "core/io/resource.h" -#include "core/variant/callable.h" -#include "quickjs_builtin_binder.h" + #define JS_HIDDEN_SYMBOL(x) ("\xFF" x) #define BINDING_DATA_FROM_JS(ctx, p_val) (JavaScriptGCHandler *)JS_GetOpaque((p_val), QuickJSBinder::get_origin_class_id((ctx))) #define GET_JSVALUE(p_gc_handler) JS_MKPTR(JS_TAG_OBJECT, (p_gc_handler).javascript_object) #define NO_MODULE_EXPORT_SUPPORT 0 -#define MODULE_HAS_REFCOUNT 0 // module seems don't follow the refrence count rule in quickjs +#define MODULE_HAS_REFCOUNT 0 // The module doesn't seem to follow the reference count rule in quickjs. #define MAX_ARGUMENT_COUNT 50 #define PROP_NAME_CONSOLE_LOG_OBJECT_TO_JSON "LOG_OBJECT_TO_JSON" #define ENDL "\r\n" -class QuickJSWorker; class QuickJSBinder : public JavaScriptBinder { - friend class QuickJSBuiltinBinder; friend class QuickJSWorker; QuickJSBuiltinBinder builtin_binder; @@ -117,7 +117,8 @@ class QuickJSBinder : public JavaScriptBinder { _FORCE_INLINE_ static void *js_binder_malloc(JSMallocState *s, size_t size) { return memalloc(size); } _FORCE_INLINE_ static void js_binder_free(JSMallocState *s, void *ptr) { - if (ptr) memfree(ptr); + if (ptr) + memfree(ptr); } _FORCE_INLINE_ static void *js_binder_realloc(JSMallocState *s, void *ptr, size_t size) { return memrealloc(ptr, size); } @@ -280,8 +281,21 @@ class QuickJSBinder : public JavaScriptBinder { } public: - QuickJSBinder(); - virtual ~QuickJSBinder(); + + QuickJSBinder() { + context_id = QuickJSBinder::global_context_id.increment(); + internal_godot_method_id = 0; + internal_godot_indexed_property_id = 0; + godot_allocator.js_malloc = QuickJSBinder::js_binder_malloc; + godot_allocator.js_free = QuickJSBinder::js_binder_free; + godot_allocator.js_realloc = QuickJSBinder::js_binder_realloc; + godot_allocator.js_malloc_usable_size = nullptr; + godot_object_class = nullptr; + godot_reference_class = nullptr; + } + + virtual ~QuickJSBinder() { + } _FORCE_INLINE_ static QuickJSBinder *get_context_binder(JSContext *ctx) { return static_cast(JS_GetContextOpaque(ctx)); diff --git a/quickjs/quickjs_builtin_binder.cpp b/thirdparty/quickjs/quickjs_builtin_binder.cpp similarity index 92% rename from quickjs/quickjs_builtin_binder.cpp rename to thirdparty/quickjs/quickjs_builtin_binder.cpp index 3a6c48fe..34aa19d8 100644 --- a/quickjs/quickjs_builtin_binder.cpp +++ b/thirdparty/quickjs/quickjs_builtin_binder.cpp @@ -1,11 +1,14 @@ -#include "quickjs_builtin_binder.h" +#include "core/io/compression.h" #include "core/math/color.h" +#include "core/os/memory.h" #include "core/variant/variant.h" -#include "quickjs_binder.h" -#include -#include + #include +#include "javascript_binder.h" +#include "quickjs_binder.h" +#include "quickjs_builtin_binder.h" + QuickJSBuiltinBinder::QuickJSBuiltinBinder() { ctx = NULL; builtin_class_map = memnew_arr(BuiltinClass, Variant::VARIANT_MAX); @@ -16,7 +19,6 @@ QuickJSBuiltinBinder::~QuickJSBuiltinBinder() { } void QuickJSBuiltinBinder::bind_builtin_object(JSContext *ctx, JSValue target, Variant::Type p_type, const void *p_object) { - void *ptr = NULL; JavaScriptGCHandler *bind = NULL; switch (p_type) { @@ -636,7 +638,6 @@ JSValue QuickJSBuiltinBinder::new_object_from(JSContext *ctx, const PackedVector } void QuickJSBuiltinBinder::bind_builtin_propties_manually() { - { // Color JSCFunctionMagic *getter = [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) -> JSValue { JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); @@ -727,22 +728,22 @@ void QuickJSBuiltinBinder::bind_builtin_propties_manually() { binder->get_builtin_binder().register_property(Variant::RECT2, "end", getter, setter, 0); binder->get_builtin_binder().register_method( - Variant::RECT2, - "grow_side", - [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + Variant::RECT2, + "grow_side", + [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { #ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(argc < 2, (JS_ThrowTypeError(ctx, "Two arguments expected for Rect2.grow_margin"))); + ERR_FAIL_COND_V(argc < 2, (JS_ThrowTypeError(ctx, "Two arguments expected for Rect2.grow_margin"))); #endif - JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); - Rect2 *ptr = bind->getRect2(); + JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); + Rect2 *ptr = bind->getRect2(); #ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::INT, argv[0]), (JS_ThrowTypeError(ctx, "number expected for argument 0 of Rect2.grow_margin"))); - ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::FLOAT, argv[0]), (JS_ThrowTypeError(ctx, "number expected for argument 1 of Rect2.grow_margin"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::INT, argv[0]), (JS_ThrowTypeError(ctx, "number expected for argument 0 of Rect2.grow_margin"))); + ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, Variant::FLOAT, argv[0]), (JS_ThrowTypeError(ctx, "number expected for argument 1 of Rect2.grow_margin"))); #endif - Rect2 ret = ptr->grow_side(Side(QuickJSBinder::js_to_int(ctx, argv[0])), QuickJSBinder::js_to_number(ctx, argv[1])); - return QuickJSBinder::variant_to_var(ctx, ret); - }, - 2); + Rect2 ret = ptr->grow_side(Side(QuickJSBinder::js_to_int(ctx, argv[0])), QuickJSBinder::js_to_number(ctx, argv[1])); + return QuickJSBinder::variant_to_var(ctx, ret); + }, + 2); } { // Transform2D @@ -896,51 +897,51 @@ void QuickJSBuiltinBinder::bind_builtin_propties_manually() { } { // Transform binder->get_builtin_binder().register_method( - Variant::TRANSFORM3D, - "xform", - [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - ERR_FAIL_COND_V(argc < 1, (JS_ThrowTypeError(ctx, "Argument expected for Transform3D.xform"))); - JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); - Transform3D *ptr = bind->getTransform3D(); - if (QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0])) { - Vector3 ret = ptr->xform(Vector3(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } else if (QuickJSBinder::validate_type(ctx, Variant::PLANE, argv[0])) { - Plane ret = ptr->xform(Plane(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } else if (QuickJSBinder::validate_type(ctx, Variant::AABB, argv[0])) { - AABB ret = ptr->xform(AABB(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } else if (QuickJSBinder::validate_type(ctx, Variant::PACKED_VECTOR3_ARRAY, argv[0])) { - PackedVector3Array ret = ptr->xform(PackedVector3Array(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } - ERR_FAIL_V(JS_ThrowTypeError(ctx, "Vector3, Plane, AABB or PackedVector3Array expected for argument #0 of Transform3D.xform")); - }, - 1); + Variant::TRANSFORM3D, + "xform", + [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + ERR_FAIL_COND_V(argc < 1, (JS_ThrowTypeError(ctx, "Argument expected for Transform3D.xform"))); + JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); + Transform3D *ptr = bind->getTransform3D(); + if (QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0])) { + Vector3 ret = ptr->xform(Vector3(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } else if (QuickJSBinder::validate_type(ctx, Variant::PLANE, argv[0])) { + Plane ret = ptr->xform(Plane(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } else if (QuickJSBinder::validate_type(ctx, Variant::AABB, argv[0])) { + AABB ret = ptr->xform(AABB(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } else if (QuickJSBinder::validate_type(ctx, Variant::PACKED_VECTOR3_ARRAY, argv[0])) { + PackedVector3Array ret = ptr->xform(PackedVector3Array(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } + ERR_FAIL_V(JS_ThrowTypeError(ctx, "Vector3, Plane, AABB or PackedVector3Array expected for argument #0 of Transform3D.xform")); + }, + 1); binder->get_builtin_binder().register_method( - Variant::TRANSFORM3D, - "xform_inv", - [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - ERR_FAIL_COND_V(argc < 1, (JS_ThrowTypeError(ctx, "Argument expected for Transform3D.xform_inv"))); - JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); - Transform3D *ptr = bind->getTransform3D(); - if (QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0])) { - Vector3 ret = ptr->xform_inv(Vector3(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } else if (QuickJSBinder::validate_type(ctx, Variant::PLANE, argv[0])) { - Plane ret = ptr->xform_inv(Plane(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } else if (QuickJSBinder::validate_type(ctx, Variant::AABB, argv[0])) { - AABB ret = ptr->xform_inv(AABB(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } else if (QuickJSBinder::validate_type(ctx, Variant::PACKED_VECTOR3_ARRAY, argv[0])) { - PackedVector3Array ret = ptr->xform_inv(PackedVector3Array(QuickJSBinder::var_to_variant(ctx, argv[0]))); - return QuickJSBinder::variant_to_var(ctx, ret); - } - ERR_FAIL_V(JS_ThrowTypeError(ctx, "Vector3, Plane, AABB or PackedVector3Array expected for argument #0 of Transform3D.xform_inv")); - }, - 1); + Variant::TRANSFORM3D, + "xform_inv", + [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + ERR_FAIL_COND_V(argc < 1, (JS_ThrowTypeError(ctx, "Argument expected for Transform3D.xform_inv"))); + JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); + Transform3D *ptr = bind->getTransform3D(); + if (QuickJSBinder::validate_type(ctx, Variant::VECTOR3, argv[0])) { + Vector3 ret = ptr->xform_inv(Vector3(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } else if (QuickJSBinder::validate_type(ctx, Variant::PLANE, argv[0])) { + Plane ret = ptr->xform_inv(Plane(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } else if (QuickJSBinder::validate_type(ctx, Variant::AABB, argv[0])) { + AABB ret = ptr->xform_inv(AABB(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } else if (QuickJSBinder::validate_type(ctx, Variant::PACKED_VECTOR3_ARRAY, argv[0])) { + PackedVector3Array ret = ptr->xform_inv(PackedVector3Array(QuickJSBinder::var_to_variant(ctx, argv[0]))); + return QuickJSBinder::variant_to_var(ctx, ret); + } + ERR_FAIL_V(JS_ThrowTypeError(ctx, "Vector3, Plane, AABB or PackedVector3Array expected for argument #0 of Transform3D.xform_inv")); + }, + 1); } { // PackedByteArray @@ -1131,10 +1132,10 @@ void QuickJSBuiltinBinder::bind_builtin_propties_manually() { JavaScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val); PackedColorArray *array = memnew(PackedColorArray(*bind->getPackedColorArray())); JSValue ret = JS_NewArrayBuffer( - ctx, (uint8_t *)(array->ptr()), array->size() * sizeof(Color), [](JSRuntime *rt, void *opaque, void *ptr) { - memdelete(static_cast(opaque)); - }, - array, false); + ctx, (uint8_t *)(array->ptr()), array->size() * sizeof(Color), [](JSRuntime *rt, void *opaque, void *ptr) { + memdelete(static_cast(opaque)); + }, + array, false); return ret; }, 0); diff --git a/quickjs/quickjs_builtin_binder.h b/thirdparty/quickjs/quickjs_builtin_binder.h similarity index 99% rename from quickjs/quickjs_builtin_binder.h rename to thirdparty/quickjs/quickjs_builtin_binder.h index 33e90159..55c697df 100644 --- a/quickjs/quickjs_builtin_binder.h +++ b/thirdparty/quickjs/quickjs_builtin_binder.h @@ -1,14 +1,16 @@ #ifndef QUICKJS_BUILTIN_BINDER_H #define QUICKJS_BUILTIN_BINDER_H -#include "quickjs/quickjs.h" #include "core/variant/variant.h" + +#include "quickjs/quickjs.h" + struct JavaScriptGCHandler; -class QuickJSBinder; typedef JSValue (*JSConstructorFunc)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv); typedef void (*JSFinalizerFunc)(JSRuntime *rt, JSValue val); +class QuickJSBinder; class QuickJSBuiltinBinder { public: struct BuiltinClass { diff --git a/thirdparty/quickjs/quickjs_callable.cpp b/thirdparty/quickjs/quickjs_callable.cpp new file mode 100644 index 00000000..07336d54 --- /dev/null +++ b/thirdparty/quickjs/quickjs_callable.cpp @@ -0,0 +1,78 @@ +#include "quickjs_callable.h" +#include "javascript_language.h" +#include "quickjs/quickjs.h" + +#include "quickjs_binder.h" +#include "quickjs_builtin_binder.h" + +bool QuickJSCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + const QuickJSCallable *a = static_cast(p_a); + const QuickJSCallable *b = static_cast(p_b); + return a->js_function.javascript_object == b->js_function.javascript_object; +} + +bool QuickJSCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { + if (compare_equal(p_a, p_b)) { + return false; + } + return p_a < p_b; +} + +QuickJSCallable::QuickJSCallable(JSContext *ctx, const JSValue &p_value) { + ERR_FAIL_COND(!JS_IsFunction(ctx, p_value)); + JSValue v = JS_DupValue(ctx, p_value); + js_function.context = ctx; + js_function.javascript_object = JS_VALUE_GET_PTR(v); +} + +QuickJSCallable::QuickJSCallable(const JavaScriptGCHandler &p_function) : JavaScriptCallable(p_function) { + JSValue js_func; + js_func.u.ptr = p_function.javascript_object; + js_func.tag = JS_TAG_OBJECT; + JSContext *ctx = static_cast(p_function.context); + ERR_FAIL_COND(JS_IsFunction(ctx, js_func)); + JS_DupValue(ctx, js_func); +} + +QuickJSCallable::~QuickJSCallable() { + if (js_function.is_valid_javascript_object()) { + JSContext *ctx = static_cast(js_function.context); + JSValue temp; + temp.u.ptr = js_function.javascript_object; + temp.tag = JS_TAG_OBJECT; + JSValue js_func = temp; + JS_FreeValue(ctx, js_func); + } +} + +uint32_t QuickJSCallable::hash() const { + JSValue js_func; + js_func.u.ptr = js_function.javascript_object; + js_func.tag = JS_TAG_OBJECT; + return hash_murmur3_one_64((uint64_t)JS_VALUE_GET_PTR(js_func)); +} + +String QuickJSCallable::get_as_text() const { + QuickJSBinder *binder = QuickJSBinder::get_context_binder(static_cast(js_function.context)); + JSValue js_func; + js_func.u.ptr = js_function.javascript_object; + js_func.tag = JS_TAG_OBJECT; + JSContext *ctx = static_cast(js_function.context); + String text = binder->js_to_string(ctx, js_func); + return text; +} + +ObjectID QuickJSCallable::get_object() const { + return JavaScriptLanguage::get_singleton()->get_callable_middleman()->get_instance_id(); +} + +void QuickJSCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { + QuickJSBinder *binder = QuickJSBinder::get_context_binder(static_cast(js_function.context)); + JSValue js_func; + js_func.tag = JS_TAG_OBJECT; + js_func.u.ptr = js_function.javascript_object; + JavaScriptGCHandler func; + func.javascript_object = JS_VALUE_GET_PTR(js_func); + JavaScriptGCHandler caller; + r_return_value = binder->call(func, caller, p_arguments, p_argcount, r_call_error); +} diff --git a/thirdparty/quickjs/quickjs_callable.h b/thirdparty/quickjs/quickjs_callable.h new file mode 100644 index 00000000..48050cd2 --- /dev/null +++ b/thirdparty/quickjs/quickjs_callable.h @@ -0,0 +1,29 @@ +#ifndef QUICKJS_CALLABLE_H +#define QUICKJS_CALLABLE_H +#include "javascript_callable.h" +#include "quickjs/quickjs.h" + +#if !defined(JS_NAN_BOXING) +struct JSValue; +#endif + +class QuickJSCallable : public JavaScriptCallable { + static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b); + static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b); + +public: + QuickJSCallable(JSContext *ctx, const JSValue &p_value); + QuickJSCallable(const JavaScriptGCHandler &p_function); + virtual ~QuickJSCallable(); + + virtual uint32_t hash() const override; + virtual String get_as_text() const override; + + virtual CompareEqualFunc get_compare_equal_func() const override { return QuickJSCallable::compare_equal; } + virtual CompareLessFunc get_compare_less_func() const override { return QuickJSCallable::compare_less; } + + virtual ObjectID get_object() const override; + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; +}; + +#endif // QUICKJS_CALLABLE_H diff --git a/quickjs/quickjs_debugger.cpp b/thirdparty/quickjs/quickjs_debugger.cpp similarity index 97% rename from quickjs/quickjs_debugger.cpp rename to thirdparty/quickjs/quickjs_debugger.cpp index 31016cde..36a54765 100644 --- a/quickjs/quickjs_debugger.cpp +++ b/thirdparty/quickjs/quickjs_debugger.cpp @@ -1,4 +1,5 @@ #include "quickjs_debugger.h" +#include #define QJS_DEBUGGER_DEBUG_LOG 0 @@ -26,7 +27,7 @@ size_t QuickJSDebugger::transport_read(void *udata, char *buffer, size_t length) #endif ERR_FAIL_COND_V(err != OK, -err); ERR_FAIL_COND_V(ret < 0, -4); - ERR_FAIL_COND_V(ret > (ssize_t)length, -6); + ERR_FAIL_COND_V(ret > (ptrdiff_t)length, -6); return ret; } @@ -41,7 +42,7 @@ size_t QuickJSDebugger::transport_write(void *udata, const char *buffer, size_t print_line(vformat("[write] %d %s", length, buffer)); #endif ERR_FAIL_COND_V(err != OK, -err); - ERR_FAIL_COND_V(ret <= 0 || ret > (ssize_t)length, -4); + ERR_FAIL_COND_V(ret <= 0 || ret > (ptrdiff_t)length, -4); return ret; } diff --git a/quickjs/quickjs_debugger.h b/thirdparty/quickjs/quickjs_debugger.h similarity index 94% rename from quickjs/quickjs_debugger.h rename to thirdparty/quickjs/quickjs_debugger.h index e509a0b7..e700d269 100644 --- a/quickjs/quickjs_debugger.h +++ b/thirdparty/quickjs/quickjs_debugger.h @@ -33,7 +33,7 @@ class QuickJSDebugger : public RefCounted { Error attach_js_debugger(JSContext *p_ctx, Ref p_peer); public: - Error connect(JSContext *ctx, const String &address); + Error connect_debugger(JSContext *ctx, const String &address); Error listen(JSContext *ctx, const String &address); void poll(); diff --git a/quickjs/quickjs_worker.cpp b/thirdparty/quickjs/quickjs_worker.cpp similarity index 100% rename from quickjs/quickjs_worker.cpp rename to thirdparty/quickjs/quickjs_worker.cpp diff --git a/quickjs/quickjs_worker.h b/thirdparty/quickjs/quickjs_worker.h similarity index 99% rename from quickjs/quickjs_worker.h rename to thirdparty/quickjs/quickjs_worker.h index 9d481dfa..de998a20 100644 --- a/quickjs/quickjs_worker.h +++ b/thirdparty/quickjs/quickjs_worker.h @@ -2,6 +2,7 @@ #define QUICKJS_WORKER_H #include "core/os/thread.h" + #include "quickjs_binder.h" class QuickJSWorker : public QuickJSBinder { diff --git a/tools/editor_tools.h b/tools/editor_tools.h deleted file mode 100644 index 040005ae..00000000 --- a/tools/editor_tools.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef JAVASCRIPT_PLUGIN_H -#define JAVASCRIPT_PLUGIN_H -#include "editor/editor_file_dialog.h" -#include "editor/editor_node.h" - -class JavaScriptPlugin : public EditorPlugin { - GDCLASS(JavaScriptPlugin, EditorPlugin); - - enum MenuItem { - ITEM_GEN_DECLARE_FILE, - ITEM_GEN_TYPESCRIPT_PROJECT, - ITEM_GEN_ENUM_BINDING_SCRIPT, - }; - - EditorFileDialog *declaration_file_dialog; - EditorFileDialog *enumberation_file_dialog; - const Dictionary *modified_api; - -protected: - static String BUILTIN_DECLARATION_TEXT; - static String TSCONFIG_CONTENT; - static String TS_DECORATORS_CONTENT; - static String PACKAGE_JSON_CONTENT; - - static void _bind_methods(); - - void _notification(int p_what); - void _on_menu_item_pressed(int item); - void _export_typescript_declare_file(const String &p_path); - void _export_enumeration_binding_file(const String &p_path); - void _generate_typescript_project(); - -public: - virtual String get_name() const override { return "JavaScriptPlugin"; } - JavaScriptPlugin(EditorNode *p_node); -}; - -#endif