58 Commits

Author SHA1 Message Date
9757a8db31 Fix installation stuff 2026-01-28 23:16:59 +00:00
cef357ffdc Fixes 2026-01-28 22:19:32 +00:00
515d5559a7 Allow ruby versions 3.2 and 3.4 for installation 2026-01-28 22:12:37 +00:00
1312c09501 Fix bug 2026-01-28 19:01:45 +00:00
b018877c03 Cleanup 2026-01-28 19:00:34 +00:00
e6f51d69b6 Add installer script 2026-01-28 18:57:23 +00:00
6abdefa808 Cleanup and minor Fixes 2026-01-28 18:46:44 +00:00
cca0177929 Allow ruby based configs and custom syntax parsers 2026-01-22 19:25:15 +00:00
6dc0813b49 Random stuff to do with scripting 2026-01-21 15:05:37 +00:00
81da75dc15 Fix bugs with hl line data structures 2026-01-20 09:37:54 +00:00
fd894e4e9f Remove unneccesary grammar files and tree-ditter mentions 2026-01-18 17:52:09 +00:00
b5c49f4277 Improve highlighters 2026-01-18 17:49:36 +00:00
c9324c13aa Fix ruby true/false detection bug 2026-01-18 13:23:54 +00:00
c8db7b14a3 Cleanup 2026-01-18 13:20:51 +00:00
d0e811904c Allow dynamic theming and improve ruby parser 2026-01-18 13:00:41 +00:00
1fda5bf246 Add custom syntax highlighter and optimize 2026-01-16 21:47:05 +00:00
04cce25bf2 Add indentation engine and other fixes 2026-01-12 22:48:51 +00:00
9ed640c88e Fix autocomplete bug when local filtering is used 2026-01-11 01:16:54 +00:00
bb87ae32f9 Whitespace cleanup 2026-01-11 01:15:49 +00:00
f2f176e8c8 Make TODO.md better structured 2026-01-11 01:14:37 +00:00
cdddb35d7c Fix mistake in README 2026-01-10 19:41:57 +00:00
e37d291e1d Cleanup 2026-01-10 19:29:56 +00:00
78bf2d666d Completions bug fixes and switch to a better html lsp 2026-01-10 19:24:38 +00:00
b20702928a Fix diagnostics box width to be a bit more smarter 2026-01-10 18:16:18 +00:00
3f2046bf9f Fix broken lsp links 2026-01-10 18:15:50 +00:00
672e1a5c4e Fix broken link 2026-01-10 17:52:53 +00:00
ae7bb754ae README.md fixes 2026-01-10 17:51:47 +00:00
9bd4145d8c Fix readme.md 2026-01-10 17:49:05 +00:00
8f69ee487b Add more features listing 2026-01-10 17:44:45 +00:00
4134c4d96d Markdown cleanup 2026-01-10 17:38:54 +00:00
7d35799394 Update README.md 2026-01-10 17:31:19 +00:00
2c1e69181a Bug Fixes and optimizations 2026-01-10 17:15:09 +00:00
b2a64f219f Completions bug fixes 2026-01-10 07:56:40 +00:00
e9da17eb34 Basic completion support 2026-01-06 11:39:17 +00:00
a905e333fc Lsp completion logic 2026-01-04 03:27:17 +00:00
ac04754318 Cleanup and ui bar 2026-01-03 17:46:04 +00:00
0390a1bc5d Cleanup 2025-12-30 15:22:09 +00:00
dc507dfc23 Make syntax highlighting smoother 2025-12-30 10:56:31 +00:00
26e0b06e24 Add strikethrough support 2025-12-30 10:55:32 +00:00
235eafb01c Rearrange code and cleanup 2025-12-30 01:19:50 +00:00
04179d1a4e Cleanup and add visible whitespaces. 2025-12-29 21:55:49 +00:00
c7068d33d7 Feat: add hover boxes and diagnostics from lsp 2025-12-29 15:56:51 +00:00
6108f78be3 Fix lsp bugs
- Fix: Incorrect setting of incremental edits for lsp and more
2025-12-27 09:53:46 +00:00
bfaba81317 Add lsp's for many different languages and minor fixes 2025-12-27 04:31:08 +00:00
a38ba1f813 Minor fixes and optimizations 2025-12-26 22:13:11 +00:00
655f0e7d77 Feat: Add syntax highlighting for a lot more languages 2025-12-26 20:46:36 +00:00
9ff3a32abd Fix highlight colors and other minor fixes 2025-12-25 23:37:49 +00:00
b6e40ae1a6 Add tree-sitter grammars for common languages I use. 2025-12-25 22:01:58 +00:00
f3c87431a3 Add lsp warnings and updates support (and other minor fixes) 2025-12-25 18:14:45 +00:00
69b981097e Improve syntax highlight injection logic 2025-12-25 04:55:56 +00:00
659628835d Add tree-sitter injections support & cleanup 2025-12-25 04:14:53 +00:00
a10dd92249 Basic lsp and precompiler header support 2025-12-24 11:08:25 +00:00
85d4039a5e Readme updates 2025-12-22 17:24:35 +00:00
43f443e128 Add virtual text support in editor rendering 2025-12-22 17:18:45 +00:00
a12e2fb1c4 Add better indentation and pasting 2025-12-22 14:56:48 +00:00
7307387f64 Optimize line iterator 2025-12-19 20:46:52 +00:00
8002012705 Update todo list 2025-12-19 15:00:16 +00:00
d5145d88a7 Basic indentation support 2025-12-18 18:55:08 +00:00
319 changed files with 53635 additions and 4486 deletions

7
.clangd Normal file
View File

@@ -0,0 +1,7 @@
CompileFlags:
Add: [-I/home/syed/main/crib/include, -I/home/syed/main/crib/libs, -I/home/syed/main/crib/libs/libruby, c++20]
Remove: []
Compiler: clang++
HeaderInsertion:
Policy: Never

3
.gitattributes vendored
View File

@@ -1,2 +1 @@
/libs/unicode_width/** linguist-vendored
*.scm linguist-language=Tree-sitter-Query
/libs/** linguist-vendored

7
.gitignore vendored
View File

@@ -3,13 +3,18 @@
*.a
*.o
*.so
!libs/libruby/libruby.so
*.yml
.vscode
samples/t_*
samples/tmp*
build
bin
.thinlto-cache/
Gemfile*
.ruby-lsp/
__old__

66
.gitmodules vendored
View File

@@ -2,67 +2,7 @@
path = libs/libgrapheme
url = git://git.suckless.org/libgrapheme
ignore = dirty
; tree-sitter
[submodule "libs/tree-sitter"]
path = libs/tree-sitter
url = https://github.com/tree-sitter/tree-sitter.git
[submodule "libs/utfcpp"]
path = libs/utfcpp
url = https://github.com/nemtrif/utfcpp.git
ignore = dirty
; Tree-sitter languages
[submodule "libs/tree-sitter-ruby"]
path = libs/tree-sitter-ruby
url = https://github.com/tree-sitter/tree-sitter-ruby.git
ignore = dirty
[submodule "libs/tree-sitter-c"]
path = libs/tree-sitter-c
url = https://github.com/tree-sitter/tree-sitter-c.git
ignore = dirty
[submodule "libs/tree-sitter-cpp"]
path = libs/tree-sitter-cpp
url = https://github.com/tree-sitter/tree-sitter-cpp.git
ignore = dirty
[submodule "libs/tree-sitter-css"]
path = libs/tree-sitter-css
url = https://github.com/tree-sitter/tree-sitter-css.git
ignore = dirty
[submodule "libs/tree-sitter-html"]
path = libs/tree-sitter-html
url = https://github.com/tree-sitter/tree-sitter-html.git
ignore = dirty
[submodule "libs/tree-sitter-javascript"]
path = libs/tree-sitter-javascript
url = https://github.com/tree-sitter/tree-sitter-javascript.git
ignore = dirty
[submodule "libs/tree-sitter-json"]
path = libs/tree-sitter-json
url = https://github.com/tree-sitter/tree-sitter-json.git
ignore = dirty
[submodule "libs/tree-sitter-python"]
path = libs/tree-sitter-python
url = https://github.com/tree-sitter/tree-sitter-python.git
ignore = dirty
[submodule "libs/tree-sitter-haskell"]
path = libs/tree-sitter-haskell
url = https://github.com/tree-sitter/tree-sitter-haskell.git
ignore = dirty
[submodule "libs/tree-sitter-go"]
path = libs/tree-sitter-go
url = https://github.com/tree-sitter/tree-sitter-go.git
ignore = dirty
[submodule "libs/tree-sitter-bash"]
path = libs/tree-sitter-bash
url = https://github.com/tree-sitter/tree-sitter-bash.git
ignore = dirty
[submodule "libs/tree-sitter-markdown"]
path = libs/tree-sitter-markdown
url = https://github.com/tree-sitter-grammars/tree-sitter-markdown
[submodule "libs/tree-sitter-make"]
path = libs/tree-sitter-make
url = https://github.com/tree-sitter-grammars/tree-sitter-make
[submodule "libs/tree-sitter-lua"]
path = libs/tree-sitter-lua
url = https://github.com/tree-sitter-grammars/tree-sitter-lua
[submodule "libs/tree-sitter-fish"]
path = libs/tree-sitter-fish
url = https://github.com/ram02z/tree-sitter-fish

116
Makefile
View File

@@ -1,41 +1,69 @@
SRC_DIR := src
BIN_DIR := bin
OBJ_DIR := build
INCLUDE_DIR := include
TARGET_DEBUG := $(BIN_DIR)/crib-dbg
TARGET_RELEASE := $(BIN_DIR)/crib
TARGET_RELEASE_32 := $(BIN_DIR)/crib-ruby3.2
TARGET_RELEASE_34 := $(BIN_DIR)/crib-ruby3.4
PCH_DEBUG := $(OBJ_DIR)/debug/pch.h.gch
PCH_RELEASE := $(OBJ_DIR)/release/pch.h.gch
CCACHE := ccache
CXX_DEBUG := $(CCACHE) g++
CXX_RELEASE := $(CCACHE) clang++
CXX := $(CCACHE) clang++
CFLAGS_DEBUG := -std=c++20 -Wall -Wextra -O0 -fno-inline -gsplit-dwarf -g -fsanitize=address -fno-omit-frame-pointer
CFLAGS_RELEASE := -std=c++20 -O3 -march=native -flto=thin \
-fno-exceptions -fno-rtti -fstrict-aliasing \
-ffast-math -funroll-loops \
-fvisibility=hidden \
RUBY32_INC := -I./libs/libruby
RUBY32_LIB := libs/libruby/libruby.so
RUBY32_PATCH := patchelf --replace-needed libruby-3.2.so.3.2 libruby.so
RUBY34_INC := \
-I/usr/include/ruby-3.4.0 \
-I/usr/include/ruby-3.4.0/x86_64-linux
RUBY34_LIB := -lruby
CFLAGS_DEBUG :=\
-std=c++23 -Wall -Wextra -Wno-c23-extensions \
-O0 -fno-inline -gsplit-dwarf\
-g -fno-omit-frame-pointer\
-Wno-unused-command-line-argument \
-I./include -I./libs -I./libs/libruby
CFLAGS_RELEASE :=\
-std=c++23 -O3 -march=native \
-fno-rtti -fstrict-aliasing \
-ffast-math -flto=thin \
-fvisibility=hidden -fuse-ld=lld \
-fomit-frame-pointer -DNDEBUG -s \
-mllvm -vectorize-loops \
-fno-unwind-tables -fno-asynchronous-unwind-tables
-fno-unwind-tables -fno-asynchronous-unwind-tables\
-Wno-unused-command-line-argument \
-Wno-c23-extensions \
-I./include -I./libs -I./libs/libruby
CFLAGS_RELEASE_32 := $(CFLAGS_RELEASE) $(RUBY32_INC)
CFLAGS_RELEASE_34 := $(CFLAGS_RELEASE) $(RUBY34_INC)
LIBS_32 := \
libs/libgrapheme/libgrapheme.a \
$(RUBY32_LIB) \
-Wl,-Bstatic -lpcre2-8 -Wl,-Bdynamic -lmagic
LIBS_34 := \
libs/libgrapheme/libgrapheme.a \
$(RUBY34_LIB) \
-Wl,-Bstatic -lpcre2-8 -Wl,-Bdynamic -lmagic
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header
UNICODE_SRC := $(wildcard libs/unicode_width/*.c)
UNICODE_OBJ_DEBUG := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/debug/unicode_width/%.o,$(UNICODE_SRC))
UNICODE_OBJ_RELEASE := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/release/unicode_width/%.o,$(UNICODE_SRC))
TREE_SITTER_LIBS := $(wildcard libs/tree-sitter-*/libtree-sitter*.a)
FISH_OBJ_PARSER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/parser.o
FISH_OBJ_SCANNER := libs/tree-sitter-fish/build/Release/obj.target/tree_sitter_fish_binding/src/scanner.o
LIBS := \
libs/libgrapheme/libgrapheme.a \
libs/tree-sitter/libtree-sitter.a \
$(TREE_SITTER_LIBS) \
$(FISH_OBJ_PARSER) \
$(FISH_OBJ_SCANNER) \
-lpcre2-8 -lmagic
SRC := $(wildcard $(SRC_DIR)/*.cc)
SRC := $(wildcard $(SRC_DIR)/**/*.cc) $(wildcard $(SRC_DIR)/*.cc)
OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC))
OBJ_RELEASE := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/release/%.o,$(SRC))
@@ -48,31 +76,45 @@ all: debug
test: $(TARGET_DEBUG)
release: $(TARGET_RELEASE)
release: $(TARGET_RELEASE_32) $(TARGET_RELEASE_34)
$(TARGET_DEBUG): $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG)
mkdir -p $(BIN_DIR)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -o $@ $^ $(LIBS)
$(TARGET_RELEASE): $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -o $@ $^ $(LIBS)
$(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc
$(PCH_DEBUG): $(INCLUDE_DIR)/pch.h
mkdir -p $(dir $@)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -MMD -MP -c $< -o $@
$(CXX) $(PCH_CFLAGS_DEBUG) -o $@ $<
$(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc
$(PCH_RELEASE): $(INCLUDE_DIR)/pch.h
mkdir -p $(dir $@)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -MMD -MP -c $< -o $@
$(CXX) $(PCH_CFLAGS_RELEASE) -o $@ $<
$(TARGET_DEBUG): $(PCH_DEBUG) $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG)
mkdir -p $(BIN_DIR)
$(CXX) $(CFLAGS_DEBUG) -o $@ $(OBJ_DEBUG) $(UNICODE_OBJ_DEBUG) $(LIBS)
patchelf --replace-needed libruby-3.2.so.3.2 libruby.so $@
$(TARGET_RELEASE_32): $(PCH_RELEASE) $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR)
$(CXX) $(CFLAGS_RELEASE_32) -o $@ $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) $(LIBS_32)
$(RUBY32_PATCH) $@
$(TARGET_RELEASE_34): $(PCH_RELEASE) $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE)
mkdir -p $(BIN_DIR)
$(CXX) $(CFLAGS_RELEASE_34) -o $@ $(OBJ_RELEASE) $(UNICODE_OBJ_RELEASE) $(LIBS_34)
$(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc $(PCH_DEBUG)
mkdir -p $(dir $@)
$(CXX) $(CFLAGS_DEBUG) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc $(PCH_RELEASE)
mkdir -p $(dir $@)
$(CXX) $(CFLAGS_RELEASE) -include $(INCLUDE_DIR)/pch.h -MMD -MP -c $< -o $@
$(OBJ_DIR)/debug/unicode_width/%.o: libs/unicode_width/%.c
mkdir -p $(dir $@)
$(CXX_DEBUG) $(CFLAGS_DEBUG) -MMD -MP -c $< -o $@
$(CXX) $(CFLAGS_DEBUG) -MMD -MP -c $< -o $@
$(OBJ_DIR)/release/unicode_width/%.o: libs/unicode_width/%.c
mkdir -p $(dir $@)
$(CXX_RELEASE) $(CFLAGS_RELEASE) -MMD -MP -c $< -o $@
$(CXX) $(CFLAGS_RELEASE) -MMD -MP -c $< -o $@
DEP_DEBUG += $(UNICODE_OBJ_DEBUG:.o=.d)
DEP_RELEASE += $(UNICODE_OBJ_RELEASE:.o=.d)

209
README.md
View File

@@ -1,26 +1,193 @@
Copyright 2025 Syed Daanish
# Crib
# Crib - a text editor
A TUI IDE.
### About
# TODO
Crib is a TUI based text editor built primaririly for personal use.<br>
Crib has a vim-style editor modes system but navigation and shortcuts are very different.<br>
It supports superfast incremental syntax highlighting.<br>
And LSP for auto-completion, diagnostics, hover docs etc.<br>
It aims to be complete general purpose IDE.<br>
(It is still very much a work in progress so a lot of things may seem incomplete)<br>
For now it is just a single file editor. I plan to add a multi-file support with file pickers and tabs soon.<br>
- [ ] Add feature where doing enter uses tree-sitter to add newline with indentation.
- it should also put stuff like `}` on the next line.
- [ ] Add the highlight of block edges when cursor is on a bracket (or in).
- [ ] Add this thing where selection double click on a bracket selects whole block.
- (only on the first time) and sets mode to `WORD`.
- [ ] Add support for virtual cursor where edits apply at all the places.
- [ ] Add alt + click to set multiple cursors.
- [ ] Add search / replace along with search / virtual cursors are searched pos.
- [ ] Add support for undo/redo.
- [ ] Add `.scm` files for all the supported languages. (2/14) Done.
- [ ] Add splash screen / minigame jumping.
- [ ] Add support for LSP & autocomplete / snippets.
- [ ] Add codeium/copilot support.
- [ ] Normalize / validate unicode on file open.
- [ ] Add git stuff.
- [ ] Fix bug where alt+up at eof adds extra line.
- [ ] Think about how i would keep fold states sensical if i added code prettying.
- [ ] Redo folding system and its relation to move_line_* functions.
## Installation
Binary can be installed with the following command:
```bash
curl https://syedm.dev/crib | sh
```
It requires `libruby-3.2.so` or `libruby.so.3.4` to be installed in the system.<br>
It also requires `libmagic` to be installed (most systems have it preinstalled).<br>
Currently only for Linux.<br>
*Tested with arch linux and ubuntu*<br>
## Building
### Get started
Make sure the repo is cloned with submodules to get `libgrapheme`.
```bash
git clone --recurse-submodules https://git.syedm.dev/SyedM/crib.git
```
### Dependencies
#### System-wide libraries
Make sure you have the following dependencies installed (apart from the standard C++ libraries):
* **[nlohmann/json](https://github.com/nlohmann/json)**
Install it via your package manager. Once installed, the header should be available as:
```cpp
#include <nlohmann/json.hpp>
```
* **[PCRE2](https://github.com/PCRE2Project/pcre2)**
Install the library to use its headers:
```cpp
#include <pcre2.h>
```
* **libmagic**
Install it so that you can include it in your code (most *nix systems have it installed):
```cpp
#include <magic.h>
```
It also uses `xclip` at runtime for copying/pasting *(TODO: make it os portable)*.
And any modern terminal should work fine - preferably `kitty` or `wezterm`.<br>
#### `./libs` folder
Some other dependancies are added as submodules or copied.<br>
- `unicode_width` is compiled by the makefile so nothing to do there.<br>
- `libgrapheme` needs to be compiled using `make` in it's folder.<br>
- ``
#### LSPs
Lsp's are defined in the `libcrib.rb` file and you can use your `config/main.rb` file to add more.<br>
The following lsp's are added by default and can be installed anywhere in your `$PATH`<br>
* [clangd](https://clangd.llvm.org/)
* [ruby-lsp](https://shopify.github.io/ruby-lsp/)
* [bash-language-server](https://github.com/bash-lsp/bash-language-server)
* [vscode-css-language-server](https://github.com/hrsh7th/vscode-langservers-extracted)
* [vscode-json-language-server](https://github.com/hrsh7th/vscode-langservers-extracted)
* [fish-lsp](https://github.com/ndonfris/fish-lsp)
* [gopls](https://pkg.go.dev/golang.org/x/tools/gopls)
* [haskell-language-server](https://github.com/haskell/haskell-language-server)
* [emmet-language-server](https://github.com/olrtg/emmet-language-server)
* [typescript-language-server](https://github.com/typescript-language-server/typescript-language-server)
* [lua-language-server](https://github.com/LuaLS/lua-language-server)
* [pyright-langserver](https://github.com/microsoft/pyright)
* [rust-analyzer](https://github.com/rust-analyzer/rust-analyzer)
* [intelephense](https://intelephense.com/)
* [marksman](https://github.com/artempyanykh/marksman)
* [nginx-language-server](https://github.com/pappasam/nginx-language-server)
* [taplo](https://taplo.tamasfe.dev/)
* [yaml-language-server](https://github.com/redhat-developer/yaml-language-server)
* [sqls](https://github.com/sqls-server/sqls)
* [make-language-server](https://github.com/Freed-Wu/autotools-language-server)
> As it is still in development, some of these may not work as expected or that well.<br>
> It should work even if the lsp is not installed but lsp features will not work.<br>
#### Compiler
`clang++` should work fine but `c++23+` is required.<br>
Can remove `ccache` if you want from the makefile.<br>
#### Compliling
```bash
make release
```
### Running
Preferably add the `bin` folder to PATH or move `bin/crib` to somewhere in PATH.<br>
For some LSP's to work properly `crib` needs to be run from the root folder of the project. *To be fixed*<br>
then do -<br>
```bash
crib ./filename.ext
```
*If `filename.ext` does not exist, it will be created*<br>
## Keybindings
TODO: add keybind information on how to set in `config/main.rb`
and default / unchangeable keybinds
## Features Implemented
#### Core workflow:
- NORMAL / INSERT / SELECT / RUNNER / JUMPER modes
- full mouse support for scrolling and multi-click word/line selection.
- Double click to select word
- Triple click to select line
#### Core editing tools:
- indent/dedent
- move lines up/down
- folding on a selected range
- yank/cut/paste via system clipboard
- per-language smart auto-indent on new line insert
- bracket/quote auto-pairing
- hooks jumping (bookmarking)
- color hex code highlighting
- current line highlighting
- all instances of current word under cursor highlighting
#### syntax highlighting and filetype detection (using extention or libmagic) for:
- ruby
<!-- TODO: -->
<!-- - bash -->
<!-- - c/cpp (and headers) -->
<!-- - css -->
<!-- - fish -->
<!-- - go/gomod -->
<!-- - haskell -->
<!-- - html/erb -->
<!-- - javascript -->
<!-- - typescript/tsx -->
<!-- - json/jsonc -->
<!-- - lua -->
<!-- - python -->
<!-- - rust -->
<!-- - php -->
<!-- - markdown -->
<!-- - nginx -->
<!-- - toml -->
<!-- - yaml -->
<!-- - sql -->
<!-- - make -->
<!-- - gdscript -->
<!-- - man pages -->
<!-- - diff/patch -->
<!-- - gitattributes/gitignore -->
<!-- - tree-sitter queries -->
<!-- - regex -->
<!-- - ini -->
#### LSP-powered features:
- diagnostics
- autocompletion
- hover docs
- formatting support
- Full file formatting on save
- Ontype formatting when inserting special characters defined by the language server
- *(few lsp's actually support this - try to configure a few more which can but need configuration and for others need to add support for external formatters)*
- A list of some lsp's can be found [here](#lsps).
- Any lsp can be added to the `config/main.rb` file.
- Though not all might work well. Open an issue if you find a lsp that doesn't work well.
**A lot lot more to come**

124
TODO.md Normal file
View File

@@ -0,0 +1,124 @@
Copyright 2025 Syed Daanish
# TODO
##### BTW Check each lsp with each of the features implemented
* Static link pcre2-8 and libmagic and add precompiled libmagic magic database for better file detection
* [ ] **LSP Bug:** Check why `fish-lsp` is behaving so off with completions filtering.
* [ ] **Critical Crash:** Fix bug where closing immediately while LSP is still loading hangs and then segfaults (especially on slow ones like fish-lsp where quick edits and exit can hang).
* [ ] **Line move:** fix the move line functions to work without the calculations from folds as folds are removed.
* [ ] **Editor Indentation Fix:** - Main : merger indentation with the parser for more accurate results.
* [ ] Fix bug where enter at start of line with ending type crashes
* [ ] Keep cache of language maps in engine to reduce lookup time.
* [ ] In indents add function to support tab which indents if before any content and inserts a pure \t otherwise.
* [ ] And backspace which undents if before any content.
* [ ] Add block indentation support.
* [ ] Ignore comments/strings from parser when auto-indenting.
* [ ] These will dedent when the block immediately after them is dedented
* [ ] Dont dedent if ending is valid starting is invalid but also empty
* [ ] Just leave asis if starting is empty
* [ ] **Readme:** Update readme to show ruby based config.
* [ ] **UI Refinement:**
* [ ] Allow completion list to be scrolled; show only `x` max items.
* [ ] Finish autocomplete box style functions.
* [ ] **Documentation UI:** Capture `Ctrl+h` / `Ctrl+l` for scrolling documentation windows.
* [ ] Redo hooks as a struct.
* [ ] breakdown the render function into smaller functions.
* Try to make all functions better now that folds have been purged
* Cleanup syntax and renderer files
* Add a thing called view which is a rect with speacial type editor . but otherwise a ruby or c++ view
* can be used for stuff like file manager/git manager/theme picker.
* allow flushing functions in ruby to tell c++ to refresh keybinds/themes etc.
* allow keybinds to be set in ruby
check::
pull diagnostics for ruby-lsp
lsp selection range - use to highlight start / end of range maybe?
goto definiton
signature help
document symbol for the top bar maybe? (or workspace symbol)
also setup workspaces
Semantic highlighting
Quick fixes
Rename symbols
probably remove solargraph support and use ruby-lsp (or sorbet?) instead because it is a pain for utf stuff
ruby-lsp also supports erb so thats a plus
move lsp configs to json and also allow configs for windows-style vs unix-style line endings and utf-8 vs utf-16
* the ruby should have an api to be able to draw windows and add mappings to them
* finish bash then do all the directive-like ones like jsonc (first to help with theme files) / toml / yaml / ini / nginx
* then markdown / html
* then gitignore / gitattributes
* then fish then sql then css and [jt]sx? then python then lua (make with type annotations for lsp results)
* then [ch](++)? then gdscript then erb then php
* then haskell then gomod then go then rust
* [ ] **Undo/Redo:** Add support for undo/redo history.
* [ ] **Auto brace selection:** Add support for auto brace selection.
* [ ] **Tree-sitter Indent:** Attempt to allow Tree-sitter to handle indentation if possible.
* [ ] **Scrolling:** Add logic where selecting at the end of the screen scrolls down (and vice versa).
* *Implementation:* Update `main.cc` to send drag events to the selected editor even if coordinates are out of bounds.
### UX
* [ ] **Editor word highlighter:** Do not recompute word under cursor if not changed.
* [ ] **Completion Filtering:**
* [ ] Stop filtering case-sensitive.
* [ ] Normalize completion edits if local filtering is used.
* [ ] **LSP Features:**
* [ ] Add LSP jumping support (Go to Definition, Hover).
* [ ] Add LSP rename support.
* [ ] Handle snippets properly in autocomplete: use only the last word in signature when replacing and set cursor to the first one.
* [ ] **Basic Autocomplete:** Keep a list of words in the current buffer for non-LSP fallback.
### Major Features
* [ ] **Search & Replace:**
* [ ] Add Search/Replace UI.
* [ ] Support capture groups (`$1`, `$2`) or allow Perl regex directly.
* [ ] Ensure virtual cursors are included in search positions.
* [ ] **Multi-Cursor:**
* [ ] Add virtual cursor support (edits apply to all locations).
* [ ] Add `Alt+Click` to set multiple cursors.
* [ ] Allow search and place cursor at all matches.
* [ ] **Block Selection:**
* [ ] Double-clicking a bracket selects the whole block (first time only) and sets mode to `WORD`.
### Visuals, UI & Extensions?
* [ ] **Status Bar:** Complete status bar and command runner.
* [ ] Add color picker/palette.
* [ ] **Git:** Add Git integration (status, diffs).
* [ ] **AI/Snippets:**
* [ ] Add snippets support (LuaSnip/VSnip style).
* [ ] Add Codeium/Copilot support (using VAI virtual text) as a test phase.
* [ ] **SQL:** Add SQL support (Viewer and Basic Editor).
* [ ] **Prolly?:** Add Splash Screen / Minigame.
### Optimizations & Fluff
* [ ] **Performance:**
* [ ] Switch JSON parser to `RapidJSON` (or similar high-performance lib).
* [ ] Decrease usage of `std::string` in UI, LSP, and warnings.
* [ ] Also for vectors into managed memory especially for completions/lsp-stuff.

127
config/main.rb Normal file
View File

@@ -0,0 +1,127 @@
# basic configuration
# This can also be used to do speacail configs for different projects.
# its ruby guys script whatever you want.
C.startup do
puts "Starting crib..."
end
C.shutdown do
puts "Exiting crib..."
end
# this can be modified by the user during runtime through keybindings
# But i need to know how to ever read this value only when needed.
# maybe i can write a function that notifies if theme maybe changed then reload
# It can also be scripted to load different theme formats into a hash usable by crib
C.theme = {
:default => { fg: 0xEEEEEE },
:shebang => { fg: 0x7DCFFF },
:error => { fg: 0xEF5168 },
:comment => { fg: 0xAAAAAA, italic: true },
:string => { fg: 0xAAD94C },
:escape => { fg: 0x7DCFFF },
:interpolation => { fg: 0x7DCFFF },
:regexp => { fg: 0xD2A6FF },
:number => { fg: 0xE6C08A },
# rubocop:disable Lint/BooleanSymbol
:true => { fg: 0x7AE93C },
:false => { fg: 0xEF5168 },
# rubocop:enable Lint/BooleanSymbol
:char => { fg: 0xFFAF70 },
:keyword => { fg: 0xFF8F40 },
:keywordoperator => { fg: 0xF07178 },
:operator => { fg: 0xFFFFFF, italic: true },
:function => { fg: 0xFFAF70 },
:type => { fg: 0xF07178 },
:constant => { fg: 0x7DCFFF },
:variableinstance => { fg: 0x95E6CB },
:variableglobal => { fg: 0xF07178 },
:annotation => { fg: 0x7DCFFF },
:directive => { fg: 0xFF8F40 },
:label => { fg: 0xD2A6FF },
:brace1 => { fg: 0xD2A6FF },
:brace2 => { fg: 0xFFAFAF },
:brace3 => { fg: 0xFFFF00 },
:brace4 => { fg: 0x0FFF0F },
:brace5 => { fg: 0xFF0F0F }
}
# # TODO: to be done once a proper api for binding and window drawing is made
# # The binds will be connected to either `editor` or windows where editor can
# # only use a preset set of stuff to bind while teh windows are purely custom
# # # this part uses dsl bindings to define the bind function
# # # Hopefully extend to give more context/power to bindings
# # # but try to keep simple for performance
# # # for default keybindings
# # C.bind [:normal, :select], :a => "insert_mode"
# # # for custom keybindings
# # C.bind :select, [:x, :c] do
# # puts "cut"
# # end
# # C.bind :jumper do
# # set [:x, :c] do
# # puts "jump to first bookmark"
# # end
# # end
# # # they can also be defined conditionally
# # # This code is just an example and doesnt actually work
# # if using_tmux?
# # bind :C-p do
# # system("tmux select-pane -U")
# # end
# # end
# This can, for example, be modified by user bindings during runtime
# TODO: dynamic registration to actually be implemented once keybinds and extentions are implemented
# A predefined list already exists and can be found in libcrib.rb
# C.lsp_config["solargraph"] = ["stdio"]
#
# C.languages[:ruby] = {
# color: 0xff8087,
# symbol: "󰴭 ",
# extensions: ["rb"],
# filenames: ["Gemfile"],
# mimetypes: ["text/x-ruby"],
# lsp: "solargraph"
# }
C.line_endings = :auto_unix # or :unix or :windows or :auto_windows
# C.extra_highlights do |_line, _idx|
# # the return can be an array of
# # [fg, bg. flags, start, end]
# # where fg and bg are integers (using 24 bit color)
# # and flags is a bitmask of bold/underline/italic etc
# # and start and end are integers strictly inside the line
# return []
# end
# The highlighter will be aplied to the language as long as the langauge is defined in C.languages
C.highlighters[:ruby_n] = {
parser: ->(line, state, line_idx) {
# the return value is a hash
# it contains the state and the highlights
# state can be of any type but will be consistent between calls
# initially nil is sent for uninitialized state the returned must be anything but nil
# the same state can be used for multiple lines
# the highlights can be an array of
# [K_type, start, end]
# K_type is a constant from the constants defined in libcrib.rb
# for ex: for strings it would be Tokens::K_STRING or for numbers Tokens::K_NUMBER etc.
# and start and end are integers strictly inside the line
return {
state: "",
tokens: [
# This will highlight the entire line as a string
# Any wrong format will not be handled and lead to crashes
{ type: Tokens::K_STRING, start: 0, end: line.length }
]
}
},
matcher: ->(state1, state2) {
# returns true if the states are equal
# And so would not need recomputation for further lines
return state1 == state2
}
}

View File

@@ -1,278 +0,0 @@
;; #bd9ae6 #000000 0 0 0 1
[
"("
")"
"{"
"}"
"["
"]"
"[["
"]]"
"(("
"))"
] @punctuation.bracket
;; #bd9ae6 #000000 0 0 0 1
[
";"
";;"
";&"
";;&"
"&"
] @punctuation.delimiter
;; #ffffff #000000 0 1 0 1
[
">"
">>"
"<"
"<<"
"&&"
"|"
"|&"
"||"
"="
"+="
"=~"
"=="
"!="
"&>"
"&>>"
"<&"
">&"
">|"
"<&-"
">&-"
"<<-"
"<<<"
".."
"!"
] @operator
;; #aad84c #000000 0 0 0 1
[
(string)
(raw_string)
(ansi_c_string)
(heredoc_body)
] @string
;; #fbb152 #000000 0 0 0 1
[
(heredoc_start)
(heredoc_end)
] @label
(variable_assignment
(word) @string)
(command
argument: "$" @string) ; bare dollar
(concatenation
(word) @string)
;; #fbb152 #000000 0 0 0 1
[
"if"
"then"
"else"
"elif"
"fi"
"case"
"in"
"esac"
] @keyword.conditional
;; #fbb152 #000000 0 0 0 1
[
"for"
"do"
"done"
"select"
"until"
"while"
] @keyword.repeat
;; #fbb152 #000000 0 0 0 1
[
"declare"
"typeset"
"readonly"
"local"
"unset"
"unsetenv"
] @keyword
;; #fbb152 #000000 0 0 0 1
"export" @keyword.import
;; #fbb152 #000000 0 0 0 1
"function" @keyword.function
;; #ebda8c #000000 0 0 0 1
(special_variable_name) @constant
;; #ebda8c #000000 0 0 0 1
((word) @constant.builtin
(#match? @constant.builtin "^(SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGBUS|SIGFPE|SIGKILL|SIGUSR1|SIGSEGV|SIGUSR2|SIGPIPE|SIGALRM|SIGTERM|SIGSTKFLT|SIGCHLD|SIGCONT|SIGSTOP|SIGTSTP|SIGTTIN|SIGTTOU|SIGURG|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGIO|SIGPWR|SIGSYS|SIGRTMIN|SIGRTMIN\+1|SIGRTMIN\+2|SIGRTMIN\+3|SIGRTMIN\+4|SIGRTMIN\+5|SIGRTMIN\+6|SIGRTMIN\+7|SIGRTMIN\+8|SIGRTMIN\+9|SIGRTMIN\+10|SIGRTMIN\+11|SIGRTMIN\+12|SIGRTMIN\+13|SIGRTMIN\+14|SIGRTMIN\+15|SIGRTMAX\-14|SIGRTMAX\-13|SIGRTMAX\-12|SIGRTMAX\-11|SIGRTMAX\-10|SIGRTMAX\-9|SIGRTMAX\-8|SIGRTMAX\-7|SIGRTMAX\-6|SIGRTMAX\-5|SIGRTMAX\-4|SIGRTMAX\-3|SIGRTMAX\-2|SIGRTMAX\-1|SIGRTMAX)$"))
;; #51eeba #000000 0 0 0 1
((word) @boolean.true
(#match? @boolean.true "^true$"))
;; #ee513a #000000 0 0 0 1
((word) @boolean.false
(#match? @boolean.false "^false$"))
;; #AAAAAA #000000 0 1 0 1
(comment) @comment @spell
;; #ffffff #000000 0 0 0 1
(test_operator) @operator
;; #e6a24c #000000 0 0 0 2
(command_substitution
"$(" @punctuation.special
")" @punctuation.special)
;; #e6a24c #000000 0 0 0 2
(process_substitution
[
"<("
">("
] @punctuation.special
")" @punctuation.special)
;; #e6a24c #000000 0 0 0 2
(arithmetic_expansion
[
"$(("
"(("
] @punctuation.special
"))" @punctuation.special)
;; #bd9ae6 #000000 0 0 0 1
(arithmetic_expansion
"," @punctuation.delimiter)
;; #ffffff #000000 0 0 0 1
(ternary_expression
[
"?"
":"
] @keyword.conditional.ternary)
;; #ffffff #000000 0 0 0 1
(binary_expression
operator: _ @operator)
;; #ffffff #000000 0 0 0 1
(unary_expression
operator: _ @operator)
;; #ffffff #000000 0 0 0 1
(postfix_expression
operator: _ @operator)
;; #aad84c #000000 0 0 0 3
(function_definition
name: (word) @function)
;; #aad84c #000000 0 0 0 3
(command_name
(word) @function.call)
;; #aad84c #000000 0 0 0 3
(command_name
(word) @function.builtin
(#match? @function.builtin "^(\.|\:|alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|compopt|continue|coproc|dirs|disown|echo|enable|eval|exec|exit|false|fc|fg|getopts|hash|help|history|jobs|kill|let|logout|mapfile|popd|printf|pushd|pwd|read|readarray|return|set|shift|shopt|source|suspend|test|time|times|trap|true|type|typeset|ulimit|umask|unalias|wait)$"))
;; #ffffff #000000 0 0 0 1
(command
argument: [
(word) @variable.parameter
(concatenation
(word) @variable.parameter)
])
;; #ffffff #000000 0 0 0 1
(declaration_command
(word) @variable.parameter)
;; #ffffff #000000 0 0 0 1
(unset_command
(word) @variable.parameter)
;; #ebda8c #000000 0 0 0 2
(number) @number
;; #ebda8c #000000 0 0 0 2
((word) @number
(#match? @number "^[0-9]+$"))
;; #aad84c #000000 0 0 0 1
(file_redirect
(word) @string.special.path)
;; #aad84c #000000 0 0 0 1
(herestring_redirect
(word) @string)
;; #ffffff #000000 0 0 0 1
(file_descriptor) @operator
;; #e6a24c #000000 0 0 0 2
(simple_expansion
"$" @punctuation.special) @none
;; #e6a24c #000000 0 0 0 2
(expansion
"${" @punctuation.special
"}" @punctuation.special) @none
;; #e6a24c #000000 0 0 0 2
(expansion
operator: _ @punctuation.special)
;; #e6a24c #000000 0 0 0 2
(expansion
"@"
.
operator: _ @character.special)
;; #e6a24c #000000 0 0 0 2
((expansion
(subscript
index: (word) @character.special))
(#any-of? @character.special "@" "*"))
;; #e6a24c #000000 0 0 0 2
"``" @punctuation.special
;; #ffffff #000000 0 0 0 1
(variable_name) @variable
;; #ebda8c #000000 0 0 0 1
((variable_name) @constant
(#match? @constant "^[A-Z][A-Z_0-9]*$"))
;; #ffffff #000000 0 0 0 1
((variable_name) @variable.builtin
(#match? @variable.builtin "^(CDPATH|HOME|IFS|MAIL|MAILPATH|OPTARG|OPTIND|PATH|PS1|PS2|_|BASH|BASHOPTS|BASHPID|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_ARGV0|BASH_CMDS|BASH_COMMAND|BASH_COMPAT|BASH_ENV|BASH_EXECUTION_STRING|BASH_LINENO|BASH_LOADABLES_PATH|BASH_REMATCH|BASH_SOURCE|BASH_SUBSHELL|BASH_VERSINFO|BASH_VERSION|BASH_XTRACEFD|CHILD_MAX|COLUMNS|COMP_CWORD|COMP_LINE|COMP_POINT|COMP_TYPE|COMP_KEY|COMP_WORDBREAKS|COMP_WORDS|COMPREPLY|COPROC|DIRSTACK|EMACS|ENV|EPOCHREALTIME|EPOCHSECONDS|EUID|EXECIGNORE|FCEDIT|FIGNORE|FUNCNAME|FUNCNEST|GLOBIGNORE|GROUPS|histchars|HISTCMD|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTIGNORE|HISTSIZE|HISTTIMEFORMAT|HOSTFILE|HOSTNAME|HOSTTYPE|IGNOREEOF|INPUTRC|INSIDE_EMACS|LANG|LC_ALL|LC_COLLATE|LC_CTYPE|LC_MESSAGES|LC_NUMERIC|LC_TIME|LINENO|LINES|MACHTYPE|MAILCHECK|MAPFILE|OLDPWD|OPTERR|OSTYPE|PIPESTATUS|POSIXLY_CORRECT|PPID|PROMPT_COMMAND|PROMPT_DIRTRIM|PS0|PS3|PS4|PWD|RANDOM|READLINE_ARGUMENT|READLINE_LINE|READLINE_MARK|READLINE_POINT|REPLY|SECONDS|SHELL|SHELLOPTS|SHLVL|SRANDOM|TIMEFORMAT|TMOUT|TMPDIR|UID)$"))
;; #ffffff #000000 0 0 0 1
(case_item
value: (word) @variable.parameter)
;; #e6a24c #000000 0 0 0 2
[
(regex)
(extglob_pattern)
] @string.regexp
;; #51eeba #000000 0 0 0 3
((program
.
(comment) @keyword.directive @nospell)
(#match? @keyword.directive "^#!/"))

View File

@@ -1,317 +0,0 @@
;; #ffffff #000000 0 0 0 1
[
(identifier)
(global_variable)
] @variable
;; #fbb152 #000000 0 0 0 1
[
"alias"
"begin"
"do"
"end"
"ensure"
"module"
"rescue"
"then"
] @keyword
;; #fbb152 #000000 0 0 0 1
"class" @keyword.type
;; #fbb152 #000000 0 0 0 1
[
"return"
"yield"
] @keyword.return
;; #fbb152 #000000 0 0 0 1
[
"and"
"or"
"in"
"not"
] @keyword.operator
;; #fbb152 #000000 0 0 0 1
[
"def"
"undef"
] @keyword.function
(method
"end" @keyword.function)
;; #fbb152 #000000 0 0 0 1
[
"case"
"else"
"elsif"
"if"
"unless"
"when"
"then"
] @keyword.conditional
(if
"end" @keyword.conditional)
;; #fbb152 #000000 0 0 0 1
[
"for"
"until"
"while"
"break"
"redo"
"retry"
"next"
] @keyword.repeat
;; #ebda8c #000000 0 0 0 1
(constant) @constant
;; #fbb152 #000000 0 0 0 1
[
"rescue"
"ensure"
] @keyword.exception
;; #aad84c #000000 0 0 0 3
"defined?" @function
;; #aad84c #000000 0 0 0 3
(call
receiver: (constant)? @type
method: [
(identifier)
(constant)
;; #ff5689 #000000 0 0 0 2
] @function.call)
(alias
(identifier) @function)
(setter
(identifier) @function)
(method
name: [
(identifier) @function
(constant) @type
])
(singleton_method
name: [
(identifier) @function
(constant) @type
])
(class
name: (constant) @type)
(module
name: (constant) @type)
(superclass
(constant) @type)
;; #ffffff #000000 0 0 0 1
[
(class_variable)
(instance_variable)
] @variable.member
((identifier) @keyword.modifier
(#match? @keyword.modifier "^(private|protected|public)$" ))
;; #fbb152 #000000 0 0 0 3
(program
(call
(identifier) @keyword.import)
(#match? @keyword.import "^(require|require_relative|load)$"))
;; #fbb152 #000000 0 0 0 4
((identifier) @constant.builtin
(#match? @constant.builtin "^(__callee__|__dir__|__id__|__method__|__send__|__ENCODING__|__FILE__|__LINE__)$" ))
;; #aad84c #000000 0 0 0 3
((identifier) @function.builtin
(#match? @function.builtin "^(attr_reader|attr_writer|attr_accessor|module_function)$" ))
((call
!receiver
method: (identifier) @function.builtin)
(#match? @function.builtin "^(include|extend|prepend|refine|using)"))
((identifier) @keyword.exception
(#match? @keyword.exception "^(raise|fail|catch|throw)" ))
;; #ffffff #000000 0 0 0 1
[
(self)
(super)
] @variable.builtin
;; #ffffff #000000 0 0 0 1
(method_parameters
(identifier) @variable.parameter)
(lambda_parameters
(identifier) @variable.parameter)
(block_parameters
(identifier) @variable.parameter)
(splat_parameter
(identifier) @variable.parameter)
(hash_splat_parameter
(identifier) @variable.parameter)
(optional_parameter
(identifier) @variable.parameter)
(destructured_parameter
(identifier) @variable.parameter)
(block_parameter
(identifier) @variable.parameter)
(keyword_parameter
(identifier) @variable.parameter)
;; #aad84c #000000 0 0 0 1
[
(string_content)
(heredoc_content)
"\""
"`"
] @string
;; #fbb152 #000000 0 0 0 1
[
(heredoc_beginning)
(heredoc_end)
] @label
;; #bd9ae6 #000000 0 0 0 2
[
(bare_symbol)
(simple_symbol)
(delimited_symbol)
(hash_key_symbol)
] @string.special.symbol
;; #e6a24c #000000 0 0 0 2
(regex
(string_content) @string.regexp)
;; #e6a24c #000000 0 0 0 2
(escape_sequence) @string.escape
;; #ebda8c #000000 0 0 0 2
(integer) @number
;; #ebda8c #000000 0 0 0 2
(float) @number.float
;; #51eeba #000000 0 0 0 1
(true) @boolean.true
;; #ee513a #000000 0 0 0 1
(false) @boolean.false
;; #ee8757 #000000 0 0 0 1
(nil) @constant.nil
;; #AAAAAA #000000 0 1 0 1
(comment) @comment
;; #51eeba #000000 0 0 0 3
((program
.
(comment) @shebang @nospell)
(#match? @shebang "^#!/"))
;; #ffffff #000000 0 0 0 1
[
"!"
"="
">>"
"<<"
">"
"<"
"**"
"*"
"/"
"%"
"+"
"-"
"&"
"|"
"^"
"%="
"+="
"-="
"*="
"/="
"=~"
"!~"
"?"
":"
] @operator
;; #ffffff #000000 0 1 0 1
[
"=="
"==="
"<=>"
"=>"
"->"
">="
"<="
"||"
"||="
"&&="
"&&"
"!="
".."
"..."
] @operator.ligature
;; #bd9ae6 #000000 0 0 0 1
[
","
";"
"."
"&."
"::"
] @punctuation.delimiter
(pair
":" @punctuation.delimiter)
;; #bd9ae6 #000000 0 0 0 1
[
"("
")"
"["
"]"
"{"
"}"
"%w("
"%i("
] @punctuation.bracket
(regex
"/" @punctuation.bracket)
(block_parameters
"|" @punctuation.bracket)
;; #e6a24c #000000 0 0 0 2
(interpolation
"#{" @punctuation.special
"}" @punctuation.special)

View File

@@ -1,212 +0,0 @@
#ifndef EDITOR_H
#define EDITOR_H
#include "../libs/tree-sitter/lib/include/tree_sitter/api.h"
#include "./knot.h"
#include "./ui.h"
#include "./utils.h"
#include <algorithm>
#include <cstdint>
#include <map>
#include <shared_mutex>
#include <unordered_map>
#include <vector>
#define CHAR 0
#define WORD 1
#define LINE 2
#define EXTRA_META 4
struct Highlight {
uint32_t fg;
uint32_t bg;
uint32_t flags;
uint8_t priority;
};
struct Span {
uint32_t start;
uint32_t end;
Highlight *hl;
bool operator<(const Span &other) const { return start < other.start; }
};
struct Spans {
std::vector<Span> spans;
Queue<std::pair<uint32_t, int64_t>> edits;
bool mid_parse = false;
std::shared_mutex mtx;
};
struct Fold {
uint32_t start;
uint32_t end;
bool contains(uint32_t line) const { return line >= start && line <= end; }
bool operator<(const Fold &other) const { return start < other.start; }
};
struct SpanCursor {
Spans &spans;
size_t index = 0;
std::vector<Span *> active;
std::shared_lock<std::shared_mutex> lock;
SpanCursor(Spans &s) : spans(s) {}
Highlight *get_highlight(uint32_t byte_offset) {
for (int i = (int)active.size() - 1; i >= 0; i--)
if (active[i]->end <= byte_offset)
active.erase(active.begin() + i);
while (index < spans.spans.size() &&
spans.spans[index].start <= byte_offset) {
if (spans.spans[index].end > byte_offset)
active.push_back(const_cast<Span *>(&spans.spans[index]));
index++;
}
Highlight *best = nullptr;
int max_prio = -1;
for (auto *s : active)
if (s->hl->priority > max_prio) {
max_prio = s->hl->priority;
best = s->hl;
}
return best;
}
void sync(uint32_t byte_offset) {
lock = std::shared_lock(spans.mtx);
active.clear();
size_t left = 0, right = spans.spans.size();
while (left < right) {
size_t mid = (left + right) / 2;
if (spans.spans[mid].start <= byte_offset)
left = mid + 1;
else
right = mid;
}
index = left;
while (left > 0) {
left--;
if (spans.spans[left].end > byte_offset)
active.push_back(const_cast<Span *>(&spans.spans[left]));
else if (byte_offset - spans.spans[left].end > 1000)
break;
}
}
};
struct Editor {
const char *filename;
Knot *root;
std::shared_mutex knot_mtx;
Coord cursor;
uint32_t cursor_preffered;
Coord selection;
bool selection_active;
int selection_type;
Coord position;
Coord size;
Coord scroll;
TSTree *tree;
TSParser *parser;
TSQuery *query;
const TSLanguage *language;
Queue<TSInputEdit> edit_queue;
std::vector<Highlight> query_map;
std::vector<Fold> folds;
Spans spans;
Spans def_spans;
uint32_t hooks[94];
bool jumper_set;
};
inline const Fold *fold_for_line(const std::vector<Fold> &folds,
uint32_t line) {
auto it = std::lower_bound(
folds.begin(), folds.end(), line,
[](const Fold &fold, uint32_t value) { return fold.start < value; });
if (it != folds.end() && it->start == line)
return &(*it);
if (it != folds.begin()) {
--it;
if (it->contains(line))
return &(*it);
}
return nullptr;
}
inline Fold *fold_for_line(std::vector<Fold> &folds, uint32_t line) {
const auto *fold =
fold_for_line(static_cast<const std::vector<Fold> &>(folds), line);
return const_cast<Fold *>(fold);
}
inline bool line_is_fold_start(const std::vector<Fold> &folds, uint32_t line) {
const Fold *fold = fold_for_line(folds, line);
return fold && fold->start == line;
}
inline bool line_is_folded(const std::vector<Fold> &folds, uint32_t line) {
return fold_for_line(folds, line) != nullptr;
}
inline uint32_t next_unfolded_row(const Editor *editor, uint32_t row) {
uint32_t limit = editor && editor->root ? editor->root->line_count : 0;
while (row < limit) {
const Fold *fold = fold_for_line(editor->folds, row);
if (!fold)
return row;
row = fold->end + 1;
}
return limit;
}
inline uint32_t prev_unfolded_row(const Editor *editor, uint32_t row) {
while (row > 0) {
const Fold *fold = fold_for_line(editor->folds, row);
if (!fold)
return row;
if (fold->start == 0)
return 0;
row = fold->start - 1;
}
return 0;
}
void apply_edit(std::vector<Span> &spans, uint32_t x, int64_t y);
Editor *new_editor(const char *filename, Coord position, Coord size);
void free_editor(Editor *editor);
void render_editor(Editor *editor);
void fold(Editor *editor, uint32_t start_line, uint32_t end_line);
void cursor_up(Editor *editor, uint32_t number);
void cursor_down(Editor *editor, uint32_t number);
Coord move_left(Editor *editor, Coord cursor, uint32_t number);
Coord move_right(Editor *editor, Coord cursor, uint32_t number);
void cursor_left(Editor *editor, uint32_t number);
void cursor_right(Editor *editor, uint32_t number);
void scroll_up(Editor *editor, int32_t number);
void scroll_down(Editor *editor, uint32_t number);
void ensure_cursor(Editor *editor);
void ensure_scroll(Editor *editor);
void handle_editor_event(Editor *editor, KeyEvent event);
void edit_erase(Editor *editor, Coord pos, int64_t len);
void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len);
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y);
char *get_selection(Editor *editor, uint32_t *out_len);
void editor_worker(Editor *editor);
void move_line_down(Editor *editor);
void move_line_up(Editor *editor);
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters);
void word_boundaries_exclusive(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col);
std::vector<Fold>::iterator find_fold_iter(Editor *editor, uint32_t line);
bool add_fold(Editor *editor, uint32_t start, uint32_t end);
bool remove_fold(Editor *editor, uint32_t line);
void apply_line_insertion(Editor *editor, uint32_t line, uint32_t rows);
void apply_line_deletion(Editor *editor, uint32_t removal_start,
uint32_t removal_end);
#endif

View File

@@ -0,0 +1,45 @@
#ifndef EDITOR_COMPLETIONS_H
#define EDITOR_COMPLETIONS_H
#include "pch.h"
#include "ui/completionbox.h"
#include "ui/hover.h"
#include "utils/utils.h"
struct CompletionItem {
std::string label;
uint8_t kind;
std::optional<std::string> detail;
std::optional<std::string> documentation;
bool is_markup = false;
bool deprecated = false;
bool asis = true;
std::string sort;
std::string filter;
bool snippet = false;
std::vector<TextEdit> edits;
json original;
std::vector<char> end_chars;
};
struct CompletionSession {
std::shared_mutex mtx;
bool active = false;
Coord hook;
std::optional<std::string> prefix;
uint8_t select = 0;
std::vector<CompletionItem> items;
std::vector<uint8_t> visible;
bool complete = true;
std::optional<char> trigger_char;
uint8_t trigger = 0;
CompletionBox box;
HoverBox hover;
uint32_t doc = UINT32_MAX;
std::atomic<bool> hover_dirty = false;
int version;
CompletionSession() : box(this) {}
};
#endif

35
include/editor/decl.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef EDITOR_DECL_H
#define EDITOR_DECL_H
#include "utils/utils.h"
struct TextEdit {
Coord start;
Coord end;
std::string text;
};
struct VWarn {
uint32_t line;
std::string text;
std::string text_full;
std::string source;
std::string code;
std::vector<std::string> see_also;
int8_t type;
uint32_t start;
uint32_t end{UINT32_MAX};
bool operator<(const VWarn &other) const { return line < other.line; }
};
struct VAI {
Coord pos;
char *text;
uint32_t len;
uint32_t lines; // number of \n in text for speed .. the ai part will not
// line wrap but multiline ones need to have its own lines
// after the first one
};
#endif

165
include/editor/editor.h Normal file
View File

@@ -0,0 +1,165 @@
#ifndef EDITOR_H
#define EDITOR_H
#include "editor/completions.h"
#include "editor/indents.h"
#include "io/knot.h"
#include "io/sysio.h"
#include "syntax/extras.h"
#include "syntax/parser.h"
#include "ui/completionbox.h"
#include "ui/diagnostics.h"
#include "ui/hover.h"
#include "utils/utils.h"
#include <cstdint>
#define CHAR 0
#define WORD 1
#define LINE 2
#define EXTRA_META 4
#define INDENT_WIDTH 2
// autocomplete lua// Bracket closing / tab on enter
struct Editor {
std::string filename;
std::string uri;
Knot *root;
std::shared_mutex knot_mtx;
Coord cursor;
uint32_t cursor_preffered;
Coord selection;
bool selection_active;
bool unix_eol; // false for windows
int selection_type;
Coord position;
Coord size;
Coord scroll;
Language lang;
uint32_t hooks[94];
bool jumper_set;
std::shared_mutex v_mtx;
std::vector<VWarn> warnings;
bool warnings_dirty;
VAI ai;
std::shared_mutex lsp_mtx;
std::shared_ptr<struct LSPInstance> lsp;
bool hover_active;
HoverBox hover;
bool diagnostics_active;
DiagnosticBox diagnostics;
std::atomic<int> lsp_version = 1;
CompletionSession completion;
IndentationEngine indents;
Parser *parser;
ExtraHighlighter extra_hl;
bool is_css_color;
};
Editor *new_editor(const char *filename_arg, Coord position, Coord size,
uint8_t eol);
void save_file(Editor *editor);
void free_editor(Editor *editor);
void render_editor(Editor *editor);
void cursor_up(Editor *editor, uint32_t number);
void cursor_down(Editor *editor, uint32_t number);
Coord move_left(Editor *editor, Coord cursor, uint32_t number);
Coord move_right(Editor *editor, Coord cursor, uint32_t number);
void cursor_left(Editor *editor, uint32_t number);
void cursor_right(Editor *editor, uint32_t number);
void scroll_up(Editor *editor, int32_t number);
void scroll_down(Editor *editor, uint32_t number);
void ensure_cursor(Editor *editor);
void ensure_scroll(Editor *editor);
void handle_editor_event(Editor *editor, KeyEvent event);
void edit_erase(Editor *editor, Coord pos, int64_t len);
void edit_insert(Editor *editor, Coord pos, char *data, uint32_t len);
void edit_replace(Editor *editor, Coord start, Coord end, const char *text,
uint32_t len);
Coord editor_hit_test(Editor *editor, uint32_t x, uint32_t y);
char *get_selection(Editor *editor, uint32_t *out_len, Coord *out_start);
void selection_bounds(Editor *editor, Coord *out_start, Coord *out_end);
void editor_worker(Editor *editor);
void move_line_down(Editor *editor);
void move_line_up(Editor *editor);
void word_boundaries(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col, uint32_t *prev_clusters,
uint32_t *next_clusters);
void word_boundaries_exclusive(Editor *editor, Coord coord, uint32_t *prev_col,
uint32_t *next_col);
void editor_lsp_handle(Editor *editor, json msg);
void apply_lsp_edits(Editor *editor, std::vector<TextEdit> edits, bool move);
void completion_resolve_doc(Editor *editor);
void complete_accept(Editor *editor);
void complete_next(Editor *editor);
void complete_prev(Editor *editor);
void complete_select(Editor *editor, uint8_t index);
void handle_completion(Editor *editor, KeyEvent event);
inline void apply_hook_insertion(Editor *editor, uint32_t line, uint32_t rows) {
for (auto &hook : editor->hooks)
if (hook > line)
hook += rows;
}
inline void apply_hook_deletion(Editor *editor, uint32_t removal_start,
uint32_t removal_end) {
for (auto &hook : editor->hooks)
if (hook > removal_start)
hook -= removal_end - removal_start + 1;
}
inline static void utf8_normalize_edit(Editor *editor, TextEdit *edit) {
std::shared_lock lock(editor->knot_mtx);
if (edit->start.row > editor->root->line_count) {
edit->start.row = editor->root->line_count;
edit->start.col = UINT32_MAX;
}
if (edit->end.row > editor->root->line_count) {
edit->end.row = editor->root->line_count;
edit->end.col = UINT32_MAX;
}
LineIterator *it = begin_l_iter(editor->root, edit->start.row);
if (!it)
return;
uint32_t len;
char *line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (edit->start.col < len)
edit->start.col = utf16_offset_to_utf8(line, len, edit->start.col);
else
edit->start.col = len;
if (edit->end.row == edit->start.row) {
if (edit->end.col < len)
edit->end.col = utf16_offset_to_utf8(line, len, edit->end.col);
else
edit->end.col = len;
free(it->buffer);
free(it);
return;
}
free(it->buffer);
free(it);
it = begin_l_iter(editor->root, edit->end.row);
if (!it)
return;
line = next_line(it, &len);
if (!line) {
free(it->buffer);
free(it);
return;
}
if (edit->end.col < len)
edit->end.col = utf16_offset_to_utf8(line, len, edit->end.col);
else
edit->end.col = len;
free(it->buffer);
free(it);
}
#endif

24
include/editor/helpers.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef EDITOR_HELPERS_H
#define EDITOR_HELPERS_H
#include "editor/editor.h"
void insert_str(Editor *editor, char *c, uint32_t len);
void insert_char(Editor *editor, char c);
void normal_mode(Editor *editor);
void backspace_edit(Editor *editor);
void delete_prev_word(Editor *editor);
void delete_next_word(Editor *editor);
void clear_hooks_at_line(Editor *editor, uint32_t line);
void cursor_prev_word(Editor *editor);
void cursor_next_word(Editor *editor);
void select_all(Editor *editor);
void fetch_lsp_hover(Editor *editor);
void handle_mouse(Editor *editor, KeyEvent event);
void indent_current_line(Editor *editor);
void dedent_current_line(Editor *editor);
void paste(Editor *editor);
void copy(Editor *editor);
void cut(Editor *editor);
#endif

152
include/editor/indents.h Normal file
View File

@@ -0,0 +1,152 @@
#ifndef EDITOR_INDENTS_H
#define EDITOR_INDENTS_H
#include "utils/utils.h"
static const std::unordered_map<std::string, uint8_t> kLangtoIndent = {
{"make", 1}, {"yaml", 2}};
// this indents the newline one level when the line (on the curser before \n is
// inserted) matches this at its end (stripped of whitespace)
static const std::unordered_map<std::string, const std::vector<std::string>>
kLangtoBlockStartsEnd = {
{"bash", {"then", "do", "in", "{", "(", "\\", "&&", "||", "|"}},
{"c", {"{", "(", ":"}},
{"cpp", {"{", "(", ":"}},
{"h", {"{", "(", ":"}},
{"css", {"{", "("}},
{"fish", {"{", "(", "^", "&&", "||", "|"}},
{"go", {"{", "(", ":"}},
{"gomod", {"{", "(", ":"}},
{"haskell", {"do", "where", "then", "else", "of"}},
{"javascript", {"{", "(", "[", ":"}},
{"typescript", {"{", "(", "[", ":"}},
{"json", {"{", "[", ":"}},
{"jsonc", {"{", "[", ":"}},
{"ruby", {"then", "else", "begin", "{", "(", "["}},
{"lua", {"then", "do", "else", "repeat", "{", "(", "["}},
{"python", {":", "(", "[", "{"}},
{"rust", {"{", "(", "[", ":"}},
{"php", {"{", "(", "[", ":"}},
{"nginx", {"{"}},
{"yaml", {":"}},
{"sql", {"("}},
{"make", {":"}},
{"gdscript", {":", "(", "[", "{"}},
};
// this indents the newline one level when the line (on the curser before \n is
// inserted) matches this at its start (stripped of whitespace)
static const std::unordered_map<std::string, const std::vector<std::string>>
kLangtoBlockStartsStart = {
{"c", {"if", "for", "while"}},
{"cpp", {"if", "for", "while"}},
{"h", {"if", "for", "while"}},
{"fish", {"if", "else", "for", "while", "switch", "case", "function"}},
{"javascript", {"if", "for", "while"}},
{"typescript", {"if", "for", "while"}},
{"ruby",
{"if", "do", "when", "rescue", "class", "module", "def", "unless",
"until", "elsif", "ensure"}},
{"lua", {"function"}},
{"nginx", {"{"}},
};
// This dedents the line (under the cursor before \n is inserted) when the line
// matches this fully (stripped of whitespace)
static const std::unordered_map<std::string, const std::vector<std::string>>
kLangtoBlockEndsFull = {
{"bash", {"fi", "done", "esac", "}", ")"}},
{"c", {"}", ")"}},
{"cpp", {"}", ")"}},
{"h", {"}", ")"}},
{"css", {"}", ")"}},
{"fish", {"end"}},
{"go", {"}", ")"}},
{"gomod", {"}", ")"}},
{"javascript", {"}", ")", "]"}},
{"typescript", {"}", ")", "]"}},
{"json", {"}", "]"}},
{"jsonc", {"}", "]"}},
{"ruby", {"end", "else", "}", ")", "]"}},
{"lua", {"else", "}", ")", "]"}},
{"python", {"}", ")", "]", "else:"}},
{"rust", {"}", ")", "]"}},
{"php",
{"}", ")", "]", "else:", "endif;", "endfor;", "endwhile;",
"endswitch;", "endcase;", "endfunction;"}},
{"nginx", {"}"}},
{"sql", {")"}},
{"gdscript", {"}", ")", "]"}},
};
// This dedents the line (under the cursor before \n is inserted) when the line
// matches this at its start (stripped of whitespace)
static const std::unordered_map<std::string, const std::vector<std::string>>
kLangtoBlockEndsStart = {
{"c", {"case", "default:", "} else"}},
{"cpp", {"case", "default:", "} else"}},
{"h", {"case", "default:", "} else"}},
{"fish", {"else if"}},
{"go", {"case", "default:", "} else"}},
{"gomod", {"}", ")"}},
{"javascript", {"case", "default:"}},
{"typescript", {"case", "default:"}},
{"json", {"}", "]"}},
{"python", {"elif"}},
{"jsonc", {"}", "]"}},
{"ruby", {"when", "elsif", "rescue", "ensure"}},
{"lua", {"end", "elseif", "until"}},
{"rust", {"case", "default:", "} else"}},
{"php", {"case", "default:", "} else"}},
};
struct IndentationEngine {
// tabs = 1, spaces = 2+
uint8_t indent = 0;
struct Editor *editor = nullptr;
void compute_indent(Editor *n_editor);
void insert_new_line(Coord cursor);
void insert_tab(Coord cursor);
uint32_t set_indent(uint32_t row, int64_t indent_level);
uint32_t indent_line(uint32_t row);
uint32_t dedent_line(uint32_t row);
void indent_block(uint32_t start, uint32_t end);
void dedent_block(uint32_t start, uint32_t end);
// fixes a autocomplete block's indentation
char *block_to_asis(Coord cursor, std::string source, uint32_t *out_len);
private:
// TODO: Ignore comments/strings too
// returns the indent level of the line itself or of the previous non-empty
uint32_t indent_expected(uint32_t row);
// returns the indent level of the line
uint32_t indent_real(char *line, uint32_t len);
};
inline static bool ends_with(const std::string &str,
const std::string &suffix) {
const size_t str_len = str.size();
const size_t suf_len = suffix.size();
if (suf_len > str_len)
return false;
for (size_t i = 0; i < suf_len; i++)
if (str[str_len - suf_len + i] != suffix[i])
return false;
return true;
}
inline static bool starts_with(const std::string &str,
const std::string &prefix) {
const size_t str_len = str.size();
const size_t pre_len = prefix.size();
if (pre_len > str_len)
return false;
for (size_t i = 0; i < pre_len; i++)
if (str[i] != prefix[i])
return false;
return true;
}
#endif

View File

@@ -1,14 +1,11 @@
#ifndef ROPE_H
#define ROPE_H
#include "./utils.h"
#include <cstdint>
#include <vector>
#include "pch.h"
#include "utils/utils.h"
#define MIN_CHUNK_SIZE 64 // 64 Bytes
#define MAX_CHUNK_SIZE 1024 * 8 // 8192 Bytes (8 KiB)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define DEPTH(n) ((n) ? (n)->depth : 0)
// Rope node definition
@@ -27,6 +24,8 @@ typedef struct LineIterator {
uint8_t top;
uint32_t offset;
Knot *stack[64];
char *buffer;
size_t capacity;
} LineIterator;
typedef struct LeafIterator {
@@ -92,6 +91,9 @@ Knot *erase(Knot *node, uint32_t offset, uint32_t len);
// returns a null terminated string, should be freed by the caller
char *read(Knot *root, uint32_t offset, uint32_t len);
// Used to read into an existing buffer
void read_into(Knot *node, uint32_t offset, uint32_t len, char *dest);
// Used to split the rope into left and right ropes
// node is the rope to be split (it is no longer valid after call / do not free)
// offset is the position of the split relative to the start of the rope
@@ -112,9 +114,9 @@ LineIterator *begin_l_iter(Knot *root, uint32_t start_line);
// Each subsequent call returns the next line as a null terminated string
// `it` is the iterator returned from begin_l_iter
// After getting the necessary lines free the iterator (no need to go upto the
// end) returns null if there are no more lines All return strings `must` be
// freed by the caller
// After getting the necessary lines free the iterator (no need to go upto
// the end) returns null if there are no more lines All return strings
// `must` be freed by the caller
char *next_line(LineIterator *it, uint32_t *out_len);
// Returns the previous line as a null terminated string
@@ -160,9 +162,11 @@ char *leaf_from_offset(Knot *root, uint32_t start_offset, uint32_t *out_len);
// compliant) I.e some forms of backtracking etc. are not supported
// root is the root of the rope to be searched
// Returns a vector of pairs of start and length offsets (in bytes)
std::vector<std::pair<size_t, size_t>> search_rope(Knot *root,
std::vector<std::pair<size_t, size_t>> search_rope_dfa(Knot *root,
const char *pattern);
std::vector<Match> search_rope(Knot *root, const char *pattern);
// Helper function to free the rope
// root is the root of the rope
// the root is no longer valid after call

116
include/io/sysio.h Normal file
View File

@@ -0,0 +1,116 @@
#ifndef UI_H
#define UI_H
#include "pch.h"
#include "utils/utils.h"
#define KEY_CHAR 0
#define KEY_SPECIAL 1
#define KEY_MOUSE 2
#define KEY_PASTE 3
#define KEY_NONE 4
#define KEY_UP 0
#define KEY_DOWN 1
#define KEY_LEFT 2
#define KEY_RIGHT 3
#define KEY_DELETE 4
#define KEY_ESC '\x1b'
#define PRESS 0
#define RELEASE 1
#define DRAG 2
#define SCROLL 3
#define LEFT_BTN 0
#define MIDDLE_BTN 1
#define RIGHT_BTN 2
#define SCROLL_BTN 3
#define NONE_BTN 4
#define SCROLL_UP 0
#define SCROLL_DOWN 1
#define SCROLL_LEFT 2
#define SCROLL_RIGHT 3
#define ALT 1
#define CNTRL 2
#define CNTRL_ALT 3
#define SHIFT 4
#define DEFAULT 0
#define BLOCK 2
#define UNDERLINE 4
#define CURSOR 6
enum CellFlags : uint8_t {
CF_NONE = 0,
CF_ITALIC = 1 << 0,
CF_BOLD = 1 << 1,
CF_UNDERLINE = 1 << 2,
CF_STRIKETHROUGH = 1 << 3
};
struct ScreenCell {
std::string utf8 = std::string("");
uint8_t width = 1;
uint32_t fg = 0;
uint32_t bg = 0;
uint8_t flags = CF_NONE;
uint32_t ul_color = 0;
};
struct KeyEvent {
/* KEY_CHAR, KEY_SPECIAL, KEY_MOUSE, KEY_PASTE, KEY_NONE */
uint8_t key_type;
/* the character / string if key_type == KEY_CHAR or KEY_PASTE */
char *c;
/* length of c */
uint32_t len;
/* KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_DELETE if key_type ==
* KEY_SPECIAL */
uint8_t special_key;
/* ALT, CNTRL, CNTRL_ALT, SHIFT if key_type == KEY_SPECIAL */
uint8_t special_modifier;
/* column of mouse click */
uint8_t mouse_x;
/* row of mouse click */
uint8_t mouse_y;
/* LEFT_BTN, MIDDLE_BTN, RIGHT_BTN, SCROLL_BTN, NONE_BTN if key_type ==
* KEY_MOUSE */
uint8_t mouse_button;
/* PRESS, RELEASE, DRAG, SCROLL if key_type == KEY_MOUSE */
uint8_t mouse_state;
/* SCROLL_UP, SCROLL_DOWN, SCROLL_LEFT, SCROLL_RIGHT if key_type ==
* KEY_MOUSE and mouse_state == SCROLL */
uint8_t mouse_direction;
/* ALT, CNTRL, CNTRL_ALT, SHIFT if key_type == KEY_MOUSE */
uint8_t mouse_modifier;
};
inline bool is_empty_cell(const ScreenCell &c) {
return c.utf8.empty() || c.utf8 == " " || c.utf8 == "\x1b";
}
Coord start_screen();
void end_screen();
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags);
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags);
void update(uint32_t row, uint32_t col, std::string utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color);
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags, uint32_t ul_color);
void set_cursor(uint8_t row, uint8_t col, uint32_t type,
bool show_cursor_param);
void render();
Coord get_size();
KeyEvent read_key();
#endif

91
include/lsp/lsp.h Normal file
View File

@@ -0,0 +1,91 @@
#ifndef LSP_H
#define LSP_H
#include "editor/editor.h"
#include "pch.h"
#include "utils/utils.h"
struct LSPPending {
std::string method;
Editor *editor = nullptr;
std::function<void(Editor *, std::string, json)> callback;
};
struct LSPOpenRequest {
Language language;
Editor *editor;
};
struct LSPInstance {
std::shared_mutex mtx;
const LSP *lsp;
std::string root_dir;
int pid{-1};
int stdin_fd{-1};
int stdout_fd{-1};
std::atomic<bool> initialized = false;
std::atomic<bool> exited = false;
bool incremental_sync = false;
bool allow_hover = false;
bool allow_completion = false;
bool allow_resolve = false;
bool allow_formatting = false;
bool allow_formatting_on_type = false;
bool is_utf8 = false;
std::vector<char> format_chars;
std::vector<char> trigger_chars;
std::vector<char> end_chars;
uint32_t last_id = 0;
Queue<json> inbox;
Queue<json> outbox;
Queue<std::pair<Language, Editor *>> open_queue;
std::unordered_map<uint32_t, LSPPending *> pending;
std::vector<Editor *> editors;
};
extern std::shared_mutex active_lsps_mtx;
extern std::unordered_map<std::string, std::shared_ptr<LSPInstance>>
active_lsps;
extern Queue<LSPOpenRequest> lsp_open_queue;
static json client_capabilities = {
{"general", {{"positionEncodings", {"utf-16"}}}},
{"textDocument",
{{"publishDiagnostics", {{"relatedInformation", true}}},
{"hover", {{"contentFormat", {"markdown", "plaintext"}}}},
{"formatting", {{"dynamicRegistration", false}}},
{"onTypeFormatting", {{"dynamicRegistration", false}}},
{"completion",
{{"completionItem",
{{"commitCharactersSupport", true},
{"dynamicRegistration", false},
{"snippetSupport", true},
{"documentationFormat", {"markdown", "plaintext"}},
{"resolveSupport", {{"properties", {"documentation"}}}},
{"insertReplaceSupport", true},
{"labelDetailsSupport", true},
{"insertTextModeSupport", {{"valueSet", {1, 2}}}},
{"deprecatedSupport", true}}},
{"completionItemKind",
{{"valueSet", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}}}},
{"contextSupport", true},
{"insertTextMode", 1}}}}}};
void lsp_send(std::shared_ptr<LSPInstance> lsp, json message,
LSPPending *pending);
void lsp_worker();
std::shared_ptr<LSPInstance> get_or_init_lsp(std::string lsp_id);
void clean_lsp(std::shared_ptr<LSPInstance> lsp, std::string lsp_id);
void close_lsp(std::string lsp_id);
void open_editor(std::shared_ptr<LSPInstance> lsp,
std::pair<Language, Editor *> entry);
void request_add_to_lsp(Language language, Editor *editor);
void add_to_lsp(Language language, Editor *editor);
void remove_from_lsp(Editor *editor);
void lsp_handle(std::shared_ptr<LSPInstance> lsp, json message);
#endif

View File

@@ -1,8 +1,7 @@
#ifndef MAIN_H
#define MAIN_H
#include <atomic>
#include <vector>
#include "pch.h"
#define NORMAL 0
#define INSERT 1
@@ -11,6 +10,8 @@
#define JUMPER 4
extern std::atomic<bool> running;
extern uint8_t mode;
extern std::atomic<uint8_t> mode;
extern std::vector<struct Editor *> editors;
extern uint8_t current_editor;
#endif

57
include/pch.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef PCH_H
#define PCH_H
#define PCRE2_CODE_UNIT_WIDTH 8
#define PCRE_WORKSPACE_SIZE 512
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include "ruby/ruby.h"
#pragma clang diagnostic pop
#include <magic.h>
#include <nlohmann/json.hpp>
#include <pcre2.h>
extern "C" {
#include "libgrapheme/grapheme.h"
#include "unicode_width/unicode_width.h"
}
#include <algorithm>
#include <atomic>
#include <cctype>
#include <chrono>
#include <cmath>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fcntl.h>
#include <filesystem>
#include <fstream>
#include <functional>
#include <limits.h>
#include <map>
#include <mutex>
#include <optional>
#include <queue>
#include <set>
#include <shared_mutex>
#include <signal.h>
#include <stack>
#include <string.h>
#include <string>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <thread>
#include <unistd.h>
#include <unordered_map>
#include <vector>
using json = nlohmann::json;
using namespace std::chrono_literals;
#endif

22
include/scripting/decl.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef SCRIPTING_DECL_H
#define SCRIPTING_DECL_H
#include "syntax/decl.h"
#include "utils/utils.h"
extern std::unordered_map<std::string, std::pair<VALUE, VALUE>>
custom_highlighters;
void ruby_start();
void ruby_shutdown();
void ruby_log(std::string msg);
void load_theme();
void load_languages_info();
uint8_t read_line_endings();
void load_custom_highlighters();
VALUE parse_custom(std::vector<Token> *tokens, VALUE parser_block,
const char *line, uint32_t len, VALUE state,
uint32_t line_num);
bool custom_compare(VALUE match_block, VALUE state1, VALUE state2);
#endif

67
include/syntax/decl.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef SYNTAX_DECL_H
#define SYNTAX_DECL_H
#include "io/knot.h"
#include "io/sysio.h"
#include "syntax/trie.h"
struct Highlight {
uint32_t fg{0xFFFFFF};
uint32_t bg{0x000000};
uint8_t flags{0};
};
enum struct TokenKind : uint8_t {
#define ADD(name) name,
#include "syntax/tokens.def"
#undef ADD
Count
};
constexpr size_t TOKEN_KIND_COUNT = static_cast<size_t>(TokenKind::Count);
const std::unordered_map<std::string, TokenKind> kind_map = {
#define ADD(name) {#name, TokenKind::name},
#include "syntax/tokens.def"
#undef ADD
};
constexpr const char tokens_def[] = "module Tokens\n"
#define STRINGIFY_HELPER(x) #x
#define STRINGIFY(x) STRINGIFY_HELPER(x)
#define ADD(name) " " #name " = " STRINGIFY(__COUNTER__) "\n"
#include "syntax/tokens.def"
#undef ADD
#undef STRINGIFY
#undef STRINGIFY_HELPER
" freeze\n"
"end";
constexpr const char crib_module[] = {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc23-extensions"
#embed "libcrib.rb"
#pragma clang diagnostic pop
, '\0'};
extern std::array<Highlight, TOKEN_KIND_COUNT> highlights;
struct Token {
uint32_t start;
uint32_t end;
TokenKind type;
};
struct LineData {
std::shared_ptr<void> in_state{nullptr};
std::vector<Token> tokens;
std::shared_ptr<void> out_state{nullptr};
};
struct CustomState {
VALUE state;
CustomState(VALUE s) : state(s) { rb_gc_register_address(&state); }
~CustomState() { rb_gc_unregister_address(&state); }
};
#endif

490
include/syntax/extras.h Normal file
View File

@@ -0,0 +1,490 @@
#ifndef SYNTAX_EXTRAS_H
#define SYNTAX_EXTRAS_H
#include "io/knot.h"
#include "syntax/decl.h"
#include "utils/utils.h"
inline static const std::vector<std::pair<std::string, uint32_t>> color_map = {
{"AliceBlue", 0xF0F8FF},
{"AntiqueWhite", 0xFAEBD7},
{"Aqua", 0x00FFFF},
{"Aquamarine", 0x7FFFD4},
{"Azure", 0xF0FFFF},
{"Beige", 0xF5F5DC},
{"Bisque", 0xFFE4C4},
{"Black", 0x000000},
{"BlanchedAlmond", 0xFFEBCD},
{"Blue", 0x0000FF},
{"BlueViolet", 0x8A2BE2},
{"Brown", 0xA52A2A},
{"BurlyWood", 0xDEB887},
{"CadetBlue", 0x5F9EA0},
{"Chartreuse", 0x7FFF00},
{"Chocolate", 0xD2691E},
{"Coral", 0xFF7F50},
{"CornflowerBlue", 0x6495ED},
{"Cornsilk", 0xFFF8DC},
{"Crimson", 0xDC143C},
{"Cyan", 0x00FFFF},
{"DarkBlue", 0x00008B},
{"DarkCyan", 0x008B8B},
{"DarkGoldenRod", 0xB8860B},
{"DarkGray", 0xA9A9A9},
{"DarkGrey", 0xA9A9A9},
{"DarkGreen", 0x006400},
{"DarkKhaki", 0xBDB76B},
{"DarkMagenta", 0x8B008B},
{"DarkOliveGreen", 0x556B2F},
{"DarkOrange", 0xFF8C00},
{"DarkOrchid", 0x9932CC},
{"DarkRed", 0x8B0000},
{"DarkSalmon", 0xE9967A},
{"DarkSeaGreen", 0x8FBC8F},
{"DarkSlateBlue", 0x483D8B},
{"DarkSlateGray", 0x2F4F4F},
{"DarkSlateGrey", 0x2F4F4F},
{"DarkTurquoise", 0x00CED1},
{"DarkViolet", 0x9400D3},
{"DeepPink", 0xFF1493},
{"DeepSkyBlue", 0x00BFFF},
{"DimGray", 0x696969},
{"DimGrey", 0x696969},
{"DodgerBlue", 0x1E90FF},
{"FireBrick", 0xB22222},
{"FloralWhite", 0xFFFAF0},
{"ForestGreen", 0x228B22},
{"Fuchsia", 0xFF00FF},
{"Gainsboro", 0xDCDCDC},
{"GhostWhite", 0xF8F8FF},
{"Gold", 0xFFD700},
{"GoldenRod", 0xDAA520},
{"Gray", 0x808080},
{"Grey", 0x808080},
{"Green", 0x008000},
{"GreenYellow", 0xADFF2F},
{"HoneyDew", 0xF0FFF0},
{"HotPink", 0xFF69B4},
{"IndianRed", 0xCD5C5C},
{"Indigo", 0x4B0082},
{"Ivory", 0xFFFFF0},
{"Khaki", 0xF0E68C},
{"Lavender", 0xE6E6FA},
{"LavenderBlush", 0xFFF0F5},
{"LawnGreen", 0x7CFC00},
{"LemonChiffon", 0xFFFACD},
{"LightBlue", 0xADD8E6},
{"LightCoral", 0xF08080},
{"LightCyan", 0xE0FFFF},
{"LightGoldenRodYellow", 0xFAFAD2},
{"LightGray", 0xD3D3D3},
{"LightGrey", 0xD3D3D3},
{"LightGreen", 0x90EE90},
{"LightPink", 0xFFB6C1},
{"LightSalmon", 0xFFA07A},
{"LightSeaGreen", 0x20B2AA},
{"LightSkyBlue", 0x87CEFA},
{"LightSlateGray", 0x778899},
{"LightSlateGrey", 0x778899},
{"LightSteelBlue", 0xB0C4DE},
{"LightYellow", 0xFFFFE0},
{"Lime", 0x00FF00},
{"LimeGreen", 0x32CD32},
{"Linen", 0xFAF0E6},
{"Magenta", 0xFF00FF},
{"Maroon", 0x800000},
{"MediumAquaMarine", 0x66CDAA},
{"MediumBlue", 0x0000CD},
{"MediumOrchid", 0xBA55D3},
{"MediumPurple", 0x9370DB},
{"MediumSeaGreen", 0x3CB371},
{"MediumSlateBlue", 0x7B68EE},
{"MediumSpringGreen", 0x00FA9A},
{"MediumTurquoise", 0x48D1CC},
{"MediumVioletRed", 0xC71585},
{"MidnightBlue", 0x191970},
{"MintCream", 0xF5FFFA},
{"MistyRose", 0xFFE4E1},
{"Moccasin", 0xFFE4B5},
{"NavajoWhite", 0xFFDEAD},
{"Navy", 0x000080},
{"OldLace", 0xFDF5E6},
{"Olive", 0x808000},
{"OliveDrab", 0x6B8E23},
{"Orange", 0xFFA500},
{"OrangeRed", 0xFF4500},
{"Orchid", 0xDA70D6},
{"PaleGoldenRod", 0xEEE8AA},
{"PaleGreen", 0x98FB98},
{"PaleTurquoise", 0xAFEEEE},
{"PaleVioletRed", 0xDB7093},
{"PapayaWhip", 0xFFEFD5},
{"PeachPuff", 0xFFDAB9},
{"Peru", 0xCD853F},
{"Pink", 0xFFC0CB},
{"Plum", 0xDDA0DD},
{"PowderBlue", 0xB0E0E6},
{"Purple", 0x800080},
{"RebeccaPurple", 0x663399},
{"Red", 0xFF0000},
{"RosyBrown", 0xBC8F8F},
{"RoyalBlue", 0x4169E1},
{"SaddleBrown", 0x8B4513},
{"Salmon", 0xFA8072},
{"SandyBrown", 0xF4A460},
{"SeaGreen", 0x2E8B57},
{"SeaShell", 0xFFF5EE},
{"Sienna", 0xA0522D},
{"Silver", 0xC0C0C0},
{"SkyBlue", 0x87CEEB},
{"SlateBlue", 0x6A5ACD},
{"SlateGray", 0x708090},
{"SlateGrey", 0x708090},
{"Snow", 0xFFFAFA},
{"SpringGreen", 0x00FF7F},
{"SteelBlue", 0x4682B4},
{"Tan", 0xD2B48C},
{"Teal", 0x008080},
{"Thistle", 0xD8BFD8},
{"Tomato", 0xFF6347},
{"Turquoise", 0x40E0D0},
{"Violet", 0xEE82EE},
{"Wheat", 0xF5DEB3},
{"White", 0xFFFFFF},
{"WhiteSmoke", 0xF5F5F5},
{"Yellow", 0xFFFF00},
{"YellowGreen", 0x9ACD32},
};
// Add word under cursor to this
struct ExtraHighlighter {
std::vector<uint32_t> colors;
std::array<std::vector<uint32_t>, 50> lines;
Trie<uint32_t> css_colors = Trie<uint32_t>();
uint32_t start = 0;
ExtraHighlighter() { css_colors.build(color_map, false); }
void render(Knot *root, uint32_t n_start, std::string word, bool is_css) {
start = n_start;
for (auto &line : lines)
line.clear();
LineIterator *it = begin_l_iter(root, start);
if (!it)
return;
uint32_t idx = 0;
uint32_t len;
char *line;
while (idx < 50 && (line = next_line(it, &len))) {
lines[idx].assign(len, UINT32_MAX - 1);
uint32_t i = 0;
while (i < len) {
if (is_css) {
std::optional<uint32_t> color;
uint32_t color_len = css_colors.match(
line, i, len, [](char c) { return isalnum(c) || c == '_'; },
&color);
if (color) {
for (uint32_t j = 0; j < color_len; j++)
lines[idx][i + j] = *color;
i += color_len;
continue;
} else if (i + 5 < len && (line[i] == 'r' || line[i] == 'R') &&
(line[i + 1] == 'g' || line[i + 1] == 'G') &&
(line[i + 2] == 'b' || line[i + 2] == 'B')) {
uint32_t start = i;
i += 3;
if (line[i] == 'a' || line[i] == 'A')
i++;
if (line[i] == '(') {
i++;
bool is_percent = false;
std::string r = "";
while (i < len && line[i] >= '0' && line[i] <= '9')
r += line[i++];
if (r.empty())
continue;
while (i < len &&
(line[i] == '.' || (line[i] >= '0' && line[i] <= '9')))
i++;
if (line[i] == '%') {
is_percent = true;
i++;
}
while (i < len && (line[i] == ',' || line[i] == ' '))
i++;
std::string g = "";
while (i < len && line[i] >= '0' && line[i] <= '9')
g += line[i++];
if (g.empty())
continue;
while (i < len &&
(line[i] == '.' || (line[i] >= '0' && line[i] <= '9')))
i++;
while (i < len &&
(line[i] == ',' || line[i] == ' ' || line[i] == '%'))
i++;
std::string b = "";
while (i < len && line[i] >= '0' && line[i] <= '9')
b += line[i++];
if (b.empty())
continue;
while (i < len &&
(line[i] == ',' || line[i] == ' ' || line[i] == '.' ||
line[i] == '/' || line[i] == '%' ||
(line[i] >= '0' && line[i] <= '9')))
i++;
if (i < len && line[i] == ')')
i++;
else
continue;
uint32_t rr, gg, bb;
if (is_percent) {
rr = std::stoul(r) * 255 / 100;
gg = std::stoul(g) * 255 / 100;
bb = std::stoul(b) * 255 / 100;
} else {
rr = std::stoul(r);
gg = std::stoul(g);
bb = std::stoul(b);
}
rr = rr > 255 ? 255 : rr;
gg = gg > 255 ? 255 : gg;
bb = bb > 255 ? 255 : bb;
uint32_t color = (rr << 16) | (gg << 8) | bb;
for (uint32_t j = start; j < i; j++)
lines[idx][j] = color;
}
continue;
} else if (i + 5 < len && (line[i] == 'h' || line[i] == 'H') &&
(line[i + 1] == 's' || line[i + 1] == 'S') &&
(line[i + 2] == 'l' || line[i + 2] == 'L')) {
uint32_t start = i;
i += 3;
if (line[i] == 'a' || line[i] == 'A')
i++;
if (line[i] == '(') {
i++;
std::string h = "";
std::string h_unit = "";
enum unit : uint8_t { deg, grad, rad, turn };
unit u = deg;
bool negative = false;
if (i < len && (line[i] == '-' || line[i] == '+')) {
negative = line[i] == '-';
i++;
}
while (i < len && line[i] >= '0' && line[i] <= '9')
h += line[i++];
if (i < len && line[i] == '.') {
h += '.';
while (i < len && line[i] >= '0' && line[i] <= '9')
h += line[i++];
}
if (h.empty())
continue;
while (i < len && ((line[i] >= 'a' && line[i] <= 'z') ||
(line[i] >= 'A' && line[i] <= 'Z')))
h_unit += line[i++];
for (size_t x = 0; x < h_unit.size(); x++)
h_unit[x] = tolower(h_unit[x]);
if (h_unit.empty())
u = deg;
else if (h_unit == "deg")
u = deg;
else if (h_unit == "grad")
u = grad;
else if (h_unit == "rad")
u = rad;
else if (h_unit == "turn")
u = turn;
else
continue;
double hue = std::stod(h);
if (negative)
hue = -hue;
switch (u) {
case deg:
break;
case grad:
hue = hue * 360.0 / 400.0;
break;
case rad:
hue = hue * 180.0 / M_PI;
break;
case turn:
hue = hue * 360.0;
break;
}
hue = fmod(hue, 360.0);
if (hue < 0)
hue += 360.0;
double h_final = hue / 360.0;
while (i < len && (line[i] == ',' || line[i] == ' '))
i++;
std::string s = "";
while (i < len && line[i] >= '0' && line[i] <= '9')
s += line[i++];
if (s.empty())
continue;
if (i < len && line[i] == '%')
i++;
else
continue;
while (i < len && (line[i] == ',' || line[i] == ' '))
i++;
std::string l = "";
while (i < len && line[i] >= '0' && line[i] <= '9')
l += line[i++];
if (l.empty())
continue;
if (i < len && line[i] == '%')
i++;
else
continue;
while (i < len &&
(line[i] == ',' || line[i] == ' ' || line[i] == '.' ||
line[i] == '/' || line[i] == '%' ||
(line[i] >= '0' && line[i] <= '9')))
i++;
if (i < len && line[i] == ')')
i++;
double s_val = std::stod(s) / 100.0;
double l_val = std::stod(l) / 100.0;
uint32_t color = hslToRgb(h_final, s_val, l_val);
for (uint32_t j = start; j < i; j++)
lines[idx][j] = color;
}
continue;
}
}
if (i + 4 < len && line[i] == '#') {
i++;
uint32_t start = i;
while (i < len && isxdigit(line[i]))
i++;
uint32_t color = 0;
if (is_css && (i - start == 3 || i - start == 4)) {
uint32_t r =
std::stoul(std::string(line + start, 1), nullptr, 16) * 0x11;
uint32_t g =
std::stoul(std::string(line + start + 1, 1), nullptr, 16) *
0x11;
uint32_t b =
std::stoul(std::string(line + start + 2, 1), nullptr, 16) *
0x11;
color = (r << 16) | (g << 8) | b;
} else if ((is_css && (i - start == 8)) || i - start == 6) {
uint32_t r = std::stoul(std::string(line + start, 2), nullptr, 16);
uint32_t g =
std::stoul(std::string(line + start + 2, 2), nullptr, 16);
uint32_t b =
std::stoul(std::string(line + start + 4, 2), nullptr, 16);
color = (r << 16) | (g << 8) | b;
} else {
continue;
}
for (uint32_t j = start - 1; j < i; j++)
lines[idx][j] = color;
continue;
} else if (i + 5 < len && line[i] == '0' && line[i + 1] == 'x') {
i += 2;
uint32_t start = i;
while (i < len && isxdigit(line[i]))
i++;
uint32_t color = 0;
if (i - start == 6) {
uint32_t r = std::stoul(std::string(line + start, 2), nullptr, 16);
uint32_t g =
std::stoul(std::string(line + start + 2, 2), nullptr, 16);
uint32_t b =
std::stoul(std::string(line + start + 4, 2), nullptr, 16);
color = (r << 16) | (g << 8) | b;
} else {
continue;
}
if (color)
color--;
else
color++;
for (uint32_t j = start - 2; j < i; j++)
lines[idx][j] = color;
continue;
}
if (i < len && (isalnum(line[i]) || line[i] == '_')) {
uint32_t start = i;
uint32_t x = 0;
bool found = true;
while (i < len && (isalnum(line[i]) || line[i] == '_')) {
if (x < word.size() && line[i] == word[x]) {
i++;
x++;
} else {
found = false;
i++;
}
}
if (found && x == word.size())
for (uint32_t j = start; j < i; j++)
lines[idx][j] = UINT32_MAX;
} else {
i += utf8_codepoint_width(line[i]);
}
}
idx++;
}
free(it->buffer);
free(it);
}
std::optional<std::pair<uint32_t, uint32_t>> get(Coord pos) {
uint32_t val;
if (pos.row < start || pos.row >= start + 50 ||
pos.col >= lines[pos.row - start].size() ||
(val = lines[pos.row - start][pos.col]) == UINT32_MAX - 1)
return std::nullopt;
return (std::pair<uint32_t, uint32_t>){fg_for_bg(val), val};
}
private:
uint32_t fg_for_bg(uint32_t color) {
uint8_t r = (color >> 16) & 0xFF;
uint8_t g = (color >> 8) & 0xFF;
uint8_t b = color & 0xFF;
double luminance = 0.299 * r + 0.587 * g + 0.114 * b;
return (luminance > 128) ? 0x010101 : 0xFFFFFF;
}
uint32_t hslToRgb(double h, double s, double l) {
double r, g, b;
if (s == 0.0) {
r = g = b = l;
} else {
auto hue2rgb = [](double p, double q, double t) -> double {
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t < 1.0 / 6)
return p + (q - p) * 6 * t;
if (t < 1.0 / 2)
return q;
if (t < 2.0 / 3)
return p + (q - p) * (2.0 / 3 - t) * 6;
return p;
};
double q = l < 0.5 ? l * (1 + s) : l + s - l * s;
double p = 2 * l - q;
r = hue2rgb(p, q, h + 1.0 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1.0 / 3);
}
uint32_t R = static_cast<uint32_t>(std::clamp(r, 0.0, 1.0) * 255);
uint32_t G = static_cast<uint32_t>(std::clamp(g, 0.0, 1.0) * 255);
uint32_t B = static_cast<uint32_t>(std::clamp(b, 0.0, 1.0) * 255);
return (R << 16) | (G << 8) | B;
}
};
#endif

47
include/syntax/langs.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef SYNTAX_LANGS_H
#define SYNTAX_LANGS_H
#include "syntax/decl.h"
#define DEF_LANG(name) \
std::shared_ptr<void> name##_parse( \
std::vector<Token> *tokens, std::shared_ptr<void> in_state, \
const char *text, uint32_t len, uint32_t line_num); \
bool name##_state_match(std::shared_ptr<void> state_1, \
std::shared_ptr<void> state_2);
#define LANG_A(name) \
{ \
#name, { name##_parse, name##_state_match } \
}
template <typename T>
inline std::shared_ptr<T> ensure_state(std::shared_ptr<T> state) {
using U = typename T::full_state_type;
if (!state)
state = std::make_shared<T>();
if (!state.unique())
state = std::make_shared<T>(*state);
if (!state->full_state)
state->full_state = std::make_shared<U>();
else if (!state->full_state.unique())
state->full_state = std::make_shared<U>(*state->full_state);
return state;
}
DEF_LANG(ruby);
DEF_LANG(bash);
inline static const std::unordered_map<
std::string,
std::tuple<std::shared_ptr<void> (*)(
std::vector<Token> *tokens, std::shared_ptr<void> in_state,
const char *text, uint32_t len, uint32_t line_num),
bool (*)(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2)>>
parsers = {
LANG_A(ruby),
LANG_A(bash),
};
#endif

400
include/syntax/libcrib.rb Normal file
View File

@@ -0,0 +1,400 @@
module C
@lsp_config = {
"clangd" => [
"--background-index",
"--clang-tidy",
"--completion-style=detailed",
"--header-insertion=never",
"--pch-storage=memory",
"--limit-results=50",
"--log=error"
],
"ruby-lsp" => [],
"solargraph" => ["stdio"],
"bash-language-server" => ["start"],
"vscode-css-language-server" => ["--stdio"],
"vscode-json-language-server" => ["--stdio"],
"fish-lsp" => ["start"],
"gopls" => ["serve"],
"haskell-language-server" => ["lsp"],
"emmet-language-server" => ["--stdio"],
"typescript-language-server" => ["--stdio"],
"lua-language-server" => [],
"pyright-langserver" => ["--stdio"],
"rust-analyzer" => [],
"intelephense" => ["--stdio"],
"marksman" => ["server"],
"nginx-language-server" => [],
"taplo" => ["lsp", "stdio"],
"yaml-language-server" => ["--stdio"],
"sqls" => ["serve"],
"make-language-server" => [],
"sql-language-server" => ["up", "--method", "stdio"]
}
@languages = {
c: {
color: 0x555555,
symbol: "",
extensions: ["c"],
filenames: [],
mimetypes: ["text/x-c"],
lsp: "clangd"
},
cpp: {
color: 0x00599C,
symbol: "",
extensions: ["cpp", "cc", "cxx"],
filenames: [],
mimetypes: ["text/x-cpp"],
lsp: "clangd"
},
h: {
color: 0xA8B9CC,
symbol: "",
extensions: ["h", "hpp"],
filenames: [],
mimetypes: ["text/x-c-header"],
lsp: "clangd"
},
css: {
color: 0x36a3d9,
symbol: "",
extensions: ["css"],
filenames: [],
mimetypes: ["text/css"],
lsp: "vscode-css-language-server"
},
fish: {
color: 0x4d5a5e,
symbol: "",
extensions: ["fish"],
filenames: [],
mimetypes: ["application/x-fish"],
lsp: "fish-lsp"
},
go: {
color: 0x00add8,
symbol: "",
extensions: ["go"],
filenames: [],
mimetypes: ["text/x-go"],
lsp: "gopls"
},
gomod: {
color: 0x00add8,
symbol: "",
extensions: ["mod"],
filenames: [],
mimetypes: ["text/x-go-mod"],
lsp: "gopls"
},
haskell: {
color: 0xa074c4,
symbol: "",
extensions: ["hs", "lhs"],
filenames: [],
mimetypes: ["text/x-haskell"],
lsp: "haskell-language-server"
},
html: {
color: 0xef8a91,
symbol: "",
extensions: ["html", "htm"],
filenames: [],
mimetypes: ["text/html"],
lsp: "emmet-language-server"
},
javascript: {
color: 0xf0df8a,
symbol: "",
extensions: ["js"],
filenames: [],
mimetypes: ["application/javascript"],
lsp: "typescript-language-server"
},
typescript: {
color: 0x36a3d9,
symbol: "",
extensions: ["ts"],
filenames: [],
mimetypes: ["application/typescript"],
lsp: "typescript-language-server"
},
json: {
color: 0xcbcb41,
symbol: "{}",
extensions: ["json"],
filenames: [],
mimetypes: ["application/json"],
lsp: "vscode-json-language-server"
},
jsonc: {
color: 0xcbcb41,
symbol: "{}",
extensions: ["jsonc"],
filenames: [],
mimetypes: ["application/json"],
lsp: "vscode-json-language-server"
},
erb: {
color: 0x6e1516,
symbol: "",
extensions: ["erb"],
filenames: [],
mimetypes: ["text/x-erb"],
lsp: "ruby-lsp"
},
lua: {
color: 0x36a3d9,
symbol: "󰢱 ",
extensions: ["lua"],
filenames: [],
mimetypes: ["text/x-lua"],
lsp: "lua-language-server"
},
python: {
color: 0x95e6cb,
symbol: "󰌠 ",
extensions: ["py"],
filenames: [],
mimetypes: ["text/x-python"],
lsp: "pyright"
},
rust: {
color: 0xdea584,
symbol: "󱘗 ",
extensions: ["rs"],
filenames: [],
mimetypes: ["text/x-rust"],
lsp: "rust-analyzer"
},
php: {
color: 0xa074c4,
symbol: "󰌟 ",
extensions: ["php"],
filenames: [],
mimetypes: ["application/x-php"],
lsp: "intelephense"
},
markdown: {
color: 0x36a3d9,
symbol: "",
extensions: ["md", "markdown"],
filenames: [],
mimetypes: ["text/markdown"],
lsp: "marksman"
},
nginx: {
color: 0x6d8086,
symbol: "",
extensions: ["conf"],
filenames: [],
mimetypes: ["text/nginx"],
lsp: "nginx-language-server"
},
toml: {
color: 0x36a3d9,
symbol: "",
extensions: ["toml"],
filenames: [],
mimetypes: ["application/toml"],
lsp: "taplo"
},
yaml: {
color: 0x6d8086,
symbol: "",
extensions: ["yml", "yaml"],
filenames: [],
mimetypes: ["text/yaml"],
lsp: "yaml-language-server"
},
sql: {
color: 0xdad8d8,
symbol: "",
extensions: ["sql"],
filenames: [],
mimetypes: ["text/x-sql"],
lsp: "sqls"
},
make: {
color: 0x4e5c61,
symbol: "",
extensions: ["Makefile", "makefile"],
filenames: [],
mimetypes: ["text/x-makefile"],
lsp: "make-language-server"
},
gdscript: {
color: 0x6d8086,
symbol: "",
extensions: ["gd"],
filenames: [],
mimetypes: ["text/x-gdscript"],
lsp: nil
},
man: {
color: 0xdad8d8,
symbol: "",
extensions: ["man"],
filenames: [],
mimetypes: ["application/x-troff-man"],
lsp: nil
},
diff: {
color: 0xDD4C35,
symbol: "",
extensions: ["diff", "patch"],
filenames: [],
mimetypes: ["text/x-diff"],
lsp: nil
},
gitattributes: {
color: 0xF05032,
symbol: "",
extensions: ["gitattributes"],
filenames: [],
mimetypes: [],
lsp: nil
},
gitignore: {
color: 0xF05032,
symbol: "",
extensions: ["gitignore"],
filenames: [],
mimetypes: [],
lsp: nil
},
regex: {
color: 0x9E9E9E,
symbol: ".*",
extensions: ["regex"],
filenames: [],
mimetypes: [],
lsp: nil
},
ini: {
color: 0x6d8086,
symbol: "",
extensions: ["ini"],
filenames: [],
mimetypes: [],
lsp: nil
},
ruby: {
color: 0xff8087,
symbol: "󰴭 ",
extensions: ["rb"],
filenames: ["Gemfile"],
mimetypes: ["text/x-ruby"],
lsp: "solargraph"
},
bash: {
color: 0x4d5a5e,
symbol: "",
extensions: ["sh"],
filenames: ["bash_profile", "bashrc"],
mimetypes: ["text/x-sh"],
lsp: "bash-language-server"
}
}
@theme = {
:default => { fg: 0xEEEEEE },
:shebang => { fg: 0x7DCFFF },
:error => { fg: 0xEF5168 },
:comment => { fg: 0xAAAAAA, italic: true },
:string => { fg: 0xAAD94C },
:escape => { fg: 0x7DCFFF },
:interpolation => { fg: 0x7DCFFF },
:regexp => { fg: 0xD2A6FF },
:number => { fg: 0xE6C08A },
# rubocop:disable Lint/BooleanSymbol
:true => { fg: 0x7AE93C },
:false => { fg: 0xEF5168 },
# rubocop:enable Lint/BooleanSymbol
:char => { fg: 0xFFAF70 },
:keyword => { fg: 0xFF8F40 },
:keywordoperator => { fg: 0xF07178 },
:operator => { fg: 0xFFFFFF, italic: true },
:function => { fg: 0xFFAF70 },
:type => { fg: 0xF07178 },
:constant => { fg: 0x7DCFFF },
:variableinstance => { fg: 0x95E6CB },
:variableglobal => { fg: 0xF07178 },
:annotation => { fg: 0x7DCFFF },
:directive => { fg: 0xFF8F40 },
:label => { fg: 0xD2A6FF },
:brace1 => { fg: 0xD2A6FF },
:brace2 => { fg: 0xFFAFAF },
:brace3 => { fg: 0xFFFF00 },
:brace4 => { fg: 0x0FFF0F },
:brace5 => { fg: 0xFF0F0F }
}
@line_endings = :auto_unix
@key_handlers = {}
@key_binds = {}
@highlighters = {}
@log_queue = []
@b_startup = nil
@b_shutdown = nil
class << self
attr_accessor :theme, :lsp_config, :languages,
:line_endings, :highlighters
attr_reader :b_startup, :b_shutdown, :b_extra_highlights
def startup(&block)
@b_startup = block
end
def shutdown(&block)
@b_shutdown = block
end
def queue_log(msg)
@log_queue << msg
end
def log_all
@log_queue.each do |msg|
puts msg
end
@log_queue = []
end
def extra_highlights(&block)
@b_extra_highlights = block
end
def bind(modes, keys = nil, action = nil, &block)
modes = [modes] unless modes.is_a?(Array)
if keys.nil?
app = self
dsl = Object.new
dsl.define_singleton_method(:set) do |k, act = nil, &blk|
app.bind(modes, k, act, &blk)
end
dsl.instance_exec(&block) if block_given?
elsif block_given?
keys = [keys] unless keys.is_a?(Array)
modes.each do |mode|
keys.each do |key|
@key_handlers[mode] ||= {}
@key_handlers[mode][key] ||= []
@key_handlers[mode][key] << block
end
end
elsif action.is_a?(String)
keys = [keys] unless keys.is_a?(Array)
modes.each do |mode|
keys.each do |key|
@key_binds[mode] ||= {}
@key_binds[mode][key] ||= []
@key_binds[mode][key] << action
end
end
end
end
end
end
at_exit { C.log_all }

245
include/syntax/line_tree.h Normal file
View File

@@ -0,0 +1,245 @@
#ifndef LINE_TREE_H
#define LINE_TREE_H
#include "syntax/decl.h"
struct LineTree {
void clear() {
std::unique_lock lock(mtx);
clear_node(root);
root = nullptr;
stack_size = 0;
}
void build(uint32_t x) {
std::unique_lock lock(mtx);
root = build_node(x);
}
LineData *at(uint32_t x) {
std::shared_lock lock(mtx);
LineNode *n = root;
while (n) {
uint32_t left_size = n->left ? n->left->size : 0;
if (x < left_size) {
n = n->left;
} else if (x < left_size + n->data.size()) {
return &n->data[x - left_size];
} else {
x -= left_size + n->data.size();
n = n->right;
}
}
return nullptr;
}
LineData *start_iter(uint32_t x) {
std::shared_lock lock(mtx);
stack_size = 0;
LineNode *n = root;
while (n) {
uint32_t left_size = n->left ? n->left->size : 0;
if (x < left_size) {
push(n, 0);
n = n->left;
} else if (x < left_size + n->data.size()) {
push(n, x - left_size + 1);
return &n->data[x - left_size];
} else {
x -= left_size + n->data.size();
push(n, UINT32_MAX);
n = n->right;
}
}
return nullptr;
}
void end_iter() { stack_size = 0; }
LineData *next() {
std::shared_lock lock(mtx);
while (stack_size) {
auto &f = stack[stack_size - 1];
LineNode *n = f.node;
if (f.index < n->data.size())
return &n->data[f.index++];
stack_size--;
if (n->right) {
n = n->right;
while (n) {
push(n, 0);
if (!n->left)
break;
n = n->left;
}
return &stack[stack_size - 1].node->data[0];
}
}
return nullptr;
}
void insert(uint32_t x, uint32_t y) {
std::unique_lock lock(mtx);
if (x > subtree_size(root))
x = subtree_size(root);
root = insert_node(root, x, y);
}
void erase(uint32_t x, uint32_t y) {
std::unique_lock lock(mtx);
if (x + y > subtree_size(root))
x = subtree_size(root) - y;
root = erase_node(root, x, y);
}
uint32_t count() {
std::shared_lock lock(mtx);
return subtree_size(root);
}
~LineTree() { clear(); }
private:
struct LineNode {
LineNode *left = nullptr;
LineNode *right = nullptr;
uint8_t depth = 1;
uint32_t size = 0;
std::vector<LineData> data;
};
struct Frame {
LineNode *node;
uint32_t index;
};
void push(LineNode *n, uint32_t x) {
stack[stack_size].node = n;
stack[stack_size].index = x;
stack_size++;
}
static void clear_node(LineNode *n) {
if (!n)
return;
clear_node(n->left);
clear_node(n->right);
delete n;
}
LineNode *root = nullptr;
Frame stack[32];
std::atomic<uint8_t> stack_size = 0;
std::shared_mutex mtx;
static constexpr uint32_t LEAF_TARGET = 256;
LineTree::LineNode *erase_node(LineNode *n, uint32_t x, uint32_t y) {
if (!n || y == 0)
return n;
uint32_t left_sz = subtree_size(n->left);
uint32_t mid_sz = n->data.size();
if (x < left_sz) {
uint32_t len = std::min(y, left_sz - x);
n->left = erase_node(n->left, x, len);
y -= len;
x = left_sz;
}
if (y > 0 && x < left_sz + mid_sz) {
uint32_t mid_x = x - left_sz;
uint32_t len = std::min(y, mid_sz - mid_x);
n->data.erase(n->data.begin() + mid_x, n->data.begin() + mid_x + len);
y -= len;
x += len;
}
if (y > 0) {
n->right = erase_node(n->right, x - left_sz - n->data.size(), y);
}
if (n->left && n->right &&
subtree_size(n->left) + subtree_size(n->right) < 256) {
return merge(n->left, n->right);
}
return rebalance(n);
}
LineTree::LineNode *insert_node(LineNode *n, uint32_t x, uint32_t y) {
if (!n) {
auto *leaf = new LineNode();
leaf->data.resize(y);
leaf->size = y;
return leaf;
}
if (!n->left && !n->right) {
n->data.insert(n->data.begin() + x, y, LineData());
fix(n);
if (n->data.size() > 512)
return split_leaf(n);
return n;
}
uint32_t left_size = subtree_size(n->left);
if (x <= left_size)
n->left = insert_node(n->left, x, y);
else
n->right = insert_node(n->right, x - left_size - n->data.size(), y);
return rebalance(n);
}
LineNode *build_node(uint32_t count) {
if (count <= LEAF_TARGET) {
auto *n = new LineNode();
n->data.resize(count);
n->size = count;
return n;
}
uint32_t left_count = count / 2;
uint32_t right_count = count - left_count;
auto *n = new LineNode();
n->left = build_node(left_count);
n->right = build_node(right_count);
fix(n);
return n;
}
static LineNode *split_leaf(LineNode *n) {
auto *right = new LineNode();
size_t mid = n->data.size() / 2;
right->data.assign(n->data.begin() + mid, n->data.end());
n->data.resize(mid);
fix(n);
fix(right);
auto *parent = new LineNode();
parent->left = n;
parent->right = right;
fix(parent);
return parent;
}
static LineNode *merge(LineNode *a, LineNode *b) {
a->data.insert(a->data.end(), b->data.begin(), b->data.end());
delete b;
fix(a);
return a;
}
static void fix(LineNode *n) {
n->depth = 1 + MAX(height(n->left), height(n->right));
n->size = subtree_size(n->left) + n->data.size() + subtree_size(n->right);
}
static LineNode *rotate_right(LineNode *y) {
LineNode *x = y->left;
LineNode *T2 = x->right;
x->right = y;
y->left = T2;
fix(y);
fix(x);
return x;
}
static LineNode *rotate_left(LineNode *x) {
LineNode *y = x->right;
LineNode *T2 = y->left;
y->left = x;
x->right = T2;
fix(x);
fix(y);
return y;
}
static LineNode *rebalance(LineNode *n) {
fix(n);
int balance = int(height(n->left)) - int(height(n->right));
if (balance > 1) {
if (height(n->left->left) < height(n->left->right))
n->left = rotate_left(n->left);
return rotate_right(n);
}
if (balance < -1) {
if (height(n->right->right) < height(n->right->left))
n->right = rotate_right(n->right);
return rotate_left(n);
}
return n;
}
static uint8_t height(LineNode *n) { return n ? n->depth : 0; }
static uint32_t subtree_size(LineNode *n) { return n ? n->size : 0; }
};
#endif

33
include/syntax/parser.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef SYNTAX_PARSER_H
#define SYNTAX_PARSER_H
#include "scripting/decl.h"
#include "syntax/decl.h"
#include "syntax/line_tree.h"
struct Parser {
struct Editor *editor = nullptr;
std::string lang;
std::shared_ptr<void> (*parse_func)(std::vector<Token> *tokens,
std::shared_ptr<void> in_state,
const char *text, uint32_t len,
uint32_t line_num);
bool (*state_match_func)(std::shared_ptr<void> state_1,
std::shared_ptr<void> state_2);
VALUE parser_block = Qnil;
VALUE match_block = Qnil;
bool is_custom{false};
std::atomic<uint32_t> scroll_max{UINT32_MAX - 2048};
std::atomic<bool> scroll_dirty{false};
std::mutex mutex;
std::mutex data_mutex;
LineTree line_tree;
UniqueQueue<uint32_t> dirty_lines;
Parser(Editor *editor, std::string n_lang, uint32_t n_scroll_max);
void edit(uint32_t start_line, uint32_t old_end_line, uint32_t inserted_rows);
void work();
void scroll(uint32_t line);
};
#endif

53
include/syntax/tokens.def Normal file
View File

@@ -0,0 +1,53 @@
ADD(K_DATA)
ADD(K_SHEBANG)
ADD(K_COMMENT)
ADD(K_ERROR)
ADD(K_STRING)
ADD(K_ESCAPE)
ADD(K_INTERPOLATION)
ADD(K_REGEXP)
ADD(K_NUMBER)
ADD(K_TRUE)
ADD(K_FALSE)
ADD(K_CHAR)
ADD(K_KEYWORD)
ADD(K_KEYWORDOPERATOR)
ADD(K_OPERATOR)
ADD(K_FUNCTION)
ADD(K_TYPE)
ADD(K_CONSTANT)
ADD(K_VARIABLEINSTANCE)
ADD(K_VARIABLEGLOBAL)
ADD(K_ANNOTATION)
ADD(K_DIRECTIVE)
ADD(K_LABEL)
ADD(K_BRACE1)
ADD(K_BRACE2)
ADD(K_BRACE3)
ADD(K_BRACE4)
ADD(K_BRACE5)
ADD(K_HEADING1)
ADD(K_HEADING2)
ADD(K_HEADING3)
ADD(K_HEADING4)
ADD(K_HEADING5)
ADD(K_HEADING6)
ADD(K_BLOCKQUOTE)
ADD(K_LIST)
ADD(K_LISTITEM)
ADD(K_CODE)
ADD(K_LANGUAGENAME)
ADD(K_LINKLABEL)
ADD(K_IMAGELABEL)
ADD(K_LINK)
ADD(K_TABLE)
ADD(K_TABLEHEADER)
ADD(K_ITALIC)
ADD(K_BOLD)
ADD(K_UNDERLINE)
ADD(K_STRIKETHROUGH)
ADD(K_HORIXONTALRULE)
ADD(K_TAG)
ADD(K_ATTRIBUTE)
ADD(K_CHECKDONE)
ADD(K_CHECKNOTDONE)

140
include/syntax/trie.h Normal file
View File

@@ -0,0 +1,140 @@
#ifndef SYNTAX_TRIE_H
#define SYNTAX_TRIE_H
#include "utils/utils.h"
template <typename T> struct Trie {
struct TrieNode {
bool is_word = false;
std::array<TrieNode *, 128> children{};
std::conditional_t<std::is_void_v<T>, char, std::optional<T>> value;
TrieNode() { children.fill(nullptr); }
};
Trie() {}
~Trie() { clear_trie(root); }
void build(const std::vector<std::string> &words, bool cs = true) {
static_assert(std::is_void_v<T>, "This build() is for Trie<void> only");
case_sensitive = cs;
for (auto &w : words)
insert(w);
}
template <typename U = T>
std::enable_if_t<!std::is_void_v<U>>
build(const std::vector<std::pair<std::string, U>> &words, bool cs = true) {
static_assert(!std::is_void_v<T>, "This build() is for typed Trie only");
case_sensitive = cs;
for (auto &[w, v] : words)
insert(w, v);
}
uint32_t match(const char *text, uint32_t pos, uint32_t len,
bool (*is_word_char)(char c)) const {
const TrieNode *node = root;
uint32_t max_len = 0;
for (uint32_t i = pos; i < len; ++i) {
unsigned char uc = static_cast<unsigned char>(text[i]);
if (uc >= 128)
return 0;
if (!case_sensitive && uc >= 'A' && uc <= 'Z')
uc = uc - 'A' + 'a';
if (!node->children[uc]) {
if (node->is_word && !is_word_char(text[i]))
return i - pos;
break;
}
node = node->children[uc];
if (node->is_word)
max_len = i - pos + 1;
}
if (max_len > 0)
if (pos + max_len < len && is_word_char(text[pos + max_len]))
return 0;
return max_len;
}
template <typename U = T>
uint32_t
match(const char *text, uint32_t pos, uint32_t len,
bool (*is_word_char)(char c),
std::conditional_t<std::is_void_v<T>, void *, std::optional<T> *>
out_val = nullptr) const {
const TrieNode *node = root;
const TrieNode *last_word_node = nullptr;
uint32_t max_len = 0;
for (uint32_t i = pos; i < len; ++i) {
unsigned char uc = static_cast<unsigned char>(text[i]);
if (uc >= 128)
break;
if (!case_sensitive && uc >= 'A' && uc <= 'Z')
uc = uc - 'A' + 'a';
if (!node->children[uc])
break;
node = node->children[uc];
if (node->is_word) {
last_word_node = node;
max_len = i - pos + 1;
}
}
if (!last_word_node) {
if (out_val)
*out_val = std::nullopt;
return 0;
}
if (pos + max_len < len && is_word_char(text[pos + max_len])) {
if (out_val)
*out_val = std::nullopt;
return 0;
}
if (out_val)
*out_val = last_word_node->value;
return max_len;
}
private:
TrieNode *root = new TrieNode();
bool case_sensitive = true;
void insert(const std::string &word) {
TrieNode *node = root;
for (char c : word) {
unsigned char uc = static_cast<unsigned char>(c);
if (uc >= 128)
return;
if (!case_sensitive && uc >= 'A' && uc <= 'Z')
uc = uc - 'A' + 'a';
if (!node->children[uc])
node->children[uc] = new TrieNode();
node = node->children[uc];
}
node->is_word = true;
}
template <typename U = T>
std::enable_if_t<!std::is_void_v<U>> insert(const std::string &word,
const U &val) {
TrieNode *node = root;
for (char c : word) {
unsigned char uc = static_cast<unsigned char>(c);
if (!case_sensitive && uc >= 'A' && uc <= 'Z')
uc = uc - 'A' + 'a';
if (!node->children[uc])
node->children[uc] = new TrieNode();
node = node->children[uc];
}
node->is_word = true;
node->value = val;
}
void clear_trie(TrieNode *node) {
if (!node)
return;
for (auto *child : node->children)
clear_trie(child);
delete node;
}
};
#endif

View File

@@ -1,16 +0,0 @@
#ifndef TS_H
#define TS_H
#include "./editor.h"
#include "./utils.h"
#include <pcre2.h>
#define HEX(s) (static_cast<uint32_t>(std::stoul(s, nullptr, 16)))
extern std::unordered_map<std::string, pcre2_code *> regex_cache;
TSQuery *load_query(const char *query_path, Editor *editor);
void ts_collect_spans(Editor *editor);
void clear_regex_cache();
#endif

View File

@@ -1,24 +0,0 @@
#include "../libs/tree-sitter/lib/include/tree_sitter/api.h"
#include <string>
struct Language {
std::string name;
const TSLanguage *(*fn)();
};
extern "C" {
const TSLanguage *tree_sitter_bash();
const TSLanguage *tree_sitter_c();
const TSLanguage *tree_sitter_cpp();
const TSLanguage *tree_sitter_css();
const TSLanguage *tree_sitter_fish();
const TSLanguage *tree_sitter_go();
const TSLanguage *tree_sitter_haskell();
const TSLanguage *tree_sitter_html();
const TSLanguage *tree_sitter_javascript();
const TSLanguage *tree_sitter_json();
const TSLanguage *tree_sitter_lua();
const TSLanguage *tree_sitter_make();
const TSLanguage *tree_sitter_python();
const TSLanguage *tree_sitter_ruby();
}

View File

@@ -1,100 +0,0 @@
#ifndef UI_H
#define UI_H
#include "./utils.h"
#include <atomic>
#include <cstdint>
#include <mutex>
#include <string.h>
#include <string>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include <vector>
#define KEY_CHAR 0
#define KEY_SPECIAL 1
#define KEY_MOUSE 2
#define KEY_NONE 3
#define KEY_UP 0
#define KEY_DOWN 1
#define KEY_LEFT 2
#define KEY_RIGHT 3
#define KEY_DELETE 4
#define KEY_ESC '\x1b'
#define PRESS 0
#define RELEASE 1
#define DRAG 2
#define SCROLL 3
#define LEFT_BTN 0
#define MIDDLE_BTN 1
#define RIGHT_BTN 2
#define SCROLL_BTN 3
#define NONE_BTN 4
#define SCROLL_UP 0
#define SCROLL_DOWN 1
#define SCROLL_LEFT 2
#define SCROLL_RIGHT 3
#define ALT 1
#define CNTRL 2
#define CNTRL_ALT 3
#define SHIFT 4
#define DEFAULT 0
#define BLOCK 2
#define UNDERLINE 4
#define CURSOR 6
enum CellFlags : uint8_t {
CF_NONE = 0,
CF_ITALIC = 1 << 0,
CF_BOLD = 1 << 1,
CF_UNDERLINE = 1 << 2,
};
struct ScreenCell {
std::string utf8 = std::string("");
uint32_t fg = 0;
uint32_t bg = 0;
uint8_t flags = CF_NONE;
};
struct KeyEvent {
uint8_t key_type;
char *c;
uint32_t len;
uint8_t special_key;
uint8_t special_modifier;
uint8_t mouse_x;
uint8_t mouse_y;
uint8_t mouse_button;
uint8_t mouse_state;
uint8_t mouse_direction;
uint8_t mouse_modifier;
};
extern uint32_t rows, cols;
extern std::vector<ScreenCell> screen;
extern std::vector<ScreenCell> old_screen;
extern std::mutex screen_mutex;
Coord start_screen();
void end_screen();
void update(uint32_t row, uint32_t col, const char *utf8, uint32_t fg,
uint32_t bg, uint8_t flags);
void set_cursor(int row, int col, int type, bool show_cursor_param);
void render();
Coord get_size();
KeyEvent read_key();
#endif

19
include/ui/bar.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef UI_BAR_H
#define UI_BAR_H
#include "editor/editor.h"
#include "io/sysio.h"
#include "utils/utils.h"
struct Bar {
Coord screen;
std::string command = "";
uint32_t cursor = 0;
Bar(Coord screen) : screen(screen) {}
void render();
void handle(KeyEvent event);
void log(std::string message);
};
#endif

View File

@@ -0,0 +1,21 @@
#ifndef UI_COMPLETIONBOX_H
#define UI_COMPLETIONBOX_H
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
struct CompletionBox {
std::shared_mutex mtx;
struct CompletionSession *session;
bool hidden = true;
std::vector<ScreenCell> cells;
Coord size;
Coord position;
CompletionBox(CompletionSession *s) : session(s) {}
void render_update();
void render(Coord pos);
};
#endif

19
include/ui/diagnostics.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef UI_DIAGNOSTICS_H
#define UI_DIAGNOSTICS_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
struct DiagnosticBox {
std::vector<VWarn> warnings;
std::vector<ScreenCell> cells;
Coord size;
void clear();
void render_first();
void render(Coord pos);
};
#endif

22
include/ui/hover.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef UI_HOVER_H
#define UI_HOVER_H
#include "editor/decl.h"
#include "io/sysio.h"
#include "pch.h"
#include "utils/utils.h"
struct HoverBox {
std::string text;
std::atomic<bool> is_markup;
uint32_t scroll_;
std::vector<ScreenCell> cells;
Coord size;
void clear();
void scroll(int32_t number);
void render_first(bool scroll = false);
void render(Coord pos);
};
#endif

View File

@@ -1,88 +0,0 @@
#ifndef UTILS_H
#define UTILS_H
#include "./ts_def.h"
#include <chrono>
#include <functional>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#define PCRE2_CODE_UNIT_WIDTH 8
#define PCRE_WORKSPACE_SIZE 512
template <typename T> struct Queue {
std::queue<T> q;
std::mutex m;
void push(T val) {
std::lock_guard<std::mutex> lock(m);
q.push(val);
}
bool pop(T &val) {
std::lock_guard<std::mutex> lock(m);
if (q.empty())
return false;
val = q.front();
q.pop();
return true;
}
bool empty() {
std::lock_guard<std::mutex> lock(m);
return q.empty();
}
};
struct Coord {
uint32_t row;
uint32_t col;
bool operator<(const Coord &other) const {
return row < other.row || (row == other.row && col < other.col);
}
bool operator<=(const Coord &other) const {
return *this < other || *this == other;
}
bool operator==(const Coord &other) const {
return row == other.row && col == other.col;
}
bool operator!=(const Coord &other) const { return !(*this == other); }
bool operator>(const Coord &other) const { return other < *this; }
bool operator>=(const Coord &other) const { return !(*this < other); }
};
int display_width(const char *str, size_t len);
uint32_t get_visual_col_from_bytes(const char *line, uint32_t len,
uint32_t byte_limit);
uint32_t get_bytes_from_visual_col(const char *line, uint32_t len,
uint32_t target_visual_col);
void log(const char *fmt, ...);
std::string get_exe_dir();
char *load_file(const char *path, uint32_t *out_len);
char *detect_file_type(const char *filename);
Language language_for_file(const char *filename);
void copy_to_clipboard(const char *text, size_t len);
char *get_from_clipboard(uint32_t *out_len);
uint32_t count_clusters(const char *line, size_t len, size_t from, size_t to);
template <typename Func, typename... Args>
auto throttle(std::chrono::milliseconds min_duration, Func &&func,
Args &&...args) {
auto start = std::chrono::steady_clock::now();
if constexpr (std::is_void_v<std::invoke_result_t<Func, Args...>>) {
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
} else {
auto result =
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
auto elapsed = std::chrono::steady_clock::now() - start;
if (elapsed < min_duration)
std::this_thread::sleep_for(min_duration - elapsed);
return result;
}
auto elapsed = std::chrono::steady_clock::now() - start;
if (elapsed < min_duration)
std::this_thread::sleep_for(min_duration - elapsed);
}
#endif

191
include/utils/utils.h Normal file
View File

@@ -0,0 +1,191 @@
#ifndef UTILS_H
#define UTILS_H
#include "pch.h"
template <typename T> struct Queue {
void push(T val) {
std::lock_guard<std::mutex> lock(m);
q.push(val);
}
std::optional<T> front() {
if (q.empty())
return std::nullopt;
return q.front();
}
bool pop(T &val) {
std::lock_guard<std::mutex> lock(m);
if (q.empty())
return false;
val = q.front();
q.pop();
return true;
}
void pop() {
std::lock_guard<std::mutex> lock(m);
q.pop();
}
bool empty() {
std::lock_guard<std::mutex> lock(m);
return q.empty();
}
private:
std::queue<T> q;
std::mutex m;
};
template <typename T> struct UniqueQueue {
bool push(const T &value) {
std::lock_guard<std::mutex> lock(m);
if (set.contains(value))
return false;
dq.push_back(value);
set.insert(value);
return true;
}
bool pop(T &out) {
std::lock_guard<std::mutex> lock(m);
if (dq.empty())
return false;
out = dq.front();
dq.pop_front();
set.erase(out);
return true;
}
bool empty() const {
std::lock_guard<std::mutex> lock(m);
return dq.empty();
}
void clear() {
std::lock_guard<std::mutex> lock(m);
dq.clear();
set.clear();
}
size_t size() const {
std::lock_guard<std::mutex> lock(m);
return dq.size();
}
private:
std::deque<T> dq;
std::set<T> set;
mutable std::mutex m;
};
struct Coord {
uint32_t row;
uint32_t col;
bool operator<(const Coord &other) const {
return row < other.row || (row == other.row && col < other.col);
}
bool operator<=(const Coord &other) const {
return *this < other || *this == other;
}
bool operator==(const Coord &other) const {
return row == other.row && col == other.col;
}
bool operator!=(const Coord &other) const { return !(*this == other); }
bool operator>(const Coord &other) const { return other < *this; }
bool operator>=(const Coord &other) const { return !(*this < other); }
};
struct Match {
size_t start;
size_t end;
std::string text;
};
struct Language {
std::string name;
std::string lsp_name;
uint32_t color;
std::string symbol;
};
struct LSP {
std::string command;
std::vector<std::string> args;
};
extern std::unordered_map<std::string, Language> languages;
extern std::unordered_map<std::string, std::string> language_extensions;
extern std::unordered_map<std::string, std::string> language_mimetypes;
extern std::unordered_map<std::string, LSP> lsps;
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define UNUSED(x) (void)(x)
#define USING(x) UNUSED(sizeof(x))
inline uint32_t HEX(const std::string &s) {
if (s.empty())
return 0xFFFFFF;
size_t start = (s.front() == '#') ? 1 : 0;
return static_cast<uint32_t>(std::stoul(s.substr(start), nullptr, 16));
}
bool compare(const char *a, const char *b, size_t n);
std::string clean_text(const std::string &input);
std::string percent_encode(const std::string &s);
std::string percent_decode(const std::string &s);
uint32_t count_clusters(const char *line, size_t len, size_t from, size_t to);
std::string trim(const std::string &s);
std::string substitute_fence(const std::string &documentation,
const std::string &lang);
int display_width(const char *str, size_t len);
uint32_t get_visual_col_from_bytes(const char *line, uint32_t len,
uint32_t byte_limit);
uint32_t get_bytes_from_visual_col(const char *line, uint32_t len,
uint32_t target_visual_col);
size_t utf8_offset_to_utf16(const char *utf8, size_t utf8_len,
size_t byte_offset);
size_t utf16_offset_to_utf8(const char *utf8, size_t utf8_len,
size_t utf16_offset);
uint8_t utf8_codepoint_width(unsigned char c);
void log(const char *fmt, ...);
std::string path_abs(const std::string &path_str);
std::string path_to_file_uri(const std::string &path_str);
std::string filename_from_path(const std::string &path);
std::string get_exe_dir();
char *load_file(const char *path, uint32_t *out_len, bool *out_eol);
char *detect_file_type(const char *filename);
Language language_for_file(const char *filename);
void copy_to_clipboard(const char *text, size_t len);
char *get_from_clipboard(uint32_t *out_len);
template <typename T>
inline T *safe_get(std::map<uint16_t, T> &m, uint16_t key) {
auto it = m.find(key);
if (it == m.end())
return nullptr;
return &it->second;
}
template <typename Func, typename... Args>
auto throttle(std::chrono::milliseconds min_duration, Func &&func,
Args &&...args) {
auto start = std::chrono::steady_clock::now();
if constexpr (std::is_void_v<std::invoke_result_t<Func, Args...>>) {
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
} else {
auto result =
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
auto elapsed = std::chrono::steady_clock::now() - start;
if (elapsed < min_duration)
std::this_thread::sleep_for(min_duration - elapsed);
return result;
}
auto elapsed = std::chrono::steady_clock::now() - start;
if (elapsed < min_duration)
std::this_thread::sleep_for(min_duration - elapsed);
}
#endif

91
installer.sh Normal file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/env sh
set -eu
install() {
BINARY_NAME="crib"
VERSION="v0.0.1-alpha"
RUBY_VERSION="3.4"
HAVE_34=0
HAVE_32=0
if ldconfig -p | grep -q libruby.so.3.4; then
HAVE_34=1
fi
if ldconfig -p | grep -q libruby-3.2.so; then
HAVE_32=1
fi
if [ "$HAVE_34" = "1" ] && [ "$HAVE_32" = "1" ]; then
echo "Multiple Ruby versions detected."
echo "Select Ruby ABI:"
echo " 1) Ruby 3.4"
echo " 2) Ruby 3.2"
read -r choice </dev/tty
case "$choice" in
1) RUBY_VERSION="3.4" ;;
2) RUBY_VERSION="3.2" ;;
*)
echo "Invalid choice"
exit 1
;;
esac
elif [ "$HAVE_34" = "1" ]; then
RUBY_VERSION="3.4"
elif [ "$HAVE_32" = "1" ]; then
RUBY_VERSION="3.2"
else
echo "No compatible Ruby library found need Ruby 3.2 or 3.4."
exit 1
fi
GITHUB_URL="https://github.com/SyedM-dev/crib/releases/download/$VERSION/crib-linux-x86_64-ruby$RUBY_VERSION"
missing_ruby=""
missing_magic=""
command -v ruby >/dev/null 2>&1 || missing_ruby="ruby"
ldconfig -p | grep libmagic >/dev/null 2>&1 || missing_magic="libmagic"
if [ -n "$missing_ruby" ] || [ -n "$missing_magic" ]; then
echo "Missing dependencies: ${missing_ruby} ${missing_magic}"
echo "Install them using your package manager:"
echo "Ubuntu/Debian: sudo apt install ruby libmagic1"
echo "Arch: sudo pacman -S ruby file"
echo "Void: sudo xbps-install -Sy ruby file"
exit 1
fi
echo "Installing Crib (Ruby $RUBY_VERSION)"
echo "Install locally (~/.local/bin) or globally (/usr/bin)? [l/g]"
read -r choice </dev/tty
case "$choice" in
l | L)
INSTALL_DIR="$HOME/.local/bin"
SUDO=""
;;
g | G)
INSTALL_DIR="/usr/bin"
SUDO="sudo"
;;
*)
echo "Invalid choice"
exit 1
;;
esac
$SUDO mkdir -p "$INSTALL_DIR"
echo "Downloading binary..."
curl -L "$GITHUB_URL" -o /tmp/"$BINARY_NAME"
$SUDO install -m 755 /tmp/"$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME"
rm -f /tmp/"$BINARY_NAME"
echo
echo "✔ Crib installed to $INSTALL_DIR"
echo "Run with: $BINARY_NAME"
echo "Ruby ABI: $RUBY_VERSION"
echo "Add $INSTALL_DIR to PATH if needed."
}
install "$@"

BIN
libs/libruby/libruby.so vendored Normal file

Binary file not shown.

40
libs/libruby/ruby.h vendored Normal file
View File

@@ -0,0 +1,40 @@
#ifndef RUBY_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_H 1
/**
* @author $Author$
* @date Sun 10 12:06:15 Jun JST 2007
* @copyright 2007-2008 Yukihiro Matsumoto
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
#define HAVE_RUBY_ATOMIC_H 1
#define HAVE_RUBY_DEBUG_H 1
#define HAVE_RUBY_DEFINES_H 1
#define HAVE_RUBY_ENCODING_H 1
#define HAVE_RUBY_FIBER_SCHEDULER_H 1
#define HAVE_RUBY_INTERN_H 1
#define HAVE_RUBY_IO_H 1
#define HAVE_RUBY_MEMORY_VIEW_H 1
#define HAVE_RUBY_MISSING_H 1
#define HAVE_RUBY_ONIGMO_H 1
#define HAVE_RUBY_ONIGURUMA_H 1
#define HAVE_RUBY_RACTOR_H 1
#define HAVE_RUBY_RANDOM_H 1
#define HAVE_RUBY_RE_H 1
#define HAVE_RUBY_REGEX_H 1
#define HAVE_RUBY_RUBY_H 1
#define HAVE_RUBY_ST_H 1
#define HAVE_RUBY_THREAD_H 1
#define HAVE_RUBY_THREAD_NATIVE_H 1
#define HAVE_RUBY_UTIL_H 1
#define HAVE_RUBY_VERSION_H 1
#define HAVE_RUBY_VM_H 1
#ifdef _WIN32
#define HAVE_RUBY_WIN32_H 1
#endif
#include "ruby/ruby.h"
#endif /* RUBY_H */

234
libs/libruby/ruby/assert.h vendored Normal file
View File

@@ -0,0 +1,234 @@
#ifndef RUBY_ASSERT_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_ASSERT_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @date Wed May 18 00:21:44 JST 1994
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
*/
#include "ruby/internal/assume.h"
#include "ruby/internal/attr/cold.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/dllexport.h"
#include "ruby/backward/2/assume.h"
/* RUBY_NDEBUG is very simple: after everything described below are done,
* define it with either NDEBUG is undefined (=0) or defined (=1). It is truly
* subordinate.
*
* RUBY_DEBUG versus NDEBUG is complicated. Assertions shall be:
*
* | -UNDEBUG | -DNDEBUG
* ---------------+----------+---------
* -URUBY_DEBUG | (*1) | disabled
* -DRUBY_DEBUG=0 | disabled | disabled
* -DRUBY_DEBUG=1 | enabled | (*2)
* -DRUBY_DEBUG | enabled | (*2)
*
* where:
*
* - (*1): Assertions shall be silently disabled, no warnings, in favour of
* commit 21991e6ca59274e41a472b5256bd3245f6596c90.
*
* - (*2): Compile-time warnings shall be issued.
*/
/** @cond INTERNAL_MACRO */
/*
* Pro tip: `!!RUBY_DEBUG-1` expands to...
*
* - `!!(-1)` (== `!0` == `1`) when RUBY_DEBUG is defined to be empty,
* - `(!!0)-1` (== `0-1` == `-1`) when RUBY_DEBUG is defined as 0, and
* - `(!!n)-1` (== `1-1` == `0`) when RUBY_DEBUG is defined as something else.
*/
#if ! defined(RUBY_DEBUG)
# define RBIMPL_RUBY_DEBUG 0
#elif !!RUBY_DEBUG-1 < 0
# define RBIMPL_RUBY_DEBUG 0
#else
# define RBIMPL_RUBY_DEBUG 1
#endif
/*
* ISO/IEC 9899 (all past versions) says that "If NDEBUG is defined as a macro
* name at the point in the source file where <assert.h> is included, ..."
* which means we must not take its defined value into account.
*/
#if defined(NDEBUG)
# define RBIMPL_NDEBUG 1
#else
# define RBIMPL_NDEBUG 0
#endif
/** @endcond */
/* Here we go... */
#undef RUBY_DEBUG
#undef RUBY_NDEBUG
#undef NDEBUG
#if defined(__DOXYGEN__)
# /** Define this macro when you want assertions. */
# define RUBY_DEBUG 0
# /** Define this macro when you don't want assertions. */
# define NDEBUG
# /** This macro is basically the same as #NDEBUG */
# define RUBY_NDEBUG 1
#elif (RBIMPL_NDEBUG == 1) && (RBIMPL_RUBY_DEBUG == 0)
# /* Assertions disabled as per request, no conflicts. */
# define RUBY_DEBUG 0
# define RUBY_NDEBUG 1
# define NDEBUG
#elif (RBIMPL_NDEBUG == 0) && (RBIMPL_RUBY_DEBUG == 1)
# /* Assertions enabled as per request, no conflicts. */
# define RUBY_DEBUG 1
# define RUBY_NDEBUG 0
# /* keep NDEBUG undefined */
#elif (RBIMPL_NDEBUG == 0) && (RBIMPL_RUBY_DEBUG == 0)
# /* The (*1) situation in above diagram. */
# define RUBY_DEBUG 0
# define RUBY_NDEBUG 1
# define NDEBUG
#elif (RBIMPL_NDEBUG == 1) && (RBIMPL_RUBY_DEBUG == 1)
# /* The (*2) situation in above diagram. */
# define RUBY_DEBUG 1
# define RUBY_NDEBUG 0
# /* keep NDEBUG undefined */
# if defined(_MSC_VER)
# pragma message("NDEBUG is ignored because RUBY_DEBUG>0.")
# elif defined(__GNUC__)
# pragma GCC warning "NDEBUG is ignored because RUBY_DEBUG>0."
# else
# error NDEBUG is ignored because RUBY_DEBUG>0.
# endif
#endif
#undef RBIMPL_NDEBUG
#undef RBIMPL_RUBY_DEBUG
/** @cond INTERNAL_MACRO */
#define RBIMPL_ASSERT_NOTHING RBIMPL_CAST((void)0)
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_COLD()
void rb_assert_failure(const char *file, int line, const char *name, const char *expr);
RBIMPL_SYMBOL_EXPORT_END()
#ifdef RUBY_FUNCTION_NAME_STRING
# define RBIMPL_ASSERT_FUNC RUBY_FUNCTION_NAME_STRING
#else
# define RBIMPL_ASSERT_FUNC RBIMPL_CAST((const char *)0)
#endif
/** @endcond */
/**
* Prints the given message, and terminates the entire process abnormally.
*
* @param mesg The message to display.
*/
#define RUBY_ASSERT_FAIL(mesg) \
rb_assert_failure(__FILE__, __LINE__, RBIMPL_ASSERT_FUNC, mesg)
/**
* Asserts that the expression is truthy. If not aborts with the message.
*
* @param expr What supposedly evaluates to true.
* @param mesg The message to display on failure.
*/
#define RUBY_ASSERT_MESG(expr, mesg) \
(RB_LIKELY(expr) ? RBIMPL_ASSERT_NOTHING : RUBY_ASSERT_FAIL(mesg))
/**
* A variant of #RUBY_ASSERT that does not interface with #RUBY_DEBUG.
*
* @copydetails #RUBY_ASSERT
*/
#define RUBY_ASSERT_ALWAYS(expr) RUBY_ASSERT_MESG((expr), #expr)
/**
* Asserts that the given expression is truthy if and only if #RUBY_DEBUG is truthy.
*
* @param expr What supposedly evaluates to true.
*/
#if RUBY_DEBUG
# define RUBY_ASSERT(expr) RUBY_ASSERT_MESG((expr), #expr)
#else
# define RUBY_ASSERT(expr) RBIMPL_ASSERT_NOTHING
#endif
/**
* A variant of #RUBY_ASSERT that interfaces with #NDEBUG instead of
* #RUBY_DEBUG. This almost resembles `assert` C standard macro, except minor
* implementation details.
*
* @copydetails #RUBY_ASSERT
*/
/* Currently `RUBY_DEBUG == ! defined(NDEBUG)` is always true. There is no
* difference any longer between this one and `RUBY_ASSERT`. */
#if defined(NDEBUG)
# define RUBY_ASSERT_NDEBUG(expr) RBIMPL_ASSERT_NOTHING
#else
# define RUBY_ASSERT_NDEBUG(expr) RUBY_ASSERT_MESG((expr), #expr)
#endif
/**
* @copydoc #RUBY_ASSERT_WHEN
* @param mesg The message to display on failure.
*/
#if RUBY_DEBUG
# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) RUBY_ASSERT_MESG((expr), (mesg))
#else
# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) \
((cond) ? RUBY_ASSERT_MESG((expr), (mesg)) : RBIMPL_ASSERT_NOTHING)
#endif
/**
* A variant of #RUBY_ASSERT that asserts when either #RUBY_DEBUG or `cond`
* parameter is truthy.
*
* @param cond Extra condition that shall hold for assertion to take effect.
* @param expr What supposedly evaluates to true.
*/
#define RUBY_ASSERT_WHEN(cond, expr) RUBY_ASSERT_MESG_WHEN((cond), (expr), #expr)
/**
* This is either #RUBY_ASSERT or #RBIMPL_ASSUME, depending on #RUBY_DEBUG.
*
* @copydetails #RUBY_ASSERT
*/
#if RUBY_DEBUG
# define RBIMPL_ASSERT_OR_ASSUME(expr) RUBY_ASSERT_ALWAYS(expr)
#elif RBIMPL_COMPILER_BEFORE(Clang, 7, 0, 0)
# /* See commit 67d259c5dccd31fe49d417fec169977712ffdf10 */
# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
#elif defined(RUBY_ASSERT_NOASSUME)
# /* See commit d300a734414ef6de7e8eb563b7cc4389c455ed08 */
# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
#elif ! defined(RBIMPL_HAVE___ASSUME)
# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
#else
# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSUME(expr)
#endif
#endif /* RUBY_ASSERT_H */

890
libs/libruby/ruby/atomic.h vendored Normal file
View File

@@ -0,0 +1,890 @@
#ifndef RUBY_ATOMIC_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_ATOMIC_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Atomic operations
*
* Basically, if we could assume either C11 or C++11, these macros are just
* redundant. Sadly we cannot. We have to do them ourselves.
*/
#include "ruby/internal/config.h"
#ifdef STDC_HEADERS
# include <stddef.h> /* size_t */
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h> /* ssize_t */
#endif
#if RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
# pragma intrinsic(_InterlockedOr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
# include <atomic.h>
#endif
#include "ruby/assert.h"
#include "ruby/backward/2/limits.h"
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/noalias.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/compiler_since.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/value.h"
#include "ruby/internal/static_assert.h"
#include "ruby/internal/stdbool.h"
/*
* Asserts that your environment supports more than one atomic types. These
* days systems tend to have such property (C11 was a standard of decades ago,
* right?) but we still support older ones.
*/
#if defined(__DOXYGEN__) || defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
# define RUBY_ATOMIC_GENERIC_MACRO 1
#endif
/**
* Type that is eligible for atomic operations. Depending on your host
* platform you might have more than one such type, but we choose one of them
* anyways.
*/
#if defined(__DOXYGEN__)
using rb_atomic_t = std::atomic<unsigned>;
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
typedef unsigned int rb_atomic_t;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
typedef unsigned int rb_atomic_t;
#elif defined(_WIN32)
typedef LONG rb_atomic_t;
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
typedef unsigned int rb_atomic_t;
#else
# error No atomic operation found
#endif
/**
* Atomically replaces the value pointed by `var` with the result of addition
* of `val` to the old value of `var`.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to add.
* @return What was stored in `var` before the addition.
* @post `var` holds `var + val`.
*/
#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val))
/**
* Atomically replaces the value pointed by `var` with the result of
* subtraction of `val` to the old value of `var`.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to subtract.
* @return What was stored in `var` before the subtraction.
* @post `var` holds `var - val`.
*/
#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val))
/**
* Atomically replaces the value pointed by `var` with the result of
* bitwise OR between `val` and the old value of `var`.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to mix.
* @return void
* @post `var` holds `var | val`.
* @note For portability, this macro can return void.
*/
#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val))
/**
* Atomically replaces the value pointed by `var` with `val`. This is just an
* assignment, but you can additionally know the previous value.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val))
/**
* Atomic compare-and-swap. This stores `val` to `var` if and only if the
* assignment changes the value of `var` from `oldval` to `newval`. You can
* detect whether the assignment happened or not using the return value.
*
* @param var A variable of ::rb_atomic_t.
* @param oldval Expected value of `var` before the assignment.
* @param newval What you want to store at `var`.
* @retval oldval Successful assignment (`var` is now `newval`).
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_CAS(var, oldval, newval) \
rbimpl_atomic_cas(&(var), (oldval), (newval))
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to set.
* @return void
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_set(&(var), (val))
/**
* Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to add.
* @return void
* @post `var` holds `var + val`.
*/
#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val))
/**
* Identical to #RUBY_ATOMIC_FETCH_SUB, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
* @param val Value to subtract.
* @return void
* @post `var` holds `var - val`.
*/
#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val))
/**
* Atomically increments the value pointed by `var`.
*
* @param var A variable of ::rb_atomic_t.
* @return void
* @post `var` holds `var + 1`.
*/
#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var))
/**
* Atomically decrements the value pointed by `var`.
*
* @param var A variable of ::rb_atomic_t.
* @return void
* @post `var` holds `var - 1`.
*/
#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var))
/**
* Identical to #RUBY_ATOMIC_INC, except it expects its argument is `size_t`.
* There are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `size_t`.
* @return void
* @post `var` holds `var + 1`.
*/
#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var))
/**
* Identical to #RUBY_ATOMIC_DEC, except it expects its argument is `size_t`.
* There are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `size_t`.
* @return void
* @post `var` holds `var - 1`.
*/
#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var))
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
* `size_t`. There are cases where ::rb_atomic_t is 32bit while `size_t` is
* 64bit. This should be used for size related operations to support such
* platforms.
*
* @param var A variable of `size_t`.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) \
rbimpl_atomic_size_exchange(&(var), (val))
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `size_t`.
* There are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `size_t`.
* @param oldval Expected value of `var` before the assignment.
* @param newval What you want to store at `var`.
* @retval oldval Successful assignment (`var` is now `newval`).
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) \
rbimpl_atomic_size_cas(&(var), (oldval), (newval))
/**
* Identical to #RUBY_ATOMIC_ADD, except it expects its arguments are `size_t`.
* There are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `size_t`.
* @param val Value to add.
* @return void
* @post `var` holds `var + val`.
*/
#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val))
/**
* Identical to #RUBY_ATOMIC_SUB, except it expects its arguments are `size_t`.
* There are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `size_t`.
* @param val Value to subtract.
* @return void
* @post `var` holds `var - val`.
*/
#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val))
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
* `void*`. There are cases where ::rb_atomic_t is 32bit while `void*` is
* 64bit. This should be used for pointer related operations to support such
* platforms.
*
* @param var A variable of `void *`.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*
* @internal
*
* :FIXME: this `(void*)` cast is evil! However `void*` is incompatible with
* some pointers, most notably function pointers.
*/
#define RUBY_ATOMIC_PTR_EXCHANGE(var, val) \
RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val))
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`.
* There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `void*`.
* @param oldval Expected value of `var` before the assignment.
* @param newval What you want to store at `var`.
* @retval oldval Successful assignment (`var` is now `newval`).
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) \
RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (oldval), (newval)))
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
* ::VALUE. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
* 64bit. This should be used for pointer related operations to support such
* platforms.
*
* @param var A variable of ::VALUE.
* @param val Value to set.
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_VALUE_EXCHANGE(var, val) \
rbimpl_atomic_value_exchange(&(var), (val))
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are ::VALUE.
* There are cases where ::rb_atomic_t is 32bit while ::VALUE is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `void*`.
* @param oldval Expected value of `var` before the assignment.
* @param newval What you want to store at `var`.
* @retval oldval Successful assignment (`var` is now `newval`).
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_VALUE_CAS(var, oldval, newval) \
rbimpl_atomic_value_cas(&(var), (oldval), (newval))
/** @cond INTERNAL_MACRO */
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_fetch_and_add(ptr, val);
#elif defined(_WIN32)
return InterlockedExchangeAdd(ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
/*
* `atomic_add_int_nv` takes its second argument as `int`! Meanwhile our
* `rb_atomic_t` is unsigned. We cannot pass `val` as-is. We have to
* manually check integer overflow.
*/
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
return atomic_add_int_nv(ptr, val) - val;
#else
# error Unsupported platform.
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
/*
* GCC on amd64 is smart enough to detect this `__atomic_add_fetch`'s
* return value is not used, then compiles it into single `LOCK ADD`
* instruction.
*/
__atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_add_and_fetch(ptr, val);
#elif defined(_WIN32)
/*
* `InterlockedExchangeAdd` is `LOCK XADD`. It seems there also is
* `_InterlockedAdd` intrinsic in ARM Windows but not for x86? Sticking to
* `InterlockedExchangeAdd` for better portability.
*/
InterlockedExchangeAdd(ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
/* Ditto for `atomic_add_int_nv`. */
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
atomic_add_int(ptr, val);
#else
# error Unsupported platform.
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_add_and_fetch(ptr, val);
#elif defined(_WIN32) && defined(_M_AMD64)
/* Ditto for `InterlockeExchangedAdd`. */
InterlockedExchangeAdd64(ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
/* Ditto for `atomic_add_int_nv`. */
RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
atomic_add_long(ptr, val);
#else
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
rbimpl_atomic_add(tmp, val);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_inc(volatile rb_atomic_t *ptr)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
rbimpl_atomic_add(ptr, 1);
#elif defined(_WIN32)
InterlockedIncrement(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_inc_uint(ptr);
#else
rbimpl_atomic_add(ptr, 1);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_size_inc(volatile size_t *ptr)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
rbimpl_atomic_size_add(ptr, 1);
#elif defined(_WIN32) && defined(_M_AMD64)
InterlockedIncrement64(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_inc_ulong(ptr);
#else
rbimpl_atomic_size_add(ptr, 1);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
return __atomic_fetch_sub(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_fetch_and_sub(ptr, val);
#elif defined(_WIN32)
/* rb_atomic_t is signed here! Safe to do `-val`. */
return InterlockedExchangeAdd(ptr, -val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
/* Ditto for `rbimpl_atomic_fetch_add`. */
const signed neg = -1;
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
return atomic_add_int_nv(ptr, neg * val) + val;
#else
# error Unsupported platform.
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_sub_and_fetch(ptr, val);
#elif defined(_WIN32)
InterlockedExchangeAdd(ptr, -val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
const signed neg = -1;
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
atomic_add_int(ptr, neg * val);
#else
# error Unsupported platform.
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_sub_and_fetch(ptr, val);
#elif defined(_WIN32) && defined(_M_AMD64)
const ssize_t neg = -1;
InterlockedExchangeAdd64(ptr, neg * val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
const signed neg = -1;
RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
atomic_add_long(ptr, neg * val);
#else
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
rbimpl_atomic_sub(tmp, val);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_dec(volatile rb_atomic_t *ptr)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
rbimpl_atomic_sub(ptr, 1);
#elif defined(_WIN32)
InterlockedDecrement(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_dec_uint(ptr);
#else
rbimpl_atomic_sub(ptr, 1);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_size_dec(volatile size_t *ptr)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
rbimpl_atomic_size_sub(ptr, 1);
#elif defined(_WIN32) && defined(_M_AMD64)
InterlockedDecrement64(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_dec_ulong(ptr);
#else
rbimpl_atomic_size_sub(ptr, 1);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_or_fetch(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_or_and_fetch(ptr, val);
#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
_InterlockedOr(ptr, val);
#elif defined(_WIN32) && defined(__GNUC__)
/* This was for old MinGW. Maybe not needed any longer? */
__asm__(
"lock\n\t"
"orl\t%1, %0"
: "=m"(ptr)
: "Ir"(val));
#elif defined(_WIN32) && defined(_M_IX86)
__asm mov eax, ptr;
__asm mov ecx, val;
__asm lock or [eax], ecx;
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_or_uint(ptr, val);
#else
# error Unsupported platform.
#endif
}
/* Nobody uses this but for theoretical backwards compatibility... */
#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
static inline rb_atomic_t
rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val)
{
return rbimpl_atomic_or(var, val);
}
#endif
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_lock_test_and_set(ptr, val);
#elif defined(_WIN32)
return InterlockedExchange(ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_swap_uint(ptr, val);
#else
# error Unsupported platform.
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline size_t
rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_lock_test_and_set(ptr, val);
#elif defined(_WIN32) && defined(_M_AMD64)
return InterlockedExchange64(ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_swap_ulong(ptr, val);
#else
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val);
return RBIMPL_CAST((size_t)ret);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
{
#if 0
#elif defined(InterlockedExchangePointer)
/* const_cast */
PVOID *pptr = RBIMPL_CAST((PVOID *)ptr);
PVOID pval = RBIMPL_CAST((PVOID)val);
return InterlockedExchangePointer(pptr, pval);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_swap_ptr(ptr, RBIMPL_CAST((void *)val));
#else
RBIMPL_STATIC_ASSERT(sizeof_voidp, sizeof *ptr == sizeof(size_t));
const size_t sval = RBIMPL_CAST((size_t)val);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
return RBIMPL_CAST((void *)sret);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline VALUE
rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
{
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
const size_t sval = RBIMPL_CAST((size_t)val);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
return RBIMPL_CAST((VALUE)sret);
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_set(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);
#else
/* Maybe std::atomic<rb_atomic_t>::store can be faster? */
rbimpl_atomic_exchange(ptr, val);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_compare_exchange_n(
ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return oldval;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_val_compare_and_swap(ptr, oldval, newval);
#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
return InterlockedCompareExchange(ptr, newval, oldval);
#elif defined(_WIN32)
PVOID *pptr = RBIMPL_CAST((PVOID *)ptr);
PVOID pold = RBIMPL_CAST((PVOID)oldval);
PVOID pnew = RBIMPL_CAST((PVOID)newval);
PVOID pret = InterlockedCompareExchange(pptr, pnew, pold);
return RBIMPL_CAST((rb_atomic_t)pret);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_cas_uint(ptr, oldval, newval);
#else
# error Unsupported platform.
#endif
}
/* Nobody uses this but for theoretical backwards compatibility... */
#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
static inline rb_atomic_t
rb_w32_atomic_cas(volatile rb_atomic_t *var, rb_atomic_t oldval, rb_atomic_t newval)
{
return rbimpl_atomic_cas(var, oldval, newval);
}
#endif
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline size_t
rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_compare_exchange_n(
ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return oldval;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_val_compare_and_swap(ptr, oldval, newval);
#elif defined(_WIN32) && defined(_M_AMD64)
return InterlockedCompareExchange64(ptr, newval, oldval);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_cas_ulong(ptr, oldval, newval);
#else
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
return rbimpl_atomic_cas(tmp, oldval, newval);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
{
#if 0
#elif defined(InterlockedExchangePointer)
/* ... Can we say that InterlockedCompareExchangePtr surly exists when
* InterlockedExchangePointer is defined? Seems so but...?*/
PVOID *pptr = RBIMPL_CAST((PVOID *)ptr);
PVOID pold = RBIMPL_CAST((PVOID)oldval);
PVOID pnew = RBIMPL_CAST((PVOID)newval);
return InterlockedCompareExchangePointer(pptr, pnew, pold);
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
void *pold = RBIMPL_CAST((void *)oldval);
void *pnew = RBIMPL_CAST((void *)newval);
return atomic_cas_ptr(ptr, pold, pnew);
#else
RBIMPL_STATIC_ASSERT(sizeof_voidp, sizeof *ptr == sizeof(size_t));
const size_t snew = RBIMPL_CAST((size_t)newval);
const size_t sold = RBIMPL_CAST((size_t)oldval);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
return RBIMPL_CAST((void *)sret);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline VALUE
rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval)
{
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
const size_t snew = RBIMPL_CAST((size_t)newval);
const size_t sold = RBIMPL_CAST((size_t)oldval);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
return RBIMPL_CAST((VALUE)sret);
}
/** @endcond */
#endif /* RUBY_ATOMIC_H */

25
libs/libruby/ruby/backward.h vendored Normal file
View File

@@ -0,0 +1,25 @@
#ifndef RUBY_RUBY_BACKWARD_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_RUBY_BACKWARD_H 1
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
#include "ruby/internal/value.h"
#include "ruby/internal/interpreter.h"
#include "ruby/backward/2/attributes.h"
#define RBIMPL_ATTR_DEPRECATED_SINCE(ver) RBIMPL_ATTR_DEPRECATED(("since " #ver))
#define RBIMPL_ATTR_DEPRECATED_INTERNAL(ver) RBIMPL_ATTR_DEPRECATED(("since "#ver", also internal"))
#define RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() RBIMPL_ATTR_DEPRECATED(("only for internal use"))
RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() void rb_clear_constant_cache(void);
/* from version.c */
#if defined(RUBY_SHOW_COPYRIGHT_TO_DIE) && !!(RUBY_SHOW_COPYRIGHT_TO_DIE+0)
# error RUBY_SHOW_COPYRIGHT_TO_DIE is deprecated
#endif
#endif /* RUBY_RUBY_BACKWARD_H */

56
libs/libruby/ruby/backward/2/assume.h vendored Normal file
View File

@@ -0,0 +1,56 @@
#ifndef RUBY_BACKWARD2_ASSUME_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_ASSUME_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #ASSUME / #RB_LIKELY / #UNREACHABLE
*/
#include "ruby/internal/config.h"
#include "ruby/internal/assume.h"
#include "ruby/internal/has/builtin.h"
#define ASSUME RBIMPL_ASSUME /**< @old{RBIMPL_ASSUME} */
#define UNREACHABLE RBIMPL_UNREACHABLE() /**< @old{RBIMPL_UNREACHABLE} */
#define UNREACHABLE_RETURN RBIMPL_UNREACHABLE_RETURN /**< @old{RBIMPL_UNREACHABLE_RETURN} */
/* likely */
#if RBIMPL_HAS_BUILTIN(__builtin_expect)
/**
* Asserts that the given Boolean expression likely holds.
*
* @param x An expression that likely holds.
*
* @note Consider this macro carefully. It has been here since when CPUs were
* like babies, but contemporary processors are beasts. They are
* smarter than mare mortals like us today. Their branch predictions
* highly expectedly outperform your use of this macro.
*/
# define RB_LIKELY(x) (__builtin_expect(!!(x), 1))
/**
* Asserts that the given Boolean expression likely doesn't hold.
*
* @param x An expression that likely doesn't hold.
*/
# define RB_UNLIKELY(x) (__builtin_expect(!!(x), 0))
#else
# define RB_LIKELY(x) (x)
# define RB_UNLIKELY(x) (x)
#endif
#endif /* RUBY_BACKWARD2_ASSUME_H */

View File

@@ -0,0 +1,165 @@
#ifndef RUBY_BACKWARD2_ATTRIBUTES_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_ATTRIBUTES_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Various attribute-related macros.
*
* ### Q&A ###
*
* - Q: Why are the macros defined in this header file so inconsistent in
* style?
*
* - A: Don't know. Don't blame me. Backward compatibility is the key here.
* I'm just preserving what they have been.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/attr/alloc_size.h"
#include "ruby/internal/attr/cold.h"
#include "ruby/internal/attr/const.h"
#include "ruby/internal/attr/deprecated.h"
#include "ruby/internal/attr/error.h"
#include "ruby/internal/attr/forceinline.h"
#include "ruby/internal/attr/format.h"
#include "ruby/internal/attr/maybe_unused.h"
#include "ruby/internal/attr/noinline.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/restrict.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/attr/warning.h"
#include "ruby/internal/has/attribute.h"
/* function attributes */
#undef CONSTFUNC
#define CONSTFUNC(x) RBIMPL_ATTR_CONST() x
#undef PUREFUNC
#define PUREFUNC(x) RBIMPL_ATTR_PURE() x
#undef DEPRECATED
#define DEPRECATED(x) RBIMPL_ATTR_DEPRECATED(("")) x
#undef DEPRECATED_BY
#define DEPRECATED_BY(n,x) RBIMPL_ATTR_DEPRECATED(("by: " # n)) x
#undef DEPRECATED_TYPE
#if defined(__GNUC__)
# define DEPRECATED_TYPE(mesg, decl) \
_Pragma("message \"DEPRECATED_TYPE is deprecated\""); \
decl RBIMPL_ATTR_DEPRECATED(mseg)
#elif defined(_MSC_VER)
# pragma deprecated(DEPRECATED_TYPE)
# define DEPRECATED_TYPE(mesg, decl) \
__pragma(message(__FILE__"("STRINGIZE(__LINE__)"): warning: " \
"DEPRECATED_TYPE is deprecated")) \
decl RBIMPL_ATTR_DEPRECATED(mseg)
#else
# define DEPRECATED_TYPE(mesg, decl) \
<-<-"DEPRECATED_TYPE is deprecated"->->
#endif
#undef RUBY_CXX_DEPRECATED
#define RUBY_CXX_DEPRECATED(mseg) RBIMPL_ATTR_DEPRECATED((mseg))
#undef NOINLINE
#define NOINLINE(x) RBIMPL_ATTR_NOINLINE() x
#ifndef MJIT_HEADER
# undef ALWAYS_INLINE
# define ALWAYS_INLINE(x) RBIMPL_ATTR_FORCEINLINE() x
#endif
#undef ERRORFUNC
#define ERRORFUNC(mesg, x) RBIMPL_ATTR_ERROR(mesg) x
#if RBIMPL_HAS_ATTRIBUTE(error)
# define HAVE_ATTRIBUTE_ERRORFUNC 1
#endif
#undef WARNINGFUNC
#define WARNINGFUNC(mesg, x) RBIMPL_ATTR_WARNING(mesg) x
#if RBIMPL_HAS_ATTRIBUTE(warning)
# define HAVE_ATTRIBUTE_WARNINGFUNC 1
#endif
/*
cold attribute for code layout improvements
RUBY_FUNC_ATTRIBUTE not used because MSVC does not like nested func macros
*/
#undef COLDFUNC
#define COLDFUNC RBIMPL_ATTR_COLD()
#define PRINTF_ARGS(decl, string_index, first_to_check) \
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, (string_index), (first_to_check)) \
decl
#undef RUBY_ATTR_ALLOC_SIZE
#define RUBY_ATTR_ALLOC_SIZE RBIMPL_ATTR_ALLOC_SIZE
#undef RUBY_ATTR_MALLOC
#define RUBY_ATTR_MALLOC RBIMPL_ATTR_RESTRICT()
#undef RUBY_ATTR_RETURNS_NONNULL
#define RUBY_ATTR_RETURNS_NONNULL RBIMPL_ATTR_RETURNS_NONNULL()
#ifndef FUNC_MINIMIZED
#define FUNC_MINIMIZED(x) x
#endif
#ifndef FUNC_UNOPTIMIZED
#define FUNC_UNOPTIMIZED(x) x
#endif
#ifndef RUBY_ALIAS_FUNCTION_TYPE
#define RUBY_ALIAS_FUNCTION_TYPE(type, prot, name, args) \
FUNC_MINIMIZED(type prot) {return (type)name args;}
#endif
#ifndef RUBY_ALIAS_FUNCTION_VOID
#define RUBY_ALIAS_FUNCTION_VOID(prot, name, args) \
FUNC_MINIMIZED(void prot) {name args;}
#endif
#ifndef RUBY_ALIAS_FUNCTION
#define RUBY_ALIAS_FUNCTION(prot, name, args) \
RUBY_ALIAS_FUNCTION_TYPE(VALUE, prot, name, args)
#endif
#undef RUBY_FUNC_NONNULL
#define RUBY_FUNC_NONNULL(n, x) RBIMPL_ATTR_NONNULL(n) x
#undef NORETURN
#define NORETURN(x) RBIMPL_ATTR_NORETURN() x
#define NORETURN_STYLE_NEW
#ifndef PACKED_STRUCT
# define PACKED_STRUCT(x) x
#endif
#ifndef PACKED_STRUCT_UNALIGNED
# if UNALIGNED_WORD_ACCESS
# define PACKED_STRUCT_UNALIGNED(x) PACKED_STRUCT(x)
# else
# define PACKED_STRUCT_UNALIGNED(x) x
# endif
#endif
#undef RB_UNUSED_VAR
#define RB_UNUSED_VAR(x) x RBIMPL_ATTR_MAYBE_UNUSED()
#endif /* RUBY_BACKWARD2_ATTRIBUTES_H */

36
libs/libruby/ruby/backward/2/bool.h vendored Normal file
View File

@@ -0,0 +1,36 @@
#ifndef RUBY_BACKWARD2_BOOL_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_BOOL_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines old TRUE / FALSE
*/
#include "ruby/internal/stdbool.h"
#ifndef FALSE
# define FALSE false
#elif FALSE
# error FALSE must be false
#endif
#ifndef TRUE
# define TRUE true
#elif ! TRUE
# error TRUE must be true
#endif
#endif /* RUBY_BACKWARD2_BOOL_H */

View File

@@ -0,0 +1,37 @@
#ifndef RUBY_BACKWARD2_GCC_VERSION_SINCE_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_GCC_VERSION_SINCE_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines old GCC_VERSION_SINCE
*/
#include "ruby/internal/compiler_since.h"
#ifndef GCC_VERSION_SINCE
#define GCC_VERSION_SINCE(x, y, z) RBIMPL_COMPILER_SINCE(GCC, (x), (y), (z))
#endif
#ifndef GCC_VERSION_BEFORE
#define GCC_VERSION_BEFORE(x, y, z) \
(RBIMPL_COMPILER_BEFORE(GCC, (x), (y), (z)) || \
(RBIMPL_COMPILER_IS(GCC) && \
((RBIMPL_COMPILER_VERSION_MAJOR == (x)) && \
((RBIMPL_COMPILER_VERSION_MINOR == (y)) && \
(RBIMPL_COMPILER_VERSION_PATCH == (z))))))
#endif
#endif /* RUBY_BACKWARD2_GCC_VERSION_SINCE_H */

131
libs/libruby/ruby/backward/2/inttypes.h vendored Normal file
View File

@@ -0,0 +1,131 @@
#ifndef RUBY_BACKWARD2_INTTYPES_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_INTTYPES_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief C99 shim for `<inttypes.h>`
*/
#include "ruby/internal/config.h" /* PRI_LL_PREFIX etc. are here */
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include "ruby/internal/value.h" /* PRI_VALUE_PREFIX is here. */
#ifndef PRI_INT_PREFIX
# define PRI_INT_PREFIX ""
#endif
#ifndef PRI_LONG_PREFIX
# define PRI_LONG_PREFIX "l"
#endif
#ifndef PRI_SHORT_PREFIX
# define PRI_SHORT_PREFIX "h"
#endif
#ifdef PRI_64_PREFIX
# /* Take that. */
#elif SIZEOF_LONG == 8
# define PRI_64_PREFIX PRI_LONG_PREFIX
#elif SIZEOF_LONG_LONG == 8
# define PRI_64_PREFIX PRI_LL_PREFIX
#endif
#ifndef PRIdPTR
# define PRIdPTR PRI_PTR_PREFIX"d"
# define PRIiPTR PRI_PTR_PREFIX"i"
# define PRIoPTR PRI_PTR_PREFIX"o"
# define PRIuPTR PRI_PTR_PREFIX"u"
# define PRIxPTR PRI_PTR_PREFIX"x"
# define PRIXPTR PRI_PTR_PREFIX"X"
#endif
#ifndef RUBY_PRI_VALUE_MARK
# define RUBY_PRI_VALUE_MARK "\v"
#endif
#if defined PRIdPTR && !defined PRI_VALUE_PREFIX
# define PRIdVALUE PRIdPTR
# define PRIoVALUE PRIoPTR
# define PRIuVALUE PRIuPTR
# define PRIxVALUE PRIxPTR
# define PRIXVALUE PRIXPTR
# define PRIsVALUE PRIiPTR"" RUBY_PRI_VALUE_MARK
#else
# define PRIdVALUE PRI_VALUE_PREFIX"d"
# define PRIoVALUE PRI_VALUE_PREFIX"o"
# define PRIuVALUE PRI_VALUE_PREFIX"u"
# define PRIxVALUE PRI_VALUE_PREFIX"x"
# define PRIXVALUE PRI_VALUE_PREFIX"X"
# define PRIsVALUE PRI_VALUE_PREFIX"i" RUBY_PRI_VALUE_MARK
#endif
#ifndef PRI_VALUE_PREFIX
# define PRI_VALUE_PREFIX ""
#endif
#ifdef PRI_TIMET_PREFIX
# /* Take that. */
#elif SIZEOF_TIME_T == SIZEOF_INT
# define PRI_TIMET_PREFIX
#elif SIZEOF_TIME_T == SIZEOF_LONG
# define PRI_TIMET_PREFIX "l"
#elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
# define PRI_TIMET_PREFIX PRI_LL_PREFIX
#endif
#ifdef PRI_PTRDIFF_PREFIX
# /* Take that. */
#elif SIZEOF_PTRDIFF_T == SIZEOF_INT
# define PRI_PTRDIFF_PREFIX ""
#elif SIZEOF_PTRDIFF_T == SIZEOF_LONG
# define PRI_PTRDIFF_PREFIX "l"
#elif SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
# define PRI_PTRDIFF_PREFIX PRI_LL_PREFIX
#endif
#ifndef PRIdPTRDIFF
# define PRIdPTRDIFF PRI_PTRDIFF_PREFIX"d"
# define PRIiPTRDIFF PRI_PTRDIFF_PREFIX"i"
# define PRIoPTRDIFF PRI_PTRDIFF_PREFIX"o"
# define PRIuPTRDIFF PRI_PTRDIFF_PREFIX"u"
# define PRIxPTRDIFF PRI_PTRDIFF_PREFIX"x"
# define PRIXPTRDIFF PRI_PTRDIFF_PREFIX"X"
#endif
#ifdef PRI_SIZE_PREFIX
# /* Take that. */
#elif SIZEOF_SIZE_T == SIZEOF_INT
# define PRI_SIZE_PREFIX ""
#elif SIZEOF_SIZE_T == SIZEOF_LONG
# define PRI_SIZE_PREFIX "l"
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
# define PRI_SIZE_PREFIX PRI_LL_PREFIX
#endif
#ifndef PRIdSIZE
# define PRIdSIZE PRI_SIZE_PREFIX"d"
# define PRIiSIZE PRI_SIZE_PREFIX"i"
# define PRIoSIZE PRI_SIZE_PREFIX"o"
# define PRIuSIZE PRI_SIZE_PREFIX"u"
# define PRIxSIZE PRI_SIZE_PREFIX"x"
# define PRIXSIZE PRI_SIZE_PREFIX"X"
#endif
#endif /* RUBY_BACKWARD2_INTTYPES_H */

99
libs/libruby/ruby/backward/2/limits.h vendored Normal file
View File

@@ -0,0 +1,99 @@
#ifndef RUBY_BACKWARD2_LIMITS_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_LIMITS_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Historical shim for `<limits.h>`.
*
* The macros in this header file are obsolescent. Does anyone really need our
* own definition of `CHAR_BIT` today?
*/
#include "ruby/internal/config.h"
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#include "ruby/backward/2/long_long.h"
#ifndef LONG_MAX
# /* assuming 32bit(2's complement) long */
# define LONG_MAX 2147483647L
#endif
#ifndef LONG_MIN
# define LONG_MIN (-LONG_MAX-1)
#endif
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
#ifdef LLONG_MAX
# /* Take that. */
#elif defined(LONG_LONG_MAX)
# define LLONG_MAX LONG_LONG_MAX
#elif defined(_I64_MAX)
# define LLONG_MAX _I64_MAX
#else
# /* assuming 64bit(2's complement) long long */
# define LLONG_MAX 9223372036854775807LL
#endif
#ifdef LLONG_MIN
# /* Take that. */
#elif defined(LONG_LONG_MIN)
# define LLONG_MIN LONG_LONG_MIN
#elif defined(_I64_MAX)
# define LLONG_MIN _I64_MIN
#else
# define LLONG_MIN (-LLONG_MAX-1)
#endif
#ifdef SIZE_MAX
# /* Take that. */
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
# define SIZE_MAX ULLONG_MAX
# define SIZE_MIN ULLONG_MIN
#elif SIZEOF_SIZE_T == SIZEOF_LONG
# define SIZE_MAX ULONG_MAX
# define SIZE_MIN ULONG_MIN
#elif SIZEOF_SIZE_T == SIZEOF_INT
# define SIZE_MAX UINT_MAX
# define SIZE_MIN UINT_MIN
#else
# define SIZE_MAX USHRT_MAX
# define SIZE_MIN USHRT_MIN
#endif
#ifdef SSIZE_MAX
# /* Take that. */
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
# define SSIZE_MAX LLONG_MAX
# define SSIZE_MIN LLONG_MIN
#elif SIZEOF_SIZE_T == SIZEOF_LONG
# define SSIZE_MAX LONG_MAX
# define SSIZE_MIN LONG_MIN
#elif SIZEOF_SIZE_T == SIZEOF_INT
# define SSIZE_MAX INT_MAX
# define SSIZE_MIN INT_MIN
#else
# define SSIZE_MAX SHRT_MAX
# define SSIZE_MIN SHRT_MIN
#endif
#endif /* RUBY_BACKWARD2_LIMITS_H */

View File

@@ -0,0 +1,73 @@
#ifndef RUBY_BACKWARD2_LONG_LONG_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_LONG_LONG_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines old #LONG_LONG
*
* No known compiler that can compile today's ruby lacks long long.
* Historically MSVC was one of such compiler, but it implemented long long a
* while ago (some time back in 2013). The macros are for backwards
* compatibility only.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/has/warning.h"
#include "ruby/internal/warning_push.h"
#if defined(__DOXYGEN__)
# /** @cond INTERNAL_MACRO */
# define HAVE_LONG_LONG 1
# define HAVE_TRUE_LONG_LONG 1
# /** @endcond */
# /** @deprecated Just use `long long` directly. */
# define LONG_LONG long long.
#elif RBIMPL_HAS_WARNING("-Wc++11-long-long")
# define HAVE_TRUE_LONG_LONG 1
# define LONG_LONG \
RBIMPL_WARNING_PUSH() \
RBIMPL_WARNING_IGNORED(-Wc++11-long-long) \
long long \
RBIMPL_WARNING_POP()
#elif RBIMPL_HAS_WARNING("-Wlong-long")
# define HAVE_TRUE_LONG_LONG 1
# define LONG_LONG \
RBIMPL_WARNING_PUSH() \
RBIMPL_WARNING_IGNORED(-Wlong-long) \
long long \
RBIMPL_WARNING_POP()
#elif defined(HAVE_LONG_LONG)
# define HAVE_TRUE_LONG_LONG 1
# define LONG_LONG long long
#elif SIZEOF___INT64 > 0
# define HAVE_LONG_LONG 1
# define LONG_LONG __int64
# undef SIZEOF_LONG_LONG
# define SIZEOF_LONG_LONG SIZEOF___INT64
#else
# error Hello! Ruby developers believe this message must not happen.
# error If you encounter this message, can you file a bug report?
# error Remember to attach a detailed description of your environment.
# error Thank you!
#endif
#endif /* RBIMPL_BACKWARD2_LONG_LONG_H */

32
libs/libruby/ruby/backward/2/r_cast.h vendored Normal file
View File

@@ -0,0 +1,32 @@
#ifndef RUBY_BACKWARD2_R_CAST_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_R_CAST_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines old R_CAST
*
* Nobody is actively using this macro.
*/
#define R_CAST(st) (struct st*)
#define RMOVED(obj) (R_CAST(RMoved)(obj))
#if defined(__GNUC__)
# warning R_CAST and RMOVED are deprecated
#elif defined(_MSC_VER)
# pragma message("warning: R_CAST and RMOVED are deprecated")
#endif
#endif /* RUBY_BACKWARD2_R_CAST_H */

36
libs/libruby/ruby/backward/2/rmodule.h vendored Normal file
View File

@@ -0,0 +1,36 @@
#ifndef RUBY_BACKWARD2_RMODULE_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_RMODULE_H
/**
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Orphan macros.
*
* These macros seems broken since at least 2011. Nobody (except ruby itself
* who is implementing the internals) could have used those macros for a while.
* Kept public as-is here to keep some theoretical backwards compatibility.
*/
#define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
#define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m)
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
#define RMODULE_SUPER(m) RCLASS_SUPER(m)
#if defined(__GNUC__)
# warning RMODULE_* macros are deprecated
#elif defined(_MSC_VER)
# pragma message("warning: RMODULE_* macros are deprecated")
#endif
#endif /* RUBY_BACKWARD2_RMODULE_H */

30
libs/libruby/ruby/backward/2/stdalign.h vendored Normal file
View File

@@ -0,0 +1,30 @@
#ifndef RUBY_BACKWARD2_STDALIGN_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_STDALIGN_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RUBY_ALIGNAS / #RUBY_ALIGNOF
*/
#include "ruby/internal/stdalign.h"
#undef RUBY_ALIGNAS
#undef RUBY_ALIGNOF
#define RUBY_ALIGNAS RBIMPL_ALIGNAS /**< @copydoc RBIMPL_ALIGNAS */
#define RUBY_ALIGNOF RBIMPL_ALIGNOF /**< @copydoc RBIMPL_ALIGNOF */
#endif /* RUBY_BACKWARD2_STDALIGN_H */

69
libs/libruby/ruby/backward/2/stdarg.h vendored Normal file
View File

@@ -0,0 +1,69 @@
#ifndef RUBY_BACKWARD2_STDARG_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_BACKWARD2_STDARG_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines old #_
*
* Nobody should ever use these macros any longer. No known compilers lack
* prototypes today. It's 21st century. Just forget them.
*/
#undef _
/**
* @deprecated Nobody practically needs this macro any longer.
* @brief This was a transition path from K&R to ANSI.
*/
#ifdef HAVE_PROTOTYPES
# define _(args) args
#else
# define _(args) ()
#endif
#undef __
/**
* @deprecated Nobody practically needs this macro any longer.
* @brief This was a transition path from K&R to ANSI.
*/
#ifdef HAVE_STDARG_PROTOTYPES
# define __(args) args
#else
# define __(args) ()
#endif
/**
* Functions declared using this macro take arbitrary arguments, including
* void.
*
* ```CXX
* void func(ANYARGS);
* ```
*
* This was a necessary evil when there was no such thing like function
* overloading. But it is the 21st century today. People generally need not
* use this. Just use a granular typed function.
*
* @see ruby::backward::cxxanyargs
*/
#ifdef __cplusplus
#define ANYARGS ...
#else
#define ANYARGS
#endif
#endif /* RUBY_BACKWARD2_STDARG_H */

View File

@@ -0,0 +1,700 @@
#ifndef RUBY_BACKWARD_CXXANYARGS_HPP //-*-C++-*-vi:ft=cpp
#define RUBY_BACKWARD_CXXANYARGS_HPP
/// @file
/// @author @shyouhei
/// @copyright This file is a part of the programming language Ruby.
/// Permission is hereby granted, to either redistribute and/or
/// modify this file, provided that the conditions mentioned in the
/// file COPYING are met. Consult the file for details.
/// @note DO NOT MODERNISE THIS FILE! As the file name implies it is
/// meant to be a backwards compatibility shim. Please stick to
/// C++ 98 and never use newer features, like `constexpr`.
/// @brief Provides old prototypes for C++ programs.
#include "ruby/internal/config.h"
#include "ruby/internal/intern/class.h"
#include "ruby/internal/intern/cont.h"
#include "ruby/internal/intern/hash.h"
#include "ruby/internal/intern/proc.h"
#include "ruby/internal/intern/thread.h"
#include "ruby/internal/intern/variable.h"
#include "ruby/internal/intern/vm.h"
#include "ruby/internal/iterator.h"
#include "ruby/internal/method.h"
#include "ruby/internal/value.h"
#include "ruby/internal/variable.h"
#include "ruby/backward/2/stdarg.h"
#include "ruby/st.h"
extern "C++" {
#ifdef HAVE_NULLPTR
#include <cstddef>
#endif
/// @brief The main namespace.
/// @note The name "ruby" might already be taken, but that must not be a
/// problem because namespaces are allowed to reopen.
namespace ruby {
/// Backwards compatibility layer.
namespace backward {
/// Provides ANYARGS deprecation warnings. In C, ANYARGS means there is no
/// function prototype. Literally anything, even including nothing, can be a
/// valid ANYARGS. So passing a correctly prototyped function pointer to an
/// ANYARGS-ed function parameter is valid, at the same time passing an
/// ANYARGS-ed function pointer to a granular typed function parameter is also
/// valid. However on the other hand in C++, ANYARGS doesn't actually mean any
/// number of arguments. C++'s ANYARGS means _variadic_ number of arguments.
/// This is incompatible with ordinal, correct function prototypes.
///
/// Luckily, function prototypes being distinct each other means they can be
/// overloaded. We can provide a compatibility layer for older Ruby APIs which
/// used to have ANYARGS. This namespace includes such attempts.
namespace cxxanyargs {
typedef VALUE type(ANYARGS); ///< ANYARGS-ed function type.
typedef void void_type(ANYARGS); ///< ANYARGS-ed function type, void variant.
typedef int int_type(ANYARGS); ///< ANYARGS-ed function type, int variant.
typedef VALUE onearg_type(VALUE); ///< Single-argumented function type.
/// @name Hooking global variables
/// @{
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Define a function-backended global variable.
/// @param[in] q Name of the variable.
/// @param[in] w Getter function.
/// @param[in] e Setter function.
/// @note Both functions can be nullptr.
/// @see rb_define_hooked_variable()
/// @deprecated Use granular typed overload instead.
inline void
rb_define_virtual_variable(const char *q, type *w, void_type *e)
{
rb_gvar_getter_t *r = reinterpret_cast<rb_gvar_getter_t*>(w);
rb_gvar_setter_t *t = reinterpret_cast<rb_gvar_setter_t*>(e);
::rb_define_virtual_variable(q, r, t);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_virtual_variable(const char *q, rb_gvar_getter_t *w, void_type *e)
{
rb_gvar_setter_t *t = reinterpret_cast<rb_gvar_setter_t*>(e);
::rb_define_virtual_variable(q, w, t);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_virtual_variable(const char *q, type *w, rb_gvar_setter_t *e)
{
rb_gvar_getter_t *r = reinterpret_cast<rb_gvar_getter_t*>(w);
::rb_define_virtual_variable(q, r, e);
}
#ifdef HAVE_NULLPTR
inline void
rb_define_virtual_variable(const char *q, rb_gvar_getter_t *w, std::nullptr_t e)
{
::rb_define_virtual_variable(q, w, e);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_virtual_variable(const char *q, type *w, std::nullptr_t e)
{
rb_gvar_getter_t *r = reinterpret_cast<rb_gvar_getter_t *>(w);
::rb_define_virtual_variable(q, r, e);
}
inline void
rb_define_virtual_variable(const char *q, std::nullptr_t w, rb_gvar_setter_t *e)
{
::rb_define_virtual_variable(q, w, e);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_virtual_variable(const char *q, std::nullptr_t w, void_type *e)
{
rb_gvar_setter_t *r = reinterpret_cast<rb_gvar_setter_t *>(e);
::rb_define_virtual_variable(q, w, r);
}
#endif
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Define a function-backended global variable.
/// @param[in] q Name of the variable.
/// @param[in] w Variable storage.
/// @param[in] e Getter function.
/// @param[in] r Setter function.
/// @note Both functions can be nullptr.
/// @see rb_define_virtual_variable()
/// @deprecated Use granular typed overload instead.
inline void
rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
{
rb_gvar_getter_t *t = reinterpret_cast<rb_gvar_getter_t*>(e);
rb_gvar_setter_t *y = reinterpret_cast<rb_gvar_setter_t*>(r);
::rb_define_hooked_variable(q, w, t, y);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_hooked_variable(const char *q, VALUE *w, rb_gvar_getter_t *e, void_type *r)
{
rb_gvar_setter_t *y = reinterpret_cast<rb_gvar_setter_t*>(r);
::rb_define_hooked_variable(q, w, e, y);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_hooked_variable(const char *q, VALUE *w, type *e, rb_gvar_setter_t *r)
{
rb_gvar_getter_t *t = reinterpret_cast<rb_gvar_getter_t*>(e);
::rb_define_hooked_variable(q, w, t, r);
}
#ifdef HAVE_NULLPTR
inline void
rb_define_hooked_variable(const char *q, VALUE *w, rb_gvar_getter_t *e, std::nullptr_t r)
{
::rb_define_hooked_variable(q, w, e, r);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_hooked_variable(const char *q, VALUE *w, type *e, std::nullptr_t r)
{
rb_gvar_getter_t *y = reinterpret_cast<rb_gvar_getter_t *>(e);
::rb_define_hooked_variable(q, w, y, r);
}
inline void
rb_define_hooked_variable(const char *q, VALUE *w, std::nullptr_t e, rb_gvar_setter_t *r)
{
::rb_define_hooked_variable(q, w, e, r);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
inline void
rb_define_hooked_variable(const char *q, VALUE *w, std::nullptr_t e, void_type *r)
{
rb_gvar_setter_t *y = reinterpret_cast<rb_gvar_setter_t *>(r);
::rb_define_hooked_variable(q, w, e, y);
}
#endif
/// @}
/// @name Exceptions and tag jumps
/// @{
// RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Old way to implement iterators.
/// @param[in] q A function that can yield.
/// @param[in] w Passed to `q`.
/// @param[in] e What is to be yielded.
/// @param[in] r Passed to `e`.
/// @return The return value of `q`.
/// @note `e` can be nullptr.
/// @deprecated This function is obsoleted since long before 2.x era. Do not
/// use it any longer. rb_block_call() is provided instead.
inline VALUE
rb_iterate(onearg_type *q, VALUE w, type *e, VALUE r)
{
rb_block_call_func_t t = reinterpret_cast<rb_block_call_func_t>(e);
return backward::rb_iterate_deprecated(q, w, t, r);
}
#ifdef HAVE_NULLPTR
RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
inline VALUE
rb_iterate(onearg_type *q, VALUE w, std::nullptr_t e, VALUE r)
{
return backward::rb_iterate_deprecated(q, w, e, r);
}
#endif
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Call a method with a block.
/// @param[in] q The self.
/// @param[in] w The method.
/// @param[in] e The # of elems of `r`
/// @param[in] r The arguments.
/// @param[in] t What is to be yielded.
/// @param[in] y Passed to `t`
/// @return Return value of `q#w(*r,&t)`
/// @note 't' can be nullptr.
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
{
rb_block_call_func_t u = reinterpret_cast<rb_block_call_func_t>(t);
return ::rb_block_call(q, w, e, r, u, y);
}
#ifdef HAVE_NULLPTR
inline VALUE
rb_block_call(VALUE q, ID w, int e, const VALUE *r, std::nullptr_t t, VALUE y)
{
return ::rb_block_call(q, w, e, r, t, y);
}
#endif
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief An equivalent of `rescue` clause.
/// @param[in] q A function that can raise.
/// @param[in] w Passed to `q`.
/// @param[in] e A function that cleans-up.
/// @param[in] r Passed to `e`.
/// @return The return value of `q` if no exception occurs, or the return
/// value of `e` if otherwise.
/// @note `e` can be nullptr.
/// @see rb_ensure()
/// @see rb_rescue2()
/// @see rb_protect()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_rescue(type *q, VALUE w, type *e, VALUE r)
{
typedef VALUE func1_t(VALUE);
typedef VALUE func2_t(VALUE, VALUE);
func1_t *t = reinterpret_cast<func1_t*>(q);
func2_t *y = reinterpret_cast<func2_t*>(e);
return ::rb_rescue(t, w, y, r);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief An equivalent of `rescue` clause.
/// @param[in] q A function that can raise.
/// @param[in] w Passed to `q`.
/// @param[in] e A function that cleans-up.
/// @param[in] r Passed to `e`.
/// @param[in] ... 0-terminated list of subclass of @ref rb_eException.
/// @return The return value of `q` if no exception occurs, or the return
/// value of `e` if otherwise.
/// @note `e` can be nullptr.
/// @see rb_ensure()
/// @see rb_rescue()
/// @see rb_protect()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_rescue2(type *q, VALUE w, type *e, VALUE r, ...)
{
typedef VALUE func1_t(VALUE);
typedef VALUE func2_t(VALUE, VALUE);
func1_t *t = reinterpret_cast<func1_t*>(q);
func2_t *y = reinterpret_cast<func2_t*>(e);
va_list ap;
va_start(ap, r);
VALUE ret = ::rb_vrescue2(t, w, y, r, ap);
va_end(ap);
return ret;
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief An equivalent of `ensure` clause.
/// @param[in] q A function that can raise.
/// @param[in] w Passed to `q`.
/// @param[in] e A function that ensures.
/// @param[in] r Passed to `e`.
/// @return The return value of `q`.
/// @note It makes no sense to pass nullptr to `e`.
/// @see rb_rescue()
/// @see rb_rescue2()
/// @see rb_protect()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_ensure(type *q, VALUE w, type *e, VALUE r)
{
typedef VALUE func1_t(VALUE);
func1_t *t = reinterpret_cast<func1_t*>(q);
func1_t *y = reinterpret_cast<func1_t*>(e);
return ::rb_ensure(t, w, y, r);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief An equivalent of `Kernel#catch`.
/// @param[in] q The "tag" string.
/// @param[in] w A function that can throw.
/// @param[in] e Passed to `w`.
/// @return What was thrown.
/// @note `q` can be a nullptr but makes no sense to pass nullptr to`w`.
/// @see rb_block_call()
/// @see rb_protect()
/// @see rb_rb_catch_obj()
/// @see rb_rescue()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_catch(const char *q, type *w, VALUE e)
{
rb_block_call_func_t r = reinterpret_cast<rb_block_call_func_t>(w);
return ::rb_catch(q, r, e);
}
#ifdef HAVE_NULLPTR
inline VALUE
rb_catch(const char *q, std::nullptr_t w, VALUE e)
{
return ::rb_catch(q, w, e);
}
#endif
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief An equivalent of `Kernel#catch`.
/// @param[in] q The "tag" object.
/// @param[in] w A function that can throw.
/// @param[in] e Passed to `w`.
/// @return What was thrown.
/// @note It makes no sense to pass nullptr to`w`.
/// @see rb_block_call()
/// @see rb_protect()
/// @see rb_rb_catch_obj()
/// @see rb_rescue()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_catch_obj(VALUE q, type *w, VALUE e)
{
rb_block_call_func_t r = reinterpret_cast<rb_block_call_func_t>(w);
return ::rb_catch_obj(q, r, e);
}
/// @}
/// @name Procs, Fibers and Threads
/// @{
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Creates a rb_cFiber instance.
/// @param[in] q The fiber body.
/// @param[in] w Passed to `q`.
/// @return What was allocated.
/// @note It makes no sense to pass nullptr to`q`.
/// @see rb_proc_new()
/// @see rb_thread_create()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_fiber_new(type *q, VALUE w)
{
rb_block_call_func_t e = reinterpret_cast<rb_block_call_func_t>(q);
return ::rb_fiber_new(e, w);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Creates a @ref rb_cProc instance.
/// @param[in] q The proc body.
/// @param[in] w Passed to `q`.
/// @return What was allocated.
/// @note It makes no sense to pass nullptr to`q`.
/// @see rb_fiber_new()
/// @see rb_thread_create()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_proc_new(type *q, VALUE w)
{
rb_block_call_func_t e = reinterpret_cast<rb_block_call_func_t>(q);
return ::rb_proc_new(e, w);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Creates a @ref rb_cThread instance.
/// @param[in] q The thread body.
/// @param[in] w Passed to `q`.
/// @return What was allocated.
/// @note It makes no sense to pass nullptr to`q`.
/// @see rb_proc_new()
/// @see rb_fiber_new()
/// @deprecated Use granular typed overload instead.
inline VALUE
rb_thread_create(type *q, void *w)
{
typedef VALUE ptr_t(void*);
ptr_t *e = reinterpret_cast<ptr_t*>(q);
return ::rb_thread_create(e, w);
}
/// @}
/// @name Hash and st_table
/// @{
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Iteration over the given table.
/// @param[in] q A table to scan.
/// @param[in] w A function to iterate.
/// @param[in] e Passed to `w`.
/// @retval 0 Always returns 0.
/// @note It makes no sense to pass nullptr to`w`.
/// @see st_foreach_check()
/// @see rb_hash_foreach()
/// @deprecated Use granular typed overload instead.
inline int
st_foreach(st_table *q, int_type *w, st_data_t e)
{
st_foreach_callback_func *r =
reinterpret_cast<st_foreach_callback_func*>(w);
return ::st_foreach(q, r, e);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Iteration over the given table.
/// @param[in] q A table to scan.
/// @param[in] w A function to iterate.
/// @param[in] e Passed to `w`.
/// @retval 0 Successful end of iteration.
/// @retval 1 Element removed during traversing.
/// @note It makes no sense to pass nullptr to`w`.
/// @see st_foreach()
/// @deprecated Use granular typed overload instead.
inline int
st_foreach_check(st_table *q, int_type *w, st_data_t e, st_data_t)
{
st_foreach_check_callback_func *t =
reinterpret_cast<st_foreach_check_callback_func*>(w);
return ::st_foreach_check(q, t, e, 0);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Iteration over the given table.
/// @param[in] q A table to scan.
/// @param[in] w A function to iterate.
/// @param[in] e Passed to `w`.
/// @note It makes no sense to pass nullptr to`w`.
/// @see st_foreach_check()
/// @deprecated Use granular typed overload instead.
inline void
st_foreach_safe(st_table *q, int_type *w, st_data_t e)
{
st_foreach_callback_func *r =
reinterpret_cast<st_foreach_callback_func*>(w);
::st_foreach_safe(q, r, e);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Iteration over the given hash.
/// @param[in] q A hash to scan.
/// @param[in] w A function to iterate.
/// @param[in] e Passed to `w`.
/// @note It makes no sense to pass nullptr to`w`.
/// @see st_foreach()
/// @deprecated Use granular typed overload instead.
inline void
rb_hash_foreach(VALUE q, int_type *w, VALUE e)
{
st_foreach_callback_func *r =
reinterpret_cast<st_foreach_callback_func*>(w);
::rb_hash_foreach(q, r, e);
}
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Iteration over each instance variable of the object.
/// @param[in] q An object.
/// @param[in] w A function to iterate.
/// @param[in] e Passed to `w`.
/// @note It makes no sense to pass nullptr to`w`.
/// @see st_foreach()
/// @deprecated Use granular typed overload instead.
inline void
rb_ivar_foreach(VALUE q, int_type *w, VALUE e)
{
st_foreach_callback_func *r =
reinterpret_cast<st_foreach_callback_func*>(w);
::rb_ivar_foreach(q, r, e);
}
/// @}
/// Driver for *_define_method. ::rb_define_method function for instance takes
/// a pointer to ANYARGS-ed functions, which in fact varies 18 different
/// prototypes. We still need to preserve ANYARGS for storages but why not
/// check the consistencies if possible. In C++ a function has its own
/// prototype, which is a compile-time constant (static type) by nature. We
/// can list up all the possible input types and provide warnings for other
/// cases. This is such attempt.
namespace define_method {
/// Type of ::rb_f_notimplement().
typedef VALUE notimpl_type(int, const VALUE *, VALUE, VALUE);
/// @brief Template metaprogramming to generate function prototypes.
/// @tparam T Type of method id (`ID` or `const char*` in practice).
/// @tparam F Definition driver e.g. ::rb_define_method.
template<typename T, void (*F)(VALUE klass, T mid, type *func, int arity)>
struct driver {
/// @brief Defines a method
/// @tparam N Arity of the function.
/// @tparam U The function in question
template<int N, typename U>
struct engine {
/* :TODO: Following deprecation attribute renders tons of warnings (one
* per every method definitions), which is annoying. Of course
* annoyance is the core feature of deprecation warnings... But that
* could be too much, especially when the warnings happen inside of
* machine-generated programs. And SWIG is known to do such thing.
* The new (granular) API was introduced in API version 2.7. As of
* this writing the version is 2.8. Let's warn this later, some time
* during 3.x. Hopefully codes in old (ANYARGS-ed) format should be
* less than now. */
#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) >= 301
RUBY_CXX_DEPRECATED("use of ANYARGS is deprecated")
#endif
/// @copydoc define(VALUE klass, T mid, U func)
/// @deprecated Pass correctly typed function instead.
static inline void
define(VALUE klass, T mid, type func)
{
F(klass, mid, func, N);
}
/// @brief Defines klass#mid as func, whose arity is N.
/// @param[in] klass Where the method lives.
/// @param[in] mid Name of the method to define.
/// @param[in] func Function that implements klass#mid.
static inline void
define(VALUE klass, T mid, U func)
{
F(klass, mid, reinterpret_cast<type *>(func), N);
}
/// @copydoc define(VALUE klass, T mid, U func)
static inline void
define(VALUE klass, T mid, notimpl_type func)
{
F(klass, mid, reinterpret_cast<type *>(func), N);
}
};
/// @cond INTERNAL_MACRO
template<int N, bool = false> struct specific : public engine<N, type *> {};
template<bool b> struct specific<15, b> : public engine<15, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<14, b> : public engine<14, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<13, b> : public engine<13, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<12, b> : public engine<12, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<11, b> : public engine<11, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<10, b> : public engine<10, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 9, b> : public engine< 9, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 8, b> : public engine< 8, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 7, b> : public engine< 7, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 6, b> : public engine< 6, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 5, b> : public engine< 5, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 4, b> : public engine< 4, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 3, b> : public engine< 3, VALUE(*)(VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 2, b> : public engine< 2, VALUE(*)(VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 1, b> : public engine< 1, VALUE(*)(VALUE, VALUE)> {};
template<bool b> struct specific< 0, b> : public engine< 0, VALUE(*)(VALUE)> {};
template<bool b> struct specific<-1, b> : public engine<-1, VALUE(*)(int argc, VALUE *argv, VALUE self)> {
using engine<-1, VALUE(*)(int argc, VALUE *argv, VALUE self)>::define;
static inline void define(VALUE c, T m, VALUE(*f)(int argc, const VALUE *argv, VALUE self)) { F(c, m, reinterpret_cast<type *>(f), -1); }
};
template<bool b> struct specific<-2, b> : public engine<-2, VALUE(*)(VALUE, VALUE)> {};
/// @endcond
};
/* We could perhaps merge this struct into the one above using variadic
* template parameters if we could assume C++11, but sadly we cannot. */
/// @copydoc ruby::backward::cxxanyargs::define_method::driver
template<typename T, void (*F)(T mid, type func, int arity)>
struct driver0 {
/// @brief Defines a method
/// @tparam N Arity of the function.
/// @tparam U The function in question
template<int N, typename U>
struct engine {
RUBY_CXX_DEPRECATED("use of ANYARGS is deprecated")
/// @copydoc define(T mid, U func)
/// @deprecated Pass correctly typed function instead.
static inline void
define(T mid, type func)
{
F(mid, func, N);
}
/// @brief Defines Kernel#mid as func, whose arity is N.
/// @param[in] mid Name of the method to define.
/// @param[in] func Function that implements klass#mid.
static inline void
define(T mid, U func)
{
F(mid, reinterpret_cast<type *>(func), N);
}
/// @copydoc define(T mid, U func)
/// @deprecated Pass correctly typed function instead.
static inline void
define(T mid, notimpl_type func)
{
F(mid, reinterpret_cast<type *>(func), N);
}
};
/// @cond INTERNAL_MACRO
template<int N, bool = false> struct specific : public engine<N, type *> {};
template<bool b> struct specific<15, b> : public engine<15, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<14, b> : public engine<14, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<13, b> : public engine<13, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<12, b> : public engine<12, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<11, b> : public engine<11, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific<10, b> : public engine<10, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 9, b> : public engine< 9, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 8, b> : public engine< 8, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 7, b> : public engine< 7, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 6, b> : public engine< 6, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 5, b> : public engine< 5, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 4, b> : public engine< 4, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 3, b> : public engine< 3, VALUE(*)(VALUE, VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 2, b> : public engine< 2, VALUE(*)(VALUE, VALUE, VALUE)> {};
template<bool b> struct specific< 1, b> : public engine< 1, VALUE(*)(VALUE, VALUE)> {};
template<bool b> struct specific< 0, b> : public engine< 0, VALUE(*)(VALUE)> {};
template<bool b> struct specific<-1, b> : public engine<-1, VALUE(*)(int argc, VALUE *argv, VALUE self)> {
using engine<-1, VALUE(*)(int argc, VALUE *argv, VALUE self)>::define;
static inline void define(T m, VALUE(*f)(int argc, const VALUE *argv, VALUE self)) { F(m, reinterpret_cast<type *>(f), -1); }
};
template<bool b> struct specific<-2, b> : public engine<-2, VALUE(*)(VALUE, VALUE)> {};
/// @endcond
};
struct rb_define_method : public driver <const char *, ::rb_define_method> {}; ///< Dispatches appropriate driver for ::rb_define_method.
struct rb_define_method_id : public driver <ID, ::rb_define_method_id> {}; ///< Dispatches appropriate driver for ::rb_define_method_id.
struct rb_define_private_method : public driver <const char *, ::rb_define_private_method> {}; ///< Dispatches appropriate driver for ::rb_define_private_method.
struct rb_define_protected_method : public driver <const char *, ::rb_define_protected_method> {}; ///< Dispatches appropriate driver for ::rb_define_protected_method.
struct rb_define_singleton_method : public driver <const char *, ::rb_define_singleton_method> {}; ///< Dispatches appropriate driver for ::rb_define_singleton_method.
struct rb_define_module_function : public driver <const char *, ::rb_define_module_function> {}; ///< Dispatches appropriate driver for ::rb_define_module_function.
struct rb_define_global_function : public driver0<const char *, ::rb_define_global_function> {}; ///< Dispatches appropriate driver for ::rb_define_global_function.
/// @brief Defines klass\#mid.
/// @param klass Where the method lives.
/// @copydetails #rb_define_global_function(mid, func, arity)
#define rb_define_method(klass, mid, func, arity) ::ruby::backward::cxxanyargs::define_method::rb_define_method::specific<arity>::define(klass, mid, func)
/// @copydoc #rb_define_method(klass, mid, func, arity)
#define rb_define_method_id(klass, mid, func, arity) ::ruby::backward::cxxanyargs::define_method::rb_define_method_id::specific<arity>::define(klass, mid, func)
/// @brief Defines klass\#mid and makes it private.
/// @copydetails #rb_define_method(klass, mid, func, arity)
#define rb_define_private_method(klass, mid, func, arity) ::ruby::backward::cxxanyargs::define_method::rb_define_private_method::specific<arity>::define(klass, mid, func)
/// @brief Defines klass\#mid and makes it protected.
/// @copydetails #rb_define_method
#define rb_define_protected_method(klass, mid, func, arity) ::ruby::backward::cxxanyargs::define_method::rb_define_protected_method::specific<arity>::define(klass, mid, func)
/// @brief Defines klass.mid.(klass, mid, func, arity)
/// @copydetails #rb_define_method
#define rb_define_singleton_method(klass, mid, func, arity) ::ruby::backward::cxxanyargs::define_method::rb_define_singleton_method::specific<arity>::define(klass, mid, func)
/// @brief Defines klass\#mid and makes it a module function.
/// @copydetails #rb_define_method(klass, mid, func, arity)
#define rb_define_module_function(klass, mid, func, arity) ::ruby::backward::cxxanyargs::define_method::rb_define_module_function::specific<arity>::define(klass, mid, func)
/// @brief Defines ::rb_mKernel \#mid.
/// @param mid Name of the defining method.
/// @param func Implementation of \#mid.
/// @param arity Arity of \#mid.
#define rb_define_global_function(mid, func, arity) ::ruby::backward::cxxanyargs::define_method::rb_define_global_function::specific<arity>::define(mid, func)
}}}}}
using namespace ruby::backward::cxxanyargs;
#endif // RUBY_BACKWARD_CXXANYARGS_HPP

505
libs/libruby/ruby/config.h vendored Normal file
View File

@@ -0,0 +1,505 @@
#ifndef INCLUDE_RUBY_CONFIG_H
#define INCLUDE_RUBY_CONFIG_H 1
/* confdefs.h */
#define HAVE_STDIO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_INTTYPES_H 1
#define HAVE_STDINT_H 1
#define HAVE_STRINGS_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_UNISTD_H 1
#define HAVE_WCHAR_H 1
#define STDC_HEADERS 1
#define _ALL_SOURCE 1
#define _DARWIN_C_SOURCE 1
#define _GNU_SOURCE 1
#define _HPUX_ALT_XOPEN_SOCKET_API 1
#define _NETBSD_SOURCE 1
#define _OPENBSD_SOURCE 1
#define _POSIX_PTHREAD_SEMANTICS 1
#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
#define __STDC_WANT_IEC_60559_BFP_EXT__ 1
#define __STDC_WANT_IEC_60559_DFP_EXT__ 1
#define __STDC_WANT_IEC_60559_EXT__ 1
#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
#define __STDC_WANT_LIB_EXT2__ 1
#define __STDC_WANT_MATH_SPEC_FUNCS__ 1
#define _TANDEM_SOURCE 1
#define __EXTENSIONS__ 1
#define RUBY_SYMBOL_EXPORT_BEGIN _Pragma("GCC visibility push(default)")
#define RUBY_SYMBOL_EXPORT_END _Pragma("GCC visibility pop")
#define HAVE_STMT_AND_DECL_IN_EXPR 1
#define HAVE_PTHREAD_H 1
#define _REENTRANT 1
#define _THREAD_SAFE 1
#define HAVE_LIBPTHREAD 1
#define THREAD_IMPL_H "thread_pthread.h"
#define THREAD_IMPL_SRC "thread_pthread.c"
#define HAVE_LIBCRYPT 1
#define HAVE_LIBDL 1
#define HAVE_DIRENT_H 1
#define HAVE__BOOL 1
#define HAVE_STDBOOL_H 1
#define HAVE_SYS_WAIT_H 1
#define HAVE_GRP_H 1
#define HAVE_FCNTL_H 1
#define HAVE_FLOAT_H 1
#define HAVE_LANGINFO_H 1
#define HAVE_LIMITS_H 1
#define HAVE_LOCALE_H 1
#define HAVE_MALLOC_H 1
#define HAVE_PWD_H 1
#define HAVE_SANITIZER_ASAN_INTERFACE_H 1
#define HAVE_STDALIGN_H 1
#define HAVE_STDIO_H 1
#define HAVE_SYS_EVENTFD_H 1
#define HAVE_SYS_FCNTL_H 1
#define HAVE_SYS_FILE_H 1
#define HAVE_SYS_IOCTL_H 1
#define HAVE_SYS_PARAM_H 1
#define HAVE_SYS_PRCTL_H 1
#define HAVE_SYS_RANDOM_H 1
#define HAVE_SYS_RESOURCE_H 1
#define HAVE_SYS_SELECT_H 1
#define HAVE_SYS_SENDFILE_H 1
#define HAVE_SYS_SOCKET_H 1
#define HAVE_SYS_SYSCALL_H 1
#define HAVE_SYS_SYSMACROS_H 1
#define HAVE_SYS_TIME_H 1
#define HAVE_SYS_TIMES_H 1
#define HAVE_SYS_UIO_H 1
#define HAVE_SYSCALL_H 1
#define HAVE_TIME_H 1
#define HAVE_UCONTEXT_H 1
#define HAVE_UTIME_H 1
#define HAVE_SYS_EPOLL_H 1
#define HAVE_STDCKDINT_H 1
#define HAVE_STDATOMIC_H 1
#define HAVE_X86INTRIN_H 1
#if defined(__x86_64__)
#define HAVE_X86INTRIN_H 1
#endif
#define HAVE_GMP_H 1
#define HAVE_LIBGMP 1
#define HAVE_TYPEOF 1
#define restrict __restrict__
#define HAVE_LONG_LONG 1
#define HAVE_OFF_T 1
#define SIZEOF_INT 4
#define SIZEOF_SHORT 2
#define SIZEOF_LONG 8
#define SIZEOF_LONG_LONG 8
#define SIZEOF___INT64 0
#define SIZEOF___INT128 16
#define SIZEOF_OFF_T 8
#define SIZEOF_VOIDP 8
#define SIZEOF_FLOAT 4
#define SIZEOF_DOUBLE 8
#define SIZEOF_TIME_T 8
#define SIZEOF_CLOCK_T 8
#define RBIMPL_ATTR_PACKED_STRUCT_BEGIN()
#define RBIMPL_ATTR_PACKED_STRUCT_END() __attribute__((packed))
#define USE_UNALIGNED_MEMBER_ACCESS 1
#define PRI_LL_PREFIX "ll"
#define HAVE_PID_T 1
#define rb_pid_t pid_t
#define SIGNEDNESS_OF_PID_T -1
#define PIDT2NUM(v) INT2NUM(v)
#define NUM2PIDT(v) NUM2INT(v)
#define PRI_PIDT_PREFIX PRI_INT_PREFIX
#define HAVE_UID_T 1
#define rb_uid_t uid_t
#define SIGNEDNESS_OF_UID_T +1
#define UIDT2NUM(v) UINT2NUM(v)
#define NUM2UIDT(v) NUM2UINT(v)
#define PRI_UIDT_PREFIX PRI_INT_PREFIX
#define HAVE_GID_T 1
#define rb_gid_t gid_t
#define SIGNEDNESS_OF_GID_T +1
#define GIDT2NUM(v) UINT2NUM(v)
#define NUM2GIDT(v) NUM2UINT(v)
#define PRI_GIDT_PREFIX PRI_INT_PREFIX
#define HAVE_TIME_T 1
#define rb_time_t time_t
#define SIGNEDNESS_OF_TIME_T -1
#define TIMET2NUM(v) LONG2NUM(v)
#define NUM2TIMET(v) NUM2LONG(v)
#define PRI_TIMET_PREFIX PRI_LONG_PREFIX
#define HAVE_DEV_T 1
#define rb_dev_t dev_t
#define SIGNEDNESS_OF_DEV_T +1
#define DEVT2NUM(v) ULONG2NUM(v)
#define NUM2DEVT(v) NUM2ULONG(v)
#define PRI_DEVT_PREFIX PRI_LONG_PREFIX
#define HAVE_MODE_T 1
#define rb_mode_t mode_t
#define SIGNEDNESS_OF_MODE_T +1
#define MODET2NUM(v) UINT2NUM(v)
#define NUM2MODET(v) NUM2UINT(v)
#define PRI_MODET_PREFIX PRI_INT_PREFIX
#define HAVE_RLIM_T 1
#define rb_rlim_t rlim_t
#define SIGNEDNESS_OF_RLIM_T +1
#define RLIM2NUM(v) ULONG2NUM(v)
#define NUM2RLIM(v) NUM2ULONG(v)
#define PRI_RLIM_PREFIX PRI_LONG_PREFIX
#define HAVE_OFF_T 1
#define rb_off_t off_t
#define SIGNEDNESS_OF_OFF_T -1
#define OFFT2NUM(v) LONG2NUM(v)
#define NUM2OFFT(v) NUM2LONG(v)
#define PRI_OFFT_PREFIX PRI_LONG_PREFIX
#define HAVE_CLOCKID_T 1
#define rb_clockid_t clockid_t
#define SIGNEDNESS_OF_CLOCKID_T -1
#define CLOCKID2NUM(v) INT2NUM(v)
#define NUM2CLOCKID(v) NUM2INT(v)
#define PRI_CLOCKID_PREFIX PRI_INT_PREFIX
#define HAVE_VA_ARGS_MACRO 1
#define HAVE__ALIGNOF 1
#define CONSTFUNC(x) __attribute__((__const__)) x
#define PUREFUNC(x) __attribute__((__pure__)) x
#define NORETURN(x) __attribute__((__noreturn__)) x
#define DEPRECATED(x) __attribute__((__deprecated__)) x
#define DEPRECATED_BY(n, x) __attribute__((__deprecated__("by " #n))) x
#define NOINLINE(x) __attribute__((__noinline__)) x
#define ALWAYS_INLINE(x) __attribute__((__always_inline__)) x
#define NO_SANITIZE(san, x) __attribute__((__no_sanitize__(san))) x
#define NO_SANITIZE_ADDRESS(x) __attribute__((__no_sanitize_address__)) x
#define NO_ADDRESS_SAFETY_ANALYSIS(x) \
__attribute__((__no_address_safety_analysis__)) x
#define WARN_UNUSED_RESULT(x) __attribute__((__warn_unused_result__)) x
#define MAYBE_UNUSED(x) __attribute__((__unused__)) x
#define ERRORFUNC(mesg, x) __attribute__((__error__ mesg)) x
#define WARNINGFUNC(mesg, x) __attribute__((__warning__ mesg)) x
#define WEAK(x) __attribute__((__weak__)) x
#define HAVE_FUNC_WEAK 1
#define RUBY_CXX_DEPRECATED(msg) __attribute__((__deprecated__(msg)))
#define HAVE_NULLPTR 1
#define FUNC_UNOPTIMIZED(x) __attribute__((__optimize__("O0"))) x
#define FUNC_MINIMIZED(x) \
__attribute__((__optimize__("-Os", "-fomit-frame-pointer"))) x
#define HAVE_ATTRIBUTE_FUNCTION_ALIAS 1
#define RUBY_ALIAS_FUNCTION_TYPE(type, prot, name, args) \
type prot __attribute__((alias(#name)));
#define RUBY_ALIAS_FUNCTION_VOID(prot, name, args) \
RUBY_ALIAS_FUNCTION_TYPE(void, prot, name, args)
#define HAVE_GCC_ATOMIC_BUILTINS 1
#define HAVE_GCC_SYNC_BUILTINS 1
#define HAVE___BUILTIN_UNREACHABLE 1
#define RUBY_FUNC_EXPORTED __attribute__((__visibility__("default"))) extern
#define RUBY_FUNC_NONNULL(n, x) __attribute__((__nonnull__(n))) x
#define RUBY_FUNCTION_NAME_STRING __func__
#define ENUM_OVER_INT 1
#define HAVE_DECL_SYS_NERR 0
#define HAVE_DECL_GETENV 1
#define SIZEOF_SIZE_T 8
#define SIZEOF_PTRDIFF_T 8
#define SIZEOF_DEV_T 8
#define PRI_SIZE_PREFIX "z"
#define PRI_PTRDIFF_PREFIX "t"
#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
#define HAVE_STRUCT_STAT_ST_BLOCKS 1
#define HAVE_STRUCT_STAT_ST_RDEV 1
#define SIZEOF_STRUCT_STAT_ST_SIZE SIZEOF_OFF_T
#define SIZEOF_STRUCT_STAT_ST_BLOCKS SIZEOF_OFF_T
#define SIZEOF_STRUCT_STAT_ST_INO SIZEOF_LONG
#define SIZEOF_STRUCT_STAT_ST_DEV SIZEOF_DEV_T
#define SIZEOF_STRUCT_STAT_ST_RDEV SIZEOF_DEV_T
#define HAVE_STRUCT_STAT_ST_ATIM 1
#define HAVE_STRUCT_STAT_ST_MTIM 1
#define HAVE_STRUCT_STAT_ST_CTIM 1
#define HAVE_STRUCT_STATX_STX_BTIME 1
#define HAVE_STRUCT_TIMEVAL 1
#define SIZEOF_STRUCT_TIMEVAL_TV_SEC SIZEOF_TIME_T
#define HAVE_STRUCT_TIMESPEC 1
#define HAVE_STRUCT_TIMEZONE 1
#define HAVE_RB_FD_INIT 1
#define HAVE_INT8_T 1
#define SIZEOF_INT8_T 1
#define HAVE_UINT8_T 1
#define SIZEOF_UINT8_T 1
#define HAVE_INT16_T 1
#define SIZEOF_INT16_T 2
#define HAVE_UINT16_T 1
#define SIZEOF_UINT16_T 2
#define HAVE_INT32_T 1
#define SIZEOF_INT32_T 4
#define HAVE_UINT32_T 1
#define SIZEOF_UINT32_T 4
#define HAVE_INT64_T 1
#define SIZEOF_INT64_T 8
#define HAVE_UINT64_T 1
#define SIZEOF_UINT64_T 8
#define HAVE_INT128_T 1
#define int128_t __int128
#define SIZEOF_INT128_T SIZEOF___INT128
#define HAVE_UINT128_T 1
#define uint128_t unsigned __int128
#define SIZEOF_UINT128_T SIZEOF___INT128
#define HAVE_INTPTR_T 1
#define SIZEOF_INTPTR_T 8
#define HAVE_UINTPTR_T 1
#define SIZEOF_UINTPTR_T 8
#define HAVE_SSIZE_T 1
#define SIZEOF_SSIZE_T 8
#define STACK_END_ADDRESS __libc_stack_end
#define GETGROUPS_T gid_t
#define HAVE_ALLOCA_H 1
#define HAVE_ALLOCA 1
#define HAVE_DUP 1
#define HAVE_DUP2 1
#define HAVE_ACOSH 1
#define HAVE_CBRT 1
#define HAVE_CRYPT 1
#define HAVE_ERF 1
#define HAVE_EXPLICIT_BZERO 1
#define HAVE_FFS 1
#define HAVE_FLOCK 1
#define HAVE_HYPOT 1
#define HAVE_LGAMMA_R 1
#define HAVE_MEMMOVE 1
#define HAVE_NAN 1
#define HAVE_NEXTAFTER 1
#define HAVE_STRCHR 1
#define HAVE_STRERROR 1
#define HAVE_STRLCAT 1
#define HAVE_STRLCPY 1
#define HAVE_STRSTR 1
#define HAVE_TGAMMA 1
#define HAVE_ISFINITE 1
#define SPT_TYPE SPT_REUSEARGV
#define HAVE_SIGNBIT 1
#define HAVE_FORK 1
#define HAVE_VFORK 1
#define HAVE_WORKING_VFORK 1
#define HAVE_WORKING_FORK 1
#define HAVE__LONGJMP 1
#define HAVE_ARC4RANDOM_BUF 1
#define HAVE_ATAN2L 1
#define HAVE_ATAN2F 1
#define HAVE_DECL_ATOMIC_SIGNAL_FENCE 1
#define HAVE_CHMOD 1
#define HAVE_CHOWN 1
#define HAVE_CHROOT 1
#define HAVE_CLOCK_GETTIME 1
#define HAVE_COPY_FILE_RANGE 1
#define HAVE_COSH 1
#define HAVE_CRYPT_R 1
#define HAVE_DIRFD 1
#define HAVE_DL_ITERATE_PHDR 1
#define HAVE_DLOPEN 1
#define HAVE_DLADDR 1
#define HAVE_DUP3 1
#define HAVE_EACCESS 1
#define HAVE_ENDGRENT 1
#define HAVE_EVENTFD 1
#define HAVE_EXECL 1
#define HAVE_EXECLE 1
#define HAVE_EXECV 1
#define HAVE_EXECVE 1
#define HAVE_FCHDIR 1
#define HAVE_FCHMOD 1
#define HAVE_FCHOWN 1
#define HAVE_FCNTL 1
#define HAVE_FDATASYNC 1
#define HAVE_FDOPENDIR 1
#define HAVE_FMOD 1
#define HAVE_FSTATAT 1
#define HAVE_FSYNC 1
#define HAVE_FTRUNCATE 1
#define HAVE_FTRUNCATE64 1
#define HAVE_GETCWD 1
#define HAVE_GETEGID 1
#define HAVE_GETENTROPY 1
#define HAVE_GETEUID 1
#define HAVE_GETGID 1
#define HAVE_GETGRNAM 1
#define HAVE_GETGRNAM_R 1
#define HAVE_GETGROUPS 1
#define HAVE_GETLOGIN 1
#define HAVE_GETLOGIN_R 1
#define HAVE_GETPGID 1
#define HAVE_GETPGRP 1
#define HAVE_GETPPID 1
#define HAVE_GETPRIORITY 1
#define HAVE_GETPWNAM 1
#define HAVE_GETPWNAM_R 1
#define HAVE_GETPWUID 1
#define HAVE_GETPWUID_R 1
#define HAVE_GETRANDOM 1
#define HAVE_GETRESGID 1
#define HAVE_GETRESUID 1
#define HAVE_GETRLIMIT 1
#define HAVE_GETSID 1
#define HAVE_GETTIMEOFDAY 1
#define HAVE_GETUID 1
#define HAVE_GMTIME_R 1
#define HAVE_INITGROUPS 1
#define HAVE_IOCTL 1
#define HAVE_KILL 1
#define HAVE_KILLPG 1
#define HAVE_LCHMOD 1
#define HAVE_LCHOWN 1
#define HAVE_LINK 1
#define HAVE_LLABS 1
#define HAVE_LOCKF 1
#define HAVE_LOG2 1
#define HAVE_LSTAT 1
#define HAVE_LUTIMES 1
#define HAVE_MALLOC_USABLE_SIZE 1
#define HAVE_MALLOC_TRIM 1
#define HAVE_MBLEN 1
#define HAVE_MEMALIGN 1
#define HAVE_WRITEV 1
#define HAVE_MEMRCHR 1
#define HAVE_MEMMEM 1
#define HAVE_MKFIFO 1
#define HAVE_MKNOD 1
#define HAVE_MKTIME 1
#define HAVE_MMAP 1
#define HAVE_MREMAP 1
#define HAVE_OPENAT 1
#define HAVE_PCLOSE 1
#define HAVE_PIPE 1
#define HAVE_PIPE2 1
#define HAVE_POLL 1
#define HAVE_POPEN 1
#define HAVE_POSIX_FADVISE 1
#define HAVE_POSIX_MADVISE 1
#define HAVE_POSIX_MEMALIGN 1
#define HAVE_PPOLL 1
#define HAVE_PREAD 1
#define HAVE_PWRITE 1
#define HAVE_QSORT_R 1
#define HAVE_READLINK 1
#define HAVE_REALPATH 1
#define HAVE_ROUND 1
#define HAVE_SCHED_GETAFFINITY 1
#define HAVE_SEEKDIR 1
#define HAVE_SENDFILE 1
#define HAVE_SETEGID 1
#define HAVE_SETENV 1
#define HAVE_SETEUID 1
#define HAVE_SETGID 1
#define HAVE_SETGROUPS 1
#define HAVE_SETPGID 1
#define HAVE_SETPGRP 1
#define HAVE_SETREGID 1
#define HAVE_SETRESGID 1
#define HAVE_SETRESUID 1
#define HAVE_SETREUID 1
#define HAVE_SETRLIMIT 1
#define HAVE_SETSID 1
#define HAVE_SETUID 1
#define HAVE_SHUTDOWN 1
#define HAVE_SIGACTION 1
#define HAVE_SIGALTSTACK 1
#define HAVE_SIGPROCMASK 1
#define HAVE_SINH 1
#define HAVE_SNPRINTF 1
#define HAVE_SYMLINK 1
#define HAVE_SYSCALL 1
#define HAVE_SYSCONF 1
#define HAVE_SYSTEM 1
#define HAVE_TANH 1
#define HAVE_TELLDIR 1
#define HAVE_TIMEGM 1
#define HAVE_TIMES 1
#define HAVE_TRUNCATE 1
#define HAVE_TRUNCATE64 1
#define HAVE_TZSET 1
#define HAVE_UMASK 1
#define HAVE_UNSETENV 1
#define HAVE_UTIMENSAT 1
#define HAVE_UTIMES 1
#define HAVE_WAIT4 1
#define HAVE_WAITPID 1
#define HAVE_STATX 1
#define HAVE_CRYPT_H 1
#define HAVE_STRUCT_CRYPT_DATA_INITIALIZED 1
#define HAVE_BUILTIN___BUILTIN_ALLOCA_WITH_ALIGN 1
#define HAVE_BUILTIN___BUILTIN_ASSUME_ALIGNED 1
#define HAVE_BUILTIN___BUILTIN_BSWAP16 1
#define HAVE_BUILTIN___BUILTIN_BSWAP32 1
#define HAVE_BUILTIN___BUILTIN_BSWAP64 1
#define HAVE_BUILTIN___BUILTIN_POPCOUNT 1
#define HAVE_BUILTIN___BUILTIN_POPCOUNTLL 1
#define HAVE_BUILTIN___BUILTIN_CLZ 1
#define HAVE_BUILTIN___BUILTIN_CLZL 1
#define HAVE_BUILTIN___BUILTIN_CLZLL 1
#define HAVE_BUILTIN___BUILTIN_CTZ 1
#define HAVE_BUILTIN___BUILTIN_CTZLL 1
#define HAVE_BUILTIN___BUILTIN_CONSTANT_P 1
#define HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR 1
#define HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P 1
#define HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P 1
#define HAVE_BUILTIN___BUILTIN_TRAP 1
#define HAVE_BUILTIN___BUILTIN_EXPECT 1
#define HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW 1
#define HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW_P 1
#define USE___BUILTIN_ADD_OVERFLOW_LONG_LONG 1
#define HAVE_BUILTIN___BUILTIN_SUB_OVERFLOW 1
#define HAVE_BUILTIN___BUILTIN_SUB_OVERFLOW_P 1
#define USE___BUILTIN_SUB_OVERFLOW_LONG_LONG 1
#define HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW 1
#define HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW_P 1
#define USE___BUILTIN_MUL_OVERFLOW_LONG_LONG 1
#define HAVE_GNU_QSORT_R 1
#define ATAN2_INF_C99 1
#define HAVE_CLOCK_GETRES 1
#define HAVE_LIBRT 1
#define HAVE_LIBRT 1
#define HAVE_TIMER_CREATE 1
#define HAVE_TIMER_SETTIME 1
#define HAVE_STRUCT_TM_TM_ZONE 1
#define HAVE_TM_ZONE 1
#define HAVE_STRUCT_TM_TM_GMTOFF 1
#define HAVE_DAYLIGHT 1
#define NEGATIVE_TIME_T 1
#define POSIX_SIGNAL 1
#define HAVE_SIG_T 1
#define RSHIFT(x, y) ((x) >> (int)(y))
#define USE_COPY_FILE_RANGE 1
#define HAVE__SC_CLK_TCK 1
#define STACK_GROW_DIRECTION -1
#define COROUTINE_H "coroutine/amd64/Context.h"
#define HAVE_SCHED_YIELD 1
#define HAVE_PTHREAD_ATTR_SETINHERITSCHED 1
#define HAVE_PTHREAD_ATTR_GETSTACK 1
#define HAVE_PTHREAD_ATTR_GETGUARDSIZE 1
#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1
#define HAVE_PTHREAD_SETNAME_NP 1
#define HAVE_PTHREAD_SIGMASK 1
#define HAVE_PTHREAD_GETATTR_NP 1
#define SET_CURRENT_THREAD_NAME(name) pthread_setname_np(pthread_self(), name)
#define SET_ANOTHER_THREAD_NAME(thid, name) pthread_setname_np(thid, name)
#define RB_THREAD_LOCAL_SPECIFIER _Thread_local
#define DEFINE_MCONTEXT_PTR(mc, uc) mcontext_t *mc = &(uc)->uc_mcontext
#define HAVE_GETCONTEXT 1
#define HAVE_SETCONTEXT 1
#define HAVE_SYS_USER_H 1
#define HAVE_CONST_PAGE_SIZE 0
#define IOCTL_REQ_TYPE unsigned long
#define NUM2IOCTLREQ(num) NUM2ULONG(num)
#define USE_ELF 1
#define HAVE_ELF_H 1
#define HAVE_LIBZ 1
#define HAVE_BACKTRACE 1
#define DLEXT_MAXLEN 3
#define DLEXT ".so"
#define SOEXT ".so"
#define LIBDIR_BASENAME "lib"
#define HAVE__SETJMP 1
#define RUBY_SETJMP(env) _setjmp((env))
#define RUBY_LONGJMP(env, val) _longjmp((env), val)
#define RUBY_JMP_BUF jmp_buf
#define USE_MODULAR_GC 0
#define USE_YJIT 1
#define USE_RJIT 1
#define RUBY_PLATFORM "x86_64-linux"
#define RB_DEFAULT_PARSER RB_DEFAULT_PARSER_PRISM
#endif /* INCLUDE_RUBY_CONFIG_H */

667
libs/libruby/ruby/debug.h vendored Normal file
View File

@@ -0,0 +1,667 @@
#ifndef RB_DEBUG_H /*-*-C++-*-vi:se ft=cpp:*/
#define RB_DEBUG_H 1
/**
* @file
* @author $Author: ko1 $
* @date Tue Nov 20 20:35:08 2012
* @copyright Copyright (C) 2012 Yukihiro Matsumoto
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/event.h"
#include "ruby/internal/value.h"
RBIMPL_SYMBOL_EXPORT_BEGIN()
/* Note: This file contains experimental APIs. */
/* APIs can be replaced at Ruby 2.0.1 or later */
/**
* @name Frame-profiling APIs
*
* @{
*/
RBIMPL_ATTR_NONNULL((3))
/**
* Queries mysterious "frame"s of the given range.
*
* The returned values are opaque backtrace pointers, which you are allowed to
* issue a very limited set of operations listed below. Don't call arbitrary
* ruby methods.
*
* @param[in] start Start position (0 means the topmost).
* @param[in] limit Number objects of `buff`.
* @param[out] buff Return buffer.
* @param[out] lines Return buffer.
* @return Number of objects filled into `buff`.
* @post `buff` is filled with backtrace pointers.
* @post `lines` is filled with `__LINE__` of each backtraces.
*
* @internal
*
* @shyouhei doesn't like this abuse of ::VALUE. It should have been
* `const struct rb_callable_method_entry_struct *`.
*/
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
/**
* Queries the path of the passed backtrace.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil The frame is implemented in C etc.
* @retval otherwise Where `frame` is running.
*/
VALUE rb_profile_frame_path(VALUE frame);
/**
* Identical to rb_profile_frame_path(), except it tries to expand the
* returning path. In case the path is `require`-d from something else
* rb_profile_frame_path() can return relative paths. This one tries to avoid
* that.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval "<cfunc>" The frame is in C.
* @retval RUBY_Qnil Can't infer real path (inside of `eval` etc.).
* @retval otherwise Where `frame` is running.
*/
VALUE rb_profile_frame_absolute_path(VALUE frame);
/**
* Queries human-readable "label" string. This is `"<main>"` for the toplevel,
* `"<compiled>"` for evaluated ones, method name for methods, class name for
* classes.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil Can't infer the label (C etc.).
* @retval "<main>" The frame is global toplevel.
* @retval "<compiled>" The frame is dynamic.
* @retval otherwise Label of the frame.
*/
VALUE rb_profile_frame_label(VALUE frame);
/**
* Identical to rb_profile_frame_label(), except it does not "qualify" the
* result. Consider the following backtrace:
*
* ```ruby
* def bar
* caller_locations
* end
*
* def foo
* [1].map { bar }.first
* end
*
* obj = foo.first
* obj.label # => "block in foo"
* obj.base_label # => "foo"
* ```
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil Can't infer the label (C etc.).
* @retval "<main>" The frame is global toplevel.
* @retval "<compiled>" The frame is dynamic.
* @retval otherwise Base label of the frame.
*/
VALUE rb_profile_frame_base_label(VALUE frame);
/**
* Identical to rb_profile_frame_label(), except it returns a qualified result.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil Can't infer the label (C etc.).
* @retval "<main>" The frame is global toplevel.
* @retval "<compiled>" The frame is dynamic.
* @retval otherwise Qualified label of the frame.
*
* @internal
*
* As of writing there is no way to obtain this return value from a Ruby
* script. This may change in future (it took 8 years and still no progress,
* though).
*/
VALUE rb_profile_frame_full_label(VALUE frame);
/**
* Queries the first line of the method of the passed frame pointer. Can be
* handy when for instance a debugger want to display the frame in question.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil Can't infer the line (C etc.).
* @retval otherwise Line number of the method in question.
*/
VALUE rb_profile_frame_first_lineno(VALUE frame);
/**
* Queries the class path of the method that the passed frame represents.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil Can't infer the class (global toplevel etc.).
* @retval otherwise Class path as in rb_class_path().
*/
VALUE rb_profile_frame_classpath(VALUE frame);
/**
* Queries if the method of the passed frame is a singleton class.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qtrue It is a singleton method.
* @retval RUBY_Qfalse Otherwise (normal method/non-method).
*/
VALUE rb_profile_frame_singleton_method_p(VALUE frame);
/**
* Queries the name of the method of the passed frame.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil The frame in question is not a method.
* @retval otherwise Name of the method of the frame.
*/
VALUE rb_profile_frame_method_name(VALUE frame);
/**
* Identical to rb_profile_frame_method_name(), except it "qualifies" the
* return value with its defining class.
*
* @param[in] frame What rb_profile_frames() returned.
* @retval RUBY_Qnil The frame in question is not a method.
* @retval otherwise Qualified name of the method of the frame.
*/
VALUE rb_profile_frame_qualified_method_name(VALUE frame);
/** @} */
/**
* @name Debug inspector APIs
*
* @{
*/
/** Opaque struct representing a debug inspector. */
typedef struct rb_debug_inspector_struct rb_debug_inspector_t;
/**
* Type of the callback function passed to rb_debug_inspector_open().
* Inspection shall happen only inside of them. The passed pointers gets
* invalidated once after the callback returns.
*
* @param[in] dc A debug context.
* @param[in,out] data What was passed to rb_debug_inspector_open().
* @return What would be the return value of rb_debug_inspector_open().
*/
typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *dc, void *data);
/**
* Prepares, executes, then cleans up a debug session.
*
* @param[in] func A callback to run inside of a debug session.
* @param[in,out] data Passed as-is to `func`.
* @return What was returned from `func`.
*/
VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data);
/**
* Queries the backtrace object of the context. This is as if you call
* `caller_locations` at the point of debugger.
*
* @param[in] dc A debug context.
* @return An array of `Thread::Backtrace::Location` which represents the
* current point of execution at `dc`.
*/
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);
/**
* Queries the current receiver of the passed context's upper frame.
*
* @param[in] dc A debug context.
* @param[in] index Index of the frame from top to bottom.
* @exception rb_eArgError `index` out of range.
* @return The current receiver at `index`-th frame.
*/
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index);
/**
* Queries the current class of the passed context's upper frame.
*
* @param[in] dc A debug context.
* @param[in] index Index of the frame from top to bottom.
* @exception rb_eArgError `index` out of range.
* @return The current class at `index`-th frame.
*/
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index);
/**
* Queries the binding of the passed context's upper frame.
*
* @param[in] dc A debug context.
* @param[in] index Index of the frame from top to bottom.
* @exception rb_eArgError `index` out of range.
* @return The binding at `index`-th frame.
*/
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index);
/**
* Queries the instruction sequence of the passed context's upper frame.
*
* @param[in] dc A debug context.
* @param[in] index Index of the frame from top to bottom.
* @exception rb_eArgError `index` out of range.
* @retval RUBY_Qnil `index`-th frame is not in Ruby (C etc.).
* @retval otherwise An instance of `RubyVM::InstructionSequence` which
* represents the instruction sequence at `index`-th
* frame.
*/
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index);
/**
* Queries the depth of the passed context's upper frame.
*
* Note that the depth is not same as the frame index because debug_inspector
* skips some special frames but the depth counts all frames.
*
* @param[in] dc A debug context.
* @param[in] index Index of the frame from top to bottom.
* @exception rb_eArgError `index` out of range.
* @retval The depth at `index`-th frame in Integer.
*/
VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index);
// A macro to recognize `rb_debug_inspector_frame_depth()` is available or not
#define RB_DEBUG_INSPECTOR_FRAME_DEPTH(dc, index) rb_debug_inspector_frame_depth(dc, index)
/**
* Return current frmae depth.
*
* @retval The depth of the current frame in Integer.
*/
VALUE rb_debug_inspector_current_depth(void);
/** @} */
/**
* @name Old style set_trace_func APIs
*
* @{
*/
/* duplicated def of include/ruby/ruby.h */
#include "ruby/internal/event.h"
/**
* Identical to rb_remove_event_hook(), except it additionally takes the data
* argument. This extra argument is the same as that of rb_add_event_hook(),
* and this function removes the hook which matches both arguments at once.
*
* @param[in] func A callback.
* @param[in] data What to be passed to `func`.
* @return Number of deleted event hooks.
* @note As multiple events can share the same `func` it is quite
* possible for the return value to become more than one.
*/
int rb_remove_event_hook_with_data(rb_event_hook_func_t func, VALUE data);
/**
* Identical to rb_add_event_hook(), except its effect is limited to the passed
* thread. Other threads are not affected by this.
*
* @param[in] thval An instance of ::rb_cThread.
* @param[in] func A callback.
* @param[in] events A set of events that `func` should run.
* @param[in] data Passed as-is to `func`.
* @exception rb_eTypeError `thval` is not a thread.
*/
void rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
/**
* Identical to rb_remove_event_hook(), except it additionally takes a thread
* argument. This extra argument is the same as that of
* rb_thread_add_event_hook(), and this function removes the hook which matches
* both arguments at once.
*
* @param[in] thval An instance of ::rb_cThread.
* @param[in] func A callback.
* @exception rb_eTypeError `thval` is not a thread.
* @return Number of deleted event hooks.
* @note As multiple events can share the same `func` it is quite
* possible for the return value to become more than one.
*/
int rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func);
/**
* Identical to rb_thread_remove_event_hook(), except it additionally takes the
* data argument. It can also be seen as a routine identical to
* rb_remove_event_hook_with_data(), except it additionally takes the thread.
* This function deletes hooks that satisfy all three criteria.
*
* @param[in] thval An instance of ::rb_cThread.
* @param[in] func A callback.
* @param[in] data What to be passed to `func`.
* @exception rb_eTypeError `thval` is not a thread.
* @return Number of deleted event hooks.
* @note As multiple events can share the same `func` it is quite
* possible for the return value to become more than one.
*/
int rb_thread_remove_event_hook_with_data(VALUE thval, rb_event_hook_func_t func, VALUE data);
/** @} */
/**
* @name TracePoint APIs
*
* @{
*/
/**
* Creates a tracepoint by registering a callback function for one or more
* tracepoint events. Once the tracepoint is created, you can use
* rb_tracepoint_enable to enable the tracepoint.
*
* @param[in] target_thread_not_supported_yet Meant for picking the
* thread in which the tracepoint is to be created.
* However, current implementation ignore this
* parameter, tracepoint is created for all threads.
* Simply specify Qnil.
* @param[in] events Event(s) to listen to.
* @param[in] func A callback function.
* @param[in,out] data Void pointer that will be passed to the callback
* function.
*
* When the callback function is called, it will be passed 2 parameters:
* 1. `VALUE tpval` - the TracePoint object from which trace args can be
* extracted.
* 1. `void *data` - A void pointer which helps to share scope with the
* callback function.
*
* It is important to note that you cannot register callbacks for normal events
* and internal events simultaneously because they are different purpose. You
* can use any Ruby APIs (calling methods and so on) on normal event hooks.
* However, in internal events, you can not use any Ruby APIs (even object
* creations). This is why we can't specify internal events by TracePoint
* directly. Limitations are MRI version specific.
*
* Example:
*
* ```CXX
* rb_tracepoint_new(
* Qnil,
* RUBY_INTERNAL_EVENT_NEWOBJ | RUBY_INTERNAL_EVENT_FREEOBJ,
* obj_event_i,
* data);
* ```
*
* In this example, a callback function `obj_event_i` will be registered for
* internal events #RUBY_INTERNAL_EVENT_NEWOBJ and
* #RUBY_INTERNAL_EVENT_FREEOBJ.
*/
VALUE rb_tracepoint_new(VALUE target_thread_not_supported_yet, rb_event_flag_t events, void (*func)(VALUE, void *), void *data);
/**
* Starts (enables) trace(s) defined by the passed object. A TracePoint object
* does not immediately take effect on creation. You have to explicitly call
* this API.
*
* @param[in] tpval An instance of TracePoint.
* @exception rb_eArgError A trace is already running.
* @return Undefined value. Forget this. It should have returned `void`.
* @post Trace(s) defined by `tpval` start.
*/
VALUE rb_tracepoint_enable(VALUE tpval);
/**
* Stops (disables) an already running instance of TracePoint.
*
* @param[in] tpval An instance of TracePoint.
* @return Undefined value. Forget this. It should have returned `void`.
* @post Trace(s) defined by `tpval` stop.
*/
VALUE rb_tracepoint_disable(VALUE tpval);
/**
* Queries if the passed TracePoint is up and running.
*
* @param[in] tpval An instance of TracePoint.
* @retval RUBY_Qtrue It is.
* @retval RUBY_Qfalse It isn't.
*/
VALUE rb_tracepoint_enabled_p(VALUE tpval);
/**
* Type that represents a specific trace event. Roughly resembles the
* tracepoint object that is passed to the block of `TracePoint.new`:
*
* ```ruby
* TracePoint.new(*events) do |obj|
* ... # ^^^^^ Resembles this object.
* end
* ```
*/
typedef struct rb_trace_arg_struct rb_trace_arg_t;
RBIMPL_ATTR_RETURNS_NONNULL()
/**
* Queries the current event of the passed tracepoint.
*
* @param[in] tpval An instance of TracePoint.
* @exception rb_eRuntimeError `tpval` is disabled.
* @return The current event.
*
* @internal
*
* `tpval` is a fake. There is only one instance of ::rb_trace_arg_t at one
* time. This function just returns that global variable.
*/
rb_trace_arg_t *rb_tracearg_from_tracepoint(VALUE tpval);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the event of the passed trace.
*
* @param[in] trace_arg A trace instance.
* @return Its event.
*/
rb_event_flag_t rb_tracearg_event_flag(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Identical to rb_tracearg_event_flag(), except it returns the name of the
* event in Ruby's symbol.
*
* @param[in] trace_arg A trace instance.
* @return Its event, in Ruby level Symbol object.
*/
VALUE rb_tracearg_event(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the line of the point where the trace is at.
*
* @param[in] trace_arg A trace instance.
* @retval 0 The trace is not at Ruby frame.
* @return otherwise Its line number.
*/
VALUE rb_tracearg_lineno(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the file name of the point where the trace is at.
*
* @param[in] trace_arg A trace instance.
* @retval RUBY_Qnil The trace is not at Ruby frame.
* @retval otherwise Its path.
*/
VALUE rb_tracearg_path(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the method name of the point where the trace is at.
*
* @param[in] trace_arg A trace instance.
* @retval RUBY_Qnil There is no method.
* @retval otherwise Its method name, in Ruby level Symbol.
*/
VALUE rb_tracearg_method_id(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Identical to rb_tracearg_method_id(), except it returns callee id like
* rb_frame_callee().
*
* @param[in] trace_arg A trace instance.
* @retval RUBY_Qnil There is no method.
* @retval otherwise Its method name, in Ruby level Symbol.
*/
VALUE rb_tracearg_callee_id(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the class that defines the method that the passed trace is at. This
* can be different from the class of rb_tracearg_self()'s return value because
* of inheritance(s).
*
* @param[in] trace_arg A trace instance.
* @retval RUBY_Qnil There is no method.
* @retval otherwise Its method's class.
*/
VALUE rb_tracearg_defined_class(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Creates a binding object of the point where the trace is at.
*
* @param[in] trace_arg A trace instance.
* @retval RUBY_Qnil The point has no binding.
* @retval otherwise Its binding.
*
* @internal
*
* @shyouhei has no idea on which situation shall this function return
* ::RUBY_Qnil.
*/
VALUE rb_tracearg_binding(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the receiver of the point trace is at.
*
* @param[in] trace_arg A trace instance.
* @return Its receiver.
*/
VALUE rb_tracearg_self(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the return value that the trace represents.
*
* @param[in] trace_arg A trace instance.
* @exception rb_eRuntimeError The tracing event is not return-related.
* @return The return value.
*/
VALUE rb_tracearg_return_value(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the raised exception that the trace represents.
*
* @param[in] trace_arg A trace instance.
* @exception rb_eRuntimeError The tracing event is not exception-related.
* @return The raised exception.
*/
VALUE rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg);
RBIMPL_ATTR_NONNULL(())
/**
* Queries the allocated/deallocated object that the trace represents.
*
* @param[in] trace_arg A trace instance.
* @exception rb_eRuntimeError The tracing event is not GC-related.
* @return The allocated/deallocated object.
*/
VALUE rb_tracearg_object(rb_trace_arg_t *trace_arg);
/** @} */
/**
* @name Postponed Job API
*
* @{
*/
/*
* Postponed Job API
* rb_postponed_job_register and rb_postponed_job_register_one are
* async-signal-safe and used via SIGPROF by the "stackprof" RubyGem
*/
/**
* Type of postponed jobs.
*
* @param[in,out] arg What was passed to rb_postponed_job_register().
*/
typedef void (*rb_postponed_job_func_t)(void *arg);
/**
* Registers a postponed job.
*
* There are situations when running a ruby program is not possible. For
* instance when a program is in a signal handler; for another instance when
* the GC is busy. On such situations however, there might be needs to do
* something. We cannot but defer such operations until we are 100% sure it is
* safe to execute them. This mechanism is called postponed jobs. This
* function registers a new one. The registered job would eventually gets
* executed.
*
* @param[in] flags (Unused) reserved for future extensions.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
* @retval 0 Postponed job buffer is full. Failed.
* @retval otherwise Opaque return value.
* @post The passed job is postponed.
*/
int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data);
/**
* Identical to rb_postponed_job_register_one(), except it additionally checks
* for duplicated registration. In case the passed job is already in the
* postponed job buffer this function does nothing.
*
* @param[in] flags (Unused) reserved for future extensions.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
* @retval 0 Postponed job buffer is full. Failed.
* @retval otherwise Opaque return value.
*/
int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data);
/** @} */
/**
* @cond INTERNAL_MACRO
*
* Anything after this are intentionally left undocumented, to honour the
* comment below.
*/
/* undocumented advanced tracing APIs */
typedef enum {
RUBY_EVENT_HOOK_FLAG_SAFE = 0x01,
RUBY_EVENT_HOOK_FLAG_DELETED = 0x02,
RUBY_EVENT_HOOK_FLAG_RAW_ARG = 0x04
} rb_event_hook_flag_t;
void rb_add_event_hook2(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flag);
void rb_thread_add_event_hook2(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flag);
/** @endcond */
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_DEBUG_H */

116
libs/libruby/ruby/defines.h vendored Normal file
View File

@@ -0,0 +1,116 @@
#ifndef RUBY_DEFINES_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_DEFINES_H 1
/**
* @file
* @author $Author$
* @date Wed May 18 00:21:44 JST 1994
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
#include "ruby/internal/config.h"
/* AC_INCLUDES_DEFAULT */
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef STDC_HEADERS
#include <stddef.h>
#include <stdlib.h>
#else
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#endif
#ifdef HAVE_STRING_H
#if !defined STDC_HEADERS && defined HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_STDALIGN_H
#include <stdalign.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef RUBY_USE_SETJMPEX
#include <setjmpex.h>
#endif
#include "ruby/backward/2/assume.h"
#include "ruby/backward/2/attributes.h"
#include "ruby/backward/2/bool.h"
#include "ruby/backward/2/long_long.h"
#include "ruby/backward/2/stdalign.h"
#include "ruby/backward/2/stdarg.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/dosish.h"
#include "ruby/internal/xmalloc.h"
#include "ruby/missing.h"
/**
* Asserts that the compilation unit includes Ruby's CAPI. This has been here
* since the very beginning (at least since version 0.49).
*/
#define RUBY
#ifdef __GNUC__
#/** This is expanded to nothing for non-GCC compilers. */
#define RB_GNUC_EXTENSION __extension__
#/** This is expanded to the passed token for non-GCC compilers. */
#define RB_GNUC_EXTENSION_BLOCK(x) __extension__({ x; })
#else
#define RB_GNUC_EXTENSION
#define RB_GNUC_EXTENSION_BLOCK(x) (x)
#endif
/** @cond INTERNAL_MACRO */
/* :FIXME: Can someone tell us why is this macro defined here? @shyouhei
* thinks this is a truly internal macro but cannot move around because he
* doesn't understand the reason of this arrangement. */
#ifndef RUBY_MBCHAR_MAXSIZE
#define RUBY_MBCHAR_MAXSIZE INT_MAX
#/* MB_CUR_MAX will not work well in C locale */
#endif
#if defined(__sparc)
RBIMPL_SYMBOL_EXPORT_BEGIN()
void rb_sparc_flush_register_windows(void);
RBIMPL_SYMBOL_EXPORT_END()
#define FLUSH_REGISTER_WINDOWS rb_sparc_flush_register_windows()
#else
#define FLUSH_REGISTER_WINDOWS ((void)0)
#endif
/** @endcond */
#endif /* RUBY_DEFINES_H */

72
libs/libruby/ruby/digest.h vendored Normal file
View File

@@ -0,0 +1,72 @@
/************************************************
digest.h - header file for ruby digest modules
$Author$
created at: Fri May 25 08:54:56 JST 2001
Copyright (C) 2001-2006 Akinori MUSHA
$RoughId: digest.h,v 1.3 2001/07/13 15:38:27 knu Exp $
$Id$
************************************************/
#include "ruby.h"
#define RUBY_DIGEST_API_VERSION 3
typedef int (*rb_digest_hash_init_func_t)(void *);
typedef void (*rb_digest_hash_update_func_t)(void *, unsigned char *, size_t);
typedef int (*rb_digest_hash_finish_func_t)(void *, unsigned char *);
typedef struct {
int api_version;
size_t digest_len;
size_t block_len;
size_t ctx_size;
rb_digest_hash_init_func_t init_func;
rb_digest_hash_update_func_t update_func;
rb_digest_hash_finish_func_t finish_func;
} rb_digest_metadata_t;
#define DEFINE_UPDATE_FUNC_FOR_UINT(name) \
void \
rb_digest_##name##_update(void *ctx, unsigned char *ptr, size_t size) \
{ \
const unsigned int stride = 16384; \
\
for (; size > stride; size -= stride, ptr += stride) { \
name##_Update(ctx, ptr, stride); \
} \
if (size > 0) name##_Update(ctx, ptr, size); \
}
#define DEFINE_FINISH_FUNC_FROM_FINAL(name) \
int \
rb_digest_##name##_finish(void *ctx, unsigned char *ptr) \
{ \
return name##_Final(ptr, ctx); \
}
static inline VALUE
rb_digest_namespace(void)
{
rb_require("digest");
return rb_path2class("Digest");
}
static inline ID
rb_id_metadata(void)
{
return rb_intern_const("metadata");
}
static inline VALUE
rb_digest_make_metadata(const rb_digest_metadata_t *meta)
{
#undef RUBY_UNTYPED_DATA_WARNING
#define RUBY_UNTYPED_DATA_WARNING 0
return rb_obj_freeze(Data_Wrap_Struct(0, 0, 0, (void *)meta));
}

31
libs/libruby/ruby/encoding.h vendored Normal file
View File

@@ -0,0 +1,31 @@
#ifndef RUBY_ENCODING_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_ENCODING_H 1
/**
* @file
* @author $Author: matz $
* @date Thu May 24 11:49:41 JST 2007
* @copyright Copyright (C) 2007 Yukihiro Matsumoto
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @brief Encoding relates APIs.
*
* These APIs are mainly for implementing encodings themselves. Encodings are
* built on top of Ruby's core CAPIs. Though not prohibited, there can be
* relatively less rooms for things in this header file be useful when writing
* an extension library.
*/
#include "ruby/ruby.h"
#include "ruby/internal/encoding/coderange.h"
#include "ruby/internal/encoding/ctype.h"
#include "ruby/internal/encoding/encoding.h"
#include "ruby/internal/encoding/pathname.h"
#include "ruby/internal/encoding/re.h"
#include "ruby/internal/encoding/sprintf.h"
#include "ruby/internal/encoding/string.h"
#include "ruby/internal/encoding/symbol.h"
#include "ruby/internal/encoding/transcode.h"
#endif /* RUBY_ENCODING_H */

374
libs/libruby/ruby/fiber/scheduler.h vendored Normal file
View File

@@ -0,0 +1,374 @@
#ifndef RUBY_FIBER_SCHEDULER_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_FIBER_SCHEDULER_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @brief Scheduler APIs.
*/
#include "ruby/internal/config.h"
#include <errno.h>
#ifdef STDC_HEADERS
#include <stddef.h> /* size_t */
#endif
#include "ruby/ruby.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/arithmetic.h"
RBIMPL_SYMBOL_EXPORT_BEGIN()
#define RUBY_FIBER_SCHEDULER_VERSION 2
struct timeval;
/**
* Wrap a `ssize_t` and `int errno` into a single `VALUE`. This interface should
* be used to safely capture results from system calls like `read` and `write`.
*
* You should use `rb_fiber_scheduler_io_result_apply` to unpack the result of
* this value and update `int errno`.
*
* You should not directly try to interpret the result value as it is considered
* an opaque representation. However, the general representation is an integer
* in the range of `[-int errno, size_t size]`. Linux generally restricts the
* result of system calls like `read` and `write` to `<= 2^31` which means this
* will typically fit within a single FIXNUM.
*
* @param[in] result The result of the system call.
* @param[in] error The value of `errno`.
* @return A `VALUE` which contains the result and/or errno.
*/
static inline VALUE
rb_fiber_scheduler_io_result(ssize_t result, int error)
{
if (result == -1) {
return RB_INT2NUM(-error);
}
else {
return RB_SIZE2NUM(result);
}
}
/**
* Apply an io result to the local thread, returning the value of the original
* system call that created it and updating `int errno`.
*
* You should not directly try to interpret the result value as it is considered
* an opaque representation.
*
* @param[in] result The `VALUE` which contains an errno and/or result size.
* @post Updates `int errno` with the value if negative.
* @return The original result of the system call.
*/
static inline ssize_t
rb_fiber_scheduler_io_result_apply(VALUE result)
{
if (RB_FIXNUM_P(result) && RB_NUM2INT(result) < 0) {
errno = -RB_NUM2INT(result);
return -1;
}
else {
return RB_NUM2SIZE(result);
}
}
/**
* Queries the current scheduler of the current thread that is calling this
* function.
*
* @retval RUBY_Qnil No scheduler has been set so far to this thread (which
* is the default).
* @retval otherwise The scheduler that was last set for the current thread
* with rb_fiber_scheduler_set().
*/
VALUE rb_fiber_scheduler_get(void);
/**
* Destructively assigns the passed scheduler to that of the current thread
* that is calling this function. If the scheduler is set, non-blocking fibers
* (created by `Fiber.new` with `blocking: false`, or by `Fiber.schedule`) call
* that scheduler's hook methods on potentially blocking operations, and the
* current thread will call scheduler's `#close` method on finalisation
* (allowing the scheduler to properly manage all non-finished fibers).
* `scheduler` can be an object of any class corresponding to
* `Fiber::SchedulerInterface`. Its implementation is up to the user.
*
* @param[in] scheduler The scheduler to set.
* @exception rb_eArgError `scheduler` does not conform the interface.
* @post Current thread's scheduler is `scheduler`.
*/
VALUE rb_fiber_scheduler_set(VALUE scheduler);
/**
* Identical to rb_fiber_scheduler_get(), except it also returns ::RUBY_Qnil in
* case of a blocking fiber. As blocking fibers do not participate schedulers'
* scheduling this function can be handy.
*
* @retval RUBY_Qnil No scheduler is in effect.
* @retval otherwise The scheduler that is in effect, if any.
*/
VALUE rb_fiber_scheduler_current(void);
/**
* Identical to rb_fiber_scheduler_current(), except it queries for that of the
* passed thread instead of the implicit current one.
*
* @param[in] thread Target thread.
* @exception rb_eTypeError `thread` is not a thread.
* @retval RUBY_Qnil No scheduler is in effect in `thread`.
* @retval otherwise The scheduler that is in effect in `thread`.
*/
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread);
/**
* Converts the passed timeout to an expression that rb_fiber_scheduler_block()
* etc. expects.
*
* @param[in] timeout A duration (can be `NULL`).
* @retval RUBY_Qnil No timeout (blocks indefinitely).
* @retval otherwise A timeout object.
*/
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout);
/**
* Closes the passed scheduler object. This expects the scheduler to wait for
* all fibers. Thus the scheduler's main loop tends to start here.
*
* @param[in] scheduler Target scheduler.
* @return What `scheduler.close` returns.
*/
VALUE rb_fiber_scheduler_close(VALUE scheduler);
/**
* Non-blocking `sleep`. Depending on scheduler implementation, this for
* instance switches to another fiber etc.
*
* @param[in] scheduler Target scheduler.
* @param[in] duration Passed as-is to `scheduler.kernel_sleep`.
* @return What `scheduler.kernel_sleep` returns.
*/
VALUE rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE duration);
/**
* Identical to rb_fiber_scheduler_kernel_sleep(), except it can pass multiple
* arguments.
*
* @param[in] scheduler Target scheduler.
* @param[in] argc Number of objects of `argv`.
* @param[in] argv Passed as-is to `scheduler.kernel_sleep`
* @return What `scheduler.kernel_sleep` returns.
*/
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv);
/* Description TBW */
#if 0
VALUE rb_fiber_scheduler_timeout_after(VALUE scheduler, VALUE timeout, VALUE exception, VALUE message);
VALUE rb_fiber_scheduler_timeout_afterv(VALUE scheduler, int argc, VALUE * argv);
int rb_fiber_scheduler_supports_process_wait(VALUE scheduler);
#endif
/**
* Non-blocking `waitpid`. Depending on scheduler implementation, this for
* instance switches to another fiber etc.
*
* @param[in] scheduler Target scheduler.
* @param[in] pid Process ID to wait.
* @param[in] flags Wait flags, e.g. `WUNTRACED`.
* @return What `scheduler.process_wait` returns.
*/
VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags);
/**
* Non-blocking wait for the passed "blocker", which is for instance
* `Thread.join` or `Mutex.lock`. Depending on scheduler implementation, this
* for instance switches to another fiber etc.
*
* @param[in] scheduler Target scheduler.
* @param[in] blocker What blocks the current fiber.
* @param[in] timeout Numeric timeout.
* @return What `scheduler.block` returns.
*/
VALUE rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout);
/**
* Wakes up a fiber previously blocked using rb_fiber_scheduler_block().
*
* @param[in] scheduler Target scheduler.
* @param[in] blocker What was awaited for.
* @param[in] fiber What to unblock.
* @return What `scheduler.unblock` returns.
*/
VALUE rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber);
/**
* Non-blocking version of rb_io_wait(). Depending on scheduler
* implementation, this for instance switches to another fiber etc.
*
* The "events" here is a Ruby level integer, which is an OR-ed value of
* `IO::READABLE`, `IO::WRITABLE`, and `IO::PRIORITY`.
*
* @param[in] scheduler Target scheduler.
* @param[in] io An io object to wait.
* @param[in] events An integer set of interests.
* @param[in] timeout Numeric timeout.
* @return What `scheduler.io_wait` returns.
*/
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout);
/**
* Non-blocking wait until the passed IO is ready for reading. This is a
* special case of rb_fiber_scheduler_io_wait(), where the interest is
* `IO::READABLE` and timeout is never.
*
* @param[in] scheduler Target scheduler.
* @param[in] io An io object to wait.
* @return What `scheduler.io_wait` returns.
*/
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io);
/**
* Non-blocking wait until the passed IO is ready for writing. This is a
* special case of rb_fiber_scheduler_io_wait(), where the interest is
* `IO::WRITABLE` and timeout is never.
*
* @param[in] scheduler Target scheduler.
* @param[in] io An io object to wait.
* @return What `scheduler.io_wait` returns.
*/
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io);
/**
* Non-blocking version of `IO.select`.
*
* It's possible that this will be emulated using a thread, so you should not
* rely on it for high performance.
*
* @param[in] scheduler Target scheduler.
* @param[in] readables An array of readable objects.
* @param[in] writables An array of writable objects.
* @param[in] exceptables An array of objects that might encounter exceptional conditions.
* @param[in] timeout Numeric timeout or nil.
* @return What `scheduler.io_select` returns, normally a 3-tuple of arrays of ready objects.
*/
VALUE rb_fiber_scheduler_io_select(VALUE scheduler, VALUE readables, VALUE writables, VALUE exceptables, VALUE timeout);
/**
* Non-blocking version of `IO.select`, `argv` variant.
*/
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv);
/**
* Non-blocking read from the passed IO.
*
* @param[in] scheduler Target scheduler.
* @param[out] io An io object to read from.
* @param[out] buffer Return buffer.
* @param[in] length Requested number of bytes to read.
* @param[in] offset The offset in the buffer to read to.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns `[-errno, size]`.
*/
VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset);
/**
* Non-blocking write to the passed IO.
*
* @param[in] scheduler Target scheduler.
* @param[out] io An io object to write to.
* @param[in] buffer What to write.
* @param[in] length Number of bytes to write.
* @param[in] offset The offset in the buffer to write from.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns `[-errno, size]`.
*/
VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset);
/**
* Non-blocking read from the passed IO at the specified offset.
*
* @param[in] scheduler Target scheduler.
* @param[out] io An io object to read from.
* @param[in] from The offset in the given IO to read the data from.
* @param[out] buffer The buffer to read the data to.
* @param[in] length Requested number of bytes to read.
* @param[in] offset The offset in the buffer to read to.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns.
*/
VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset);
/**
* Non-blocking write to the passed IO at the specified offset.
*
* @param[in] scheduler Target scheduler.
* @param[out] io An io object to write to.
* @param[in] from The offset in the given IO to write the data to.
* @param[in] buffer The buffer to write the data from.
* @param[in] length Number of bytes to write.
* @param[in] offset The offset in the buffer to write from.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns.
*/
VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset);
/**
* Non-blocking read from the passed IO using a native buffer.
*
* @param[in] scheduler Target scheduler.
* @param[out] io An io object to read from.
* @param[out] buffer Return buffer.
* @param[in] size Size of the return buffer.
* @param[in] length Requested number of bytes to read.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns.
*/
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length);
/**
* Non-blocking write to the passed IO using a native buffer.
*
* @param[in] scheduler Target scheduler.
* @param[out] io An io object to write to.
* @param[in] buffer What to write.
* @param[in] size Size of the buffer.
* @param[in] length Number of bytes to write.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns.
*/
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length);
/**
* Non-blocking close the given IO.
*
* @param[in] scheduler Target scheduler.
* @param[in] io An io object to close.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_close`.
* @return otherwise What `scheduler.io_close` returns.
*/
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io);
/**
* Non-blocking DNS lookup.
*
* @param[in] scheduler Target scheduler.
* @param[in] hostname A host name to query.
* @retval RUBY_Qundef `scheduler` doesn't have `#address_resolve`.
* @return otherwise What `scheduler.address_resolve` returns.
*/
VALUE rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname);
/**
* Create and schedule a non-blocking fiber.
*
*/
VALUE rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat);
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_FIBER_SCHEDULER_H */

64
libs/libruby/ruby/intern.h vendored Normal file
View File

@@ -0,0 +1,64 @@
#ifndef RUBY_INTERN_H /*-*-C++-*-vi:se ft=cpp:*/
#define RUBY_INTERN_H 1
/**
* @file
* @author $Author$
* @date Thu Jun 10 14:22:17 JST 1993
* @copyright Copyright (C) 1993-2007 Yukihiro Matsumoto
* @copyright Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
* @copyright Copyright (C) 2000 Information-technology Promotion Agency, Japan
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
#include "ruby/internal/config.h"
#include "ruby/defines.h"
#include <stdarg.h>
#include "ruby/st.h"
/*
* Functions and variables that are used by more than one source file of
* the kernel.
*/
#include "ruby/internal/intern/array.h"
#include "ruby/internal/intern/bignum.h"
#include "ruby/internal/intern/class.h"
#include "ruby/internal/intern/compar.h"
#include "ruby/internal/intern/complex.h"
#include "ruby/internal/intern/cont.h"
#include "ruby/internal/intern/dir.h"
#include "ruby/internal/intern/enum.h"
#include "ruby/internal/intern/enumerator.h"
#include "ruby/internal/intern/error.h"
#include "ruby/internal/intern/eval.h"
#include "ruby/internal/intern/file.h"
#include "ruby/internal/intern/gc.h"
#include "ruby/internal/intern/hash.h"
#include "ruby/internal/intern/io.h"
#include "ruby/internal/intern/load.h"
#include "ruby/internal/intern/marshal.h"
#include "ruby/internal/intern/numeric.h"
#include "ruby/internal/intern/object.h"
#include "ruby/internal/intern/parse.h"
#include "ruby/internal/intern/proc.h"
#include "ruby/internal/intern/process.h"
#include "ruby/internal/intern/random.h"
#include "ruby/internal/intern/range.h"
#include "ruby/internal/intern/rational.h"
#include "ruby/internal/intern/re.h"
#include "ruby/internal/intern/ruby.h"
#include "ruby/internal/intern/select.h"
#include "ruby/internal/intern/signal.h"
#include "ruby/internal/intern/sprintf.h"
#include "ruby/internal/intern/string.h"
#include "ruby/internal/intern/struct.h"
#include "ruby/internal/intern/thread.h"
#include "ruby/internal/intern/time.h"
#include "ruby/internal/intern/variable.h"
#include "ruby/internal/intern/vm.h"
#endif /* RUBY_INTERN_H */

58
libs/libruby/ruby/internal/abi.h vendored Normal file
View File

@@ -0,0 +1,58 @@
#ifndef RUBY_ABI_H
#define RUBY_ABI_H
#ifdef RUBY_ABI_VERSION /* should match the definition in config.h */
/* This number represents Ruby's ABI version.
*
* In development Ruby, it should be bumped every time an ABI incompatible
* change is introduced. This will force other developers to rebuild extension
* gems.
*
* The following cases are considered as ABI incompatible changes:
* - Changing any data structures.
* - Changing macros or inline functions causing a change in behavior.
* - Deprecating or removing function declarations.
*
* The following cases are NOT considered as ABI incompatible changes:
* - Any changes that does not involve the header files in the `include`
* directory.
* - Adding macros, inline functions, or function declarations.
* - Backwards compatible refactors.
* - Editing comments.
*
* In released versions of Ruby, this number is not defined since teeny
* versions of Ruby should guarantee ABI compatibility.
*/
#define RUBY_ABI_VERSION 3
/* Windows does not support weak symbols so ruby_abi_version will not exist
* in the shared library. */
#if defined(HAVE_FUNC_WEAK) && !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# define RUBY_DLN_CHECK_ABI
#endif
#endif /* RUBY_ABI_VERSION */
#ifdef RUBY_DLN_CHECK_ABI
# ifdef __cplusplus
extern "C" {
# endif
RUBY_FUNC_EXPORTED unsigned long long __attribute__((weak))
ruby_abi_version(void)
{
# ifdef RUBY_ABI_VERSION
return RUBY_ABI_VERSION;
# else
return 0;
# endif
}
# ifdef __cplusplus
}
# endif
#endif
#endif

376
libs/libruby/ruby/internal/anyargs.h vendored Normal file
View File

@@ -0,0 +1,376 @@
#ifndef RBIMPL_ANYARGS_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ANYARGS_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Function overloads to issue warnings around #ANYARGS.
*
* For instance ::rb_define_method takes a pointer to #ANYARGS -ed functions,
* which in fact varies 18 different prototypes. We still need to preserve
* #ANYARGS for storages but why not check the consistencies if possible. With
* those complex macro overlays defined in this header file, use of a function
* pointer gets checked against the corresponding arity argument.
*
* ### Q&A ###
*
* - Q: Where did the magic number "18" came from in the description above?
*
* - A: Count the case branch of `vm_method.c:call_cfunc_invoker_func()`. Note
* also that the 18 branches has lasted for at least 25 years. See also
* commit 200e0ee2fd3c1c006c528874a88f684447215524.
*
* - Q: What is this `__weakref__` thing?
*
* - A: That is a kind of function overloading mechanism that GCC provides. In
* this case for instance `rb_define_method_00` is an alias of
* ::rb_define_method, with a strong type.
*
* - Q: What is this `__transparent_union__` thing?
*
* A: That is another kind of function overloading mechanism that GCC
* provides. In this case the attributed function pointer is either
* `VALUE(*)(int,VALUE*,VALUE)` or `VALUE(*)(int,const VALUE*,VALUE)`.
*
* This is better than `void*` or #ANYARGS because we can reject all other
* possibilities than the two.
*
* - Q: What does this #rb_define_method macro mean?
*
* - A: It selects appropriate alias of the ::rb_define_method function,
* depending on the last (arity) argument.
*
* - Q: Why the special case for ::rb_f_notimplement ?
*
* - A: Function pointer to ::rb_f_notimplement is special cased in
* `vm_method.c:rb_add_method_cfunc()`. That should be handled by the
* `__builtin_choose_expr` chain inside of #rb_define_method macro
* expansion. In order to do so, comparison like
* `(func == rb_f_notimplement)` is inappropriate for
* `__builtin_choose_expr`'s expression (which must be a compile-time
* integer constant but the address of ::rb_f_notimplement is not fixed
* until the linker). Instead we are using
* `__builtin_types_compatible_p`, and in doing so we need to distinguish
* ::rb_f_notimplement from others, by type.
*/
#include "ruby/internal/attr/maybe_unused.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/weakref.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/config.h"
#include "ruby/internal/has/attribute.h"
#include "ruby/internal/intern/class.h"
#include "ruby/internal/intern/vm.h"
#include "ruby/internal/method.h"
#include "ruby/internal/value.h"
#include "ruby/backward/2/stdarg.h"
#if defined(__cplusplus)
# include "ruby/backward/cxxanyargs.hpp"
#elif defined(_WIN32) || defined(__CYGWIN__)
# /* Skip due to [Bug #16134] */
#elif ! RBIMPL_HAS_ATTRIBUTE(transparent_union)
# /* :TODO: improve here, please find a way to support. */
#elif ! defined(HAVE_VA_ARGS_MACRO)
# /* :TODO: improve here, please find a way to support. */
#else
# /** @cond INTERNAL_MACRO */
# if ! defined(HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P)
# define RBIMPL_CFUNC_IS_rb_f_notimplement(f) 0
# else
# define RBIMPL_CFUNC_IS_rb_f_notimplement(f) \
__builtin_types_compatible_p( \
__typeof__(f), \
__typeof__(rb_f_notimplement))
# endif
# if ! defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P)
# define RBIMPL_ANYARGS_DISPATCH(expr, truthy, falsy) (falsy)
# else
# define RBIMPL_ANYARGS_DISPATCH(expr, truthy, falsy) \
__builtin_choose_expr( \
__builtin_choose_expr( \
__builtin_constant_p(expr), \
(expr), 0), \
(truthy), (falsy))
# endif
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_m2(n) RBIMPL_ANYARGS_DISPATCH((n) == -2, rb_define_singleton_method_m2, rb_define_singleton_method_m3)
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_m1(n) RBIMPL_ANYARGS_DISPATCH((n) == -1, rb_define_singleton_method_m1, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_m2(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_00(n) RBIMPL_ANYARGS_DISPATCH((n) == 0, rb_define_singleton_method_00, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_m1(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_01(n) RBIMPL_ANYARGS_DISPATCH((n) == 1, rb_define_singleton_method_01, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_00(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_02(n) RBIMPL_ANYARGS_DISPATCH((n) == 2, rb_define_singleton_method_02, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_01(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_03(n) RBIMPL_ANYARGS_DISPATCH((n) == 3, rb_define_singleton_method_03, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_02(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_04(n) RBIMPL_ANYARGS_DISPATCH((n) == 4, rb_define_singleton_method_04, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_03(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_05(n) RBIMPL_ANYARGS_DISPATCH((n) == 5, rb_define_singleton_method_05, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_04(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_06(n) RBIMPL_ANYARGS_DISPATCH((n) == 6, rb_define_singleton_method_06, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_05(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_07(n) RBIMPL_ANYARGS_DISPATCH((n) == 7, rb_define_singleton_method_07, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_06(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_08(n) RBIMPL_ANYARGS_DISPATCH((n) == 8, rb_define_singleton_method_08, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_07(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_09(n) RBIMPL_ANYARGS_DISPATCH((n) == 9, rb_define_singleton_method_09, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_08(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_10(n) RBIMPL_ANYARGS_DISPATCH((n) == 10, rb_define_singleton_method_10, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_09(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_11(n) RBIMPL_ANYARGS_DISPATCH((n) == 11, rb_define_singleton_method_11, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_10(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_12(n) RBIMPL_ANYARGS_DISPATCH((n) == 12, rb_define_singleton_method_12, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_11(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_singleton_method_13, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_12(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_singleton_method_14, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_13(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_singleton_method_15, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_14(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_m2(n) RBIMPL_ANYARGS_DISPATCH((n) == -2, rb_define_protected_method_m2, rb_define_protected_method_m3)
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_m1(n) RBIMPL_ANYARGS_DISPATCH((n) == -1, rb_define_protected_method_m1, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_m2(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_00(n) RBIMPL_ANYARGS_DISPATCH((n) == 0, rb_define_protected_method_00, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_m1(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_01(n) RBIMPL_ANYARGS_DISPATCH((n) == 1, rb_define_protected_method_01, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_00(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_02(n) RBIMPL_ANYARGS_DISPATCH((n) == 2, rb_define_protected_method_02, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_01(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_03(n) RBIMPL_ANYARGS_DISPATCH((n) == 3, rb_define_protected_method_03, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_02(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_04(n) RBIMPL_ANYARGS_DISPATCH((n) == 4, rb_define_protected_method_04, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_03(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_05(n) RBIMPL_ANYARGS_DISPATCH((n) == 5, rb_define_protected_method_05, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_04(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_06(n) RBIMPL_ANYARGS_DISPATCH((n) == 6, rb_define_protected_method_06, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_05(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_07(n) RBIMPL_ANYARGS_DISPATCH((n) == 7, rb_define_protected_method_07, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_06(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_08(n) RBIMPL_ANYARGS_DISPATCH((n) == 8, rb_define_protected_method_08, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_07(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_09(n) RBIMPL_ANYARGS_DISPATCH((n) == 9, rb_define_protected_method_09, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_08(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_10(n) RBIMPL_ANYARGS_DISPATCH((n) == 10, rb_define_protected_method_10, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_09(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_11(n) RBIMPL_ANYARGS_DISPATCH((n) == 11, rb_define_protected_method_11, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_10(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_12(n) RBIMPL_ANYARGS_DISPATCH((n) == 12, rb_define_protected_method_12, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_11(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_protected_method_13, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_12(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_protected_method_14, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_13(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_protected_method_15, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_14(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_m2(n) RBIMPL_ANYARGS_DISPATCH((n) == -2, rb_define_private_method_m2, rb_define_private_method_m3)
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_m1(n) RBIMPL_ANYARGS_DISPATCH((n) == -1, rb_define_private_method_m1, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_m2(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_00(n) RBIMPL_ANYARGS_DISPATCH((n) == 0, rb_define_private_method_00, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_m1(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_01(n) RBIMPL_ANYARGS_DISPATCH((n) == 1, rb_define_private_method_01, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_00(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_02(n) RBIMPL_ANYARGS_DISPATCH((n) == 2, rb_define_private_method_02, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_01(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_03(n) RBIMPL_ANYARGS_DISPATCH((n) == 3, rb_define_private_method_03, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_02(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_04(n) RBIMPL_ANYARGS_DISPATCH((n) == 4, rb_define_private_method_04, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_03(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_05(n) RBIMPL_ANYARGS_DISPATCH((n) == 5, rb_define_private_method_05, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_04(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_06(n) RBIMPL_ANYARGS_DISPATCH((n) == 6, rb_define_private_method_06, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_05(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_07(n) RBIMPL_ANYARGS_DISPATCH((n) == 7, rb_define_private_method_07, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_06(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_08(n) RBIMPL_ANYARGS_DISPATCH((n) == 8, rb_define_private_method_08, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_07(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_09(n) RBIMPL_ANYARGS_DISPATCH((n) == 9, rb_define_private_method_09, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_08(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_10(n) RBIMPL_ANYARGS_DISPATCH((n) == 10, rb_define_private_method_10, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_09(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_11(n) RBIMPL_ANYARGS_DISPATCH((n) == 11, rb_define_private_method_11, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_10(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_12(n) RBIMPL_ANYARGS_DISPATCH((n) == 12, rb_define_private_method_12, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_11(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_private_method_13, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_12(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_private_method_14, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_13(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_private_method_15, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_14(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_m2(n) RBIMPL_ANYARGS_DISPATCH((n) == -2, rb_define_module_function_m2, rb_define_module_function_m3)
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_m1(n) RBIMPL_ANYARGS_DISPATCH((n) == -1, rb_define_module_function_m1, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_m2(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_00(n) RBIMPL_ANYARGS_DISPATCH((n) == 0, rb_define_module_function_00, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_m1(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_01(n) RBIMPL_ANYARGS_DISPATCH((n) == 1, rb_define_module_function_01, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_00(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_02(n) RBIMPL_ANYARGS_DISPATCH((n) == 2, rb_define_module_function_02, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_01(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_03(n) RBIMPL_ANYARGS_DISPATCH((n) == 3, rb_define_module_function_03, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_02(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_04(n) RBIMPL_ANYARGS_DISPATCH((n) == 4, rb_define_module_function_04, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_03(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_05(n) RBIMPL_ANYARGS_DISPATCH((n) == 5, rb_define_module_function_05, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_04(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_06(n) RBIMPL_ANYARGS_DISPATCH((n) == 6, rb_define_module_function_06, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_05(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_07(n) RBIMPL_ANYARGS_DISPATCH((n) == 7, rb_define_module_function_07, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_06(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_08(n) RBIMPL_ANYARGS_DISPATCH((n) == 8, rb_define_module_function_08, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_07(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_09(n) RBIMPL_ANYARGS_DISPATCH((n) == 9, rb_define_module_function_09, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_08(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_10(n) RBIMPL_ANYARGS_DISPATCH((n) == 10, rb_define_module_function_10, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_09(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_11(n) RBIMPL_ANYARGS_DISPATCH((n) == 11, rb_define_module_function_11, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_10(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_12(n) RBIMPL_ANYARGS_DISPATCH((n) == 12, rb_define_module_function_12, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_11(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_module_function_13, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_12(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_module_function_14, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_13(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_module_function_15, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_14(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_m2(n) RBIMPL_ANYARGS_DISPATCH((n) == -2, rb_define_global_function_m2, rb_define_global_function_m3)
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_m1(n) RBIMPL_ANYARGS_DISPATCH((n) == -1, rb_define_global_function_m1, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_m2(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_00(n) RBIMPL_ANYARGS_DISPATCH((n) == 0, rb_define_global_function_00, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_m1(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_01(n) RBIMPL_ANYARGS_DISPATCH((n) == 1, rb_define_global_function_01, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_00(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_02(n) RBIMPL_ANYARGS_DISPATCH((n) == 2, rb_define_global_function_02, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_01(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_03(n) RBIMPL_ANYARGS_DISPATCH((n) == 3, rb_define_global_function_03, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_02(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_04(n) RBIMPL_ANYARGS_DISPATCH((n) == 4, rb_define_global_function_04, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_03(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_05(n) RBIMPL_ANYARGS_DISPATCH((n) == 5, rb_define_global_function_05, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_04(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_06(n) RBIMPL_ANYARGS_DISPATCH((n) == 6, rb_define_global_function_06, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_05(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_07(n) RBIMPL_ANYARGS_DISPATCH((n) == 7, rb_define_global_function_07, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_06(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_08(n) RBIMPL_ANYARGS_DISPATCH((n) == 8, rb_define_global_function_08, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_07(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_09(n) RBIMPL_ANYARGS_DISPATCH((n) == 9, rb_define_global_function_09, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_08(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_10(n) RBIMPL_ANYARGS_DISPATCH((n) == 10, rb_define_global_function_10, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_09(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_11(n) RBIMPL_ANYARGS_DISPATCH((n) == 11, rb_define_global_function_11, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_10(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_12(n) RBIMPL_ANYARGS_DISPATCH((n) == 12, rb_define_global_function_12, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_11(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_global_function_13, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_12(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_global_function_14, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_13(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_global_function_15, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_14(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_m2(n) RBIMPL_ANYARGS_DISPATCH((n) == -2, rb_define_method_id_m2, rb_define_method_id_m3)
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_m1(n) RBIMPL_ANYARGS_DISPATCH((n) == -1, rb_define_method_id_m1, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_m2(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_00(n) RBIMPL_ANYARGS_DISPATCH((n) == 0, rb_define_method_id_00, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_m1(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_01(n) RBIMPL_ANYARGS_DISPATCH((n) == 1, rb_define_method_id_01, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_00(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_02(n) RBIMPL_ANYARGS_DISPATCH((n) == 2, rb_define_method_id_02, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_01(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_03(n) RBIMPL_ANYARGS_DISPATCH((n) == 3, rb_define_method_id_03, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_02(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_04(n) RBIMPL_ANYARGS_DISPATCH((n) == 4, rb_define_method_id_04, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_03(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_05(n) RBIMPL_ANYARGS_DISPATCH((n) == 5, rb_define_method_id_05, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_04(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_06(n) RBIMPL_ANYARGS_DISPATCH((n) == 6, rb_define_method_id_06, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_05(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_07(n) RBIMPL_ANYARGS_DISPATCH((n) == 7, rb_define_method_id_07, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_06(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_08(n) RBIMPL_ANYARGS_DISPATCH((n) == 8, rb_define_method_id_08, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_07(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_09(n) RBIMPL_ANYARGS_DISPATCH((n) == 9, rb_define_method_id_09, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_08(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_10(n) RBIMPL_ANYARGS_DISPATCH((n) == 10, rb_define_method_id_10, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_09(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_11(n) RBIMPL_ANYARGS_DISPATCH((n) == 11, rb_define_method_id_11, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_10(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_12(n) RBIMPL_ANYARGS_DISPATCH((n) == 12, rb_define_method_id_12, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_11(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_method_id_13, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_12(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_method_id_14, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_13(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_method_id_15, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_14(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_m2(n) RBIMPL_ANYARGS_DISPATCH((n) == -2, rb_define_method_m2, rb_define_method_m3)
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_m1(n) RBIMPL_ANYARGS_DISPATCH((n) == -1, rb_define_method_m1, RBIMPL_ANYARGS_DISPATCH_rb_define_method_m2(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_00(n) RBIMPL_ANYARGS_DISPATCH((n) == 0, rb_define_method_00, RBIMPL_ANYARGS_DISPATCH_rb_define_method_m1(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_01(n) RBIMPL_ANYARGS_DISPATCH((n) == 1, rb_define_method_01, RBIMPL_ANYARGS_DISPATCH_rb_define_method_00(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_02(n) RBIMPL_ANYARGS_DISPATCH((n) == 2, rb_define_method_02, RBIMPL_ANYARGS_DISPATCH_rb_define_method_01(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_03(n) RBIMPL_ANYARGS_DISPATCH((n) == 3, rb_define_method_03, RBIMPL_ANYARGS_DISPATCH_rb_define_method_02(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_04(n) RBIMPL_ANYARGS_DISPATCH((n) == 4, rb_define_method_04, RBIMPL_ANYARGS_DISPATCH_rb_define_method_03(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_05(n) RBIMPL_ANYARGS_DISPATCH((n) == 5, rb_define_method_05, RBIMPL_ANYARGS_DISPATCH_rb_define_method_04(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_06(n) RBIMPL_ANYARGS_DISPATCH((n) == 6, rb_define_method_06, RBIMPL_ANYARGS_DISPATCH_rb_define_method_05(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_07(n) RBIMPL_ANYARGS_DISPATCH((n) == 7, rb_define_method_07, RBIMPL_ANYARGS_DISPATCH_rb_define_method_06(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_08(n) RBIMPL_ANYARGS_DISPATCH((n) == 8, rb_define_method_08, RBIMPL_ANYARGS_DISPATCH_rb_define_method_07(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_09(n) RBIMPL_ANYARGS_DISPATCH((n) == 9, rb_define_method_09, RBIMPL_ANYARGS_DISPATCH_rb_define_method_08(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_10(n) RBIMPL_ANYARGS_DISPATCH((n) == 10, rb_define_method_10, RBIMPL_ANYARGS_DISPATCH_rb_define_method_09(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_11(n) RBIMPL_ANYARGS_DISPATCH((n) == 11, rb_define_method_11, RBIMPL_ANYARGS_DISPATCH_rb_define_method_10(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_12(n) RBIMPL_ANYARGS_DISPATCH((n) == 12, rb_define_method_12, RBIMPL_ANYARGS_DISPATCH_rb_define_method_11(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_method_13, RBIMPL_ANYARGS_DISPATCH_rb_define_method_12(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_method_14, RBIMPL_ANYARGS_DISPATCH_rb_define_method_13(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_method_15, RBIMPL_ANYARGS_DISPATCH_rb_define_method_14(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_singleton_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_15(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_protected_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_15(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_private_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_15(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_module_function_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_15(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_global_function_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_15(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_method_id_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_15(n))
# define RBIMPL_ANYARGS_DISPATCH_rb_define_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_method_15(n))
# define RBIMPL_ANYARGS_ATTRSET(sym) RBIMPL_ATTR_MAYBE_UNUSED() RBIMPL_ATTR_NONNULL(()) RBIMPL_ATTR_WEAKREF(sym)
# define RBIMPL_ANYARGS_DECL(sym, ...) \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _notimpl(__VA_ARGS__, VALUE(*)(int, const VALUE *, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m3(__VA_ARGS__, VALUE(*)(ANYARGS), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m2(__VA_ARGS__, VALUE(*)(VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m1(__VA_ARGS__, VALUE(*)(int, union { VALUE *x; const VALUE *y; } __attribute__((__transparent_union__)), VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _00(__VA_ARGS__, VALUE(*)(VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _01(__VA_ARGS__, VALUE(*)(VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _02(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _03(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _04(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _05(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _06(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _07(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _08(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _09(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _10(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _11(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _12(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _13(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _14(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int); \
RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _15(__VA_ARGS__, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE), int);
RBIMPL_ANYARGS_DECL(rb_define_singleton_method, VALUE, const char *)
RBIMPL_ANYARGS_DECL(rb_define_protected_method, VALUE, const char *)
RBIMPL_ANYARGS_DECL(rb_define_private_method, VALUE, const char *)
RBIMPL_ANYARGS_DECL(rb_define_module_function, VALUE, const char *)
RBIMPL_ANYARGS_DECL(rb_define_global_function, const char *)
RBIMPL_ANYARGS_DECL(rb_define_method_id, VALUE, ID)
RBIMPL_ANYARGS_DECL(rb_define_method, VALUE, const char *)
/** @endcond */
/**
* @brief Defines klass\#mid.
* @see ::rb_define_method
* @param klass Where the method lives.
* @param mid Name of the defining method.
* @param func Implementation of klass\#mid.
* @param arity Arity of klass\#mid.
*/
#define rb_define_method(klass, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_method((arity), (func))((klass), (mid), (func), (arity))
/**
* @brief Defines klass\#mid.
* @see ::rb_define_method_id
* @param klass Where the method lives.
* @param mid Name of the defining method.
* @param func Implementation of klass\#mid.
* @param arity Arity of klass\#mid.
*/
#define rb_define_method_id(klass, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_method_id((arity), (func))((klass), (mid), (func), (arity))
/**
* @brief Defines obj.mid.
* @see ::rb_define_singleton_method
* @param obj Where the method lives.
* @param mid Name of the defining method.
* @param func Implementation of obj.mid.
* @param arity Arity of obj.mid.
*/
#define rb_define_singleton_method(obj, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method((arity), (func))((obj), (mid), (func), (arity))
/**
* @brief Defines klass\#mid and make it protected.
* @see ::rb_define_protected_method
* @param klass Where the method lives.
* @param mid Name of the defining method.
* @param func Implementation of klass\#mid.
* @param arity Arity of klass\#mid.
*/
#define rb_define_protected_method(klass, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method((arity), (func))((klass), (mid), (func), (arity))
/**
* @brief Defines klass\#mid and make it private.
* @see ::rb_define_private_method
* @param klass Where the method lives.
* @param mid Name of the defining method.
* @param func Implementation of klass\#mid.
* @param arity Arity of klass\#mid.
*/
#define rb_define_private_method(klass, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_private_method((arity), (func))((klass), (mid), (func), (arity))
/**
* @brief Defines mod\#mid and make it a module function.
* @see ::rb_define_module_function
* @param mod Where the method lives.
* @param mid Name of the defining method.
* @param func Implementation of mod\#mid.
* @param arity Arity of mod\#mid.
*/
#define rb_define_module_function(mod, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_module_function((arity), (func))((mod), (mid), (func), (arity))
/**
* @brief Defines ::rb_mKerbel \#mid.
* @see ::rb_define_global_function
* @param mid Name of the defining method.
* @param func Implementation of ::rb_mKernel \#mid.
* @param arity Arity of ::rb_mKernel \#mid.
*/
#define rb_define_global_function(mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_global_function((arity), (func))((mid), (func), (arity))
#endif /* __cplusplus */
/**
* This macro is to properly cast a function parameter of *_define_method
* family. It has been around since 1.x era so you can maximise backwards
* compatibility by using it.
*
* ```CXX
* rb_define_method(klass, "method", RUBY_METHOD_FUNC(func), arity);
* ```
*
* @param func A pointer to a function that implements a method.
*/
#if ! defined(RUBY_DEVEL)
# define RUBY_METHOD_FUNC(func) RBIMPL_CAST((VALUE (*)(ANYARGS))(func))
#elif ! RUBY_DEVEL
# define RUBY_METHOD_FUNC(func) RBIMPL_CAST((VALUE (*)(ANYARGS))(func))
#elif ! defined(rb_define_method)
# define RUBY_METHOD_FUNC(func) RBIMPL_CAST((VALUE (*)(ANYARGS))(func))
#else
# define RUBY_METHOD_FUNC(func) (func)
#endif
#endif /* RBIMPL_ANYARGS_H */

39
libs/libruby/ruby/internal/arithmetic.h vendored Normal file
View File

@@ -0,0 +1,39 @@
#ifndef RBIMPL_ARITHMETIC_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Conversion between C's arithmetic types and Ruby's numeric
* types.
*/
#include "ruby/internal/arithmetic/char.h"
#include "ruby/internal/arithmetic/double.h"
#include "ruby/internal/arithmetic/fixnum.h"
#include "ruby/internal/arithmetic/gid_t.h"
#include "ruby/internal/arithmetic/int.h"
#include "ruby/internal/arithmetic/intptr_t.h"
#include "ruby/internal/arithmetic/long.h"
#include "ruby/internal/arithmetic/long_long.h"
#include "ruby/internal/arithmetic/mode_t.h"
#include "ruby/internal/arithmetic/off_t.h"
#include "ruby/internal/arithmetic/pid_t.h"
#include "ruby/internal/arithmetic/short.h"
#include "ruby/internal/arithmetic/size_t.h"
#include "ruby/internal/arithmetic/st_data_t.h"
#include "ruby/internal/arithmetic/uid_t.h"
#endif /* RBIMPL_ARITHMETIC_H */

View File

@@ -0,0 +1,81 @@
#ifndef RBIMPL_ARITHMETIC_CHAR_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_CHAR_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `char` and Ruby's.
*/
#include "ruby/internal/arithmetic/int.h" /* NUM2INT is here, but */
#include "ruby/internal/arithmetic/long.h" /* INT2FIX is here.*/
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/const.h"
#include "ruby/internal/attr/constexpr.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/core/rstring.h"
#include "ruby/internal/value_type.h"
#define RB_NUM2CHR rb_num2char_inline /**< @alias{rb_num2char_inline} */
#define NUM2CHR RB_NUM2CHR /**< @old{RB_NUM2CHR} */
#define CHR2FIX RB_CHR2FIX /**< @old{RB_CHR2FIX} */
/** @cond INTERNAL_MACRO */
#define RB_CHR2FIX RB_CHR2FIX
/** @endcond */
RBIMPL_ATTR_CONST_UNLESS_DEBUG()
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
RBIMPL_ATTR_ARTIFICIAL()
/**
* Converts a C's `unsigned char` into an instance of ::rb_cInteger.
*
* @param[in] c Arbitrary `unsigned char` value.
* @return An instance of ::rb_cInteger.
*
* @internal
*
* Nobody explicitly states this but in Ruby, a char means an unsigned integer
* value of range 0..255. This is a general principle. AFAIK there is no
* single line of code where char is signed.
*/
static inline VALUE
RB_CHR2FIX(unsigned char c)
{
return RB_INT2FIX(c);
}
/**
* Converts an instance of ::rb_cNumeric into C's `char`. At the same time it
* accepts a String of more than one character, and returns its first byte. In
* the early days there was a Ruby level "character" literal `?c`, which
* roughly worked this way.
*
* @param[in] x Either a string or a numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `unsigned int`.
* @return The passed value converted into C's `char`.
*/
static inline char
rb_num2char_inline(VALUE x)
{
if (RB_TYPE_P(x, RUBY_T_STRING) && (RSTRING_LEN(x)>=1))
return RSTRING_PTR(x)[0];
else
return RBIMPL_CAST((char)RB_NUM2INT(x));
}
#endif /* RBIMPL_ARITHMETIC_CHAR_H */

View File

@@ -0,0 +1,72 @@
#ifndef RBIMPL_ARITHMETIC_DOUBLE_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_DOUBLE_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `double` and Ruby's.
*/
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
#define NUM2DBL rb_num2dbl /**< @old{rb_num2dbl} */
#define RFLOAT_VALUE rb_float_value /**< @old{rb_float_value} */
#define DBL2NUM rb_float_new /**< @old{rb_float_new} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
* Converts an instance of ::rb_cNumeric into C's `double`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @return The passed value converted into C's `double`.
*/
double rb_num2dbl(VALUE num);
RBIMPL_ATTR_PURE()
/**
* Extracts its double value from an instance of ::rb_cFloat.
*
* @param[in] num An instance of ::rb_cFloat.
* @pre Must not pass anything other than a Fixnum.
* @return The passed value converted into C's `double`.
*/
double rb_float_value(VALUE num);
/**
* Converts a C's `double` into an instance of ::rb_cFloat.
*
* @param[in] d Arbitrary `double` value.
* @return An instance of ::rb_cFloat.
*/
VALUE rb_float_new(double d);
/**
* Identical to rb_float_new(), except it does not generate Flonums.
*
* @param[in] d Arbitrary `double` value.
* @return An instance of ::rb_cFloat.
*
* @internal
*
* @shyouhei has no idea why it is here.
*/
VALUE rb_float_new_in_heap(double d);
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_ARITHMETIC_DOUBLE_H */

View File

@@ -0,0 +1,60 @@
#ifndef RBIMPL_ARITHMETIC_FIXNUM_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_FIXNUM_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Handling of integers formerly known as Fixnums.
*/
#include "ruby/backward/2/limits.h"
#define FIXABLE RB_FIXABLE /**< @old{RB_FIXABLE} */
#define FIXNUM_MAX RUBY_FIXNUM_MAX /**< @old{RUBY_FIXNUM_MAX} */
#define FIXNUM_MIN RUBY_FIXNUM_MIN /**< @old{RUBY_FIXNUM_MIN} */
#define NEGFIXABLE RB_NEGFIXABLE /**< @old{RB_NEGFIXABLE} */
#define POSFIXABLE RB_POSFIXABLE /**< @old{RB_POSFIXABLE} */
/**
* Checks if the passed value is in range of fixnum, assuming it is a positive
* number. Can sometimes be useful for C's unsigned integer types.
*
* @internal
*
* FIXABLE can be applied to anything, from double to intmax_t. The problem is
* double. On a 64bit system RUBY_FIXNUM_MAX is 4,611,686,018,427,387,903,
* which is not representable by a double. The nearest value that a double can
* represent is 4,611,686,018,427,387,904, which is not fixable. The
* seemingly-strange "< FIXNUM_MAX + 1" expression below is due to this.
*/
#define RB_POSFIXABLE(_) ((_) < RUBY_FIXNUM_MAX + 1)
/**
* Checks if the passed value is in range of fixnum, assuming it is a negative
* number. This is an implementation of #RB_FIXABLE. Rarely used stand alone.
*/
#define RB_NEGFIXABLE(_) ((_) >= RUBY_FIXNUM_MIN)
/** Checks if the passed value is in range of fixnum */
#define RB_FIXABLE(_) (RB_POSFIXABLE(_) && RB_NEGFIXABLE(_))
/** Maximum possible value that a fixnum can represent. */
#define RUBY_FIXNUM_MAX (LONG_MAX / 2)
/** Minimum possible value that a fixnum can represent. */
#define RUBY_FIXNUM_MIN (LONG_MIN / 2)
#endif /* RBIMPL_ARITHMETIC_FIXNUM_H */

View File

@@ -0,0 +1,41 @@
#ifndef RBIMPL_ARITHMETIC_GID_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_GID_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `gid_t` and Ruby's.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/long.h"
/** Converts a C's `gid_t` into an instance of ::rb_cInteger. */
#ifndef GIDT2NUM
# define GIDT2NUM RB_LONG2NUM
#endif
/** Converts an instance of ::rb_cNumeric into C's `gid_t`. */
#ifndef NUM2GIDT
# define NUM2GIDT RB_NUM2LONG
#endif
/** A rb_sprintf() format prefix to be used for a `gid_t` parameter. */
#ifndef PRI_GIDT_PREFIX
# define PRI_GIDT_PREFIX PRI_LONG_PREFIX
#endif
#endif /* RBIMPL_ARITHMETIC_GID_T_H */

View File

@@ -0,0 +1,264 @@
#ifndef RBIMPL_ARITHMETIC_INT_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_INT_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `int` and Ruby's.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/fixnum.h"
#include "ruby/internal/arithmetic/intptr_t.h"
#include "ruby/internal/arithmetic/long.h"
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/const.h"
#include "ruby/internal/attr/constexpr.h"
#include "ruby/internal/compiler_is.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/special_consts.h"
#include "ruby/internal/value.h"
#include "ruby/internal/warning_push.h"
#include "ruby/assert.h"
#define RB_INT2NUM rb_int2num_inline /**< @alias{rb_int2num_inline} */
#define RB_NUM2INT rb_num2int_inline /**< @alias{rb_num2int_inline} */
#define RB_UINT2NUM rb_uint2num_inline /**< @alias{rb_uint2num_inline} */
#define FIX2INT RB_FIX2INT /**< @old{RB_FIX2INT} */
#define FIX2UINT RB_FIX2UINT /**< @old{RB_FIX2UINT} */
#define INT2NUM RB_INT2NUM /**< @old{RB_INT2NUM} */
#define NUM2INT RB_NUM2INT /**< @old{RB_NUM2INT} */
#define NUM2UINT RB_NUM2UINT /**< @old{RB_NUM2UINT} */
#define UINT2NUM RB_UINT2NUM /**< @old{RB_UINT2NUM} */
/** @cond INTERNAL_MACRO */
#define RB_FIX2INT RB_FIX2INT
#define RB_NUM2UINT RB_NUM2UINT
#define RB_FIX2UINT RB_FIX2UINT
/** @endcond */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
* Converts an instance of ::rb_cNumeric into C's `long`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `int`.
* @return The passed value converted into C's `long`.
*
* @internal
*
* Yes, the API is really strange. It returns `long`, but raises when the
* value is out of `int`. This seems to be due to the fact that Matz favoured
* K&R before, and his machine at that moment was an ILP32 architecture.
*/
long rb_num2int(VALUE num);
/**
* Identical to rb_num2int().
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `int`.
* @return The passed value converted into C's `long`.
*
* @internal
*
* This function seems to be a complete waste of disk space. @shyouhei has no
* idea why this is a different thing from rb_num2short().
*/
long rb_fix2int(VALUE num);
/**
* Converts an instance of ::rb_cNumeric into C's `unsigned long`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `unsigned int`.
* @return The passed value converted into C's `unsigned long`.
*
* @internal
*
* Yes, the API is really strange. It returns `unsigned long`, but raises when
* the value is out of `unsigned int`. This seems to be due to the fact that
* Matz favoured K&R before, and his machine at that moment was an ILP32
* architecture.
*/
unsigned long rb_num2uint(VALUE num);
/**
* Identical to rb_num2uint().
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `unsigned int`.
* @return The passed value converted into C's `unsigned long`.
*
* @internal
*
* This function seems to be a complete waste of disk space. @shyouhei has no
* idea why this is a different thing from rb_num2short().
*/
unsigned long rb_fix2uint(VALUE num);
RBIMPL_SYMBOL_EXPORT_END()
RBIMPL_ATTR_ARTIFICIAL()
/**
* Converts a Fixnum into C's `int`.
*
* @param[in] x Some Fixnum.
* @pre Must not pass anything other than a Fixnum.
* @return The passed value converted into C's `int`.
*/
static inline int
RB_FIX2INT(VALUE x)
{
/* "FIX2INT raises a TypeError if passed nil", says rubyspec. Not sure if
* that is a desired behaviour but just preserve backwards compatilibily.
*/
#if 0
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
#endif
long ret;
if /* constexpr */ (sizeof(int) < sizeof(long)) {
ret = rb_fix2int(x);
}
else {
ret = RB_FIX2LONG(x);
}
return RBIMPL_CAST((int)ret);
}
/**
* Converts an instance of ::rb_cNumeric into C's `int`.
*
* @param[in] x Something numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `int`.
* @return The passed value converted into C's `int`.
*/
static inline int
rb_num2int_inline(VALUE x)
{
long ret;
if /* constexpr */ (sizeof(int) == sizeof(long)) {
ret = RB_NUM2LONG(x);
}
else if (RB_FIXNUM_P(x)) {
ret = rb_fix2int(x);
}
else {
ret = rb_num2int(x);
}
return RBIMPL_CAST((int)ret);
}
/**
* Converts an instance of ::rb_cNumeric into C's `unsigned int`.
*
* @param[in] x Something numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `unsigned int`.
* @return The passed value converted into C's `unsigned int`.
*/
RBIMPL_ATTR_ARTIFICIAL()
static inline unsigned int
RB_NUM2UINT(VALUE x)
{
unsigned long ret;
if /* constexpr */ (sizeof(int) < sizeof(long)) {
ret = rb_num2uint(x);
}
else {
ret = RB_NUM2ULONG(x);
}
return RBIMPL_CAST((unsigned int)ret);
}
RBIMPL_ATTR_ARTIFICIAL()
/**
* Converts a Fixnum into C's `int`.
*
* @param[in] x Some Fixnum.
* @pre Must not pass anything other than a Fixnum.
* @return The passed value converted into C's `int`.
*/
static inline unsigned int
RB_FIX2UINT(VALUE x)
{
#if 0 /* Ditto for RB_FIX2INT. */
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
#endif
unsigned long ret;
if /* constexpr */ (sizeof(int) < sizeof(long)) {
ret = rb_fix2uint(x);
}
else {
ret = RB_FIX2ULONG(x);
}
return RBIMPL_CAST((unsigned int)ret);
}
RBIMPL_WARNING_PUSH()
#if RBIMPL_COMPILER_IS(GCC)
RBIMPL_WARNING_IGNORED(-Wtype-limits) /* We can ignore them here. */
#elif RBIMPL_HAS_WARNING("-Wtautological-constant-out-of-range-compare")
RBIMPL_WARNING_IGNORED(-Wtautological-constant-out-of-range-compare)
#endif
/**
* Converts a C's `int` into an instance of ::rb_cInteger.
*
* @param[in] v Arbitrary `int` value.
* @return An instance of ::rb_cInteger.
*/
static inline VALUE
rb_int2num_inline(int v)
{
if (RB_FIXABLE(v))
return RB_INT2FIX(v);
else
return rb_int2big(v);
}
/**
* Converts a C's `unsigned int` into an instance of ::rb_cInteger.
*
* @param[in] v Arbitrary `unsigned int` value.
* @return An instance of ::rb_cInteger.
*/
static inline VALUE
rb_uint2num_inline(unsigned int v)
{
if (RB_POSFIXABLE(v))
return RB_LONG2FIX(v);
else
return rb_uint2big(v);
}
RBIMPL_WARNING_POP()
#endif /* RBIMPL_ARITHMETIC_INT_H */

View File

@@ -0,0 +1,74 @@
#ifndef RBIMPL_ARITHMETIC_INTPTR_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_INTPTR_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `intptr_t` and Ruby's.
*/
#include "ruby/internal/config.h"
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include "ruby/internal/value.h"
#include "ruby/internal/dllexport.h"
#define rb_int_new rb_int2inum /**< @alias{rb_int2inum} */
#define rb_uint_new rb_uint2inum /**< @alias{rb_uint2inum} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
* Converts a C's `intptr_t` into an instance of ::rb_cInteger.
*
* @param[in] i Arbitrary `intptr_t` value.
* @return An instance of ::rb_cInteger.
* @note This function always allocates Bignums, even if the given number
* is small enough to fit into a Fixnum.
*/
VALUE rb_int2big(intptr_t i);
/**
* Converts a C's `intptr_t` into an instance of ::rb_cInteger.
*
* @param[in] i Arbitrary `intptr_t` value.
* @return An instance of ::rb_cInteger.
*/
VALUE rb_int2inum(intptr_t i);
/**
* Converts a C's `intptr_t` into an instance of ::rb_cInteger.
*
* @param[in] i Arbitrary `intptr_t` value.
* @return An instance of ::rb_cInteger.
* @note This function always allocates Bignums, even if the given number
* is small enough to fit into a Fixnum.
*/
VALUE rb_uint2big(uintptr_t i);
/**
* Converts a C's `uintptr_t` into an instance of ::rb_cInteger.
*
* @param[in] i Arbitrary `uintptr_t` value.
* @return An instance of ::rb_cInteger.
*/
VALUE rb_uint2inum(uintptr_t i);
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_ARITHMETIC_INTPTR_T_H */

View File

@@ -0,0 +1,356 @@
#ifndef RBIMPL_ARITHMETIC_LONG_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_LONG_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `long` and Ruby's.
*
* ### Q&A ###
*
* - Q: Why are INT2FIX etc. here, not in `int.h`?
*
* - A: Because they are in fact handling `long`. It seems someone did not
* understand the difference of `int` and `long` when they designed those
* macros.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/fixnum.h" /* FIXABLE */
#include "ruby/internal/arithmetic/intptr_t.h" /* rb_int2big etc.*/
#include "ruby/internal/assume.h"
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/cold.h"
#include "ruby/internal/attr/const.h"
#include "ruby/internal/attr/constexpr.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/special_consts.h" /* FIXNUM_FLAG */
#include "ruby/internal/value.h"
#include "ruby/assert.h"
#define FIX2LONG RB_FIX2LONG /**< @old{RB_FIX2LONG} */
#define FIX2ULONG RB_FIX2ULONG /**< @old{RB_FIX2ULONG} */
#define INT2FIX RB_INT2FIX /**< @old{RB_INT2FIX} */
#define LONG2FIX RB_INT2FIX /**< @old{RB_INT2FIX} */
#define LONG2NUM RB_LONG2NUM /**< @old{RB_LONG2NUM} */
#define NUM2LONG RB_NUM2LONG /**< @old{RB_NUM2LONG} */
#define NUM2ULONG RB_NUM2ULONG /**< @old{RB_NUM2ULONG} */
#define RB_FIX2LONG rb_fix2long /**< @alias{rb_fix2long} */
#define RB_FIX2ULONG rb_fix2ulong /**< @alias{rb_fix2ulong} */
#define RB_LONG2FIX RB_INT2FIX /**< @alias{RB_INT2FIX} */
#define RB_LONG2NUM rb_long2num_inline /**< @alias{rb_long2num_inline} */
#define RB_NUM2LONG rb_num2long_inline /**< @alias{rb_num2long_inline} */
#define RB_NUM2ULONG rb_num2ulong_inline /**< @alias{rb_num2ulong_inline} */
#define RB_ULONG2NUM rb_ulong2num_inline /**< @alias{rb_ulong2num_inline} */
#define ULONG2NUM RB_ULONG2NUM /**< @old{RB_ULONG2NUM} */
#define rb_fix_new RB_INT2FIX /**< @alias{RB_INT2FIX} */
#define rb_long2int rb_long2int_inline /**< @alias{rb_long2int_inline} */
/** @cond INTERNAL_MACRO */
#define RB_INT2FIX RB_INT2FIX
/** @endcond */
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_COLD()
/**
* This is an utility function to raise an ::rb_eRangeError.
*
* @param[in] num A signed value about to overflow.
* @exception rb_eRangeError `num` is out of range of `int`.
*/
void rb_out_of_int(SIGNED_VALUE num);
/**
* Converts an instance of ::rb_cNumeric into C's `long`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `long`.
* @return The passed value converted into C's `long`.
*/
long rb_num2long(VALUE num);
/**
* Converts an instance of ::rb_cNumeric into C's `unsigned long`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `unsigned long`.
* @return The passed value converted into C's `unsigned long`.
*/
unsigned long rb_num2ulong(VALUE num);
RBIMPL_SYMBOL_EXPORT_END()
RBIMPL_ATTR_CONST_UNLESS_DEBUG()
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
RBIMPL_ATTR_ARTIFICIAL()
/**
* Converts a C's `long` into an instance of ::rb_cInteger.
*
* @param[in] i Arbitrary `long` value.
* @return An instance of ::rb_cInteger.
*/
static inline VALUE
RB_INT2FIX(long i)
{
RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(i));
/* :NOTE: VALUE can be wider than long. As j being unsigned, 2j+1 is fully
* defined. Also it can be compiled into a single LEA instruction. */
const unsigned long j = i;
const unsigned long k = (j << 1) + RUBY_FIXNUM_FLAG;
const long l = k;
const SIGNED_VALUE m = l; /* Sign extend */
const VALUE n = m;
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(n));
return n;
}
/**
* Checks if `int` can hold the given integer.
*
* @param[in] n Arbitrary `long` value.
* @exception rb_eRangeError `n` is out of range of `int`.
* @return Identical value of type `int`
*/
static inline int
rb_long2int_inline(long n)
{
int i = RBIMPL_CAST((int)n);
if /* constexpr */ (sizeof(long) <= sizeof(int)) {
RBIMPL_ASSUME(i == n);
}
if (i != n)
rb_out_of_int(n);
return i;
}
RBIMPL_ATTR_CONST_UNLESS_DEBUG()
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
/**
* @private
*
* This is an implementation detail of rb_fix2long(). People don't use it
* directly.
*
* @param[in] x A Fixnum.
* @return Identical value of type `long`
* @pre Must not pass anything other than a Fixnum.
*/
static inline long
rbimpl_fix2long_by_idiv(VALUE x)
{
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
/* :NOTE: VALUE can be wider than long. (x-1)/2 never overflows because
* RB_FIXNUM_P(x) holds. Also it has no portability issue like y>>1
* below. */
const SIGNED_VALUE y = x - RUBY_FIXNUM_FLAG;
const SIGNED_VALUE z = y / 2;
const long w = RBIMPL_CAST((long)z);
RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(w));
return w;
}
RBIMPL_ATTR_CONST_UNLESS_DEBUG()
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
/**
* @private
*
* This is an implementation detail of rb_fix2long(). People don't use it
* directly.
*
* @param[in] x A Fixnum.
* @return Identical value of type `long`
* @pre Must not pass anything other than a Fixnum.
*/
static inline long
rbimpl_fix2long_by_shift(VALUE x)
{
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
/* :NOTE: VALUE can be wider than long. If right shift is arithmetic, this
* is noticeably faster than above. */
const SIGNED_VALUE y = x;
const SIGNED_VALUE z = y >> 1;
const long w = RBIMPL_CAST((long)z);
RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(w));
return w;
}
RBIMPL_ATTR_CONST()
RBIMPL_ATTR_CONSTEXPR(CXX11)
/**
* @private
*
* This is an implementation detail of rb_fix2long(). People don't use it
* directly.
*
* @retval true This C compiler's right shift operator is arithmetic.
* @retval false This C compiler's right shift operator is logical.
*/
static inline bool
rbimpl_right_shift_is_arithmetic_p(void)
{
return (-1 >> 1) == -1;
}
RBIMPL_ATTR_CONST_UNLESS_DEBUG()
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
/**
* Converts a Fixnum into C's `long`.
*
* @param[in] x Some Fixnum.
* @pre Must not pass anything other than a Fixnum.
* @return The passed value converted into C's `long`.
*/
static inline long
rb_fix2long(VALUE x)
{
if /* constexpr */ (rbimpl_right_shift_is_arithmetic_p()) {
return rbimpl_fix2long_by_shift(x);
}
else {
return rbimpl_fix2long_by_idiv(x);
}
}
RBIMPL_ATTR_CONST_UNLESS_DEBUG()
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
/**
* Converts a Fixnum into C's `unsigned long`.
*
* @param[in] x Some Fixnum.
* @pre Must not pass anything other than a Fixnum.
* @return The passed value converted into C's `unsigned long`.
* @note Negative fixnums will be converted into large unsigned longs.
*/
static inline unsigned long
rb_fix2ulong(VALUE x)
{
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
return rb_fix2long(x);
}
/**
* Converts an instance of ::rb_cNumeric into C's `long`.
*
* @param[in] x Something numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `long`.
* @return The passed value converted into C's `long`.
*/
static inline long
rb_num2long_inline(VALUE x)
{
if (RB_FIXNUM_P(x))
return RB_FIX2LONG(x);
else
return rb_num2long(x);
}
/**
* Converts an instance of ::rb_cNumeric into C's `unsigned long`.
*
* @param[in] x Something numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `unsigned long`.
* @return The passed value converted into C's `unsigned long`.
*
* @internal
*
* This (negative fixnum would become a large unsigned long while negative
* bignum is an exception) has been THE behaviour of NUM2ULONG since the
* beginning. It is strange, but we can no longer change how it works at this
* moment. We have to get by with it.
*
* @see https://bugs.ruby-lang.org/issues/9089
*/
static inline unsigned long
rb_num2ulong_inline(VALUE x)
{
if (RB_FIXNUM_P(x))
return RB_FIX2ULONG(x);
else
return rb_num2ulong(x);
}
/**
* Converts a C's `long` into an instance of ::rb_cInteger.
*
* @param[in] v Arbitrary `long` value.
* @return An instance of ::rb_cInteger.
*/
static inline VALUE
rb_long2num_inline(long v)
{
if (RB_FIXABLE(v))
return RB_LONG2FIX(v);
else
return rb_int2big(v);
}
/**
* Converts a C's `unsigned long` into an instance of ::rb_cInteger.
*
* @param[in] v Arbitrary `unsigned long` value.
* @return An instance of ::rb_cInteger.
*/
static inline VALUE
rb_ulong2num_inline(unsigned long v)
{
if (RB_POSFIXABLE(v))
return RB_LONG2FIX(v);
else
return rb_uint2big(v);
}
/**
* @cond INTERNAL_MACRO
*
* Following overload is necessary because sometimes INT2FIX is used as a enum
* value (e.g. `enum { FOO = INT2FIX(0) };`). THIS IS NG in theory because a
* VALUE does not fit into an enum (which must be a signed int). But we cannot
* break existing codes.
*/
#if RBIMPL_HAS_ATTR_CONSTEXPR_CXX14
# /* C++ can write constexpr as enum values. */
#elif ! defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P)
# undef INT2FIX
# define INT2FIX(i) (RBIMPL_CAST((VALUE)(i)) << 1 | RUBY_FIXNUM_FLAG)
#else
# undef INT2FIX
# define INT2FIX(i) \
__builtin_choose_expr( \
__builtin_constant_p(i), \
RBIMPL_CAST((VALUE)(i)) << 1 | RUBY_FIXNUM_FLAG, \
RB_INT2FIX(i))
#endif
/** @endcond */
#endif /* RBIMPL_ARITHMETIC_LONG_H */

View File

@@ -0,0 +1,135 @@
#ifndef RBIMPL_ARITHMETIC_LONG_LONG_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_LONG_LONG_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `long long` and Ruby's.
*/
#include "ruby/internal/value.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/special_consts.h"
#include "ruby/backward/2/long_long.h"
#define RB_LL2NUM rb_ll2num_inline /**< @alias{rb_ll2num_inline} */
#define RB_ULL2NUM rb_ull2num_inline /**< @alias{rb_ull2num_inline} */
#define LL2NUM RB_LL2NUM /**< @old{RB_LL2NUM} */
#define ULL2NUM RB_ULL2NUM /**< @old{RB_ULL2NUM} */
#define RB_NUM2LL rb_num2ll_inline /**< @alias{rb_num2ll_inline} */
#define RB_NUM2ULL rb_num2ull_inline /**< @alias{rb_num2ull_inline} */
#define NUM2LL RB_NUM2LL /**< @old{RB_NUM2LL} */
#define NUM2ULL RB_NUM2ULL /**< @old{RB_NUM2ULL} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
* Converts a C's `long long` into an instance of ::rb_cInteger.
*
* @param[in] num Arbitrary `long long` value.
* @return An instance of ::rb_cInteger.
*/
VALUE rb_ll2inum(LONG_LONG num);
/**
* Converts a C's `unsigned long long` into an instance of ::rb_cInteger.
*
* @param[in] num Arbitrary `unsigned long long` value.
* @return An instance of ::rb_cInteger.
*/
VALUE rb_ull2inum(unsigned LONG_LONG num);
/**
* Converts an instance of ::rb_cNumeric into C's `long long`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `long long`.
* @return The passed value converted into C's `long long`.
*/
LONG_LONG rb_num2ll(VALUE num);
/**
* Converts an instance of ::rb_cNumeric into C's `unsigned long long`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `unsigned long long`.
* @return The passed value converted into C's `unsigned long long`.
*/
unsigned LONG_LONG rb_num2ull(VALUE num);
RBIMPL_SYMBOL_EXPORT_END()
/**
* Converts a C's `long long` into an instance of ::rb_cInteger.
*
* @param[in] n Arbitrary `long long` value.
* @return An instance of ::rb_cInteger
*/
static inline VALUE
rb_ll2num_inline(LONG_LONG n)
{
if (FIXABLE(n)) return LONG2FIX((long)n);
return rb_ll2inum(n);
}
/**
* Converts a C's `unsigned long long` into an instance of ::rb_cInteger.
*
* @param[in] n Arbitrary `unsigned long long` value.
* @return An instance of ::rb_cInteger
*/
static inline VALUE
rb_ull2num_inline(unsigned LONG_LONG n)
{
if (POSFIXABLE(n)) return LONG2FIX((long)n);
return rb_ull2inum(n);
}
/**
* Converts an instance of ::rb_cNumeric into C's `long long`.
*
* @param[in] x Something numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `long long`.
* @return The passed value converted into C's `long long`.
*/
static inline LONG_LONG
rb_num2ll_inline(VALUE x)
{
if (RB_FIXNUM_P(x))
return RB_FIX2LONG(x);
else
return rb_num2ll(x);
}
/**
* Converts an instance of ::rb_cNumeric into C's `unsigned long long`.
*
* @param[in] x Something numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `unsigned long long`.
* @return The passed value converted into C's `unsigned long long`.
*/
static inline unsigned LONG_LONG
rb_num2ull_inline(VALUE x)
{
if (RB_FIXNUM_P(x))
return RB_FIX2LONG(x);
else
return rb_num2ull(x);
}
#endif /* RBIMPL_ARITHMETIC_LONG_LONG_H */

View File

@@ -0,0 +1,41 @@
#ifndef RBIMPL_ARITHMETIC_MODE_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_MODE_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `mode_t` and Ruby's.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/int.h"
/** Converts a C's `mode_t` into an instance of ::rb_cInteger. */
#ifndef NUM2MODET
# define NUM2MODET RB_NUM2INT
#endif
/** Converts an instance of ::rb_cNumeric into C's `mode_t`. */
#ifndef MODET2NUM
# define MODET2NUM RB_INT2NUM
#endif
/** A rb_sprintf() format prefix to be used for a `mode_t` parameter. */
#ifndef PRI_MODET_PREFIX
# define PRI_MODET_PREFIX PRI_INT_PREFIX
#endif
#endif /* RBIMPL_ARITHMETIC_MODE_T_H */

View File

@@ -0,0 +1,62 @@
#ifndef RBIMPL_ARITHMETIC_OFF_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_OFF_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `off_t` and Ruby's.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/int.h"
#include "ruby/internal/arithmetic/long.h"
#include "ruby/internal/arithmetic/long_long.h"
#include "ruby/backward/2/long_long.h"
/** Converts a C's `off_t` into an instance of ::rb_cInteger. */
#ifdef OFFT2NUM
# /* take that. */
#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
# define OFFT2NUM RB_LL2NUM
#elif SIZEOF_OFF_T == SIZEOF_LONG
# define OFFT2NUM RB_LONG2NUM
#else
# define OFFT2NUM RB_INT2NUM
#endif
/** Converts an instance of ::rb_cNumeric into C's `off_t`. */
#ifdef NUM2OFFT
# /* take that. */
#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
# define NUM2OFFT RB_NUM2LL
#elif SIZEOF_OFF_T == SIZEOF_LONG
# define NUM2OFFT RB_NUM2LONG
#else
# define NUM2OFFT RB_NUM2INT
#endif
/** A rb_sprintf() format prefix to be used for an `off_t` parameter. */
#ifdef PRI_OFFT_PREFIX
# /* take that. */
#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
# define PRI_OFFT_PREFIX PRI_LL_PREFIX
#elif SIZEOF_OFF_T == SIZEOF_LONG
# define PRI_OFFT_PREFIX PRI_LONG_PREFIX
#else
# define PRI_OFFT_PREFIX PRI_INT_PREFIX
#endif
#endif /* RBIMPL_ARITHMETIC_OFF_T_H */

View File

@@ -0,0 +1,41 @@
#ifndef RBIMPL_ARITHMETIC_PID_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_PID_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `pid_t` and Ruby's.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/long.h"
/** Converts a C's `pid_t` into an instance of ::rb_cInteger. */
#ifndef PIDT2NUM
# define PIDT2NUM RB_LONG2NUM
#endif
/** Converts an instance of ::rb_cNumeric into C's `pid_t`. */
#ifndef NUM2PIDT
# define NUM2PIDT RB_NUM2LONG
#endif
/** A rb_sprintf() format prefix to be used for a `pid_t` parameter. */
#ifndef PRI_PIDT_PREFIX
# define PRI_PIDT_PREFIX PRI_LONG_PREFIX
#endif
#endif /* RBIMPL_ARITHMETIC_PID_T_H */

View File

@@ -0,0 +1,113 @@
#ifndef RBIMPL_ARITHMETIC_SHORT_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_SHORT_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `short` and Ruby's.
*
* Shyouhei wonders: why there is no SHORT2NUM, given there are both
* #USHORT2NUM and #CHR2FIX?
*/
#include "ruby/internal/value.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/special_consts.h"
#define RB_NUM2SHORT rb_num2short_inline /**< @alias{rb_num2short_inline} */
#define RB_NUM2USHORT rb_num2ushort /**< @alias{rb_num2ushort} */
#define NUM2SHORT RB_NUM2SHORT /**< @old{RB_NUM2SHORT} */
#define NUM2USHORT RB_NUM2USHORT /**< @old{RB_NUM2USHORT} */
#define USHORT2NUM RB_INT2FIX /**< @old{RB_INT2FIX} */
#define RB_FIX2SHORT rb_fix2short /**< @alias{rb_fix2ushort} */
#define FIX2SHORT RB_FIX2SHORT /**< @old{RB_FIX2SHORT} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
* Converts an instance of ::rb_cNumeric into C's `short`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `short`.
* @return The passed value converted into C's `short`.
*/
short rb_num2short(VALUE num);
/**
* Converts an instance of ::rb_cNumeric into C's `unsigned short`.
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `unsigned short`.
* @return The passed value converted into C's `unsigned short`.
*/
unsigned short rb_num2ushort(VALUE num);
/**
* Identical to rb_num2short().
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `short`.
* @return The passed value converted into C's `short`.
*
* @internal
*
* This function seems to be a complete waste of disk space. @shyouhei has no
* idea why this is a different thing from rb_num2short().
*/
short rb_fix2short(VALUE num);
/**
* Identical to rb_num2ushort().
*
* @param[in] num Something numeric.
* @exception rb_eTypeError `num` is not a numeric.
* @exception rb_eRangeError `num` is out of range of `unsigned short`.
* @return The passed value converted into C's `unsigned short`.
*
* @internal
*
* This function seems to be a complete waste of disk space. @shyouhei has no
* idea why this is a different thing from rb_num2ushort().
*/
unsigned short rb_fix2ushort(VALUE num);
RBIMPL_SYMBOL_EXPORT_END()
/**
* Identical to rb_num2short().
*
* @param[in] x Something numeric.
* @exception rb_eTypeError `x` is not a numeric.
* @exception rb_eRangeError `x` is out of range of `short`.
* @return The passed value converted into C's `short`.
*
* @internal
*
* This function seems to be a complete waste of time. @shyouhei has no idea
* why this is a different thing from rb_num2short().
*/
static inline short
rb_num2short_inline(VALUE x)
{
if (RB_FIXNUM_P(x))
return rb_fix2short(x);
else
return rb_num2short(x);
}
#endif /* RBIMPL_ARITHMETIC_SHORT_H */

View File

@@ -0,0 +1,66 @@
#ifndef RBIMPL_ARITHMETIC_SIZE_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_SIZE_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `size_t` and Ruby's.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/int.h"
#include "ruby/internal/arithmetic/long.h"
#include "ruby/internal/arithmetic/long_long.h"
#include "ruby/backward/2/long_long.h"
#if defined(__DOXYGEN__)
# /** Converts a C's `size_t` into an instance of ::rb_cInteger. */
# define RB_SIZE2NUM RB_ULONG2NUM
# /** Converts a C's `ssize_t` into an instance of ::rb_cInteger. */
# define RB_SSIZE2NUM RB_LONG2NUM
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
# define RB_SIZE2NUM RB_ULL2NUM
# define RB_SSIZE2NUM RB_LL2NUM
#elif SIZEOF_SIZE_T == SIZEOF_LONG
# define RB_SIZE2NUM RB_ULONG2NUM
# define RB_SSIZE2NUM RB_LONG2NUM
#else
# define RB_SIZE2NUM RB_UINT2NUM
# define RB_SSIZE2NUM RB_INT2NUM
#endif
#if defined(__DOXYGEN__)
# /** Converts an instance of ::rb_cInteger into C's `size_t`. */
# define RB_NUM2SIZE RB_NUM2ULONG
# /** Converts an instance of ::rb_cInteger into C's `ssize_t`. */
# define RB_NUM2SSIZE RB_NUM2LONG
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
# define RB_NUM2SIZE RB_NUM2ULL
# define RB_NUM2SSIZE RB_NUM2LL
#elif SIZEOF_SIZE_T == SIZEOF_LONG
# define RB_NUM2SIZE RB_NUM2ULONG
# define RB_NUM2SSIZE RB_NUM2LONG
#else
# define RB_NUM2SIZE RB_NUM2UINT
# define RB_NUM2SSIZE RB_NUM2INT
#endif
#define NUM2SIZET RB_NUM2SIZE /**< @old{RB_NUM2SIZE} */
#define SIZET2NUM RB_SIZE2NUM /**< @old{RB_SIZE2NUM} */
#define NUM2SSIZET RB_NUM2SSIZE /**< @old{RB_NUM2SSIZE} */
#define SSIZET2NUM RB_SSIZE2NUM /**< @old{RB_SSIZE2NUM} */
#endif /* RBIMPL_ARITHMETIC_SIZE_T_H */

View File

@@ -0,0 +1,75 @@
#ifndef RBIMPL_ARITHMERIC_ST_DATA_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMERIC_ST_DATA_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `st_data_t` and Ruby's.
*/
#include "ruby/internal/arithmetic/fixnum.h"
#include "ruby/internal/arithmetic/long.h"
#include "ruby/internal/attr/artificial.h"
#include "ruby/internal/attr/const.h"
#include "ruby/internal/attr/constexpr.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/value.h"
#include "ruby/assert.h"
#include "ruby/st.h"
#define ST2FIX RB_ST2FIX /**< @old{RB_ST2FIX} */
/** @cond INTERNAL_MACRO */
#define RB_ST2FIX RB_ST2FIX
/** @endcond */
RBIMPL_ATTR_CONST_UNLESS_DEBUG()
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
RBIMPL_ATTR_ARTIFICIAL()
/**
* Converts a C's `st_data_t` into an instance of ::rb_cInteger.
*
* @param[in] i The data in question.
* @return A converted result
* @warning THIS CONVERSION LOSES DATA! Be warned.
* @see https://bugs.ruby-lang.org/issues/13877
* @see https://bugs.ruby-lang.org/issues/14218
*
* @internal
*
* This is needed because of hash functions. Hash functions return
* `st_data_t`, which could theoretically be bigger than Fixnums. However
* allocating Bignums for them every time we calculate hash values is just too
* heavy. To avoid penalty we need to ignore some upper bit(s) and stick to
* Fixnums. This function is used for that purpose.
*/
static inline VALUE
RB_ST2FIX(st_data_t i)
{
SIGNED_VALUE x = i;
if (x >= 0) {
x &= RUBY_FIXNUM_MAX;
}
else {
x |= RUBY_FIXNUM_MIN;
}
RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(x));
unsigned long y = RBIMPL_CAST((unsigned long)x);
return RB_LONG2FIX(y);
}
#endif /* RBIMPL_ARITHMETIC_ST_DATA_T_H */

View File

@@ -0,0 +1,41 @@
#ifndef RBIMPL_ARITHMETIC_UID_T_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ARITHMETIC_UID_T_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Arithmetic conversion between C's `uid_t` and Ruby's.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/long.h"
/** Converts a C's `uid_t` into an instance of ::rb_cInteger. */
#ifndef UIDT2NUM
# define UIDT2NUM RB_LONG2NUM
#endif
/** Converts an instance of ::rb_cNumeric into C's `uid_t`. */
#ifndef NUM2UIDT
# define NUM2UIDT RB_NUM2LONG
#endif
/** A rb_sprintf() format prefix to be used for a `uid_t` parameter. */
#ifndef PRI_UIDT_PREFIX
# define PRI_UIDT_PREFIX PRI_LONG_PREFIX
#endif
#endif /* RBIMPL_ARITHMETIC_UID_T_H */

87
libs/libruby/ruby/internal/assume.h vendored Normal file
View File

@@ -0,0 +1,87 @@
#ifndef RBIMPL_ASSUME_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ASSUME_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ASSUME / #RBIMPL_UNREACHABLE.
*
* These macros must be defined at once because:
*
* - #RBIMPL_ASSUME could fallback to #RBIMPL_UNREACHABLE.
* - #RBIMPL_UNREACHABLE could fallback to #RBIMPL_ASSUME.
*/
#include "ruby/internal/config.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/compiler_since.h"
#include "ruby/internal/has/builtin.h"
#include "ruby/internal/warning_push.h"
/** @cond INTERNAL_MACRO */
#if defined(HAVE___ASSUME)
# define RBIMPL_HAVE___ASSUME
#endif
/** @endcond */
/** Wraps (or simulates) `__builtin_unreachable`. */
#if RBIMPL_HAS_BUILTIN(__builtin_unreachable)
# define RBIMPL_UNREACHABLE_RETURN(_) __builtin_unreachable()
#elif defined(RBIMPL_HAVE___ASSUME)
# define RBIMPL_UNREACHABLE_RETURN(_) return (__assume(0), (_))
#else
# define RBIMPL_UNREACHABLE_RETURN(_) return (_)
#endif
/** Wraps (or simulates) `__builtin_unreachable`. */
#if RBIMPL_HAS_BUILTIN(__builtin_unreachable)
# define RBIMPL_UNREACHABLE __builtin_unreachable
#elif defined(RBIMPL_HAVE___ASSUME)
# define RBIMPL_UNREACHABLE() __assume(0)
#endif
/** Wraps (or simulates) `__assume`. */
#if RBIMPL_COMPILER_SINCE(Intel, 13, 0, 0)
# /* icc warnings are false positives. Ignore them. */
# /* "warning #2261: __assume expression with side effects discarded" */
# define RBIMPL_ASSUME(expr) \
RBIMPL_WARNING_PUSH() \
RBIMPL_WARNING_IGNORED(2261) \
__assume(expr) \
RBIMPL_WARNING_POP()
#elif defined(RBIMPL_HAVE___ASSUME)
# define RBIMPL_ASSUME __assume
#elif RBIMPL_HAS_BUILTIN(__builtin_assume)
# define RBIMPL_ASSUME __builtin_assume
#elif ! defined(RBIMPL_UNREACHABLE)
# define RBIMPL_ASSUME(_) RBIMPL_CAST((void)(_))
#else
# define RBIMPL_ASSUME(_) \
(RB_LIKELY(!!(_)) ? RBIMPL_CAST((void)0) : RBIMPL_UNREACHABLE())
#endif
#if ! defined(RBIMPL_UNREACHABLE)
# define RBIMPL_UNREACHABLE() RBIMPL_ASSUME(0)
#endif
#endif /* RBIMPL_ASSUME_H */

View File

@@ -0,0 +1,32 @@
#ifndef RBIMPL_ATTR_ALLOC_SIZE_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_ALLOC_SIZE_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_ALLOC_SIZE.
*/
#include "ruby/internal/has/attribute.h"
/** Wraps (or simulates) `__attribute__((alloc_size))` */
#if RBIMPL_HAS_ATTRIBUTE(alloc_size)
# define RBIMPL_ATTR_ALLOC_SIZE(tuple) __attribute__((__alloc_size__ tuple))
#else
# define RBIMPL_ATTR_ALLOC_SIZE(tuple) /* void */
#endif
#endif /* RBIMPL_ATTR_ALLOC_SIZE_H */

View File

@@ -0,0 +1,46 @@
#ifndef RBIMPL_ATTR_ARTIFICIAL_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_ARTIFICIAL_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_ARTIFICIAL.
*
* ### Q&A ###
*
* - Q: What is this attribute? I don't get what GCC manual is talking about.
*
* - A: In short it is an attribute to manipulate GDB backtraces. The
* attribute makes the best sense when it comes with
* __attribute__((always_inline)). When a function annotated with this
* attribute gets inlined, and when you somehow look at a backtrace which
* includes such inlined call site, then the backtrace shows the caller
* and not the callee. This is handy for instance when an identical
* function is inlined more than once in a single big function. On such
* case it gets vital to know where the inlining happened in the callee.
* See also https://stackoverflow.com/a/21936099
*/
#include "ruby/internal/has/attribute.h"
/** Wraps (or simulates) `__attribute__((artificial))` */
#if RBIMPL_HAS_ATTRIBUTE(artificial)
# define RBIMPL_ATTR_ARTIFICIAL() __attribute__((__artificial__))
#else
# define RBIMPL_ATTR_ARTIFICIAL() /* void */
#endif
#endif /* RBIMPL_ATTR_ARTIFICIAL_H */

37
libs/libruby/ruby/internal/attr/cold.h vendored Normal file
View File

@@ -0,0 +1,37 @@
#ifndef RBIMPL_ATTR_COLD_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_COLD_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_COLD.
*/
#include "ruby/internal/compiler_is.h"
#include "ruby/internal/has/attribute.h"
/** Wraps (or simulates) `__attribute__((cold))` */
#if RBIMPL_COMPILER_IS(SunPro)
# /* Recent SunPro has __has_attribute, and is broken. */
# /* It reports it has attribute cold, reality isn't (warnings issued). */
# define RBIMPL_ATTR_COLD() /* void */
#elif RBIMPL_HAS_ATTRIBUTE(cold)
# define RBIMPL_ATTR_COLD() __attribute__((__cold__))
#else
# define RBIMPL_ATTR_COLD() /* void */
#endif
#endif /* RBIMPL_ATTR_COLD_H */

46
libs/libruby/ruby/internal/attr/const.h vendored Normal file
View File

@@ -0,0 +1,46 @@
#ifndef RBIMPL_ATTR_CONST_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_CONST_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_CONST.
*/
#include "ruby/internal/compiler_since.h"
#include "ruby/internal/has/attribute.h"
#include "ruby/internal/has/declspec_attribute.h"
/** Wraps (or simulates) `__attribute__((const))` */
#if RBIMPL_HAS_ATTRIBUTE(const)
# define RBIMPL_ATTR_CONST() __attribute__((__const__))
#elif RBIMPL_HAS_DECLSPEC_ATTRIBUTE(noalias)
# /* If a function can be a const, that is also a noalias. */
# define RBIMPL_ATTR_CONST() __declspec(noalias)
#elif RBIMPL_COMPILER_SINCE(SunPro, 5, 10, 0)
# define RBIMPL_ATTR_CONST() _Pragma("no_side_effect")
#else
# define RBIMPL_ATTR_CONST() /* void */
#endif
/** Enables #RBIMPL_ATTR_CONST if and only if. ! #RUBY_DEBUG. */
#if !defined(RUBY_DEBUG) || !RUBY_DEBUG
# define RBIMPL_ATTR_CONST_UNLESS_DEBUG() RBIMPL_ATTR_CONST()
#else
# define RBIMPL_ATTR_CONST_UNLESS_DEBUG() /* void */
#endif
#endif /* RBIMPL_ATTR_CONST_H */

View File

@@ -0,0 +1,84 @@
#ifndef RBIMPL_ATTR_CONSTEXPR_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_CONSTEXPR_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief #RBIMPL_ATTR_CONSTEXPR.
*/
#include "ruby/internal/has/feature.h"
#include "ruby/internal/compiler_is.h"
/** @cond INTERNAL_MACRO */
#if ! defined(__cplusplus)
# /* Makes no sense. */
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 0
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 0
#elif defined(__cpp_constexpr)
# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 (__cpp_constexpr >= 200704L)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 (__cpp_constexpr >= 201304L)
#elif RBIMPL_COMPILER_SINCE(MSVC, 19, 0, 0)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 RBIMPL_COMPILER_SINCE(MSVC, 19, 00, 00)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 RBIMPL_COMPILER_SINCE(MSVC, 19, 11, 00)
#elif RBIMPL_COMPILER_SINCE(SunPro, 5, 13, 0)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 (__cplusplus >= 201103L)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 (__cplusplus >= 201402L)
#elif RBIMPL_COMPILER_SINCE(GCC, 4, 9, 0)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 (__cplusplus >= 201103L)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 (__cplusplus >= 201402L)
#elif RBIMPL_HAS_FEATURE(cxx_relaxed_constexpr)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 1
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 1
#elif RBIMPL_HAS_FEATURE(cxx_constexpr)
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 1
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 0
#else
# /* :FIXME: icpc must have constexpr but don't know how to detect. */
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX11 0
# define RBIMPL_HAS_ATTR_CONSTEXPR_CXX14 0
#endif
/** @endcond */
/** Wraps (or simulates) C++11 `constexpr`. */
#if RBIMPL_HAS_ATTR_CONSTEXPR_CXX14
# define RBIMPL_ATTR_CONSTEXPR(_) constexpr
#elif RBIMPL_HAS_ATTR_CONSTEXPR_CXX11
# define RBIMPL_ATTR_CONSTEXPR(_) RBIMPL_ATTR_CONSTEXPR_ ## _
# define RBIMPL_ATTR_CONSTEXPR_CXX11 constexpr
# define RBIMPL_ATTR_CONSTEXPR_CXX14 /* void */
#else
# define RBIMPL_ATTR_CONSTEXPR(_) /* void */
#endif
/** Enables #RBIMPL_ATTR_CONSTEXPR if and only if. ! #RUBY_DEBUG. */
#if !RUBY_DEBUG
# define RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(_) RBIMPL_ATTR_CONSTEXPR(_)
#else
# define RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(_) /* void */
#endif
#endif /* RBIMPL_ATTR_CONSTEXPR_H */

View File

@@ -0,0 +1,75 @@
#ifndef RBIMPL_ATTR_DEPRECATED_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_DEPRECATED_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_DEPRECATED.
*/
#include "ruby/internal/compiler_since.h"
#include "ruby/internal/has/attribute.h"
#include "ruby/internal/has/c_attribute.h"
#include "ruby/internal/has/cpp_attribute.h"
#include "ruby/internal/has/declspec_attribute.h"
#include "ruby/internal/has/extension.h"
/** Wraps (or simulates) `[[deprecated]]` */
#if defined(__COVERITY__)
/* Coverity Scan emulates gcc but seems not to support this attribute correctly */
# define RBIMPL_ATTR_DEPRECATED(msg)
#elif RBIMPL_HAS_EXTENSION(attribute_deprecated_with_message)
# define RBIMPL_ATTR_DEPRECATED(msg) __attribute__((__deprecated__ msg))
#elif defined(__cplusplus) && RBIMPL_COMPILER_SINCE(GCC, 10, 1, 0) && RBIMPL_COMPILER_BEFORE(GCC, 10, 3, 0)
# /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95302 */
# define RBIMPL_ATTR_DEPRECATED(msg) /* disable until they fix this bug */
#elif RBIMPL_COMPILER_SINCE(GCC, 4, 5, 0)
# define RBIMPL_ATTR_DEPRECATED(msg) __attribute__((__deprecated__ msg))
#elif RBIMPL_COMPILER_SINCE(Intel, 13, 0, 0)
# define RBIMPL_ATTR_DEPRECATED(msg) __attribute__((__deprecated__ msg))
#elif RBIMPL_HAS_ATTRIBUTE(deprecated) /* but not with message. */
# define RBIMPL_ATTR_DEPRECATED(msg) __attribute__((__deprecated__))
#elif RBIMPL_COMPILER_SINCE(MSVC, 14, 0, 0)
# define RBIMPL_ATTR_DEPRECATED(msg) __declspec(deprecated msg)
#elif RBIMPL_HAS_DECLSPEC_ATTRIBUTE(deprecated)
# define RBIMPL_ATTR_DEPRECATED(msg) __declspec(deprecated)
#elif RBIMPL_HAS_CPP_ATTRIBUTE(deprecated)
# define RBIMPL_ATTR_DEPRECATED(msg) [[deprecated msg]]
#elif RBIMPL_HAS_C_ATTRIBUTE(deprecated)
# define RBIMPL_ATTR_DEPRECATED(msg) [[deprecated msg]]
#else
# define RBIMPL_ATTR_DEPRECATED(msg) /* void */
#endif
/** This is when a function is used internally (for backwards compatibility
* etc.), but extension libraries must consider it deprecated. */
#if defined(RUBY_EXPORT)
# define RBIMPL_ATTR_DEPRECATED_EXT(msg) /* void */
#else
# define RBIMPL_ATTR_DEPRECATED_EXT(msg) RBIMPL_ATTR_DEPRECATED(msg)
#endif
#endif /* RBIMPL_ATTR_DEPRECATED_H */

View File

@@ -0,0 +1,42 @@
#ifndef RBIMPL_ATTR_DIAGNOSE_IF_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_DIAGNOSE_IF_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_DIAGNOSE_IF.
*/
#include "ruby/internal/has/attribute.h"
#include "ruby/internal/warning_push.h"
/** Wraps (or simulates) `__attribute__((diagnose_if))` */
#if RBIMPL_COMPILER_BEFORE(Clang, 5, 0, 0)
# /* https://bugs.llvm.org/show_bug.cgi?id=34319 */
# define RBIMPL_ATTR_DIAGNOSE_IF(_, __, ___) /* void */
#elif RBIMPL_HAS_ATTRIBUTE(diagnose_if)
# define RBIMPL_ATTR_DIAGNOSE_IF(_, __, ___) \
RBIMPL_WARNING_PUSH() \
RBIMPL_WARNING_IGNORED(-Wgcc-compat) \
__attribute__((__diagnose_if__(_, __, ___))) \
RBIMPL_WARNING_POP()
#else
# define RBIMPL_ATTR_DIAGNOSE_IF(_, __, ___) /* void */
#endif
#endif /* RBIMPL_ATTR_DIAGNOSE_IF_H */

View File

@@ -0,0 +1,32 @@
#ifndef RBIMPL_ATTR_ENUM_EXTENSIBILITY_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_ENUM_EXTENSIBILITY_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief #RBIMPL_ATTR_ENUM_EXTENSIBILITY.
*/
#include "ruby/internal/has/attribute.h"
/** Wraps (or simulates) `__attribute__((enum_extensibility))` */
#if RBIMPL_HAS_ATTRIBUTE(enum_extensibility)
# define RBIMPL_ATTR_ENUM_EXTENSIBILITY(_) __attribute__((__enum_extensibility__(_)))
#else
# define RBIMPL_ATTR_ENUM_EXTENSIBILITY(_) /* void */
#endif
#endif /* RBIMPL_ATTR_ENUM_EXTENSIBILITY_H */

32
libs/libruby/ruby/internal/attr/error.h vendored Normal file
View File

@@ -0,0 +1,32 @@
#ifndef RBIMPL_ATTR_ERROR_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_ERROR_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_ERROR.
*/
#include "ruby/internal/has/attribute.h"
/** Wraps (or simulates) `__attribute__((error))` */
#if RBIMPL_HAS_ATTRIBUTE(error)
# define RBIMPL_ATTR_ERROR(msg) __attribute__((__error__ msg))
#else
# define RBIMPL_ATTR_ERROR(msg) /* void */
#endif
#endif /* RBIMPL_ATTR_ERROR_H */

View File

@@ -0,0 +1,33 @@
#ifndef RBIMPL_ATTR_FLAG_ENUM_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_FLAG_ENUM_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_FLAG_ENUM.
* @see https://clang.llvm.org/docs/AttributeReference.html#flag_enum
*/
#include "ruby/internal/has/attribute.h"
/** Wraps (or simulates) `__attribute__((flag_enum)` */
#if RBIMPL_HAS_ATTRIBUTE(flag_enum)
# define RBIMPL_ATTR_FLAG_ENUM() __attribute__((__flag_enum__))
#else
# define RBIMPL_ATTR_FLAG_ENUM() /* void */
#endif
#endif /* RBIMPLATTR_FLAG_ENUM_H */

View File

@@ -0,0 +1,40 @@
#ifndef RBIMPL_ATTR_FORCEINLINE_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_FORCEINLINE_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_FORCEINLINE.
*/
#include "ruby/internal/compiler_since.h"
#include "ruby/internal/has/attribute.h"
/**
* Wraps (or simulates) `__forceinline`. MSVC complains on declarations like
* `static inline __forceinline void foo()`. It seems MSVC's `inline` and
* `__forceinline` are mutually exclusive. We have to mimic that behaviour for
* non-MSVC compilers.
*/
#if RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
# define RBIMPL_ATTR_FORCEINLINE() __forceinline
#elif RBIMPL_HAS_ATTRIBUTE(always_inline)
# define RBIMPL_ATTR_FORCEINLINE() __attribute__((__always_inline__)) inline
#else
# define RBIMPL_ATTR_FORCEINLINE() inline
#endif
#endif /* RBIMPL_ATTR_FORCEINLINE_H */

View File

@@ -0,0 +1,38 @@
#ifndef RBIMPL_ATTR_FORMAT_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_FORMAT_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_FORMAT.
*/
#include "ruby/internal/has/attribute.h"
/** Wraps (or simulates) `__attribute__((format))` */
#if RBIMPL_HAS_ATTRIBUTE(format)
# define RBIMPL_ATTR_FORMAT(x, y, z) __attribute__((__format__(x, y, z)))
#else
# define RBIMPL_ATTR_FORMAT(x, y, z) /* void */
#endif
#if defined(__MINGW_PRINTF_FORMAT)
# define RBIMPL_PRINTF_FORMAT __MINGW_PRINTF_FORMAT
#else
# define RBIMPL_PRINTF_FORMAT __printf__
#endif
#endif /* RBIMPL_ATTR_FORMAT_H */

View File

@@ -0,0 +1,38 @@
#ifndef RBIMPL_ATTR_MAYBE_UNUSED_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_MAYBE_UNUSED_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_MAYBE_UNUSED.
*/
#include "ruby/internal/has/attribute.h"
#include "ruby/internal/has/c_attribute.h"
#include "ruby/internal/has/cpp_attribute.h"
/** Wraps (or simulates) `[[maybe_unused]]` */
#if RBIMPL_HAS_CPP_ATTRIBUTE(maybe_unused)
# define RBIMPL_ATTR_MAYBE_UNUSED() [[maybe_unused]]
#elif RBIMPL_HAS_C_ATTRIBUTE(maybe_unused)
# define RBIMPL_ATTR_MAYBE_UNUSED() [[maybe_unused]]
#elif RBIMPL_HAS_ATTRIBUTE(unused)
# define RBIMPL_ATTR_MAYBE_UNUSED() __attribute__((__unused__))
#else
# define RBIMPL_ATTR_MAYBE_UNUSED() /* void */
#endif
#endif /* RBIMPL_ATTR_MAYBE_UNUSED */

View File

@@ -0,0 +1,69 @@
#ifndef RBIMPL_ATTR_NOALIAS_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_NOALIAS_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_NOALIAS.
*
* ### Q&A ###
*
* - Q: There are seemingly similar attributes named #RBIMPL_ATTR_CONST,
* #RBIMPL_ATTR_PURE, and #RBIMPL_ATTR_NOALIAS. What are the difference?
*
* - A: Allowed operations are different.
*
* - #RBIMPL_ATTR_CONST ... Functions attributed by this are not allowed to
* read/write _any_ pointers at all (there are exceptional situations
* when reading a pointer is possible but forget that; they are too
* exceptional to be useful). Just remember that everything pointer-
* related are NG.
*
* - #RBIMPL_ATTR_PURE ... Functions attributed by this can read any
* nonvolatile pointers, but no writes are allowed at all. The ability
* to read _any_ nonvolatile pointers makes it possible to mark ::VALUE-
* taking functions as being pure, as long as they are read-only.
*
* - #RBIMPL_ATTR_NOALIAS ... Can both read/write, but only through
* pointers passed to the function as parameters. This is a typical
* situation when you create a C++ non-static member function which only
* concerns `this`. No global variables are allowed to read/write. So
* this is not a super-set of being pure. If you want to read something,
* that has to be passed to the function as a pointer. ::VALUE -taking
* functions thus cannot be attributed as such.
*/
#include "ruby/internal/compiler_since.h"
#include "ruby/internal/has/declspec_attribute.h"
/** Wraps (or simulates) `__declspec((noalias))` */
#if RBIMPL_COMPILER_BEFORE(Clang, 12, 0, 0)
# /*
# * `::llvm::Attribute::ArgMemOnly` was buggy before. Maybe because nobody
# * actually seriously used it. It seems they somehow mitigated the situation
# * in LLVM 12. Still not found the exact changeset which fiexed the
# * attribute, though.
# *
# * :FIXME: others (armclang, xlclang, ...) can also be affected?
# */
# define RBIMPL_ATTR_NOALIAS() /* void */
#elif RBIMPL_HAS_DECLSPEC_ATTRIBUTE(noalias)
# define RBIMPL_ATTR_NOALIAS() __declspec(noalias)
#else
# define RBIMPL_ATTR_NOALIAS() /* void */
#endif
#endif /* RBIMPL_ATTR_NOALIAS_H */

View File

@@ -0,0 +1,45 @@
#ifndef RBIMPL_ATTR_NODISCARD_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_NODISCARD_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_NODISCARD.
*/
#include "ruby/internal/has/attribute.h"
#include "ruby/internal/has/c_attribute.h"
#include "ruby/internal/has/cpp_attribute.h"
/**
* Wraps (or simulates) `[[nodiscard]]`. In C++ (at least since C++20) a
* nodiscard attribute can have a message why the result shall not be ignored.
* However GCC attribute and SAL annotation cannot take them.
*/
#if RBIMPL_HAS_CPP_ATTRIBUTE(nodiscard)
# define RBIMPL_ATTR_NODISCARD() [[nodiscard]]
#elif RBIMPL_HAS_C_ATTRIBUTE(nodiscard)
# define RBIMPL_ATTR_NODISCARD() [[nodiscard]]
#elif RBIMPL_HAS_ATTRIBUTE(warn_unused_result)
# define RBIMPL_ATTR_NODISCARD() __attribute__((__warn_unused_result__))
#elif defined(_Check_return_)
# /* Take SAL definition. */
# define RBIMPL_ATTR_NODISCARD() _Check_return_
#else
# define RBIMPL_ATTR_NODISCARD() /* void */
#endif
#endif /* RBIMPL_ATTR_NODISCARD_H */

View File

@@ -0,0 +1,91 @@
#ifndef RBIMPL_ATTR_NOEXCEPT_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_NOEXCEPT_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_NOEXCEPT.
*
* This isn't actually an attribute in C++ but who cares...
*
* Mainly due to aesthetic reasons, this one is rarely used in the project.
* But can be handy on occasions, especially when a function's noexcept-ness
* depends on its calling functions.
*
* ### Q&A ###
*
* - Q: Can a function that raises Ruby exceptions be attributed `noexcept`?
*
* - A: Yes. `noexcept` is about C++ exceptions, not Ruby's. They don't
* interface each other. You can safely attribute a function that raises
* Ruby exceptions as `noexcept`.
*
* - Q: How, then, can I assert that a function I wrote doesn't raise any Ruby
* exceptions?
*
* - A: `__attribute__((__leaf__))` is for that purpose. A function attributed
* as leaf can still throw C++ exceptions, but not Ruby's. Note however,
* that it's extremely difficult -- if not impossible -- to assert that a
* function doesn't raise any Ruby exceptions at all. Use of that
* attribute is not recommended; mere mortals can't properly use that by
* hand.
*
* - Q: Does it make sense to attribute an inline function `noexcept`?
*
* - A: I thought so before. But no, I don't think they are useful any longer.
*
* - When an inline function attributed `noexcept` actually doesn't throw
* any exceptions at all: these days I don't see any difference in
* generated assembly by adding/removing this attribute. C++ compilers
* get smarter and smarter. Today they can infer if it actually throws
* or not without any annotations by humans (correct me if I'm wrong).
*
* - When an inline function attributed `noexcepr` actually _does_ throw an
* exception: they have to call `std::terminate` then (C++ standard
* mandates so). This means exception handling routines are actually
* enforced, not omitted. This doesn't impact runtime performance (The
* Itanium C++ ABI has zero-cost exception handling), but does impact on
* generated binary size. This is bad.
*/
#include "ruby/internal/compiler_since.h"
#include "ruby/internal/has/feature.h"
/** Wraps (or simulates) C++11 `noexcept` */
#if ! defined(__cplusplus)
# /* Doesn't make sense. */
# define RBIMPL_ATTR_NOEXCEPT(_) /* void */
#elif RBIMPL_HAS_FEATURE(cxx_noexcept)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#elif defined(__GXX_EXPERIMENTAL_CXX0X__) && __GXX_EXPERIMENTAL_CXX0X__
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#elif defined(__INTEL_CXX11_MODE__)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#elif RBIMPL_COMPILER_SINCE(MSVC, 19, 0, 0)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#elif __cplusplus >= 201103L
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#else
# define RBIMPL_ATTR_NOEXCEPT(_) /* void */
#endif
#endif /* RBIMPL_ATTR_NOEXCEPT_H */

View File

@@ -0,0 +1,35 @@
#ifndef RBIMPL_ATTR_NOINLINE_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_ATTR_NOINLINE_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Defines #RBIMPL_ATTR_NOINLINE.
*/
#include "ruby/internal/has/attribute.h"
#include "ruby/internal/has/declspec_attribute.h"
/** Wraps (or simulates) `__declspec(noinline)` */
#if RBIMPL_HAS_DECLSPEC_ATTRIBUTE(noinline)
# define RBIMPL_ATTR_NOINLINE() __declspec(noinline)
#elif RBIMPL_HAS_ATTRIBUTE(noinline)
# define RBIMPL_ATTR_NOINLINE() __attribute__((__noinline__))
#else
# define RBIMPL_ATTR_NOINLINE() /* void */
#endif
#endif /* RBIMPL_ATTR_NOINLINE_H */

Some files were not shown because too many files have changed in this diff Show More