Compare commits
414 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38a7f4f7d5 | ||
|
|
1605959a04 | ||
|
|
b837e0005a | ||
|
|
58937a5366 | ||
|
|
8562c03f80 | ||
|
|
1cd61b9169 | ||
|
|
c69e289afe | ||
|
|
91b46b05ad | ||
|
|
2412760f1c | ||
|
|
d83c5493c7 | ||
|
|
d041703dc6 | ||
|
|
ecba13c38e | ||
|
|
cd3a4bb8c8 | ||
|
|
97f72b93e1 | ||
|
|
e93d57983e | ||
|
|
43c4a3bfdc | ||
|
|
954cc0e8bc | ||
|
|
ad48325dff | ||
|
|
fa1ad20d5d | ||
|
|
0547dede21 | ||
|
|
284ae23db2 | ||
|
|
9105f28c13 | ||
|
|
06cc43b11f | ||
|
|
d879d0d924 | ||
|
|
25bc84817a | ||
|
|
8fb0dfad94 | ||
|
|
c2138037d2 | ||
|
|
fadd64c1e9 | ||
|
|
4552691aed | ||
|
|
bab5c0589f | ||
|
|
2a2c614eb4 | ||
|
|
12529ec81e | ||
|
|
0179609a49 | ||
|
|
860c551aa6 | ||
|
|
1ba3474a5a | ||
|
|
f26c283541 | ||
|
|
56e9dab2ce | ||
|
|
b1fcae5cec | ||
|
|
93245ac37a | ||
|
|
3f795e44c7 | ||
|
|
e732e5158e | ||
|
|
2f5c033f09 | ||
|
|
6099369019 | ||
|
|
8d2b65386c | ||
|
|
ed835225cf | ||
|
|
43c1bc8d5f | ||
|
|
17832fe18c | ||
|
|
252f3f0bd6 | ||
|
|
e042aad819 | ||
|
|
9966daf0cf | ||
|
|
daf5e9cccf | ||
|
|
bf63d731d3 | ||
|
|
12abfc0fcf | ||
|
|
dea1b520f7 | ||
|
|
a5c268491e | ||
|
|
bf34f553bb | ||
|
|
97c61404ca | ||
|
|
c40d9f54a2 | ||
|
|
5e08593358 | ||
|
|
1f06b12f86 | ||
|
|
c7351f724e | ||
|
|
1851bce497 | ||
|
|
5fb8503fd2 | ||
|
|
792716eefc | ||
|
|
15a6c779b8 | ||
|
|
93d24e7106 | ||
|
|
b8a185c112 | ||
|
|
e242e65569 | ||
|
|
62ab33a434 | ||
|
|
f403916ef8 | ||
|
|
38f1585ac6 | ||
|
|
1f757270d9 | ||
|
|
e6de8401bf | ||
|
|
df2e34ac51 | ||
|
|
7bbd3a7e36 | ||
|
|
85a736d49b | ||
|
|
f9eb313f7c | ||
|
|
9cec486a1b | ||
|
|
7734c654a7 | ||
|
|
8e5fff6c5f | ||
|
|
faa9a740db | ||
|
|
70e39e9902 | ||
|
|
9f0b3963cb | ||
|
|
7ec2ce851c | ||
|
|
94ee4223d2 | ||
|
|
a64f4219e9 | ||
|
|
78e96cc312 | ||
|
|
89b111edca | ||
|
|
ec38943c53 | ||
|
|
ea654ef235 | ||
|
|
288b705450 | ||
|
|
73ca579056 | ||
|
|
8b5d7dc181 | ||
|
|
f05f6294cd | ||
|
|
b2c466cf3f | ||
|
|
da1b9a0e91 | ||
|
|
6cbb5a9215 | ||
|
|
cfdbb86bfa | ||
|
|
d61783b2c0 | ||
|
|
65c1e1b9e5 | ||
|
|
17d509a45a | ||
|
|
c7649766fd | ||
|
|
c0ec5e53ba | ||
|
|
a0a18017e8 | ||
|
|
411b84fcc2 | ||
|
|
e499eeb8cc | ||
|
|
803d1de5db | ||
|
|
fc8117c8e7 | ||
|
|
8bef0ede1b | ||
|
|
88128cde48 | ||
|
|
d0217e62f0 | ||
|
|
bba680b636 | ||
|
|
feb914b5c4 | ||
|
|
0a65ea34f3 | ||
|
|
bf299edfc7 | ||
|
|
6b0122547e | ||
|
|
88c0e149b5 | ||
|
|
38091b2021 | ||
|
|
ce87f293aa | ||
|
|
dca028a84f | ||
|
|
be3c4ab24a | ||
|
|
67c9a14902 | ||
|
|
014bdb795f | ||
|
|
df7e8b2e64 | ||
|
|
2b5fdd3548 | ||
|
|
e92a0eb901 | ||
|
|
e72a67f5de | ||
|
|
65dc291ff5 | ||
|
|
0bfc190a86 | ||
|
|
f8303f2e7a | ||
|
|
8ad72b167c | ||
|
|
7747082ae8 | ||
|
|
a7727adca2 | ||
|
|
028b53816d | ||
|
|
5a77117a9b | ||
|
|
05777019c8 | ||
|
|
7ebaad5099 | ||
|
|
09885c8f41 | ||
|
|
4f5ebb279d | ||
|
|
91ebf88c97 | ||
|
|
a608c51e36 | ||
|
|
3877dcf83a | ||
|
|
72d176b77a | ||
|
|
8840968e07 | ||
|
|
b6b889bff6 | ||
|
|
a30bdcbb50 | ||
|
|
82275d49a6 | ||
|
|
ee335de222 | ||
|
|
01bf7c8c38 | ||
|
|
5529a1b0b3 | ||
|
|
363be18599 | ||
|
|
ae8ad3b68b | ||
|
|
348b850e36 | ||
|
|
92c267758e | ||
|
|
b7d1ab6105 | ||
|
|
f7f1b4f594 | ||
|
|
6492bea846 | ||
|
|
b1cb89b0c2 | ||
|
|
7ecd98b0a0 | ||
|
|
7d7d4db329 | ||
|
|
e6bfe1fc88 | ||
|
|
151d3a9610 | ||
|
|
905ed36afd | ||
|
|
7fe9c9366e | ||
|
|
d5237d1a07 | ||
|
|
7bd3b29a11 | ||
|
|
60aa74257f | ||
|
|
ca0492d997 | ||
|
|
944133de6e | ||
|
|
174fdd40da | ||
|
|
ffa823f748 | ||
|
|
a83f7a822e | ||
|
|
29d527bee1 | ||
|
|
75e282c2ac | ||
|
|
8419d9114b | ||
|
|
1c414af7b9 | ||
|
|
834e8c64c5 | ||
|
|
1b3bb86546 | ||
|
|
aa560f42e7 | ||
|
|
4e69cd28cd | ||
|
|
5f0e30e17a | ||
|
|
d682771c35 | ||
|
|
ace3c3e421 | ||
|
|
94005b0c22 | ||
|
|
e9177c8932 | ||
|
|
d62c2d913e | ||
|
|
9ea88fe247 | ||
|
|
e0867a5d11 | ||
|
|
ae91101ea1 | ||
|
|
515057c41a | ||
|
|
d946ba426e | ||
|
|
07874cf77f | ||
|
|
1d9f9e838b | ||
|
|
101691e970 | ||
|
|
e2498c31ea | ||
|
|
9d8c6122cc | ||
|
|
227dda38a2 | ||
|
|
e2091413ea | ||
|
|
4976e82f0f | ||
|
|
5e949d2c6f | ||
|
|
fec7688241 | ||
|
|
2732f6036e | ||
|
|
387c44031a | ||
|
|
6cbd1c5fb1 | ||
|
|
447b9e1ea7 | ||
|
|
be08bcaafc | ||
|
|
1b5e8e0181 | ||
|
|
d2ffbd0395 | ||
|
|
88cb607975 | ||
|
|
e392956e2a | ||
|
|
3028081fa2 | ||
|
|
4003c59471 | ||
|
|
2e042f0c59 | ||
|
|
9a4238d4e2 | ||
|
|
c184dc8d2f | ||
|
|
32f41a04ac | ||
|
|
4b8174f75a | ||
|
|
313e14bc54 | ||
|
|
7aca31992b | ||
|
|
56f53e508f | ||
|
|
6c18dc63aa | ||
|
|
7b498065b5 | ||
|
|
81bd225ff7 | ||
|
|
074090a0aa | ||
|
|
3fcbcca8e4 | ||
|
|
dbaf12b043 | ||
|
|
9eb9b48534 | ||
|
|
e085fd1d57 | ||
|
|
9cc71b320b | ||
|
|
7b74cf1ab9 | ||
|
|
fb0c0e07f7 | ||
|
|
c6bb4a23ae | ||
|
|
70e271959b | ||
|
|
379abeb262 | ||
|
|
9e884847b1 | ||
|
|
5dadf9a087 | ||
|
|
c0630b782a | ||
|
|
62beb73aa2 | ||
|
|
7b6fe0159f | ||
|
|
dad22b1686 | ||
|
|
a715a51865 | ||
|
|
d4ec2319f9 | ||
|
|
88b980ac17 | ||
|
|
867c01d5e8 | ||
|
|
c8a064af3e | ||
|
|
12439f2b99 | ||
|
|
fb47ea301f | ||
|
|
6adecbd7aa | ||
|
|
f71e34fd9f | ||
|
|
dfe89588f0 | ||
|
|
d89b68a279 | ||
|
|
2a4a01cb7b | ||
|
|
c81b7f6bb4 | ||
|
|
0c11afad7a | ||
|
|
d6b26c9975 | ||
|
|
98c628f3eb | ||
|
|
36b2026075 | ||
|
|
7c535ff1a3 | ||
|
|
c6436ea6d1 | ||
|
|
5a8dee3cbe | ||
|
|
d9450d6e12 | ||
|
|
80377b3705 | ||
|
|
847a76b3a2 | ||
|
|
2c3d46bb80 | ||
|
|
e0cb6d4531 | ||
|
|
78f0177ac4 | ||
|
|
4688434c08 | ||
|
|
8913eeb1c1 | ||
|
|
75574e97cc | ||
|
|
f4089bc164 | ||
|
|
b0f04d91bf | ||
|
|
3b514d194c | ||
|
|
3ba405383e | ||
|
|
87f6c8087f | ||
|
|
90a83c8f11 | ||
|
|
27f892a14b | ||
|
|
bf4525d82d | ||
|
|
6bfb1a7fff | ||
|
|
a53ab7438c | ||
|
|
d85a080f9b | ||
|
|
4dbfc9483e | ||
|
|
53097ab183 | ||
|
|
9978a370f1 | ||
|
|
24995f46cb | ||
|
|
7ddc8c6aeb | ||
|
|
4a447f5c12 | ||
|
|
e56647f24d | ||
|
|
25238b53c9 | ||
|
|
1ed798342a | ||
|
|
1d6eb07c62 | ||
|
|
8e3d76b7ea | ||
|
|
d8838503b2 | ||
|
|
78b7742354 | ||
|
|
3d9dca47b8 | ||
|
|
c06c96bc1f | ||
|
|
db128dbc40 | ||
|
|
d6f87a8254 | ||
|
|
4c5f37db0f | ||
|
|
3e5338c902 | ||
|
|
848b7c7a34 | ||
|
|
4bf5dd15e9 | ||
|
|
d4273d8e3f | ||
|
|
780347776b | ||
|
|
5dd6986ad4 | ||
|
|
51bf41009e | ||
|
|
4defe734e2 | ||
|
|
e3cb4ebfdc | ||
|
|
c6345279cc | ||
|
|
e5a9af9a31 | ||
|
|
c0e1e31572 | ||
|
|
1e58c365ed | ||
|
|
bf87b76adb | ||
|
|
c8e06b5837 | ||
|
|
ee5cd06077 | ||
|
|
140352b637 | ||
|
|
b369321e2f | ||
|
|
b9aaba7b16 | ||
|
|
07519732a1 | ||
|
|
ae71f3c186 | ||
|
|
e1236f9deb | ||
|
|
3c9bfb5b4d | ||
|
|
86b50b0a93 | ||
|
|
da6706cb93 | ||
|
|
2842a109da | ||
|
|
021ddefb10 | ||
|
|
7d0b47c5cb | ||
|
|
9351a1f900 | ||
|
|
0ac48369fe | ||
|
|
e57ee17532 | ||
|
|
a897683272 | ||
|
|
38eb981d2c | ||
|
|
b524472b9e | ||
|
|
fc04083cb2 | ||
|
|
b1225951f2 | ||
|
|
24fd2e1849 | ||
|
|
5e5c975a9c | ||
|
|
c6336e920f | ||
|
|
cd19625522 | ||
|
|
3ac95a9213 | ||
|
|
e57ea9b501 | ||
|
|
14b335a51e | ||
|
|
319e746a55 | ||
|
|
eb4d721175 | ||
|
|
a4f850c0c6 | ||
|
|
0a8e25b405 | ||
|
|
1557a76225 | ||
|
|
d4fa379f11 | ||
|
|
e09c5fcb3c | ||
|
|
815fe25f2c | ||
|
|
5e5c84ba27 | ||
|
|
2974b23f26 | ||
|
|
697c21b120 | ||
|
|
1f72a52015 | ||
|
|
43bcf1051d | ||
|
|
bf8aa502f9 | ||
|
|
f0e92343cb | ||
|
|
48efd6689e | ||
|
|
090e689689 | ||
|
|
9d16df5f25 | ||
|
|
02651c93a7 | ||
|
|
2b1d4b6672 | ||
|
|
9087dac6fe | ||
|
|
762ed994c1 | ||
|
|
2c8a9d1160 | ||
|
|
f613316046 | ||
|
|
6b1bc15f37 | ||
|
|
9a77a0c201 | ||
|
|
755cdbb238 | ||
|
|
1996db4b95 | ||
|
|
6297f69e70 | ||
|
|
a796f9f8a8 | ||
|
|
0de9c57ade | ||
|
|
95dc01cdcb | ||
|
|
364d3996f4 | ||
|
|
33af9e878b | ||
|
|
9f8b9ea806 | ||
|
|
d53876ee1b | ||
|
|
4f654e81c8 | ||
|
|
aa33ddcf19 | ||
|
|
c8a57676b4 | ||
|
|
d0d2bc1996 | ||
|
|
2b8d2b0026 | ||
|
|
735953a262 | ||
|
|
1c686f10a1 | ||
|
|
b7088510c5 | ||
|
|
3bdb921ee5 | ||
|
|
74b48ff56b | ||
|
|
9410370cc5 | ||
|
|
743ddf83c1 | ||
|
|
caa707325a | ||
|
|
3c588e67b8 | ||
|
|
6c26dad048 | ||
|
|
393e2c125e | ||
|
|
e56dc2ed6a | ||
|
|
4a449ed85e | ||
|
|
88dbe90075 | ||
|
|
a6f6451434 | ||
|
|
8a4370c1f6 | ||
|
|
7a068450b3 | ||
|
|
ae3222e4c2 | ||
|
|
27b4bfa3fa | ||
|
|
8af229947f | ||
|
|
f235a2f539 | ||
|
|
b0ebb479f6 | ||
|
|
df92e21520 | ||
|
|
a1a25cc57f | ||
|
|
e9aaf8e0af | ||
|
|
7a80e407af | ||
|
|
57f8d535fb | ||
|
|
fcc444a100 | ||
|
|
8ccb3c21e1 | ||
|
|
0484d4bb77 | ||
|
|
3ce9567f62 | ||
|
|
765e812b77 |
74
.github/workflows/doc.yml
vendored
Normal file
74
.github/workflows/doc.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
name: Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "**" ]
|
||||
pull_request:
|
||||
branches: [ "**" ]
|
||||
|
||||
jobs:
|
||||
doc_verify:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install embedme
|
||||
run: npm install -g embedme
|
||||
|
||||
- name: Verify README.md embedded code
|
||||
run: npx embedme --verify README.md
|
||||
|
||||
doc_test:
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macos-latest
|
||||
- ubuntu-24.04
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Install dependencies on macOS
|
||||
if: startsWith(matrix.os, 'macos')
|
||||
run: |
|
||||
set -e
|
||||
set -x
|
||||
source doc/_readme/scripts/install_macos.sh
|
||||
|
||||
- name: Install dependencies on Ubuntu
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
set -e
|
||||
set -x
|
||||
source doc/_readme/scripts/install_ubuntu.sh
|
||||
|
||||
- name: Install llgo
|
||||
run: |
|
||||
set -e
|
||||
set -x
|
||||
git() {
|
||||
if [ "$1" = "clone" ]; then
|
||||
# do nothing because we already have the branch
|
||||
cd ..
|
||||
else
|
||||
command git "$@"
|
||||
fi
|
||||
}
|
||||
source doc/_readme/scripts/install_llgo.sh
|
||||
|
||||
- name: Test doc code blocks
|
||||
run: |
|
||||
set -e
|
||||
set -x
|
||||
source doc/_readme/scripts/run.sh
|
||||
|
||||
61
.github/workflows/go.yml
vendored
61
.github/workflows/go.yml
vendored
@@ -5,11 +5,27 @@ name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "*" ]
|
||||
branches: [ "**" ]
|
||||
pull_request:
|
||||
branches: [ "*" ]
|
||||
branches: [ "**" ]
|
||||
|
||||
jobs:
|
||||
fmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Check formatting
|
||||
run: |
|
||||
if [ -n "$(go fmt ./...)" ]; then
|
||||
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test:
|
||||
strategy:
|
||||
@@ -26,7 +42,8 @@ jobs:
|
||||
if: startsWith(matrix.os, 'macos')
|
||||
run: |
|
||||
brew update
|
||||
brew install llvm@${{matrix.llvm}} pkg-config bdw-gc openssl
|
||||
brew install llvm@${{matrix.llvm}} bdw-gc openssl libffi
|
||||
brew link --force libffi
|
||||
echo "$(brew --prefix llvm@${{matrix.llvm}})/bin" >> $GITHUB_PATH
|
||||
|
||||
# Install optional deps for demos.
|
||||
@@ -45,7 +62,7 @@ jobs:
|
||||
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{matrix.llvm}} main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y llvm-${{matrix.llvm}}-dev clang-${{matrix.llvm}} lld-${{matrix.llvm}} pkg-config libgc-dev libssl-dev zlib1g-dev
|
||||
sudo apt-get install -y llvm-${{matrix.llvm}}-dev clang-${{matrix.llvm}} libclang-${{matrix.llvm}}-dev lld-${{matrix.llvm}} pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev
|
||||
echo "/usr/lib/llvm-${{matrix.llvm}}/bin" >> $GITHUB_PATH
|
||||
|
||||
# Install optional deps for demos.
|
||||
@@ -65,7 +82,7 @@ jobs:
|
||||
numpy # for github.com/goplus/llgo/py/numpy
|
||||
torch # for github.com/goplus/llgo/py/torch
|
||||
)
|
||||
pip3 install --break-system-packages "${py_deps[@]}"
|
||||
pip3.12 install --break-system-packages "${py_deps[@]}"
|
||||
|
||||
- name: Clang information
|
||||
run: |
|
||||
@@ -81,6 +98,9 @@ jobs:
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
- name: Install
|
||||
run: go install ./...
|
||||
|
||||
- name: Test
|
||||
if: ${{!startsWith(matrix.os, 'macos')}}
|
||||
run: go test -v ./...
|
||||
@@ -89,31 +109,48 @@ jobs:
|
||||
if: startsWith(matrix.os, 'macos')
|
||||
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
||||
|
||||
- name: Install
|
||||
run: go install ./...
|
||||
|
||||
- name: LLGO tests
|
||||
if: ${{!startsWith(matrix.os, 'ubuntu')}}
|
||||
run: |
|
||||
echo "Test result on ${{matrix.os}} with LLVM ${{matrix.llvm}}" > result.md
|
||||
bash .github/workflows/test_llgo.sh
|
||||
|
||||
- name: chore/_xtool build tests
|
||||
run: |
|
||||
cd chore/_xtool
|
||||
llgo build -v ./...
|
||||
|
||||
- name: LLDB tests
|
||||
if: ${{startsWith(matrix.os, 'macos')}}
|
||||
run: |
|
||||
echo "Test lldb with llgo plugin on ${{matrix.os}} with LLVM ${{matrix.llvm}}"
|
||||
bash _lldb/runtest.sh -v
|
||||
|
||||
- name: Test demos
|
||||
continue-on-error: true
|
||||
run: bash .github/workflows/test_demo.sh
|
||||
run: |
|
||||
# TODO(lijie): force python3-embed to be linked with python-3.12-embed
|
||||
# Currently, python3-embed is python-3.13-embed, doesn't work with pytorch
|
||||
# Will remove this after pytorch is fixed.
|
||||
pcdir=$HOME/pc
|
||||
mkdir -p $pcdir
|
||||
libdir=$(pkg-config --variable=libdir python-3.12-embed)
|
||||
echo "libdir: $libdir"
|
||||
ln -s $libdir/pkgconfig/python-3.12-embed.pc $pcdir/python3-embed.pc
|
||||
export PKG_CONFIG_PATH=$pcdir
|
||||
bash .github/workflows/test_demo.sh
|
||||
|
||||
- name: Show test result
|
||||
run: cat result.md
|
||||
|
||||
- name: PR comment with test result
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
if: false
|
||||
with:
|
||||
filePath: result.md
|
||||
comment_tag: test-result-on-${{matrix.os}}-with-llvm-${{matrix.llvm}}
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{secrets.CODECOV_TOKEN}}
|
||||
slug: goplus/llgo
|
||||
|
||||
6
.github/workflows/test_demo.sh
vendored
6
.github/workflows/test_demo.sh
vendored
@@ -1,13 +1,13 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# llgo run subdirectories under _demo and _pydemo
|
||||
# llgo run subdirectories under _demo and _pydemo that contain *.go files
|
||||
total=0
|
||||
failed=0
|
||||
failed_cases=""
|
||||
for d in ./_demo/* ./_pydemo/*; do
|
||||
total=$((total+1))
|
||||
if [ -d "$d" ]; then
|
||||
if [ -d "$d" ] && [ -n "$(ls "$d"/*.go 2>/dev/null)" ]; then
|
||||
total=$((total+1))
|
||||
echo "Testing $d"
|
||||
if ! (cd "$d" && llgo run .); then
|
||||
echo "FAIL"
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,6 +26,9 @@ build.dir/
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Debug symbols
|
||||
*.dSYM
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
*.swp
|
||||
|
||||
27
README.md
27
README.md
@@ -47,6 +47,8 @@ You can import a C/C++ standard library in LLGo!
|
||||
|
||||
Here is a simple example:
|
||||
|
||||
<!-- embedme doc/_readme/llgo_simple/simple.go -->
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -77,6 +79,8 @@ llgo run .
|
||||
|
||||
LLGo use `go:linkname` to link an extern symbol througth its ABI:
|
||||
|
||||
<!-- embedme doc/_readme/llgo_call_c/call_c.go#L3-L6 -->
|
||||
|
||||
```go
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
@@ -86,6 +90,8 @@ func Sqrt(x float64) float64
|
||||
|
||||
You can directly integrate it into [your own code](_demo/linkname/linkname.go):
|
||||
|
||||
<!-- embedme doc/_readme/llgo_call_c/call_c.go -->
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -101,6 +107,8 @@ func main() {
|
||||
|
||||
Or put it into a package (see [c/math](c/math/math.go)):
|
||||
|
||||
<!-- embedme doc/_readme/llgo_call_cmath/call_cmath.go -->
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -135,6 +143,8 @@ Note: For third-party libraries (such as pandas and pytorch), you still need to
|
||||
|
||||
Here is an example:
|
||||
|
||||
<!-- embedme doc/_readme/llgo_call_py/call_py.go -->
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -152,6 +162,8 @@ func main() {
|
||||
|
||||
It is equivalent to the following Python code:
|
||||
|
||||
<!-- embedme doc/_readme/llgo_call_py/call_math.py -->
|
||||
|
||||
```py
|
||||
import math
|
||||
|
||||
@@ -163,6 +175,8 @@ Here, We call `py.Float(2)` to create a Python number 2, and pass it to Python
|
||||
|
||||
Let's look at a slightly more complex example. For example, we use `numpy` to calculate:
|
||||
|
||||
<!-- embedme doc/_readme/llgo_py_list/py_list.go -->
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -340,20 +354,26 @@ Follow these steps to generate the `llgo` command (its usage is the same as the
|
||||
|
||||
### on macOS
|
||||
|
||||
<!-- embedme doc/_readme/scripts/install_macos.sh#L2-L1000 -->
|
||||
|
||||
```sh
|
||||
brew update
|
||||
brew install llvm@18 pkg-config bdw-gc openssl
|
||||
brew install llvm@18 bdw-gc openssl cjson libffi
|
||||
brew install python@3.12 # optional
|
||||
brew link --force libffi
|
||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||
|
||||
```
|
||||
|
||||
### on Linux (Debian/Ubuntu)
|
||||
|
||||
<!-- embedme doc/_readme/scripts/install_ubuntu.sh#L2-L1000 -->
|
||||
|
||||
```sh
|
||||
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-18 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y llvm-18-dev clang-18 lld-18 pkg-config libgc-dev libssl-dev zlib1g-dev
|
||||
sudo apt-get install -y llvm-18-dev clang-18 libclang-18-dev lld-18 pkg-config libgc-dev libssl-dev zlib1g-dev libcjson-dev libsqlite3-dev
|
||||
sudo apt-get install -y python3.12-dev # optional
|
||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||
```
|
||||
@@ -373,9 +393,12 @@ TODO
|
||||
|
||||
How do I generate these tools?
|
||||
|
||||
<!-- embedme doc/_readme/scripts/install_llgo.sh#L2-L1000 -->
|
||||
|
||||
```sh
|
||||
git clone https://github.com/goplus/llgo.git
|
||||
cd llgo
|
||||
go install -v ./cmd/...
|
||||
go install -v ./chore/... # compile all tools except pydump
|
||||
cd chore/_xtool
|
||||
llgo install ./... # compile pydump
|
||||
|
||||
31
_demo/async/async/async.go
Normal file
31
_demo/async/async/async.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package async
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type Void = [0]byte
|
||||
|
||||
type Future[T any] interface {
|
||||
Then(cb func(T))
|
||||
}
|
||||
|
||||
type future[T any] struct {
|
||||
cb func(func(T))
|
||||
}
|
||||
|
||||
func (f *future[T]) Then(cb func(T)) {
|
||||
f.cb(cb)
|
||||
}
|
||||
|
||||
func Async[T any](fn func(func(T))) Future[T] {
|
||||
return &future[T]{fn}
|
||||
}
|
||||
|
||||
func Run[T any](future Future[T]) T {
|
||||
var ret T
|
||||
future.Then(func(v T) {
|
||||
ret = v
|
||||
})
|
||||
return ret
|
||||
}
|
||||
23
_demo/async/main.go
Normal file
23
_demo/async/main.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/goplus/llgo/_demo/async/async"
|
||||
"github.com/goplus/llgo/_demo/async/timeout"
|
||||
)
|
||||
|
||||
func Sleep(i int, d time.Duration) async.Future[int] {
|
||||
return async.Async(func(resolve func(int)) {
|
||||
timeout.Timeout(d).Then(func(async.Void) {
|
||||
resolve(i)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func main() {
|
||||
async.Run(async.Async(func(resolve func(async.Void)) {
|
||||
println("read file")
|
||||
defer resolve(async.Void{})
|
||||
}))
|
||||
}
|
||||
16
_demo/async/timeout/timeout.go
Normal file
16
_demo/async/timeout/timeout.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package timeout
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/goplus/llgo/_demo/async/async"
|
||||
)
|
||||
|
||||
func Timeout(d time.Duration) async.Future[async.Void] {
|
||||
return async.Async(func(resolve func(async.Void)) {
|
||||
go func() {
|
||||
time.Sleep(d)
|
||||
resolve(async.Void{})
|
||||
}()
|
||||
})
|
||||
}
|
||||
55
_demo/cgobasic/cgobasic.go
Normal file
55
_demo/cgobasic/cgobasic.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// C.CString example
|
||||
cstr := C.CString("Hello, World!")
|
||||
C.puts(cstr)
|
||||
|
||||
// C.CBytes example
|
||||
bytes := []byte{65, 66, 67, 68} // ABCD
|
||||
cbytes := C.CBytes(bytes)
|
||||
|
||||
// C.GoString example
|
||||
gostr := C.GoString(cstr)
|
||||
println("Converted back to Go string: ", gostr)
|
||||
|
||||
// C.GoStringN example (with length limit)
|
||||
gostringN := C.GoStringN(cstr, 5) // only take first 5 characters
|
||||
println("Length-limited string: ", gostringN)
|
||||
|
||||
// C.GoBytes example
|
||||
gobytes := C.GoBytes(cbytes, 4) // 4 is the length
|
||||
println("Converted back to Go byte slice: ", gobytes)
|
||||
|
||||
// C math library examples
|
||||
x := 2.0
|
||||
// Calculate square root
|
||||
sqrtResult := C.sqrt(C.double(x))
|
||||
fmt.Printf("sqrt(%v) = %v\n", x, float64(sqrtResult))
|
||||
|
||||
// Calculate sine
|
||||
sinResult := C.sin(C.double(x))
|
||||
fmt.Printf("sin(%v) = %v\n", x, float64(sinResult))
|
||||
|
||||
// Calculate cosine
|
||||
cosResult := C.cos(C.double(x))
|
||||
fmt.Printf("cos(%v) = %v\n", x, float64(cosResult))
|
||||
|
||||
// Calculate natural logarithm
|
||||
logResult := C.log(C.double(x))
|
||||
fmt.Printf("log(%v) = %v\n", x, float64(logResult))
|
||||
|
||||
C.free(unsafe.Pointer(cstr))
|
||||
C.free(cbytes)
|
||||
}
|
||||
15
_demo/cgocfiles/cgocfiles.go
Normal file
15
_demo/cgocfiles/cgocfiles.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#include "in.h"
|
||||
*/
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
r := C.test_structs(&C.s4{a: 1}, &C.s8{a: 1, b: 2}, &C.s12{a: 1, b: 2, c: 3}, &C.s16{a: 1, b: 2, c: 3, d: 4}, &C.s20{a: 1, b: 2, c: 3, d: 4, e: 5})
|
||||
fmt.Println(r)
|
||||
if r != 35 {
|
||||
panic("test_structs failed")
|
||||
}
|
||||
}
|
||||
12
_demo/cgocfiles/in.c
Normal file
12
_demo/cgocfiles/in.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include "in.h"
|
||||
|
||||
int test_structs(s4* s4, s8* s8, s12* s12, s16* s16, s20* s20) {
|
||||
printf("s4.a: %d\n", s4->a);
|
||||
printf("s8.a: %d, s8.b: %d\n", s8->a, s8->b);
|
||||
printf("s12.a: %d, s12.b: %d, s12.c: %d\n", s12->a, s12->b, s12->c);
|
||||
printf("s16.a: %d, s16.b: %d, s16.c: %d, s16.d: %d\n", s16->a, s16->b, s16->c, s16->d);
|
||||
printf("s20.a: %d, s20.b: %d, s20.c: %d, s20.d: %d, s20.e: %d\n", s20->a, s20->b, s20->c, s20->d, s20->e);
|
||||
|
||||
return s4->a + s8->a + s8->b + s12->a + s12->b + s12->c + s16->a + s16->b + s16->c + s16->d + s20->a + s20->b + s20->c + s20->d + s20->e;
|
||||
}
|
||||
33
_demo/cgocfiles/in.h
Normal file
33
_demo/cgocfiles/in.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
} s4;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} s8;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} s12;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
} s16;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
int e;
|
||||
} s20;
|
||||
|
||||
extern int test_structs(s4* s4, s8* s8, s12* s12, s16* s16, s20* s20);
|
||||
11
_demo/cgodefer/cgodefer.go
Normal file
11
_demo/cgodefer/cgodefer.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
p := C.malloc(1024)
|
||||
defer C.free(p)
|
||||
}
|
||||
16
_demo/cgofull/bar.go
Normal file
16
_demo/cgofull/bar.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DBAR
|
||||
#include <stdio.h>
|
||||
#include "foo.h"
|
||||
static void foo(Foo* f) {
|
||||
printf("foo in bar: %d\n", f->a);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func Bar(f *C.Foo) {
|
||||
C.print_foo(f)
|
||||
C.foo(f)
|
||||
}
|
||||
95
_demo/cgofull/cgofull.go
Normal file
95
_demo/cgofull/cgofull.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo windows,!amd64 CFLAGS: -D_WIN32
|
||||
#cgo !windows CFLAGS: -D_POSIX
|
||||
#cgo windows,amd64 CFLAGS: -D_WIN64
|
||||
#cgo linux,amd64 CFLAGS: -D_LINUX64
|
||||
#cgo !windows,amd64 CFLAGS: -D_UNIX64
|
||||
#include <stdio.h>
|
||||
#include "foo.h"
|
||||
typedef struct {
|
||||
int a;
|
||||
} s4;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} s8;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} s12;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
} s16;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
int e;
|
||||
} s20;
|
||||
|
||||
static int test_structs(s4* s4, s8* s8, s12* s12, s16* s16, s20* s20) {
|
||||
printf("s4.a: %d\n", s4->a);
|
||||
printf("s8.a: %d, s8.b: %d\n", s8->a, s8->b);
|
||||
printf("s12.a: %d, s12.b: %d, s12.c: %d\n", s12->a, s12->b, s12->c);
|
||||
printf("s16.a: %d, s16.b: %d, s16.c: %d, s16.d: %d\n", s16->a, s16->b, s16->c, s16->d);
|
||||
printf("s20.a: %d, s20.b: %d, s20.c: %d, s20.d: %d, s20.e: %d\n", s20->a, s20->b, s20->c, s20->d, s20->e);
|
||||
|
||||
return s4->a + s8->a + s8->b + s12->a + s12->b + s12->c + s16->a + s16->b + s16->c + s16->d + s20->a + s20->b + s20->c + s20->d + s20->e;
|
||||
}
|
||||
|
||||
static void test_macros() {
|
||||
#ifdef FOO
|
||||
printf("FOO is defined\n");
|
||||
#endif
|
||||
#ifdef BAR
|
||||
printf("BAR is defined\n");
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
printf("WIN32 is defined\n");
|
||||
#endif
|
||||
#ifdef _POSIX
|
||||
printf("POSIX is defined\n");
|
||||
#endif
|
||||
#ifdef _WIN64
|
||||
printf("WIN64 is defined\n");
|
||||
#endif
|
||||
#ifdef _LINUX64
|
||||
printf("LINUX64 is defined\n");
|
||||
#endif
|
||||
#ifdef _UNIX64
|
||||
printf("UNIX64 is defined\n");
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
runPy()
|
||||
f := &C.Foo{a: 1}
|
||||
Foo(f)
|
||||
Bar(f)
|
||||
C.test_macros()
|
||||
r := C.test_structs(&C.s4{a: 1}, &C.s8{a: 1, b: 2}, &C.s12{a: 1, b: 2, c: 3}, &C.s16{a: 1, b: 2, c: 3, d: 4}, &C.s20{a: 1, b: 2, c: 3, d: 4, e: 5})
|
||||
fmt.Println(r)
|
||||
if r != 35 {
|
||||
panic("test_structs failed")
|
||||
}
|
||||
}
|
||||
|
||||
func runPy() {
|
||||
Initialize()
|
||||
defer Finalize()
|
||||
Run("print('Hello, Python!')")
|
||||
}
|
||||
6
_demo/cgofull/foo.c
Normal file
6
_demo/cgofull/foo.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include "foo.h"
|
||||
|
||||
void print_foo(Foo* f) {
|
||||
printf("print_foo: %d\n", f->a);
|
||||
}
|
||||
16
_demo/cgofull/foo.go
Normal file
16
_demo/cgofull/foo.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DFOO
|
||||
#include <stdio.h>
|
||||
#include "foo.h"
|
||||
static void foo(Foo* f) {
|
||||
printf("foo in bar: %d\n", f->a);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func Foo(f *C.Foo) {
|
||||
C.print_foo(f)
|
||||
C.foo(f)
|
||||
}
|
||||
7
_demo/cgofull/foo.h
Normal file
7
_demo/cgofull/foo.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
} Foo;
|
||||
|
||||
extern void print_foo(Foo* f);
|
||||
24
_demo/cgofull/py.go
Normal file
24
_demo/cgofull/py.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo pkg-config: python3-embed
|
||||
#include <Python.h>
|
||||
*/
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
func Initialize() {
|
||||
C.Py_Initialize()
|
||||
}
|
||||
|
||||
func Finalize() {
|
||||
C.Py_Finalize()
|
||||
}
|
||||
|
||||
func Run(code string) error {
|
||||
if C.PyRun_SimpleString(C.CString(code)) != 0 {
|
||||
C.PyErr_Print()
|
||||
return fmt.Errorf("failed to run code")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
13
_demo/cgopython/cgopython.go
Normal file
13
_demo/cgopython/cgopython.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo pkg-config: python3-embed
|
||||
#include <Python.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
C.Py_Initialize()
|
||||
defer C.Py_Finalize()
|
||||
C.PyRun_SimpleString(C.CString("print('Hello, Python!')"))
|
||||
}
|
||||
28
_demo/checkfile/demo.go
Normal file
28
_demo/checkfile/demo.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tempDir := os.TempDir()
|
||||
noexist := filepath.Join(tempDir, "noexist.txt")
|
||||
|
||||
if _, err := os.Stat(noexist); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Println("noexist:", err.Error())
|
||||
} else {
|
||||
fmt.Println("exist,other err:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Open(noexist); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Println("noexist:", err.Error())
|
||||
} else {
|
||||
fmt.Println("exist,other err:", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
41
_demo/reflectfunc/reflectfunc.go
Normal file
41
_demo/reflectfunc/reflectfunc.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func add(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
func main() {
|
||||
fn := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var i int
|
||||
fn1 := func() {
|
||||
i++
|
||||
}
|
||||
fn2 := func() func() {
|
||||
return func() {
|
||||
println("closure", i)
|
||||
}
|
||||
}
|
||||
fns := []any{add, fn, fn1, fn2}
|
||||
for _, fn := range fns {
|
||||
v := reflect.ValueOf(fn)
|
||||
fmt.Println(v.Type())
|
||||
fmt.Println(v.Kind())
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("not func: %T", fn))
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
fmt.Println(t)
|
||||
fmt.Println(t.Kind())
|
||||
if t.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("not func: %T", fn))
|
||||
}
|
||||
}
|
||||
}
|
||||
31
_demo/syncdebug/syncdebug.go
Normal file
31
_demo/syncdebug/syncdebug.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
llsync "github.com/goplus/llgo/c/pthread/sync"
|
||||
)
|
||||
|
||||
type L struct {
|
||||
mu sync.Mutex
|
||||
s string
|
||||
i int
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func main() {
|
||||
l := &L{s: "hello", i: 123, w: os.Stdout}
|
||||
println("sizeof(L):", unsafe.Sizeof(L{}))
|
||||
println("sizeof(sync.Mutex):", unsafe.Sizeof(sync.Mutex{}))
|
||||
println("sizeof(llsync.Mutex):", unsafe.Sizeof(llsync.Mutex{}))
|
||||
println("l:", l, "l.s:", l.s, "l.i:", l.i, "l.w:", l.w)
|
||||
l.mu.Lock()
|
||||
println("locked")
|
||||
println("l:", l, "l.s:", l.s, "l.i:", l.i, "l.w:", l.w)
|
||||
l.w.Write([]byte(l.s))
|
||||
l.w.Write([]byte("\n"))
|
||||
l.mu.Unlock()
|
||||
}
|
||||
115
_lldb/README.md
Normal file
115
_lldb/README.md
Normal file
@@ -0,0 +1,115 @@
|
||||
## LLGo Plugin of LLDB
|
||||
|
||||
### Build with debug info
|
||||
|
||||
```shell
|
||||
LLGO_DEBUG=1 llgo build -o cl/_testdata/debug/out ./cl/_testdata/debug
|
||||
```
|
||||
|
||||
### Debug with lldb
|
||||
|
||||
```shell
|
||||
_lldb/runlldb.sh ./cl/_testdata/debug/out
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```shell
|
||||
/opt/homebrew/bin/lldb -O "command script import _lldb/llgo_plugin.py" ./cl/_testdata/debug/out
|
||||
# github.com/goplus/llgo/cl/_testdata/debug
|
||||
Breakpoint 1: no locations (pending).
|
||||
Breakpoint set in dummy target, will get copied into future targets.
|
||||
(lldb) command script import _lldb/llgo_plugin.py
|
||||
(lldb) target create "./cl/_testdata/debug/out"
|
||||
Current executable set to '/Users/lijie/source/goplus/llgo/cl/_testdata/debug/out' (arm64).
|
||||
(lldb) r
|
||||
Process 21992 launched: '/Users/lijie/source/goplus/llgo/cl/_testdata/debug/out' (arm64)
|
||||
globalInt: 301
|
||||
s: 0x100123e40
|
||||
0x100123be0
|
||||
5 8
|
||||
called function with struct
|
||||
1 2 3 4 5 6 7 8 9 10 +1.100000e+01 +1.200000e+01 true (+1.300000e+01+1.400000e+01i) (+1.500000e+01+1.600000e+01i) [3/3]0x1001129a0 [3/3]0x100112920 hello 0x1001149b0 0x100123ab0 0x100123d10 0x1001149e0 (0x100116810,0x1001149d0) 0x10011bf00 0x10010fa80 (0x100116840,0x100112940) 0x10001b4a4
|
||||
9
|
||||
1 (0x1001167e0,0x100112900)
|
||||
called function with types
|
||||
0x100123e40
|
||||
0x1000343d0
|
||||
Process 21992 stopped
|
||||
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
|
||||
frame #0: 0x000000010001b3b4 out`main at in.go:225:12
|
||||
222 // s.i8: '\x01'
|
||||
223 // s.i16: 2
|
||||
224 s.i8 = 0x12
|
||||
-> 225 println(s.i8)
|
||||
226 // Expected:
|
||||
227 // all variables: globalInt globalStruct globalStructPtr s i err
|
||||
228 // s.i8: '\x12'
|
||||
(lldb) v
|
||||
var i int = <variable not available>
|
||||
var s github.com/goplus/llgo/cl/_testdata/debug.StructWithAllTypeFields = {
|
||||
i8 = '\x12',
|
||||
i16 = 2,
|
||||
i32 = 3,
|
||||
i64 = 4,
|
||||
i = 5,
|
||||
u8 = '\x06',
|
||||
u16 = 7,
|
||||
u32 = 8,
|
||||
u64 = 9,
|
||||
u = 10,
|
||||
f32 = 11,
|
||||
f64 = 12,
|
||||
b = true,
|
||||
c64 = {real = 13, imag = 14},
|
||||
c128 = {real = 15, imag = 16},
|
||||
slice = []int{21, 22, 23},
|
||||
arr = [3]int{24, 25, 26},
|
||||
arr2 = [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}},
|
||||
s = "hello",
|
||||
e = {i = 30},
|
||||
pf = 0x0000000100123d10,
|
||||
pi = 0x00000001001149e0,
|
||||
intr = {type = 0x0000000100116810, data = 0x00000001001149d0},
|
||||
m = {count = 4296130304},
|
||||
c = {},
|
||||
err = {type = 0x0000000100116840, data = 0x0000000100112940},
|
||||
fn = {f = 0x000000010001b4a4, data = 0x00000001001149c0},
|
||||
pad1 = 100,
|
||||
pad2 = 200
|
||||
}
|
||||
var globalStructPtr *github.com/goplus/llgo/cl/_testdata/debug.StructWithAllTypeFields = <variable not available>
|
||||
var globalStruct github.com/goplus/llgo/cl/_testdata/debug.StructWithAllTypeFields = {
|
||||
i8 = '\x01',
|
||||
i16 = 2,
|
||||
i32 = 3,
|
||||
i64 = 4,
|
||||
i = 5,
|
||||
u8 = '\x06',
|
||||
u16 = 7,
|
||||
u32 = 8,
|
||||
u64 = 9,
|
||||
u = 10,
|
||||
f32 = 11,
|
||||
f64 = 12,
|
||||
b = true,
|
||||
c64 = {real = 13, imag = 14},
|
||||
c128 = {real = 15, imag = 16},
|
||||
slice = []int{21, 22, 23},
|
||||
arr = [3]int{24, 25, 26},
|
||||
arr2 = [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}},
|
||||
s = "hello",
|
||||
e = {i = 30},
|
||||
pf = 0x0000000100123d10,
|
||||
pi = 0x00000001001149e0,
|
||||
intr = {type = 0x0000000100116810, data = 0x00000001001149d0},
|
||||
m = {count = 4296130304},
|
||||
c = {},
|
||||
err = {type = 0x0000000100116840, data = 0x0000000100112940},
|
||||
fn = {f = 0x000000010001b4a4, data = 0x00000001001149c0},
|
||||
pad1 = 100,
|
||||
pad2 = 200
|
||||
}
|
||||
var globalInt int = 301
|
||||
var err error = {type = 0x0000000100112900, data = 0x000000000000001a}
|
||||
```
|
||||
40
_lldb/common.sh
Normal file
40
_lldb/common.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to find LLDB 18+
|
||||
find_lldb() {
|
||||
local lldb_paths=(
|
||||
"/opt/homebrew/bin/lldb"
|
||||
"/usr/local/bin/lldb"
|
||||
"/usr/bin/lldb"
|
||||
"lldb" # This will use the system PATH
|
||||
)
|
||||
|
||||
for lldb_path in "${lldb_paths[@]}"; do
|
||||
if command -v "$lldb_path" >/dev/null 2>&1; then
|
||||
local version
|
||||
version=$("$lldb_path" --version | grep -oE '[0-9]+' | head -1)
|
||||
if [ "$version" -ge 18 ]; then
|
||||
echo "$lldb_path"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Error: LLDB 18 or higher not found" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find LLDB 18+
|
||||
LLDB_PATH=$(find_lldb)
|
||||
echo "LLDB_PATH: $LLDB_PATH"
|
||||
$LLDB_PATH --version
|
||||
export LLDB_PATH
|
||||
|
||||
# Default package path
|
||||
export DEFAULT_PACKAGE_PATH="./cl/_testdata/debug"
|
||||
|
||||
# Function to build the project
|
||||
build_project() {
|
||||
local package_path="$1"
|
||||
LLGO_DEBUG=1 go run ./cmd/llgo build -o "${package_path}/debug.out" "${package_path}"
|
||||
}
|
||||
297
_lldb/llgo_plugin.py
Normal file
297
_lldb/llgo_plugin.py
Normal file
@@ -0,0 +1,297 @@
|
||||
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
|
||||
|
||||
from typing import List, Optional, Dict, Any, Tuple
|
||||
import re
|
||||
import lldb
|
||||
|
||||
|
||||
def log(*args: Any, **kwargs: Any) -> None:
|
||||
print(*args, **kwargs, flush=True)
|
||||
|
||||
|
||||
def __lldb_init_module(debugger: lldb.SBDebugger, _: Dict[str, Any]) -> None:
|
||||
debugger.HandleCommand(
|
||||
'command script add -f llgo_plugin.print_go_expression p')
|
||||
debugger.HandleCommand(
|
||||
'command script add -f llgo_plugin.print_all_variables v')
|
||||
|
||||
|
||||
def is_llgo_compiler(_target: lldb.SBTarget) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def get_indexed_value(value: lldb.SBValue, index: int) -> Optional[lldb.SBValue]:
|
||||
if not value or not value.IsValid():
|
||||
return None
|
||||
|
||||
type_name = value.GetType().GetName()
|
||||
|
||||
if type_name.startswith('[]'): # Slice
|
||||
data_ptr = value.GetChildMemberWithName('data')
|
||||
element_type = data_ptr.GetType().GetPointeeType()
|
||||
element_size = element_type.GetByteSize()
|
||||
ptr_value = int(data_ptr.GetValue(), 16)
|
||||
element_address = ptr_value + index * element_size
|
||||
target = value.GetTarget()
|
||||
return target.CreateValueFromAddress(
|
||||
f"element_{index}", lldb.SBAddress(element_address, target), element_type)
|
||||
elif value.GetType().IsArrayType(): # Array
|
||||
return value.GetChildAtIndex(index)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def evaluate_expression(frame: lldb.SBFrame, expression: str) -> Optional[lldb.SBValue]:
|
||||
parts = re.findall(r'\*|\w+|\(|\)|\[.*?\]|\.', expression)
|
||||
|
||||
def evaluate_part(i: int) -> Tuple[Optional[lldb.SBValue], int]:
|
||||
nonlocal parts
|
||||
value: Optional[lldb.SBValue] = None
|
||||
while i < len(parts):
|
||||
part = parts[i]
|
||||
|
||||
if part == '*':
|
||||
sub_value, i = evaluate_part(i + 1)
|
||||
if sub_value and sub_value.IsValid():
|
||||
value = sub_value.Dereference()
|
||||
else:
|
||||
return None, i
|
||||
elif part == '(':
|
||||
depth = 1
|
||||
j = i + 1
|
||||
while j < len(parts) and depth > 0:
|
||||
if parts[j] == '(':
|
||||
depth += 1
|
||||
elif parts[j] == ')':
|
||||
depth -= 1
|
||||
j += 1
|
||||
value, i = evaluate_part(i + 1)
|
||||
i = j - 1
|
||||
elif part == ')':
|
||||
return value, i + 1
|
||||
elif part == '.':
|
||||
if value is None:
|
||||
value = frame.FindVariable(parts[i+1])
|
||||
else:
|
||||
value = value.GetChildMemberWithName(parts[i+1])
|
||||
i += 2
|
||||
elif part.startswith('['):
|
||||
index = int(part[1:-1])
|
||||
value = get_indexed_value(value, index)
|
||||
i += 1
|
||||
else:
|
||||
if value is None:
|
||||
value = frame.FindVariable(part)
|
||||
else:
|
||||
value = value.GetChildMemberWithName(part)
|
||||
i += 1
|
||||
|
||||
if not value or not value.IsValid():
|
||||
return None, i
|
||||
|
||||
return value, i
|
||||
|
||||
value, _ = evaluate_part(0)
|
||||
return value
|
||||
|
||||
|
||||
def print_go_expression(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, _internal_dict: Dict[str, Any]) -> None:
|
||||
frame = debugger.GetSelectedTarget().GetProcess(
|
||||
).GetSelectedThread().GetSelectedFrame()
|
||||
value = evaluate_expression(frame, command)
|
||||
if value and value.IsValid():
|
||||
result.AppendMessage(format_value(value, debugger))
|
||||
else:
|
||||
result.AppendMessage(
|
||||
f"Error: Unable to evaluate expression '{command}'")
|
||||
|
||||
|
||||
def print_all_variables(debugger: lldb.SBDebugger, _command: str, result: lldb.SBCommandReturnObject, _internal_dict: Dict[str, Any]) -> None:
|
||||
target = debugger.GetSelectedTarget()
|
||||
if not is_llgo_compiler(target):
|
||||
result.AppendMessage("Not a LLGo compiled binary.")
|
||||
return
|
||||
|
||||
frame = debugger.GetSelectedTarget().GetProcess(
|
||||
).GetSelectedThread().GetSelectedFrame()
|
||||
variables = frame.GetVariables(True, True, True, True)
|
||||
|
||||
output: List[str] = []
|
||||
for var in variables:
|
||||
type_name = map_type_name(var.GetType().GetName())
|
||||
formatted = format_value(var, debugger, include_type=False, indent=0)
|
||||
output.append(f"var {var.GetName()} {type_name} = {formatted}")
|
||||
|
||||
result.AppendMessage("\n".join(output))
|
||||
|
||||
|
||||
def is_pointer(frame: lldb.SBFrame, var_name: str) -> bool:
|
||||
var = frame.FindVariable(var_name)
|
||||
return var.IsValid() and var.GetType().IsPointerType()
|
||||
|
||||
|
||||
def format_value(var: lldb.SBValue, debugger: lldb.SBDebugger, include_type: bool = True, indent: int = 0) -> str:
|
||||
if not var.IsValid():
|
||||
return "<variable not available>"
|
||||
|
||||
var_type = var.GetType()
|
||||
type_class = var_type.GetTypeClass()
|
||||
type_name = map_type_name(var_type.GetName())
|
||||
|
||||
# Handle typedef types
|
||||
original_type_name = type_name
|
||||
while var_type.IsTypedefType():
|
||||
var_type = var_type.GetTypedefedType()
|
||||
type_name = map_type_name(var_type.GetName())
|
||||
type_class = var_type.GetTypeClass()
|
||||
|
||||
if var_type.IsPointerType():
|
||||
return format_pointer(var, debugger, indent, original_type_name)
|
||||
|
||||
if type_name.startswith('[]'): # Slice
|
||||
return format_slice(var, debugger, indent)
|
||||
elif var_type.IsArrayType():
|
||||
return format_array(var, debugger, indent)
|
||||
elif type_name == 'string': # String
|
||||
return format_string(var)
|
||||
elif type_class in [lldb.eTypeClassStruct, lldb.eTypeClassClass]:
|
||||
return format_struct(var, debugger, include_type, indent, original_type_name)
|
||||
else:
|
||||
value = var.GetValue()
|
||||
summary = var.GetSummary()
|
||||
if value is not None:
|
||||
return f"{value}" if include_type else str(value)
|
||||
elif summary is not None:
|
||||
return f"{summary}" if include_type else summary
|
||||
else:
|
||||
return "<variable not available>"
|
||||
|
||||
|
||||
def format_slice(var: lldb.SBValue, debugger: lldb.SBDebugger, indent: int) -> str:
|
||||
length = var.GetChildMemberWithName('len').GetValue()
|
||||
if length is None:
|
||||
return "<variable not available>"
|
||||
length = int(length)
|
||||
data_ptr = var.GetChildMemberWithName('data')
|
||||
elements: List[str] = []
|
||||
|
||||
ptr_value = int(data_ptr.GetValue(), 16)
|
||||
element_type = data_ptr.GetType().GetPointeeType()
|
||||
element_size = element_type.GetByteSize()
|
||||
|
||||
target = debugger.GetSelectedTarget()
|
||||
indent_str = ' ' * indent
|
||||
next_indent_str = ' ' * (indent + 1)
|
||||
|
||||
for i in range(length):
|
||||
element_address = ptr_value + i * element_size
|
||||
element = target.CreateValueFromAddress(
|
||||
f"element_{i}", lldb.SBAddress(element_address, target), element_type)
|
||||
value = format_value(
|
||||
element, debugger, include_type=False, indent=indent+1)
|
||||
elements.append(value)
|
||||
|
||||
type_name = var.GetType().GetName()
|
||||
|
||||
if len(elements) > 5: # 如果元素数量大于5,则进行折行显示
|
||||
result = f"{type_name}{{\n{next_indent_str}" + \
|
||||
f",\n{next_indent_str}".join(elements) + f"\n{indent_str}}}"
|
||||
else:
|
||||
result = f"{type_name}{{{', '.join(elements)}}}"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def format_array(var: lldb.SBValue, debugger: lldb.SBDebugger, indent: int) -> str:
|
||||
elements: List[str] = []
|
||||
indent_str = ' ' * indent
|
||||
next_indent_str = ' ' * (indent + 1)
|
||||
|
||||
for i in range(var.GetNumChildren()):
|
||||
value = format_value(var.GetChildAtIndex(
|
||||
i), debugger, include_type=False, indent=indent+1)
|
||||
elements.append(value)
|
||||
|
||||
array_size = var.GetNumChildren()
|
||||
element_type = map_type_name(var.GetType().GetArrayElementType().GetName())
|
||||
type_name = f"[{array_size}]{element_type}"
|
||||
|
||||
if len(elements) > 5: # wrap line if too many elements
|
||||
return f"{type_name}{{\n{next_indent_str}" + f",\n{next_indent_str}".join(elements) + f"\n{indent_str}}}"
|
||||
else:
|
||||
return f"{type_name}{{{', '.join(elements)}}}"
|
||||
|
||||
|
||||
def format_string(var: lldb.SBValue) -> str:
|
||||
summary = var.GetSummary()
|
||||
if summary is not None:
|
||||
return summary # Keep the quotes
|
||||
else:
|
||||
data = var.GetChildMemberWithName('data').GetValue()
|
||||
length = var.GetChildMemberWithName('len').GetValue()
|
||||
if data and length:
|
||||
length = int(length)
|
||||
error = lldb.SBError()
|
||||
return '"%s"' % var.process.ReadCStringFromMemory(int(data, 16), length + 1, error)
|
||||
return "<variable not available>"
|
||||
|
||||
|
||||
def format_struct(var: lldb.SBValue, debugger: lldb.SBDebugger, include_type: bool = True, indent: int = 0, type_name: str = "") -> str:
|
||||
children: List[str] = []
|
||||
indent_str = ' ' * indent
|
||||
next_indent_str = ' ' * (indent + 1)
|
||||
|
||||
for i in range(var.GetNumChildren()):
|
||||
child = var.GetChildAtIndex(i)
|
||||
child_name = child.GetName()
|
||||
child_value = format_value(
|
||||
child, debugger, include_type=False, indent=indent+1)
|
||||
children.append(f"{child_name} = {child_value}")
|
||||
|
||||
if len(children) > 5: # 如果字段数量大于5,则进行折行显示
|
||||
struct_content = "{\n" + ",\n".join(
|
||||
[f"{next_indent_str}{child}" for child in children]) + f"\n{indent_str}}}"
|
||||
else:
|
||||
struct_content = f"{{{', '.join(children)}}}"
|
||||
|
||||
if include_type:
|
||||
return f"{type_name}{struct_content}"
|
||||
else:
|
||||
return struct_content
|
||||
|
||||
|
||||
def format_pointer(var: lldb.SBValue, _debugger: lldb.SBDebugger, _indent: int, _type_name: str) -> str:
|
||||
if not var.IsValid() or var.GetValueAsUnsigned() == 0:
|
||||
return "<variable not available>"
|
||||
return var.GetValue() # Return the address as a string
|
||||
|
||||
|
||||
def map_type_name(type_name: str) -> str:
|
||||
# Handle pointer types
|
||||
if type_name.endswith('*'):
|
||||
base_type = type_name[:-1].strip()
|
||||
mapped_base_type = map_type_name(base_type)
|
||||
return f"*{mapped_base_type}"
|
||||
|
||||
# Map other types
|
||||
type_mapping: Dict[str, str] = {
|
||||
'long': 'int',
|
||||
'void': 'unsafe.Pointer',
|
||||
'char': 'byte',
|
||||
'short': 'int16',
|
||||
'int': 'int32',
|
||||
'long long': 'int64',
|
||||
'unsigned char': 'uint8',
|
||||
'unsigned short': 'uint16',
|
||||
'unsigned int': 'uint32',
|
||||
'unsigned long': 'uint',
|
||||
'unsigned long long': 'uint64',
|
||||
'float': 'float32',
|
||||
'double': 'float64',
|
||||
}
|
||||
|
||||
for c_type, go_type in type_mapping.items():
|
||||
if type_name.startswith(c_type):
|
||||
return type_name.replace(c_type, go_type, 1)
|
||||
|
||||
return type_name
|
||||
15
_lldb/runlldb.sh
Executable file
15
_lldb/runlldb.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Source common functions and variables
|
||||
# shellcheck source=./_lldb/common.sh
|
||||
source "$(dirname "$0")/common.sh"
|
||||
|
||||
executable="$1"
|
||||
|
||||
# Get the directory of the current script
|
||||
script_dir="$(dirname "$0")"
|
||||
|
||||
# Run LLDB with the LLGO plugin
|
||||
"$LLDB_PATH" -O "command script import ${script_dir}/llgo_plugin.py" "$executable"
|
||||
69
_lldb/runtest.sh
Executable file
69
_lldb/runtest.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Source common functions and variables
|
||||
# shellcheck source=./_lldb/common.sh
|
||||
# shellcheck disable=SC1091
|
||||
source "$(dirname "$0")/common.sh" || exit 1
|
||||
|
||||
# Parse command-line arguments
|
||||
package_path="$DEFAULT_PACKAGE_PATH"
|
||||
verbose=False
|
||||
interactive=False
|
||||
plugin_path=None
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-v|--verbose)
|
||||
verbose=True
|
||||
shift
|
||||
;;
|
||||
-i|--interactive)
|
||||
interactive=True
|
||||
shift
|
||||
;;
|
||||
-p|--plugin)
|
||||
plugin_path="\"$2\""
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
package_path="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Build the project
|
||||
build_project "$package_path" || exit 1
|
||||
|
||||
# Set up the result file path
|
||||
result_file="/tmp/lldb_exit_code"
|
||||
|
||||
# Prepare LLDB commands
|
||||
lldb_commands=(
|
||||
"command script import _lldb/llgo_plugin.py"
|
||||
"command script import _lldb/test.py"
|
||||
"script test.run_tests_with_result('${package_path}/debug.out', ['${package_path}/in.go'], $verbose, $interactive, $plugin_path, '$result_file')"
|
||||
"quit"
|
||||
)
|
||||
|
||||
# Run LLDB with prepared commands
|
||||
lldb_command_string=""
|
||||
for cmd in "${lldb_commands[@]}"; do
|
||||
lldb_command_string+=" -o \"$cmd\""
|
||||
done
|
||||
|
||||
|
||||
# Run LLDB with the test script
|
||||
eval "$LLDB_PATH $lldb_command_string"
|
||||
|
||||
# Read the exit code from the result file
|
||||
if [ -f "$result_file" ]; then
|
||||
exit_code=$(cat "$result_file")
|
||||
rm "$result_file"
|
||||
exit "$exit_code"
|
||||
else
|
||||
echo "Error: Could not find exit code file"
|
||||
exit 1
|
||||
fi
|
||||
402
_lldb/test.py
Normal file
402
_lldb/test.py
Normal file
@@ -0,0 +1,402 @@
|
||||
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import signal
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Optional, Set, Dict, Any
|
||||
import lldb
|
||||
import llgo_plugin
|
||||
from llgo_plugin import log
|
||||
|
||||
|
||||
class LLDBTestException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Test:
|
||||
source_file: str
|
||||
line_number: int
|
||||
variable: str
|
||||
expected_value: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestResult:
|
||||
test: Test
|
||||
status: str
|
||||
actual: Optional[str] = None
|
||||
message: Optional[str] = None
|
||||
missing: Optional[Set[str]] = None
|
||||
extra: Optional[Set[str]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestCase:
|
||||
source_file: str
|
||||
start_line: int
|
||||
end_line: int
|
||||
tests: List[Test]
|
||||
|
||||
|
||||
@dataclass
|
||||
class CaseResult:
|
||||
test_case: TestCase
|
||||
function: str
|
||||
results: List[TestResult]
|
||||
|
||||
|
||||
@dataclass
|
||||
class TestResults:
|
||||
total: int = 0
|
||||
passed: int = 0
|
||||
failed: int = 0
|
||||
case_results: List[CaseResult] = field(default_factory=list)
|
||||
|
||||
|
||||
class LLDBDebugger:
|
||||
def __init__(self, executable_path: str, plugin_path: Optional[str] = None) -> None:
|
||||
self.executable_path: str = executable_path
|
||||
self.plugin_path: Optional[str] = plugin_path
|
||||
self.debugger: lldb.SBDebugger = lldb.SBDebugger.Create()
|
||||
self.debugger.SetAsync(False)
|
||||
self.target: Optional[lldb.SBTarget] = None
|
||||
self.process: Optional[lldb.SBProcess] = None
|
||||
self.type_mapping: Dict[str, str] = {
|
||||
'long': 'int',
|
||||
'unsigned long': 'uint',
|
||||
}
|
||||
|
||||
def setup(self) -> None:
|
||||
if self.plugin_path:
|
||||
self.debugger.HandleCommand(
|
||||
f'command script import "{self.plugin_path}"')
|
||||
self.target = self.debugger.CreateTarget(self.executable_path)
|
||||
if not self.target:
|
||||
raise LLDBTestException(
|
||||
f"Failed to create target for {self.executable_path}")
|
||||
|
||||
self.debugger.HandleCommand(
|
||||
'command script add -f llgo_plugin.print_go_expression p')
|
||||
self.debugger.HandleCommand(
|
||||
'command script add -f llgo_plugin.print_all_variables v')
|
||||
|
||||
def set_breakpoint(self, file_spec: str, line_number: int) -> lldb.SBBreakpoint:
|
||||
bp = self.target.BreakpointCreateByLocation(file_spec, line_number)
|
||||
if not bp.IsValid():
|
||||
raise LLDBTestException(
|
||||
f"Failed to set breakpoint at {file_spec}: {line_number}")
|
||||
return bp
|
||||
|
||||
def run_to_breakpoint(self) -> None:
|
||||
if not self.process:
|
||||
self.process = self.target.LaunchSimple(None, None, os.getcwd())
|
||||
else:
|
||||
self.process.Continue()
|
||||
if self.process.GetState() != lldb.eStateStopped:
|
||||
raise LLDBTestException("Process didn't stop at breakpoint")
|
||||
|
||||
def get_variable_value(self, var_expression: str) -> Optional[str]:
|
||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
||||
value = llgo_plugin.evaluate_expression(frame, var_expression)
|
||||
if value and value.IsValid():
|
||||
return llgo_plugin.format_value(value, self.debugger)
|
||||
return None
|
||||
|
||||
def get_all_variable_names(self) -> Set[str]:
|
||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
||||
return set(var.GetName() for var in frame.GetVariables(True, True, True, True))
|
||||
|
||||
def get_current_function_name(self) -> str:
|
||||
frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
|
||||
return frame.GetFunctionName()
|
||||
|
||||
def cleanup(self) -> None:
|
||||
if self.process and self.process.IsValid():
|
||||
self.process.Kill()
|
||||
lldb.SBDebugger.Destroy(self.debugger)
|
||||
|
||||
def run_console(self) -> bool:
|
||||
log("\nEntering LLDB interactive mode.")
|
||||
log("Type 'quit' to exit and continue with the next test case.")
|
||||
log("Use Ctrl+D to exit and continue, or Ctrl+C to abort all tests.")
|
||||
|
||||
old_stdin, old_stdout, old_stderr = sys.stdin, sys.stdout, sys.stderr
|
||||
sys.stdin, sys.stdout, sys.stderr = sys.__stdin__, sys.__stdout__, sys.__stderr__
|
||||
|
||||
self.debugger.SetAsync(True)
|
||||
self.debugger.HandleCommand("settings set auto-confirm true")
|
||||
self.debugger.HandleCommand("command script import lldb")
|
||||
|
||||
interpreter = self.debugger.GetCommandInterpreter()
|
||||
continue_tests = True
|
||||
|
||||
def keyboard_interrupt_handler(_sig: Any, _frame: Any) -> None:
|
||||
nonlocal continue_tests
|
||||
log("\nTest execution aborted by user.")
|
||||
continue_tests = False
|
||||
raise KeyboardInterrupt
|
||||
|
||||
original_handler = signal.signal(
|
||||
signal.SIGINT, keyboard_interrupt_handler)
|
||||
|
||||
try:
|
||||
while continue_tests:
|
||||
log("\n(lldb) ", end="")
|
||||
try:
|
||||
command = input().strip()
|
||||
except EOFError:
|
||||
log("\nExiting LLDB interactive mode. Continuing with next test case.")
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
if command.lower() == 'quit':
|
||||
log("\nExiting LLDB interactive mode. Continuing with next test case.")
|
||||
break
|
||||
|
||||
result = lldb.SBCommandReturnObject()
|
||||
interpreter.HandleCommand(command, result)
|
||||
log(result.GetOutput().rstrip() if result.Succeeded()
|
||||
else result.GetError().rstrip())
|
||||
|
||||
finally:
|
||||
signal.signal(signal.SIGINT, original_handler)
|
||||
sys.stdin, sys.stdout, sys.stderr = old_stdin, old_stdout, old_stderr
|
||||
|
||||
return continue_tests
|
||||
|
||||
|
||||
def parse_expected_values(source_files: List[str]) -> List[TestCase]:
|
||||
test_cases: List[TestCase] = []
|
||||
for source_file in source_files:
|
||||
with open(source_file, 'r', encoding='utf-8') as f:
|
||||
content = f.readlines()
|
||||
i = 0
|
||||
while i < len(content):
|
||||
line = content[i].strip()
|
||||
if line.startswith('// Expected:'):
|
||||
start_line = i + 1
|
||||
tests: List[Test] = []
|
||||
i += 1
|
||||
while i < len(content):
|
||||
line = content[i].strip()
|
||||
if not line.startswith('//'):
|
||||
break
|
||||
parts = line.lstrip('//').strip().split(':', 1)
|
||||
if len(parts) == 2:
|
||||
var, value = map(str.strip, parts)
|
||||
tests.append(Test(source_file, i + 1, var, value))
|
||||
i += 1
|
||||
end_line = i
|
||||
test_cases.append(
|
||||
TestCase(source_file, start_line, end_line, tests))
|
||||
else:
|
||||
i += 1
|
||||
return test_cases
|
||||
|
||||
|
||||
def execute_tests(executable_path: str, test_cases: List[TestCase], verbose: bool, interactive: bool, plugin_path: Optional[str]) -> TestResults:
|
||||
results = TestResults()
|
||||
|
||||
for test_case in test_cases:
|
||||
debugger = LLDBDebugger(executable_path, plugin_path)
|
||||
try:
|
||||
if verbose:
|
||||
log(
|
||||
f"\nSetting breakpoint at {test_case.source_file}:{test_case.end_line}")
|
||||
debugger.setup()
|
||||
debugger.set_breakpoint(test_case.source_file, test_case.end_line)
|
||||
debugger.run_to_breakpoint()
|
||||
|
||||
all_variable_names = debugger.get_all_variable_names()
|
||||
|
||||
case_result = execute_test_case(
|
||||
debugger, test_case, all_variable_names)
|
||||
|
||||
results.total += len(case_result.results)
|
||||
results.passed += sum(1 for r in case_result.results if r.status == 'pass')
|
||||
results.failed += sum(1 for r in case_result.results if r.status != 'pass')
|
||||
results.case_results.append(case_result)
|
||||
|
||||
case = case_result.test_case
|
||||
loc = f"{case.source_file}:{case.start_line}-{case.end_line}"
|
||||
if verbose or interactive or any(r.status != 'pass' for r in case_result.results):
|
||||
log(f"\nTest case: {loc} in function '{case_result.function}'")
|
||||
for result in case_result.results:
|
||||
print_test_result(result, verbose=verbose)
|
||||
|
||||
if interactive and any(r.status != 'pass' for r in case_result.results):
|
||||
log("\nTest case failed. Entering LLDB interactive mode.")
|
||||
continue_tests = debugger.run_console()
|
||||
if not continue_tests:
|
||||
log("Aborting all tests.")
|
||||
break
|
||||
|
||||
finally:
|
||||
debugger.cleanup()
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def run_tests(executable_path: str, source_files: List[str], verbose: bool, interactive: bool, plugin_path: Optional[str]) -> int:
|
||||
test_cases = parse_expected_values(source_files)
|
||||
if verbose:
|
||||
log(f"Running tests for {', '.join(source_files)} with {executable_path}")
|
||||
log(f"Found {len(test_cases)} test cases")
|
||||
|
||||
results = execute_tests(executable_path, test_cases,
|
||||
verbose, interactive, plugin_path)
|
||||
print_test_results(results)
|
||||
|
||||
# Return 0 if all tests passed, 1 otherwise
|
||||
return 0 if results.failed == 0 else 1
|
||||
|
||||
|
||||
def execute_test_case(debugger: LLDBDebugger, test_case: TestCase, all_variable_names: Set[str]) -> CaseResult:
|
||||
results: List[TestResult] = []
|
||||
|
||||
for test in test_case.tests:
|
||||
if test.variable == "all variables":
|
||||
result = execute_all_variables_test(test, all_variable_names)
|
||||
else:
|
||||
result = execute_single_variable_test(debugger, test)
|
||||
results.append(result)
|
||||
|
||||
return CaseResult(test_case, debugger.get_current_function_name(), results)
|
||||
|
||||
|
||||
def execute_all_variables_test(test: Test, all_variable_names: Set[str]) -> TestResult:
|
||||
expected_vars = set(test.expected_value.split())
|
||||
if expected_vars == all_variable_names:
|
||||
return TestResult(
|
||||
test=test,
|
||||
status='pass',
|
||||
actual=all_variable_names
|
||||
)
|
||||
else:
|
||||
return TestResult(
|
||||
test=test,
|
||||
status='fail',
|
||||
actual=all_variable_names,
|
||||
missing=expected_vars - all_variable_names,
|
||||
extra=all_variable_names - expected_vars
|
||||
)
|
||||
|
||||
|
||||
def execute_single_variable_test(debugger: LLDBDebugger, test: Test) -> TestResult:
|
||||
actual_value = debugger.get_variable_value(test.variable)
|
||||
if actual_value is None:
|
||||
return TestResult(
|
||||
test=test,
|
||||
status='error',
|
||||
message=f'Unable to fetch value for {test.variable}'
|
||||
)
|
||||
|
||||
actual_value = actual_value.strip()
|
||||
expected_value = test.expected_value.strip()
|
||||
|
||||
if actual_value == expected_value:
|
||||
return TestResult(
|
||||
test=test,
|
||||
status='pass',
|
||||
actual=actual_value
|
||||
)
|
||||
else:
|
||||
return TestResult(
|
||||
test=test,
|
||||
status='fail',
|
||||
actual=actual_value
|
||||
)
|
||||
|
||||
|
||||
def print_test_results(results: TestResults) -> None:
|
||||
log("\nTest results:")
|
||||
log(f" Total tests: {results.total}")
|
||||
log(f" Passed tests: {results.passed}")
|
||||
log(f" Failed tests: {results.failed}")
|
||||
if results.total == results.passed:
|
||||
log("All tests passed!")
|
||||
else:
|
||||
log("Some tests failed")
|
||||
|
||||
|
||||
def print_test_result(result: TestResult, verbose: bool) -> None:
|
||||
status_symbol = "✓" if result.status == 'pass' else "✗"
|
||||
status_text = "Pass" if result.status == 'pass' else "Fail"
|
||||
test = result.test
|
||||
|
||||
if result.status == 'pass':
|
||||
if verbose:
|
||||
log(f"{status_symbol} Line {test.line_number}, {test.variable}: {status_text}")
|
||||
if test.variable == 'all variables':
|
||||
log(f" Variables: {', '.join(sorted(result.actual))}")
|
||||
else: # fail or error
|
||||
log(f"{status_symbol} Line {test.line_number}, {test.variable}: {status_text}")
|
||||
if test.variable == 'all variables':
|
||||
if result.missing:
|
||||
log(f" Missing variables: {', '.join(sorted(result.missing))}")
|
||||
if result.extra:
|
||||
log(f" Extra variables: {', '.join(sorted(result.extra))}")
|
||||
log(f" Expected: {', '.join(sorted(test.expected_value.split()))}")
|
||||
log(f" Actual: {', '.join(sorted(result.actual))}")
|
||||
elif result.status == 'error':
|
||||
log(f" Error: {result.message}")
|
||||
else:
|
||||
log(f" Expected: {test.expected_value}")
|
||||
log(f" Actual: {result.actual}")
|
||||
|
||||
|
||||
def run_tests_with_result(executable_path: str, source_files: List[str], verbose: bool, interactive: bool, plugin_path: Optional[str], result_path: str) -> int:
|
||||
try:
|
||||
exit_code = run_tests(executable_path, source_files,
|
||||
verbose, interactive, plugin_path)
|
||||
except Exception as e:
|
||||
log(f"An error occurred during test execution: {str(e)}")
|
||||
exit_code = 2 # Use a different exit code for unexpected errors
|
||||
|
||||
try:
|
||||
with open(result_path, 'w', encoding='utf-8') as f:
|
||||
f.write(str(exit_code))
|
||||
except IOError as e:
|
||||
log(f"Error writing result to file {result_path}: {str(e)}")
|
||||
# If we can't write to the file, we should still return the exit code
|
||||
|
||||
return exit_code
|
||||
|
||||
|
||||
def main() -> None:
|
||||
log(sys.argv)
|
||||
parser = argparse.ArgumentParser(
|
||||
description="LLDB 18 Debug Script with DWARF 5 Support")
|
||||
parser.add_argument("executable", help="Path to the executable")
|
||||
parser.add_argument("sources", nargs='+', help="Paths to the source files")
|
||||
parser.add_argument("-v", "--verbose", action="store_true",
|
||||
help="Enable verbose output")
|
||||
parser.add_argument("-i", "--interactive", action="store_true",
|
||||
help="Enable interactive mode on test failure")
|
||||
parser.add_argument("--plugin", help="Path to the LLDB plugin")
|
||||
parser.add_argument("--result-path", help="Path to write the result")
|
||||
args = parser.parse_args()
|
||||
|
||||
plugin_path = args.plugin or os.path.join(os.path.dirname(
|
||||
os.path.realpath(__file__)), "go_lldb_plugin.py")
|
||||
|
||||
try:
|
||||
if args.result_path:
|
||||
exit_code = run_tests_with_result(args.executable, args.sources,
|
||||
args.verbose, args.interactive, plugin_path, args.result_path)
|
||||
else:
|
||||
exit_code = run_tests(args.executable, args.sources,
|
||||
args.verbose, args.interactive, plugin_path)
|
||||
except Exception as e:
|
||||
log(f"An unexpected error occurred: {str(e)}")
|
||||
exit_code = 2 # Use a different exit code for unexpected errors
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
6
c/c.go
6
c/c.go
@@ -85,6 +85,9 @@ func Calloc(num uintptr, size uintptr) Pointer
|
||||
//go:linkname Free C.free
|
||||
func Free(ptr Pointer)
|
||||
|
||||
//go:linkname Realloc C.realloc
|
||||
func Realloc(ptr Pointer, size uintptr) Pointer
|
||||
|
||||
//go:linkname Memcpy C.memcpy
|
||||
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
||||
|
||||
@@ -273,3 +276,6 @@ func GetoptLong(argc Int, argv **Char, optstring *Char, longopts *Option, longin
|
||||
func GetoptLongOnly(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Sysconf C.sysconf
|
||||
func Sysconf(name Int) Long
|
||||
|
||||
669
c/cjson/cjson.go
669
c/cjson/cjson.go
@@ -26,87 +26,25 @@ const (
|
||||
LLGoPackage = "link: $(pkg-config --libs libcjson); -lcjson"
|
||||
)
|
||||
|
||||
type Bool c.Int
|
||||
|
||||
// llgo:type C
|
||||
type JSON struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
//go:linkname Parse C.cJSON_Parse
|
||||
func Parse(value *c.Char) *JSON
|
||||
|
||||
//go:linkname ParseWithLength C.cJSON_ParseWithLength
|
||||
func ParseWithLength(value *byte, valueLength uintptr) *JSON
|
||||
|
||||
func ParseBytes(value []byte) *JSON {
|
||||
return ParseWithLength(unsafe.SliceData(value), uintptr(len(value)))
|
||||
return ParseWithLength((*c.Char)(unsafe.Pointer(unsafe.SliceData(value))), uintptr(len(value)))
|
||||
}
|
||||
|
||||
func ParseString(value string) *JSON {
|
||||
return ParseWithLength(unsafe.StringData(value), uintptr(len(value)))
|
||||
return ParseWithLength((*c.Char)(unsafe.Pointer(unsafe.StringData(value))), uintptr(len(value)))
|
||||
}
|
||||
|
||||
//go:linkname Null C.cJSON_CreateNull
|
||||
func Null() *JSON
|
||||
|
||||
//go:linkname True C.cJSON_CreateTrue
|
||||
func True() *JSON
|
||||
|
||||
//go:linkname False C.cJSON_CreateFalse
|
||||
func False() *JSON
|
||||
|
||||
//go:linkname Bool C.cJSON_CreateBool
|
||||
func Bool(boolean c.Int) *JSON
|
||||
|
||||
//go:linkname Number C.cJSON_CreateNumber
|
||||
func Number(num float64) *JSON
|
||||
|
||||
//go:linkname String C.cJSON_CreateString
|
||||
func String(str *c.Char) *JSON
|
||||
|
||||
//go:linkname Array C.cJSON_CreateArray
|
||||
func Array() *JSON
|
||||
|
||||
//go:linkname Object C.cJSON_CreateObject
|
||||
func Object() *JSON
|
||||
|
||||
// raw json
|
||||
// CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
//
|
||||
//go:linkname Raw C.cJSON_CreateRaw
|
||||
func Raw(raw *c.Char) *JSON
|
||||
|
||||
// Create a string where valuestring references a string so
|
||||
// it will not be freed by Delete
|
||||
// Render a cJSON entity to text for transfer/storage without any formatting.
|
||||
//
|
||||
//go:linkname StringRef C.cJSON_CreateStringReference
|
||||
func StringRef(str *c.Char) *JSON
|
||||
|
||||
// Create an object that only references it's elements so
|
||||
// they will not be freed by Delete
|
||||
//
|
||||
//go:linkname ObjectRef C.cJSON_CreateObjectReference
|
||||
func ObjectRef(child *JSON) *JSON
|
||||
|
||||
// Create an array that only references it's elements so
|
||||
// they will not be freed by Delete
|
||||
//
|
||||
//go:linkname ArrayRef C.cJSON_CreateArrayReference
|
||||
func ArrayRef(child *JSON) *JSON
|
||||
|
||||
// Delete a JSON entity and all subentities.
|
||||
//
|
||||
// llgo:link (*JSON).Delete C.cJSON_Delete
|
||||
func (o *JSON) Delete() {}
|
||||
|
||||
// Append item to the specified array.
|
||||
//
|
||||
// llgo:link (*JSON).AddItem C.cJSON_AddItemToArray
|
||||
func (o *JSON) AddItem(item *JSON) c.Int { return 0 }
|
||||
|
||||
// Append item to the specified object.
|
||||
//
|
||||
// llgo:link (*JSON).SetItem C.cJSON_AddItemToObject
|
||||
func (o *JSON) SetItem(key *c.Char, item *JSON) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*JSON).CStr C.cJSON_PrintUnformatted
|
||||
func (o *JSON) CStr() *c.Char { return nil }
|
||||
|
||||
@@ -115,39 +53,618 @@ func (o *JSON) CStr() *c.Char { return nil }
|
||||
// llgo:link (*JSON).Cstr C.cJSON_PrintUnformatted
|
||||
func (o *JSON) Cstr() *c.Char { return nil }
|
||||
|
||||
// malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks
|
||||
//
|
||||
//go:linkname FreeCStr C.cJSON_free
|
||||
func FreeCStr(*c.Char)
|
||||
|
||||
// CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
//
|
||||
// returns the version of cJSON as a string
|
||||
//
|
||||
//go:linkname Version C.cJSON_Version
|
||||
func Version() *c.Char
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
//
|
||||
// Memory Management: the caller is always responsible to free
|
||||
// the results from all variants of cJSON_Parse (with cJSON_Delete)
|
||||
// and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or
|
||||
// cJSON_free as appropriate). The exception is cJSON_PrintPreallocated,
|
||||
// where the caller has full responsibility of the buffer.
|
||||
//
|
||||
//go:linkname Parse C.cJSON_Parse
|
||||
func Parse(value *c.Char) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
//
|
||||
// Memory Management: the caller is always responsible to free
|
||||
// the results from all variants of cJSON_Parse (with cJSON_Delete)
|
||||
// and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or
|
||||
// cJSON_free as appropriate). The exception is cJSON_PrintPreallocated,
|
||||
// where the caller has full responsibility of the buffer.
|
||||
//
|
||||
//go:linkname ParseWithLength C.cJSON_ParseWithLength
|
||||
func ParseWithLength(value *c.Char, valueLength uintptr) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_Bool require_null_terminated);
|
||||
//
|
||||
// ParseWithOpts allows you to require (and check) that the JSON is null terminated,
|
||||
// and to retrieve the pointer to the final byte parsed.
|
||||
// If you supply a ptr in return_parse_end and parsing fails, then
|
||||
// return_parse_end will contain a pointer to the error so will match
|
||||
// cJSON_GetErrorPtr().
|
||||
//
|
||||
//go:linkname ParseWithOpts C.cJSON_ParseWithOpts
|
||||
func ParseWithOpts(value *c.Char, return_parse_end **c.Char, require_null_terminated Bool) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_Bool require_null_terminated);
|
||||
//
|
||||
// ParseWithOpts allows you to require (and check) that the JSON is null terminated,
|
||||
// and to retrieve the pointer to the final byte parsed.
|
||||
// If you supply a ptr in return_parse_end and parsing fails, then
|
||||
// return_parse_end will contain a pointer to the error so will match
|
||||
// cJSON_GetErrorPtr().
|
||||
//
|
||||
//go:linkname ParseWithLengthOpts C.cJSON_ParseWithLengthOpts
|
||||
func ParseWithLengthOpts(value *c.Char, buffer_length uintptr, return_parse_end **c.Char, require_null_terminated Bool) *JSON
|
||||
|
||||
// CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
// Render a JSON entity to text for transfer/storage.
|
||||
//
|
||||
// llgo:link (*JSON).Print C.cJSON_Print
|
||||
func (o *JSON) Print() *c.Char { return nil }
|
||||
|
||||
// CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
// Render a JSON entity to text for transfer/storage without any formatting.
|
||||
//
|
||||
// llgo:link (*JSON).PrintUnformatted C.cJSON_PrintUnformatted
|
||||
func (o *JSON) PrintUnformatted() *c.Char { return nil }
|
||||
|
||||
// CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_Bool fmt);
|
||||
//
|
||||
// Render a JSON entity to text using a buffered strategy.
|
||||
//
|
||||
// prebuffer is a guess at the final size. guessing well reduces reallocation.
|
||||
//
|
||||
// fmt=0 gives unformatted, =1 gives formatted.
|
||||
//
|
||||
// llgo:link (*JSON).PrintBuffered C.cJSON_PrintBuffered
|
||||
func (o *JSON) PrintBuffered(prebuffer c.Int, fmt c.Int) *c.Char { return nil }
|
||||
func (o *JSON) PrintBuffered(prebuffer c.Int, fmt Bool) *c.Char { return nil }
|
||||
|
||||
// llgo:link (*JSON).GetObjectItemCaseSensitive C.cJSON_GetObjectItemCaseSensitive
|
||||
func (o *JSON) GetObjectItemCaseSensitive(key *c.Char) *JSON { return nil }
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_Bool format);
|
||||
//
|
||||
// Render a cJSON entity to text using a buffer already allocated in memory with given
|
||||
// length. Returns 1 on success and 0 on failure.
|
||||
// note that cJSON is not always 100% accurate in estimating how much memory it will use,
|
||||
// so to be safe allocate 5 bytes more than you actually need
|
||||
//
|
||||
// llgo:link (*JSON).PrintPreallocated C.cJSON_PrintPreallocated
|
||||
func (o *JSON) PrintPreallocated(buffer *c.Char, length c.Int, format Bool) Bool {
|
||||
return Bool(0)
|
||||
}
|
||||
|
||||
// CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
// Delete a JSON entity and all subentities.
|
||||
//
|
||||
// llgo:link (*JSON).Delete C.cJSON_Delete
|
||||
func (o *JSON) Delete() {}
|
||||
|
||||
// CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
//
|
||||
// Returns the number of items in an array (or object).
|
||||
//
|
||||
// llgo:link (*JSON).GetArraySize C.cJSON_GetArraySize
|
||||
func (o *JSON) GetArraySize() c.Int { return 0 }
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
//
|
||||
// Retrieve item number "index" from array "array". Returns NULL if unsuccessful.
|
||||
//
|
||||
// llgo:link (*JSON).GetArrayItem C.cJSON_GetArrayItem
|
||||
func (o *JSON) GetArrayItem(index c.Int) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
//
|
||||
// Get item "string" from object. Case insensitive.
|
||||
//
|
||||
// llgo:link (*JSON).GetObjectItem C.cJSON_GetObjectItem
|
||||
func (o *JSON) GetObjectItem(s *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
//
|
||||
// Get item "string" from object. Case sensitive.
|
||||
//
|
||||
// llgo:link (*JSON).GetObjectItemCaseSensitive C.cJSON_GetObjectItemCaseSensitive
|
||||
func (o *JSON) GetObjectItemCaseSensitive(key *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
//
|
||||
// llgo:link (*JSON).HasObjectItem C.cJSON_HasObjectItem
|
||||
func (o *JSON) HasObjectItem(s *c.Char) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
//
|
||||
// For analysing failed parses. This returns a pointer to the parse error.
|
||||
// You'll probably need to look a few chars back to make sense of it.
|
||||
// Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds.
|
||||
//
|
||||
//go:linkname GetErrorPtr C.cJSON_GetErrorPtr
|
||||
func GetErrorPtr() *c.Char
|
||||
|
||||
// CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
//
|
||||
// Check item type and return its value
|
||||
//
|
||||
// llgo:link (*JSON).GetStringValue C.cJSON_GetStringValue
|
||||
func (o *JSON) GetStringValue() *c.Char { return nil }
|
||||
|
||||
// CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
//
|
||||
// Check item type and return its value
|
||||
//
|
||||
// llgo:link (*JSON).GetNumberValue C.cJSON_GetNumberValue
|
||||
func (o *JSON) GetNumberValue() c.Double { return 0 }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsInvalid C.cJSON_IsInvalid
|
||||
func (o *JSON) IsInvalid() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsFalse(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsFalse C.cJSON_IsFalse
|
||||
func (o *JSON) IsFalse() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsTrue(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsTrue C.cJSON_IsTrue
|
||||
func (o *JSON) IsTrue() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsBool(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsBool C.cJSON_IsBool
|
||||
func (o *JSON) IsBool() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsNull(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsNull C.cJSON_IsNull
|
||||
func (o *JSON) IsNull() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsNumber(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsNumber C.cJSON_IsNumber
|
||||
func (o *JSON) IsNumber() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsString(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsString C.cJSON_IsString
|
||||
func (o *JSON) IsString() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsArray(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsArray C.cJSON_IsArray
|
||||
func (o *JSON) IsArray() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsObject(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsObject C.cJSON_IsObject
|
||||
func (o *JSON) IsObject() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_IsRaw(const cJSON * const item);
|
||||
//
|
||||
// These functions check the type of an item
|
||||
//
|
||||
// llgo:link (*JSON).IsRaw C.cJSON_IsRaw
|
||||
func (o *JSON) IsRaw() Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
//
|
||||
// These calls create a cJSON item of the appropriate type.
|
||||
//
|
||||
//go:linkname Null C.cJSON_CreateNull
|
||||
func Null() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
//
|
||||
// same as Null func
|
||||
//
|
||||
//go:linkname CreateNull C.cJSON_CreateNull
|
||||
func CreateNull() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
//
|
||||
//go:linkname True C.cJSON_CreateTrue
|
||||
func True() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
//
|
||||
// same as True func
|
||||
//
|
||||
//go:linkname CreateTrue C.cJSON_CreateTrue
|
||||
func CreateTrue() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
//
|
||||
//go:linkname False C.cJSON_CreateFalse
|
||||
func False() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
//
|
||||
// same as False func
|
||||
//
|
||||
//go:linkname CreateFalse C.cJSON_CreateFalse
|
||||
func CreateFalse() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_Bool boolean);
|
||||
//
|
||||
// same as Bool func
|
||||
//
|
||||
//go:linkname CreateBool C.cJSON_CreateBool
|
||||
func CreateBool(boolean c.Int) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
//
|
||||
//go:linkname Number C.cJSON_CreateNumber
|
||||
func Number(num float64) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
//
|
||||
// same as Number func
|
||||
//
|
||||
//go:linkname CreateNumber C.cJSON_CreateNumber
|
||||
func CreateNumber(num float64) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
//
|
||||
//go:linkname String C.cJSON_CreateString
|
||||
func String(str *c.Char) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
//
|
||||
// same as String func
|
||||
//
|
||||
//go:linkname CreateString C.cJSON_CreateString
|
||||
func CreateString(str *c.Char) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
// raw json
|
||||
//
|
||||
//go:linkname Raw C.cJSON_CreateRaw
|
||||
func Raw(raw *c.Char) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
//
|
||||
// same as Raw func
|
||||
//
|
||||
//go:linkname CreateRaw C.cJSON_CreateRaw
|
||||
func CreateRaw(raw *c.Char) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
//
|
||||
//go:linkname Array C.cJSON_CreateArray
|
||||
func Array() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
//
|
||||
// same as Array func
|
||||
//
|
||||
//go:linkname CreateArray C.cJSON_CreateArray
|
||||
func CreateArray() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
//
|
||||
//go:linkname Object C.cJSON_CreateObject
|
||||
func Object() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
//
|
||||
// same as Object func
|
||||
//
|
||||
//go:linkname CreateObject C.cJSON_CreateObject
|
||||
func CreateObject() *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
//
|
||||
// Create a string where valuestring references a string so
|
||||
// it will not be freed by Delete
|
||||
//
|
||||
//go:linkname StringRef C.cJSON_CreateStringReference
|
||||
func StringRef(str *c.Char) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
//
|
||||
// same as StringRef func
|
||||
//
|
||||
//go:linkname CreateStringReference C.cJSON_CreateStringReference
|
||||
func CreateStringReference(str *c.Char) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
//
|
||||
// Create an object that only references it's elements so
|
||||
// they will not be freed by Delete
|
||||
//
|
||||
//go:linkname ObjectRef C.cJSON_CreateObjectReference
|
||||
func ObjectRef(child *JSON) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
//
|
||||
// same as ObjectRef func
|
||||
//
|
||||
//go:linkname CreateObjectReference C.cJSON_CreateObjectReference
|
||||
func CreateObjectReference(child *JSON) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
//
|
||||
// Create an array that only references it's elements so
|
||||
// they will not be freed by Delete
|
||||
//
|
||||
//go:linkname ArrayRef C.cJSON_CreateArrayReference
|
||||
func ArrayRef(child *JSON) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
//
|
||||
// same as ArrayRef func
|
||||
//
|
||||
//go:linkname CreateArrayReference C.cJSON_CreateArrayReference
|
||||
func CreateArrayReference(child *JSON) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
//
|
||||
//go:linkname CreateIntArray C.cJSON_CreateIntArray
|
||||
func CreateIntArray(numbers *c.Int, count c.Int) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
//
|
||||
//go:linkname CreateFloatArray C.cJSON_CreateFloatArray
|
||||
func CreateFloatArray(numbers *c.Float, count c.Int) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
//
|
||||
//go:linkname CreateDoubleArray C.cJSON_CreateDoubleArray
|
||||
func CreateDoubleArray(numbers *c.Double, count c.Int) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
//
|
||||
//go:linkname CreateStringArray C.cJSON_CreateStringArray
|
||||
func CreateStringArray(strings *c.Char, count c.Int) *JSON
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
//
|
||||
// Append item to the specified array.
|
||||
//
|
||||
// llgo:link (*JSON).AddItem C.cJSON_AddItemToArray
|
||||
func (o *JSON) AddItem(item *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
//
|
||||
// same as AddItem func
|
||||
//
|
||||
// llgo:link (*JSON).AddItemToArray C.cJSON_AddItemToArray
|
||||
func (o *JSON) AddItemToArray(item *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
//
|
||||
// Append item to the specified object.
|
||||
//
|
||||
// llgo:link (*JSON).SetItem C.cJSON_AddItemToObject
|
||||
func (o *JSON) SetItem(key *c.Char, item *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
//
|
||||
// same as SetItem func
|
||||
//
|
||||
// llgo:link (*JSON).AddItemToObject C.cJSON_AddItemToObject
|
||||
func (o *JSON) AddItemToObject(key *c.Char, item *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
//
|
||||
// Use this when string is definitely const (i.e. a literal, or as good as),
|
||||
// and will definitely survive the cJSON object.
|
||||
// warning that When this function was used, make sure to always check that
|
||||
// (item->type & cJSON_StringIsConst) is zero before writing to `item->string`
|
||||
//
|
||||
// llgo:link (*JSON).AddItemToObjectCS C.cJSON_AddItemToObjectCS
|
||||
func (o *JSON) AddItemToObjectCS(s *c.Char, item *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
//
|
||||
// Append reference to item to the specified array/object.
|
||||
// Use this when you want to add an existing cJSON to a new cJSON,
|
||||
// but don't want to corrupt your existing cJSON.
|
||||
//
|
||||
// llgo:link (*JSON).AddItemReferenceToArray C.cJSON_AddItemReferenceToArray
|
||||
func (o *JSON) AddItemReferenceToArray(item *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
//
|
||||
// llgo:link (*JSON).AddItemReferenceToObject C.cJSON_AddItemReferenceToObject
|
||||
func (o *JSON) AddItemReferenceToObject(s *c.Char, item *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
//
|
||||
// Remove/Detach items from Arrays/Objects.
|
||||
//
|
||||
// llgo:link (*JSON).DetachItemViaPointer C.cJSON_DetachItemViaPointer
|
||||
func (o *JSON) DetachItemViaPointer(item *JSON) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
//
|
||||
// llgo:link (*JSON).DetachItemFromArray C.cJSON_DetachItemFromArray
|
||||
func (o *JSON) DetachItemFromArray(which c.Int) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
//
|
||||
// llgo:link (*JSON).DeleteItemFromArray C.cJSON_DeleteItemFromArray
|
||||
func (o *JSON) DeleteItemFromArray(which c.Int) {}
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
//
|
||||
// llgo:link (*JSON).DetachItemFromObject C.cJSON_DetachItemFromObject
|
||||
func (o *JSON) DetachItemFromObject(s *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
//
|
||||
// llgo:link (*JSON).DetachItemFromObjectCaseSensitive C.cJSON_DetachItemFromObjectCaseSensitive
|
||||
func (o *JSON) DetachItemFromObjectCaseSensitive(s *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
//
|
||||
// llgo:link (*JSON).DeleteItemFromObject C.cJSON_DeleteItemFromObject
|
||||
func (o *JSON) DeleteItemFromObject(s *c.Char) {}
|
||||
|
||||
// CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
//
|
||||
// llgo:link (*JSON).DeleteItemFromObjectCaseSensitive C.cJSON_DeleteItemFromObjectCaseSensitive
|
||||
func (o *JSON) DeleteItemFromObjectCaseSensitive(s *c.Char) {}
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
//
|
||||
// Update array items.
|
||||
// Shifts pre-existing items to the right.
|
||||
//
|
||||
// llgo:link (*JSON).InsertItemInArray C.cJSON_InsertItemInArray
|
||||
func (o *JSON) InsertItemInArray(which c.Int, newitem *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
//
|
||||
// llgo:link (*JSON).ReplaceItemViaPointer C.cJSON_ReplaceItemViaPointer
|
||||
func (o *JSON) ReplaceItemViaPointer(item *JSON, replacement *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
//
|
||||
// llgo:link (*JSON).ReplaceItemInArray C.cJSON_ReplaceItemInArray
|
||||
func (o *JSON) ReplaceItemInArray(which c.Int, newitem *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
//
|
||||
// llgo:link (*JSON).ReplaceItemInObject C.cJSON_ReplaceItemInObject
|
||||
func (o *JSON) ReplaceItemInObject(s *c.Char, newitem *JSON) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
//
|
||||
// llgo:link (*JSON).ReplaceItemInObjectCaseSensitive C.cJSON_ReplaceItemInObjectCaseSensitive
|
||||
func (o *JSON) ReplaceItemInObjectCaseSensitive(s *c.Char, newitem *JSON) Bool {
|
||||
return Bool(0)
|
||||
}
|
||||
|
||||
// CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_Bool recurse);
|
||||
//
|
||||
// Duplicate a cJSON item
|
||||
//
|
||||
// Duplicate will create a new, identical cJSON item to the one you pass,
|
||||
// in new memory that will need to be released. With recurse!=0,
|
||||
// it will duplicate any children connected to the item.
|
||||
// The item->next and ->prev pointers are always zero on return from Duplicate.
|
||||
//
|
||||
// llgo:link (*JSON).Duplicate C.cJSON_Duplicate
|
||||
func (o *JSON) Duplicate(recurse Bool) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON_Bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_Bool case_sensitive);
|
||||
//
|
||||
// Recursively compare two cJSON items for equality. If either a or b is NULL or invalid,
|
||||
// they will be considered unequal. case_sensitive determines if object keys are treated
|
||||
// case sensitive (1) or case insensitive (0)
|
||||
//
|
||||
// llgo:link (*JSON).Compare C.cJSON_Compare
|
||||
func (o *JSON) Compare(b *JSON, case_sensitive Bool) Bool { return Bool(0) }
|
||||
|
||||
// CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
//
|
||||
// Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
// The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
// but should point to a readable and writable address area.
|
||||
//
|
||||
//go:linkname Minify C.cJSON_Minify
|
||||
func Minify()
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
//
|
||||
// Helper functions for creating and adding items to an object at the same time.
|
||||
// They return the added item or NULL on failure.
|
||||
//
|
||||
// llgo:link (*JSON).AddNullToObject C.cJSON_AddNullToObject
|
||||
func (o *JSON) AddNullToObject(name *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
//
|
||||
// llgo:link (*JSON).AddTrueToObject C.cJSON_AddTrueToObject
|
||||
func (o *JSON) AddTrueToObject(name *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
//
|
||||
// llgo:link (*JSON).AddFalseToObject C.cJSON_AddFalseToObject
|
||||
func (o *JSON) AddFalseToObject(name *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_Bool boolean);
|
||||
//
|
||||
// llgo:link (*JSON).AddBoolToObject C.cJSON_AddBoolToObject
|
||||
func (o *JSON) AddBoolToObject(name *c.Char, b Bool) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
//
|
||||
// llgo:link (*JSON).AddNumberToObject C.cJSON_AddNumberToObject
|
||||
func (o *JSON) AddNumberToObject(name *c.Char, num c.Double) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
//
|
||||
// llgo:link (*JSON).AddStringToObject C.cJSON_AddStringToObject
|
||||
func (o *JSON) AddStringToObject(name *c.Char, s *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
//
|
||||
// llgo:link (*JSON).AddRawToObject C.cJSON_AddRawToObject
|
||||
func (o *JSON) AddRawToObject(name *c.Char, raw *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
//
|
||||
// llgo:link (*JSON).AddObjectToObject C.cJSON_AddObjectToObject
|
||||
func (o *JSON) AddObjectToObject(name *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
//
|
||||
// llgo:link (*JSON).AddArrayToObject C.cJSON_AddArrayToObject
|
||||
func (o *JSON) AddArrayToObject(name *c.Char) *JSON { return nil }
|
||||
|
||||
// CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
//
|
||||
// helper for the cJSON_SetNumberValue macro
|
||||
//
|
||||
// llgo:link (*JSON).SetNumberHelper C.cJSON_SetNumberHelper
|
||||
func (o *JSON) SetNumberHelper(number c.Double) c.Double { return 0 }
|
||||
|
||||
// CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
//
|
||||
// Change the valuestring of a cJSON_String object, only takes effect when type of
|
||||
// object is cJSON_String
|
||||
//
|
||||
// llgo:link (*JSON).SetValuestring C.cJSON_SetValuestring
|
||||
func (o *JSON) SetValuestring(v *c.Char) *c.Char { return nil }
|
||||
|
||||
// CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
//
|
||||
// malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks
|
||||
//
|
||||
//go:linkname Malloc C.cJSON_malloc
|
||||
func Malloc(size uintptr)
|
||||
|
||||
// CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
//
|
||||
//go:linkname Free C.cJSON_free
|
||||
func Free(ptr unsafe.Pointer)
|
||||
|
||||
//go:linkname FreeCStr C.cJSON_free
|
||||
func FreeCStr(*c.Char)
|
||||
|
||||
35
c/clang/_demo/inclusion/inclusion.go
Normal file
35
c/clang/_demo/inclusion/inclusion.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/clang"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, unit, err := clangutils.CreateTranslationUnit(&clangutils.Config{
|
||||
File: "#include <stddef.h>",
|
||||
Temp: true,
|
||||
IsCpp: false,
|
||||
})
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
clang.GetInclusions(unit, func(included_file clang.File, inclusion_stack *clang.SourceLocation, include_len c.Uint, client_data c.Pointer) {
|
||||
filename := included_file.FileName()
|
||||
c.Printf(c.Str("Included file: %s Include length: %d\n"), filename.CStr(), include_len)
|
||||
inclusions := unsafe.Slice(inclusion_stack, include_len)
|
||||
for i := range inclusions {
|
||||
loc := inclusions[i]
|
||||
var file clang.File
|
||||
var line, column c.Uint
|
||||
loc.SpellingLocation(&file, &line, &column, nil)
|
||||
filename = file.FileName()
|
||||
c.Printf(c.Str(" included from: %s:%d:%d\n"), filename.CStr(), line, column)
|
||||
}
|
||||
}, nil)
|
||||
}
|
||||
@@ -15,6 +15,14 @@ CXChildVisitResult wrap_visitor(CXCursor cursor, CXCursor parent, CXClientData d
|
||||
|
||||
extern "C" {
|
||||
|
||||
void wrap_clang_getLocation(CXTranslationUnit tu, CXFile file, unsigned line, unsigned column, CXSourceLocation *loc) {
|
||||
*loc = clang_getLocation(tu, file, line, column);
|
||||
}
|
||||
|
||||
void wrap_clang_getLocationForOffset(CXTranslationUnit tu, CXFile file, unsigned offset, CXSourceLocation *loc) {
|
||||
*loc = clang_getLocationForOffset(tu, file, offset);
|
||||
}
|
||||
|
||||
void wrap_clang_getTranslationUnitCursor(CXTranslationUnit uint, CXCursor *cur) {
|
||||
*cur = clang_getTranslationUnitCursor(uint);
|
||||
}
|
||||
@@ -33,6 +41,12 @@ void wrap_clang_getOverriddenCursors(CXCursor *cursor, CXCursor **overridden, un
|
||||
clang_getOverriddenCursors(*cursor, overridden, num_overridden);
|
||||
}
|
||||
|
||||
CXFile wrap_clang_getIncludedFile(CXCursor *cursor) { return clang_getIncludedFile(*cursor); }
|
||||
|
||||
void wrap_clang_getCursor(CXTranslationUnit uint, CXSourceLocation *loc, CXCursor *cur) {
|
||||
*cur = clang_getCursor(uint, *loc);
|
||||
}
|
||||
|
||||
void wrap_clang_getCursorLocation(CXCursor *cur, CXSourceLocation *loc) { *loc = clang_getCursorLocation(*cur); }
|
||||
|
||||
void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); }
|
||||
@@ -109,10 +123,22 @@ enum CX_StorageClass wrap_clang_Cursor_getStorageClass(CXCursor *cursor) {
|
||||
return clang_Cursor_getStorageClass(*cursor);
|
||||
}
|
||||
|
||||
CXString wrap_clang_getCursorUSR(CXCursor *cur) { return clang_getCursorUSR(*cur); }
|
||||
|
||||
CXString wrap_clang_getCursorSpelling(CXCursor *cur) { return clang_getCursorSpelling(*cur); }
|
||||
|
||||
CXString wrap_clang_getCursorDisplayName(CXCursor *cur) { return clang_getCursorDisplayName(*cur); }
|
||||
|
||||
void wrap_clang_getCursorReferenced(CXCursor *cur, CXCursor *referenced) {
|
||||
*referenced = clang_getCursorReferenced(*cur);
|
||||
}
|
||||
|
||||
unsigned wrap_clang_Cursor_isVariadic(CXCursor *cur) { return clang_Cursor_isVariadic(*cur); }
|
||||
|
||||
void wrap_clang_Cursor_getCommentRange(CXCursor *cur, CXSourceRange *range) {
|
||||
*range = clang_Cursor_getCommentRange(*cur);
|
||||
}
|
||||
|
||||
CXString wrap_clang_Cursor_getRawCommentText(CXCursor *cursor) { return clang_Cursor_getRawCommentText(*cursor); }
|
||||
|
||||
CXString wrap_clang_Cursor_getMangling(CXCursor *cur) { return clang_Cursor_getMangling(*cur); }
|
||||
@@ -176,9 +202,15 @@ unsigned wrap_clang_visitChildren(CXCursor *parent, wrap_CXCursorVisitor visitor
|
||||
return clang_visitChildren(*parent, wrap_visitor, CXClientData(&data));
|
||||
}
|
||||
|
||||
int wrap_clang_Location_isInSystemHeader(CXSourceLocation *loc) { return clang_Location_isInSystemHeader(*loc); }
|
||||
|
||||
void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigned *line, unsigned *column,
|
||||
unsigned *offset) {
|
||||
clang_getSpellingLocation(*loc, file, line, column, offset);
|
||||
}
|
||||
|
||||
void wrap_clang_getRangeStart(CXSourceRange *range, CXSourceLocation *loc) { *loc = clang_getRangeStart(*range); }
|
||||
|
||||
void wrap_clang_getRangeEnd(CXSourceRange *range, CXSourceLocation *loc) { *loc = clang_getRangeEnd(*range); }
|
||||
|
||||
} // extern "C"
|
||||
|
||||
182
c/clang/clang.go
182
c/clang/clang.go
@@ -1157,6 +1157,30 @@ type UnsavedFile struct {
|
||||
Length c.Ulong
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the source location associated with a given file/line/column
|
||||
* in a particular translation unit.
|
||||
*/
|
||||
// llgo:link (*TranslationUnit).wrapGetLocation C.wrap_clang_getLocation
|
||||
func (t *TranslationUnit) wrapGetLocation(file File, line, column c.Uint, loc *SourceLocation) {}
|
||||
|
||||
func (t *TranslationUnit) GetLocation(file File, line, column c.Uint) (ret SourceLocation) {
|
||||
t.wrapGetLocation(file, line, column, &ret)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the source location associated with a given character offset
|
||||
* in a particular translation unit.
|
||||
*/
|
||||
// llgo:link (*TranslationUnit).wrapGetLocationForOffset C.wrap_clang_getLocationForOffset
|
||||
func (t *TranslationUnit) wrapGetLocationForOffset(file File, offset c.Uint, loc *SourceLocation) {}
|
||||
|
||||
func (t *TranslationUnit) GetLocationForOffset(file File, offset c.Uint) (ret SourceLocation) {
|
||||
t.wrapGetLocationForOffset(file, offset, &ret)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* An "index" that consists of a set of translation units that would
|
||||
* typically be linked together into an executable or library.
|
||||
@@ -1710,6 +1734,43 @@ func (c Cursor) OverriddenCursors(overridden **Cursor, numOverridden *c.Uint) {
|
||||
// llgo:link (*Cursor).DisposeOverriddenCursors C.clang_disposeOverriddenCursors
|
||||
func (c *Cursor) DisposeOverriddenCursors() {}
|
||||
|
||||
/**
|
||||
* Retrieve the file that is included by the given inclusion directive
|
||||
* cursor.
|
||||
*/
|
||||
// llgo:link (*Cursor).wrapIncludedFile C.wrap_clang_getIncludedFile
|
||||
func (c *Cursor) wrapIncludedFile() File {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c Cursor) IncludedFile() (file File) {
|
||||
return c.wrapIncludedFile()
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a source location to the cursor that describes the entity at that
|
||||
* location in the source code.
|
||||
*
|
||||
* clang_getCursor() maps an arbitrary source location within a translation
|
||||
* unit down to the most specific cursor that describes the entity at that
|
||||
* location. For example, given an expression \c x + y, invoking
|
||||
* clang_getCursor() with a source location pointing to "x" will return the
|
||||
* cursor for "x"; similarly for "y". If the cursor points anywhere between
|
||||
* "x" or "y" (e.g., on the + or the whitespace around it), clang_getCursor()
|
||||
* will return a cursor referring to the "+" expression.
|
||||
*
|
||||
* \returns a cursor representing the entity at the given source location, or
|
||||
* a NULL cursor if no such entity can be found.
|
||||
*/
|
||||
|
||||
// llgo:link (*TranslationUnit).wrapGetCursor C.wrap_clang_getCursor
|
||||
func (l *TranslationUnit) wrapGetCursor(loc *SourceLocation, cur *Cursor) {}
|
||||
|
||||
func (l *TranslationUnit) GetCursor(loc *SourceLocation) (cur Cursor) {
|
||||
l.wrapGetCursor(loc, &cur)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the physical location of the source constructor referenced
|
||||
* by the given cursor.
|
||||
@@ -2166,6 +2227,24 @@ func (c Cursor) StorageClass() (ret StorageClass) {
|
||||
return c.wrapStorageClass()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a Unified Symbol Resolution (USR) for the entity referenced
|
||||
* by the given cursor.
|
||||
*
|
||||
* A Unified Symbol Resolution (USR) is a string that identifies a particular
|
||||
* entity (function, class, variable, etc.) within a program. USRs can be
|
||||
* compared across translation units to determine, e.g., when references in
|
||||
* one translation refer to an entity defined in another translation unit.
|
||||
*/
|
||||
// llgo:link (*Cursor).wrapUSR C.wrap_clang_getCursorUSR
|
||||
func (*Cursor) wrapUSR() (ret String) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c Cursor) USR() (ret String) {
|
||||
return c.wrapUSR()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a name for the entity referenced by this cursor.
|
||||
*/
|
||||
@@ -2178,6 +2257,39 @@ func (c Cursor) String() (ret String) {
|
||||
return c.wrapString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the display name for the entity referenced by this cursor.
|
||||
*
|
||||
* The display name contains extra information that helps identify the cursor,
|
||||
* such as the parameters of a function or template or the arguments of a
|
||||
* class template specialization.
|
||||
*/
|
||||
// llgo:link (*Cursor).wrapDisplayName C.wrap_clang_getCursorDisplayName
|
||||
func (*Cursor) wrapDisplayName() (ret String) {
|
||||
return
|
||||
}
|
||||
func (c Cursor) DisplayName() (ret String) {
|
||||
return c.wrapDisplayName()
|
||||
}
|
||||
|
||||
/** For a cursor that is a reference, retrieve a cursor representing the
|
||||
* entity that it references.
|
||||
*
|
||||
* Reference cursors refer to other entities in the AST. For example, an
|
||||
* Objective-C superclass reference cursor refers to an Objective-C class.
|
||||
* This function produces the cursor for the Objective-C class from the
|
||||
* cursor for the superclass reference. If the input cursor is a declaration or
|
||||
* definition, it returns that declaration or definition unchanged.
|
||||
* Otherwise, returns the NULL cursor.
|
||||
*/
|
||||
// llgo:link (*Cursor).wrapReferenced C.wrap_clang_getCursorReferenced
|
||||
func (*Cursor) wrapReferenced(referenced *Cursor) {}
|
||||
|
||||
func (c Cursor) Referenced() (referenced Cursor) {
|
||||
c.wrapReferenced(&referenced)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns non-zero if the given cursor is a variadic function or method.
|
||||
*/
|
||||
@@ -2186,6 +2298,19 @@ func (*Cursor) wrapIsVariadic() (ret c.Uint) { return 0 }
|
||||
|
||||
func (c Cursor) IsVariadic() (ret c.Uint) { return c.wrapIsVariadic() }
|
||||
|
||||
/**
|
||||
* Given a cursor that represents a declaration, return the associated
|
||||
* comment's source range. The range may include multiple consecutive comments
|
||||
* with whitespace in between.
|
||||
*/
|
||||
// llgo:link (*Cursor).wrapCommentRange C.wrap_clang_Cursor_getCommentRange
|
||||
func (c *Cursor) wrapCommentRange(ret *SourceRange) {}
|
||||
|
||||
func (c Cursor) CommentRange() (loc SourceRange) {
|
||||
c.wrapCommentRange(&loc)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a cursor that represents a declaration, return the associated
|
||||
* comment text, including comment markers.
|
||||
@@ -2578,6 +2703,29 @@ func VisitChildren(
|
||||
//llgo:type C
|
||||
type Visitor func(cursor, parent Cursor, clientData ClientData) ChildVisitResult
|
||||
|
||||
/**
|
||||
* Visitor invoked for each file in a translation unit
|
||||
* (used with clang_getInclusions()).
|
||||
*
|
||||
* This visitor function will be invoked by clang_getInclusions() for each
|
||||
* file included (either at the top-level or by \#include directives) within
|
||||
* a translation unit. The first argument is the file being included, and
|
||||
* the second and third arguments provide the inclusion stack. The
|
||||
* array is sorted in order of immediate inclusion. For example,
|
||||
* the first element refers to the location that included 'included_file'.
|
||||
*/
|
||||
//llgo:type C
|
||||
type InclusionVisitor func(included_file File, inclusion_stack *SourceLocation, include_len c.Uint, client_data ClientData)
|
||||
|
||||
/**
|
||||
* Visit the set of preprocessor inclusions in a translation unit.
|
||||
* The visitor function is called with the provided data for every included
|
||||
* file. This does not include headers included by the PCH file (unless one
|
||||
* is inspecting the inclusions in the PCH file itself).
|
||||
*/
|
||||
//go:linkname GetInclusions C.clang_getInclusions
|
||||
func GetInclusions(tu *TranslationUnit, visitor InclusionVisitor, client_data ClientData)
|
||||
|
||||
/**
|
||||
* Tokenize the source code described by the given range into raw
|
||||
* lexical tokens.
|
||||
@@ -2608,6 +2756,16 @@ func (t *TranslationUnit) Tokenize(ran SourceRange, tokens **Token, numTokens *c
|
||||
// llgo:link (*TranslationUnit).DisposeTokens C.clang_disposeTokens
|
||||
func (t *TranslationUnit) DisposeTokens(tokens *Token, numTokens c.Uint) {}
|
||||
|
||||
/**
|
||||
* Returns non-zero if the given source location is in a system header.
|
||||
*/
|
||||
// llgo:link (*SourceLocation).wrapIsInSystemHeader C.wrap_clang_Location_isInSystemHeader
|
||||
func (l *SourceLocation) wrapIsInSystemHeader() (ret c.Uint) { return 0 }
|
||||
|
||||
func (l SourceLocation) IsInSystemHeader() (ret c.Uint) {
|
||||
return l.wrapIsInSystemHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the file, line, column, and offset represented by
|
||||
* the given source location.
|
||||
@@ -2637,5 +2795,29 @@ func (l SourceLocation) SpellingLocation(file *File, line, column, offset *c.Uin
|
||||
l.wrapSpellingLocation(file, line, column, offset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a source location representing the first character within a
|
||||
* source range.
|
||||
*/
|
||||
// llgo:link (*SourceRange).wrapRangeStart C.wrap_clang_getRangeStart
|
||||
func (r *SourceRange) wrapRangeStart(loc *SourceLocation) { return }
|
||||
|
||||
func (r SourceRange) RangeStart() (loc SourceLocation) {
|
||||
r.wrapRangeStart(&loc)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a source location representing the last character within a
|
||||
* source range.
|
||||
*/
|
||||
// llgo:link (*SourceRange).wrapRangeEnd C.wrap_clang_getRangeEnd
|
||||
func (r *SourceRange) wrapRangeEnd(loc *SourceLocation) { return }
|
||||
|
||||
func (r SourceRange) RangeEnd() (loc SourceLocation) {
|
||||
r.wrapRangeEnd(&loc)
|
||||
return
|
||||
}
|
||||
|
||||
//llgo:link File.FileName C.clang_getFileName
|
||||
func (File) FileName() (ret String) { return }
|
||||
|
||||
25
c/ffi/_demo/_wrap/wrap.c
Normal file
25
c/ffi/_demo/_wrap/wrap.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
|
||||
struct array
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
int k;
|
||||
};
|
||||
|
||||
int demo1(struct array a)
|
||||
{
|
||||
printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k);
|
||||
return a.x+a.y+a.z+a.k;
|
||||
}
|
||||
|
||||
int demo2( int (*fn)(struct array)) {
|
||||
printf("c.demo2: %p\n",fn);
|
||||
struct array a;
|
||||
a.x = 1;
|
||||
a.y = 2;
|
||||
a.z = 3;
|
||||
a.k = 4;
|
||||
return (*fn)(a);
|
||||
}
|
||||
65
c/ffi/_demo/cfunc/main.go
Normal file
65
c/ffi/_demo/cfunc/main.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
LLGoFiles = "../_wrap/wrap.c"
|
||||
)
|
||||
|
||||
//llgo:type C
|
||||
type Callback func(array) c.Int
|
||||
|
||||
//go:linkname demo1 C.demo1
|
||||
func demo1(array) c.Int
|
||||
|
||||
//go:linkname demo2 C.demo2
|
||||
func demo2(fn Callback) c.Int
|
||||
|
||||
//llgo:type C
|
||||
type array struct {
|
||||
x c.Int
|
||||
y c.Int
|
||||
z c.Int
|
||||
k c.Int
|
||||
}
|
||||
|
||||
var (
|
||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
||||
)
|
||||
|
||||
func main() {
|
||||
cdemo1()
|
||||
cdemo2()
|
||||
}
|
||||
|
||||
func cdemo1() {
|
||||
var cif ffi.Cif
|
||||
tarray := &ffi.Type{0, 0, ffi.Struct, &[]*ffi.Type{typeInt32, typeInt32, typeInt32, typeInt32, nil}[0]}
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{tarray}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
ar := array{1, 2, 3, 4}
|
||||
var ret int32
|
||||
ffi.Call(&cif, c.Func(demo1), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&ar)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
|
||||
func cdemo2() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
fn := c.Func(demo1)
|
||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fn)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
93
c/ffi/_demo/closure/main.go
Normal file
93
c/ffi/_demo/closure/main.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link"
|
||||
LLGoFiles = "../_wrap/wrap.c"
|
||||
)
|
||||
|
||||
//llgo:type C
|
||||
type Callback func(array) c.Int
|
||||
|
||||
//go:linkname demo1 C.demo1
|
||||
func demo1(array) c.Int
|
||||
|
||||
//go:linkname demo2 C.demo2
|
||||
func demo2(fn Callback) c.Int
|
||||
|
||||
//llgo:type C
|
||||
type array struct {
|
||||
x c.Int
|
||||
y c.Int
|
||||
z c.Int
|
||||
k c.Int
|
||||
}
|
||||
|
||||
func demo(a array) c.Int {
|
||||
c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k)
|
||||
return a.x + a.y + a.z + a.k
|
||||
}
|
||||
|
||||
var (
|
||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
||||
)
|
||||
|
||||
func main() {
|
||||
gofn()
|
||||
c.Printf(c.Str("\n"))
|
||||
goclosure()
|
||||
}
|
||||
|
||||
func gofn() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var fncode unsafe.Pointer
|
||||
closure := ffi.ClosureAlloc(&fncode)
|
||||
defer ffi.ClosureFree(closure)
|
||||
status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
||||
ar := *(*array)(ffi.Index(args, 0))
|
||||
*(*c.Int)(ret) = demo(ar)
|
||||
}, nil, fncode)
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
|
||||
func goclosure() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
fn := func(ar array) c.Int {
|
||||
c.Printf(c.Str("call closure %d\n"), cif.NArgs)
|
||||
return demo(ar)
|
||||
}
|
||||
var fncode unsafe.Pointer
|
||||
closure := ffi.ClosureAlloc(&fncode)
|
||||
defer ffi.ClosureFree(closure)
|
||||
status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) {
|
||||
ar := *(*array)(ffi.Index(args, 0))
|
||||
fn := *(*func(array) c.Int)(userdata)
|
||||
*(*c.Int)(ret) = fn(ar)
|
||||
}, unsafe.Pointer(&fn), fncode)
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
26
c/ffi/_demo/printf/main.go
Normal file
26
c/ffi/_demo/printf/main.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/ffi"
|
||||
)
|
||||
|
||||
var (
|
||||
typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil}
|
||||
typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil}
|
||||
)
|
||||
|
||||
func main() {
|
||||
var cif ffi.Cif
|
||||
status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, 1, 2, typeInt32, &[]*ffi.Type{typePointer, typeInt32}[0])
|
||||
if status != ffi.OK {
|
||||
panic(status)
|
||||
}
|
||||
var ret int32
|
||||
text := c.Str("hello world: %d\n")
|
||||
var n int32 = 100
|
||||
ffi.Call(&cif, c.Func(c.Printf), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&text), unsafe.Pointer(&n)}[0])
|
||||
c.Printf(c.Str("ret: %d\n"), ret)
|
||||
}
|
||||
5
c/ffi/_wrap/libffi.c
Normal file
5
c/ffi/_wrap/libffi.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <ffi.h>
|
||||
|
||||
void *llog_ffi_closure_alloc(void **code) {
|
||||
return ffi_closure_alloc(sizeof(ffi_closure), code);
|
||||
}
|
||||
7
c/ffi/abi.go
Normal file
7
c/ffi/abi.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64))
|
||||
|
||||
package ffi
|
||||
|
||||
const (
|
||||
DefaultAbi = 1
|
||||
)
|
||||
7
c/ffi/abi_amd64.go
Normal file
7
c/ffi/abi_amd64.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build freebsd || linux || darwin
|
||||
|
||||
package ffi
|
||||
|
||||
const (
|
||||
DefaultAbi = 2
|
||||
)
|
||||
132
c/ffi/ffi.go
Normal file
132
c/ffi/ffi.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package ffi
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs libffi); -lffi"
|
||||
LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c"
|
||||
)
|
||||
|
||||
const (
|
||||
Void = iota
|
||||
Int
|
||||
Float
|
||||
Double
|
||||
LongDouble
|
||||
Uint8
|
||||
Sint8
|
||||
Uint16
|
||||
Sint16
|
||||
Uint32
|
||||
Sint32
|
||||
Uint64
|
||||
Sint64
|
||||
Struct
|
||||
Pointer
|
||||
Complex
|
||||
)
|
||||
|
||||
const (
|
||||
OK = iota
|
||||
BAD_TYPEDEF
|
||||
BAD_ABI
|
||||
BAD_ARGTYPE
|
||||
)
|
||||
|
||||
type Type struct {
|
||||
Size uintptr
|
||||
Alignment uint16
|
||||
Type uint16
|
||||
Elements **Type
|
||||
}
|
||||
|
||||
/*typedef struct {
|
||||
ffi_abi abi;
|
||||
unsigned nargs;
|
||||
ffi_type **arg_types;
|
||||
ffi_type *rtype;
|
||||
unsigned bytes;
|
||||
unsigned flags;
|
||||
#ifdef FFI_EXTRA_CIF_FIELDS
|
||||
FFI_EXTRA_CIF_FIELDS;
|
||||
#endif
|
||||
} ffi_cif;
|
||||
*/
|
||||
|
||||
type Cif struct {
|
||||
Abi c.Uint
|
||||
NArgs c.Uint
|
||||
ArgTypes **Type
|
||||
RType *Type
|
||||
Bytes c.Uint
|
||||
Flags c.Uint
|
||||
//Extra c.Uint
|
||||
}
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_cif(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCif C.ffi_prep_cif
|
||||
func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||
ffi_abi abi,
|
||||
unsigned int nfixedargs,
|
||||
unsigned int ntotalargs,
|
||||
ffi_type *rtype,
|
||||
ffi_type **atypes);
|
||||
*/
|
||||
//go:linkname PrepCifVar C.ffi_prep_cif_var
|
||||
func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint
|
||||
|
||||
/*
|
||||
void ffi_call(ffi_cif *cif,
|
||||
void (*fn)(void),
|
||||
void *rvalue,
|
||||
void **avalue);
|
||||
*/
|
||||
//go:linkname Call C.ffi_call
|
||||
func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer)
|
||||
|
||||
// void *ffi_closure_alloc (size_t size, void **code);
|
||||
//
|
||||
//go:linkname ClosureAlloc C.llog_ffi_closure_alloc
|
||||
func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
// void ffi_closure_free (void *);
|
||||
//
|
||||
//go:linkname ClosureFree C.ffi_closure_free
|
||||
func ClosureFree(unsafe.Pointer)
|
||||
|
||||
/*
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure*,
|
||||
ffi_cif *,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc);
|
||||
*/
|
||||
|
||||
//llgo:type C
|
||||
type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer)
|
||||
|
||||
//go:linkname PreClosureLoc C.ffi_prep_closure_loc
|
||||
func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint
|
||||
|
||||
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(ptr) + offset)
|
||||
}
|
||||
|
||||
func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer {
|
||||
return (*(*unsafe.Pointer)(add(unsafe.Pointer(args), i*unsafe.Sizeof(0))))
|
||||
}
|
||||
@@ -213,6 +213,16 @@ func LoopNew() *Loop {
|
||||
return nil
|
||||
}
|
||||
|
||||
// llgo:link (*Loop).SetData C.uv_loop_set_data
|
||||
func (loop *Loop) SetData(data c.Pointer) {
|
||||
return
|
||||
}
|
||||
|
||||
// llgo:link (*Loop).GetData C.uv_loop_get_data
|
||||
func (loop *Loop) GetData() c.Pointer {
|
||||
return nil
|
||||
}
|
||||
|
||||
// llgo:link (*Loop).Now C.uv_now
|
||||
func (loop *Loop) Now() c.UlongLong {
|
||||
return 0
|
||||
|
||||
@@ -265,6 +265,11 @@ func (req *Req) GetType() ReqType {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Req).Cancel C.uv_cancel
|
||||
func (req *Req) Cancel() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Stream related function and method */
|
||||
|
||||
78
c/libuv/thread.go
Normal file
78
c/libuv/thread.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package libuv
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
type Thread struct {
|
||||
Unused [8]byte
|
||||
}
|
||||
|
||||
type ThreadOptions struct {
|
||||
flags c.Uint
|
||||
stackSize uintptr
|
||||
}
|
||||
|
||||
type Work struct {
|
||||
Unused [128]byte
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Function type */
|
||||
|
||||
// llgo:type C
|
||||
type ThreadCb func(arg c.Pointer)
|
||||
|
||||
//llgo:type C
|
||||
type WorkCb func(req *Work)
|
||||
|
||||
//llgo:type C
|
||||
type AfterWorkCb func(req *Work, status c.Int)
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Thread related functions and method. */
|
||||
|
||||
//go:linkname ThreadEqual C.uv_thread_equal
|
||||
func ThreadEqual(t1 *Thread, t2 *Thread) c.Int
|
||||
|
||||
//go:linkname ThreadGetCPU C.uv_thread_getcpu
|
||||
func ThreadGetCPU() c.Int
|
||||
|
||||
//go:linkname ThreadSelf C.uv_thread_self
|
||||
func ThreadSelf() Thread
|
||||
|
||||
// llgo:link (*Thread).Create C.uv_thread_create
|
||||
func (t *Thread) Create(entry ThreadCb, arg c.Pointer) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Thread).CreateEx C.uv_thread_create_ex
|
||||
func (t *Thread) CreateEx(entry ThreadCb, params *ThreadOptions, arg c.Pointer) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Thread).Join C.uv_thread_join
|
||||
func (t *Thread) Join() c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Thread).SetAffinity C.uv_thread_set_affinity
|
||||
func (t *Thread) SetAffinity(cpuMask *c.Char, oldMask *c.Char, maskSize uintptr) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// llgo:link (*Thread).GetAffinity C.uv_thread_get_affinity
|
||||
func (t *Thread) GetAffinity(cpuMask *c.Char, maskSize uintptr) c.Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/* Work related functions and method. */
|
||||
|
||||
//go:linkname QueueWork C.uv_queue_work
|
||||
func QueueWork(loop *Loop, req *Work, workCb WorkCb, afterWorkCb AfterWorkCb) c.Int
|
||||
@@ -13,7 +13,7 @@ func coroutineFunc(L *lua.State) c.Int {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
@@ -18,7 +18,7 @@ func coroutineFunc(L *lua.State) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
@@ -29,7 +29,7 @@ func createCountdown(L *lua.State) c.Int {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
L.Openlibs()
|
||||
defer L.Close()
|
||||
L.Register(c.Str("create_countdown"), createCountdown)
|
||||
|
||||
@@ -24,7 +24,7 @@ func customPanic(L *lua.State) c.Int {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
48
c/lua/_demo/debug/debug.go
Normal file
48
c/lua/_demo/debug/debug.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func Hook(L *lua.State, ar *lua.Debug) {
|
||||
L.Getinfo(c.Str("nSl"), ar)
|
||||
c.Printf(c.Str("Hook called:"))
|
||||
if name := ar.Name; name != nil {
|
||||
c.Printf(c.Str("name: %s,"), name)
|
||||
}
|
||||
if what := ar.What; what != nil {
|
||||
c.Printf(c.Str("what: %s,"), what)
|
||||
}
|
||||
c.Printf(c.Str("source: %s,"), c.Pointer(unsafe.SliceData(ar.ShortSrc[:])))
|
||||
c.Printf(c.Str("line: %d\n"), ar.Currentline)
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
|
||||
L.Sethook(Hook, lua.MASKLINE, 0)
|
||||
|
||||
code :=
|
||||
`function hello(name)
|
||||
print('Hello, ' .. name .. '!')
|
||||
end
|
||||
hello('llgo')`
|
||||
if res := L.Dostring(c.Str(code)); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Hook called:what: main,source: [string "function hello(name) ..."],line: 3
|
||||
Hook called:what: main,source: [string "function hello(name) ..."],line: 1
|
||||
Hook called:what: main,source: [string "function hello(name) ..."],line: 4
|
||||
Hook called:name: hello,what: Lua,source: [string "function hello(name) ..."],line: 2
|
||||
Hello, llgo!
|
||||
Hook called:name: hello,what: Lua,source: [string "function hello(name) ..."],line: 3
|
||||
*/
|
||||
@@ -33,7 +33,7 @@ func reader(L *lua.State, data c.Pointer, size *c.Ulong) *c.Char {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func writer(L *lua.State, p c.Pointer, sz c.Ulong, ud c.Pointer) c.Int {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
if res := L.Loadstring(c.Str("function doubleNumber(x) ! return x * 2 end")); res != lua.OK {
|
||||
|
||||
42
c/lua/_demo/extraspace/extraspace.go
Normal file
42
c/lua/_demo/extraspace/extraspace.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func GetData(L *lua.State) c.Int {
|
||||
extra := (*int)(L.Getextraspace())
|
||||
L.Pushfstring(c.Str("Stored integer is: %d"), *extra)
|
||||
return 1
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
extra := (*int)(L.Getextraspace())
|
||||
*extra = 42
|
||||
|
||||
difference := uintptr(unsafe.Pointer(L)) - uintptr(L.Getextraspace())
|
||||
if difference == unsafe.Sizeof(uintptr(0)) {
|
||||
c.Printf(c.Str("Extra space is pointer size\n"), unsafe.Sizeof(uintptr(0)))
|
||||
}
|
||||
|
||||
L.Pushcfunction(GetData)
|
||||
L.Setglobal(c.Str("GetData"))
|
||||
|
||||
if L.Dostring(c.Str("print(GetData())")) != lua.OK {
|
||||
c.Printf(c.Str("Error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Extra space is pointer size
|
||||
Stored integer is: 42
|
||||
*/
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
if res := L.Dostring(c.Str("print('hello world')")); res != lua.OK {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
@@ -29,7 +29,7 @@ func printStack(L *lua.State, message string) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
@@ -17,7 +17,7 @@ func printStack(L *lua.State, stateName *c.Char) {
|
||||
|
||||
func main() {
|
||||
// Create a new Lua state and open libraries
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
|
||||
@@ -68,7 +68,7 @@ func main() {
|
||||
printStack(L, c.Str("L1"))
|
||||
|
||||
// Create a second Lua state
|
||||
L1 := lua.Newstate()
|
||||
L1 := lua.Newstate__1()
|
||||
defer L1.Close()
|
||||
|
||||
// Move two elements to the new state
|
||||
|
||||
36
c/lua/_demo/state-alloc/alloc.go
Normal file
36
c/lua/_demo/state-alloc/alloc.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func alloc(ud c.Pointer, ptr c.Pointer, osize c.Ulong, nsize c.Ulong) c.Pointer {
|
||||
if nsize == 0 {
|
||||
c.Free(ptr)
|
||||
return nil
|
||||
} else {
|
||||
return c.Realloc(ptr, uintptr(nsize))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate__0(alloc, nil)
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
if res := L.Dostring(c.Str("print('new state success')")); res != lua.OK {
|
||||
println("newstate error")
|
||||
}
|
||||
|
||||
allocf := L.Getallocf(nil)
|
||||
L.Setallocf(allocf, nil)
|
||||
|
||||
if res := L.Dostring(c.Str("print('set newstate success')")); res != lua.OK {
|
||||
println("set newstate error")
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
new state success
|
||||
set newstate success
|
||||
*/
|
||||
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
@@ -8,53 +10,91 @@ import (
|
||||
func printTable(L *lua.State) {
|
||||
L.Pushnil()
|
||||
for L.Next(-2) != 0 {
|
||||
key := L.Tostring(-2)
|
||||
value := L.Tostring(-1)
|
||||
c.Printf(c.Str("%s - %s\n"), key, value)
|
||||
switch L.Type(-2) {
|
||||
case lua.STRING:
|
||||
key := L.Tostring(-2)
|
||||
c.Printf(c.Str("%s - %s\n"), key, value)
|
||||
case lua.NUMBER:
|
||||
key := L.Tonumber(-2)
|
||||
c.Printf(c.Str("[%.0f] - %s\n"), key, value)
|
||||
case lua.LIGHTUSERDATA:
|
||||
c.Printf(c.Str("[pointer] - %s\n"), value)
|
||||
default:
|
||||
c.Printf(c.Str("unknown key type %s %d\n"), L.Typename(-2), L.Type(-2))
|
||||
}
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
L.Newtable()
|
||||
|
||||
// set table name:John
|
||||
L.Pushstring(c.Str("name"))
|
||||
L.Pushstring(c.Str("John"))
|
||||
L.Settable(-3)
|
||||
|
||||
// set table age:30
|
||||
L.Pushstring(c.Str("age"))
|
||||
L.Pushnumber(30)
|
||||
L.Settable(-3)
|
||||
|
||||
// set table field fullname:John Doe
|
||||
L.Pushstring(c.Str("John Doe"))
|
||||
L.Setfield(-2, c.Str("fullname"))
|
||||
|
||||
// set index field
|
||||
L.Pushinteger(123)
|
||||
L.Seti(-2, c.Int(1))
|
||||
|
||||
// set pointer key field
|
||||
pointerKey := c.AllocaCStr("pointer key")
|
||||
L.Pushstring(c.Str("pointer value"))
|
||||
L.Rawsetp(-2, unsafe.Pointer(pointerKey))
|
||||
|
||||
// get field by Getfield
|
||||
L.Getfield(-1, c.Str("name"))
|
||||
c.Printf(c.Str("%s\n"), L.Tostring(-1))
|
||||
c.Printf(c.Str("name: %s\n"), L.Tostring(-1))
|
||||
L.Pop(1)
|
||||
|
||||
// get field by Rawget
|
||||
L.Pushstring(c.Str("fullname"))
|
||||
L.Rawget(-2)
|
||||
c.Printf(c.Str("fullname: %s\n"), L.Tostring(-1))
|
||||
L.Pop(1)
|
||||
|
||||
// get field by Gettable
|
||||
L.Pushstring(c.Str("age"))
|
||||
L.Gettable(-2)
|
||||
age := int(L.Tonumber(-1))
|
||||
c.Printf(c.Str("Age: %d\n"), age)
|
||||
L.Pop(1)
|
||||
|
||||
// get index field
|
||||
L.Geti(-1, c.Int(1))
|
||||
c.Printf(c.Str("Index[%d] value: %d\n"), 1, L.Tointeger(-1))
|
||||
L.Pop(1)
|
||||
|
||||
c.Printf(c.Str("All entries in the table:\n"))
|
||||
printTable(L)
|
||||
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
John
|
||||
name: John
|
||||
fullname: John Doe
|
||||
Age: 30
|
||||
Index[1] value: 123
|
||||
All entries in the table:
|
||||
age - 30.0
|
||||
fullname - John Doe
|
||||
[1] - 123
|
||||
name - John
|
||||
[pointer] - pointer value
|
||||
fullname - John Doe
|
||||
age - 30.0
|
||||
*/
|
||||
|
||||
44
c/lua/_demo/thread/thread.go
Normal file
44
c/lua/_demo/thread/thread.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func pushThread(state *lua.State, name string) {
|
||||
isMain := state.Pushthread()
|
||||
if isMain != 0 {
|
||||
c.Printf(c.Str("%s Thread is main\n"), c.AllocaCStr(name))
|
||||
} else {
|
||||
c.Printf(c.Str("%s Thread is not main\n"), c.AllocaCStr(name))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
pushThread(L, "main")
|
||||
L.Pop(1)
|
||||
newThread := L.Newthread()
|
||||
pushThread(newThread, "newthread")
|
||||
|
||||
state := newThread.Tothread(-1)
|
||||
if newThread == state {
|
||||
c.Printf(c.Str("Successfully retrieved thread from stack\n"))
|
||||
}
|
||||
status := state.Status()
|
||||
c.Printf(c.Str("New thread status: %d"), status)
|
||||
|
||||
if L.Closethread(newThread) != lua.OK {
|
||||
println("Failed to close thread status %d", state.Status())
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
main Thread is main
|
||||
newthread Thread is not main
|
||||
Successfully retrieved thread from stack
|
||||
New thread status: 0
|
||||
*/
|
||||
@@ -12,7 +12,7 @@ type lightdata struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
L := lua.Newstate__1()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ func (L *State) Loadfile(filename *c.Char) c.Int { return L.Loadfilex(filename,
|
||||
// llgo:link (*State).Loadstring C.luaL_loadstring
|
||||
func (L *State) Loadstring(s *c.Char) c.Int { return 0 }
|
||||
|
||||
//go:linkname Newstate C.luaL_newstate
|
||||
func Newstate() *State
|
||||
//go:linkname Newstate__1 C.luaL_newstate
|
||||
func Newstate__1() *State
|
||||
|
||||
// /*
|
||||
// ** ===============================================================
|
||||
|
||||
416
c/lua/lua.go
416
c/lua/lua.go
@@ -10,18 +10,18 @@ const (
|
||||
LLGoPackage = "link: $(pkg-config --libs lua); -llua -lm"
|
||||
)
|
||||
|
||||
// /* mark for precompiled code ('<esc>Lua') */
|
||||
/* mark for precompiled code ('<esc>Lua') */
|
||||
|
||||
// /* option for multiple returns in 'lua_pcall' and 'lua_call' */
|
||||
/* option for multiple returns in 'lua_pcall' and 'lua_call' */
|
||||
const (
|
||||
MULTRET = -1
|
||||
)
|
||||
|
||||
// /*
|
||||
// ** Pseudo-indices
|
||||
// ** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
||||
// ** space after that to help overflow detection)
|
||||
// */
|
||||
/*
|
||||
* Pseudo-indices
|
||||
* (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
||||
* space after that to help overflow detection)
|
||||
*/
|
||||
|
||||
const (
|
||||
REGISTRYINDEX = -MAXSTACK - 1000
|
||||
@@ -31,7 +31,7 @@ func Upvalueindex(i c.Int) c.Int {
|
||||
return c.Int(REGISTRYINDEX) - i
|
||||
}
|
||||
|
||||
// /* thread status */
|
||||
/* thread status */
|
||||
const (
|
||||
OK = 0
|
||||
YIELD = 1
|
||||
@@ -45,9 +45,9 @@ type State struct {
|
||||
Unused [8]byte
|
||||
}
|
||||
|
||||
// /*
|
||||
// ** basic types
|
||||
// */
|
||||
/*
|
||||
* basic types
|
||||
*/
|
||||
const (
|
||||
NONE c.Int = -1
|
||||
NIL c.Int = 0
|
||||
@@ -59,50 +59,50 @@ const (
|
||||
FUNCTION c.Int = 6
|
||||
USERDATA c.Int = 7
|
||||
THREAD c.Int = 8
|
||||
UMTYPES c.Int = 9
|
||||
NUMTYPES c.Int = 9
|
||||
)
|
||||
|
||||
// /* minimum Lua stack available to a C function */
|
||||
/* minimum Lua stack available to a C function */
|
||||
const (
|
||||
MINSTACK = 20
|
||||
)
|
||||
|
||||
// /* predefined values in the registry */
|
||||
/* predefined values in the registry */
|
||||
const (
|
||||
RIDX_MAINTHREAD = 1
|
||||
RIDX_GLOBALS = 2
|
||||
RIDX_LAST = RIDX_GLOBALS
|
||||
)
|
||||
|
||||
// /* type of numbers in Lua */
|
||||
/* type of numbers in Lua */
|
||||
type Number = c.Double
|
||||
|
||||
// /* type for integer functions */
|
||||
/* type for integer functions */
|
||||
type Integer = c.Int
|
||||
|
||||
// /* unsigned integer type */
|
||||
/* unsigned integer type */
|
||||
type Unsigned = c.Uint
|
||||
|
||||
// /* type for continuation-function contexts */
|
||||
/* type for continuation-function contexts */
|
||||
type KContext = c.Pointer
|
||||
|
||||
// /*
|
||||
// ** Type for C functions registered with Lua
|
||||
// */
|
||||
/*
|
||||
* Type for C functions registered with Lua
|
||||
*/
|
||||
|
||||
// llgo:type C
|
||||
type CFunction func(L *State) c.Int
|
||||
|
||||
// /*
|
||||
// ** Type for continuation functions
|
||||
// */
|
||||
/*
|
||||
* Type for continuation functions
|
||||
*/
|
||||
|
||||
// llgo:type C
|
||||
type KFunction func(L *State, status c.Int, ctx KContext) c.Int
|
||||
|
||||
// /*
|
||||
// ** Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
// */
|
||||
/*
|
||||
* Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
*/
|
||||
|
||||
// llgo:type C
|
||||
type Reader func(L *State, ud c.Pointer, sz *c.Ulong) *c.Char
|
||||
@@ -110,66 +110,61 @@ type Reader func(L *State, ud c.Pointer, sz *c.Ulong) *c.Char
|
||||
// llgo:type C
|
||||
type Writer func(L *State, p c.Pointer, sz c.Ulong, ud c.Pointer) c.Int
|
||||
|
||||
// /*
|
||||
// ** Type for memory-allocation functions
|
||||
// */
|
||||
/*
|
||||
* Type for memory-allocation functions
|
||||
*/
|
||||
|
||||
// typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
// llgo:type C
|
||||
type Alloc func(ud c.Pointer, ptr c.Pointer, osize c.Ulong, nsize c.Ulong) c.Pointer
|
||||
|
||||
// /*
|
||||
// ** Type for warning functions
|
||||
// */
|
||||
/*
|
||||
* Type for warning functions
|
||||
*/
|
||||
|
||||
// typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
|
||||
// llgo:type C
|
||||
type WarnFunction func(ud c.Pointer, msg c.Char, tocont c.Int)
|
||||
|
||||
// /*
|
||||
// ** Type used by the debug API to collect debug information
|
||||
// */
|
||||
/*
|
||||
* Functions to be called by the debugger in specific events
|
||||
*/
|
||||
|
||||
// typedef struct lua_Debug lua_Debug;
|
||||
// llgo:type C
|
||||
type Hook func(L *State, ar *Debug)
|
||||
|
||||
// /*
|
||||
// ** Functions to be called by the debugger in specific events
|
||||
// */
|
||||
|
||||
// typedef void (*lua_Hook) (State *L, lua_Debug *ar);
|
||||
|
||||
// /*
|
||||
// ** generic extra include file
|
||||
// */
|
||||
|
||||
// #if defined(LUA_USER_H)
|
||||
// #include LUA_USER_H
|
||||
// #endif
|
||||
|
||||
// /*
|
||||
// ** RCS ident string
|
||||
// */
|
||||
/*
|
||||
* RCS ident string
|
||||
*/
|
||||
|
||||
// extern const char lua_ident[];
|
||||
|
||||
// /*
|
||||
// ** state manipulation
|
||||
// */
|
||||
/*
|
||||
** state manipulation
|
||||
*/
|
||||
|
||||
// llgo:link (*State).Close C.lua_close
|
||||
func (L *State) Close() {}
|
||||
|
||||
// State *(lua_newstate) (lua_Alloc f, void *ud);
|
||||
// llgo:link Newstate__0 C.lua_newstate
|
||||
func Newstate__0(f Alloc, ud c.Pointer) *State { return nil }
|
||||
|
||||
// llgo:link (*State).Newthread C.lua_newthread
|
||||
func (L *State) Newthread() *State { return nil }
|
||||
|
||||
// int (lua_closethread) (State *L, State *from);
|
||||
// int (lua_resetthread) (State *L); /* Deprecated! */
|
||||
// llgo:link (*State).Closethread C.lua_closethread
|
||||
func (L *State) Closethread(from *State) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Resetthread C.lua_resetthread
|
||||
func (L *State) Resetthread(from *State) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Atpanic C.lua_atpanic
|
||||
func (L *State) Atpanic(panicf CFunction) CFunction { return nil }
|
||||
|
||||
// lua_Number (lua_version) (State *L);
|
||||
// llgo:link (*State).Version C.lua_version
|
||||
func (L *State) Version() Number { return 0 }
|
||||
|
||||
// /*
|
||||
// ** basic stack manipulation
|
||||
// */
|
||||
/*
|
||||
* basic stack manipulation
|
||||
*/
|
||||
|
||||
// llgo:link (*State).Absindex C.lua_absindex
|
||||
func (L *State) Absindex(idx c.Int) c.Int { return 0 }
|
||||
@@ -195,9 +190,9 @@ func (L *State) Checkstack(n c.Int) c.Int { return 0 }
|
||||
// llgo:link (*State).Xmove C.lua_xmove
|
||||
func (L *State) Xmove(to *State, n c.Int) {}
|
||||
|
||||
// /*
|
||||
// ** access functions (stack -> C)
|
||||
// */
|
||||
/*
|
||||
* access functions (stack -> C)
|
||||
*/
|
||||
|
||||
// llgo:link (*State).Isnumber C.lua_isnumber
|
||||
func (L *State) Isnumber(idx c.Int) c.Int { return 0 }
|
||||
@@ -240,16 +235,20 @@ func (L *State) Tocfunction(idx c.Int) CFunction { return nil }
|
||||
// llgo:link (*State).Touserdata C.lua_touserdata
|
||||
func (L *State) Touserdata(idx c.Int) c.Pointer { return nil }
|
||||
|
||||
// LUA_API State *(lua_tothread) (State *L, int idx);
|
||||
// LUA_API const void *(lua_topointer) (State *L, int idx);
|
||||
// llgo:link (*State).Tothread C.lua_tothread
|
||||
func (L *State) Tothread(idx c.Int) *State { return nil }
|
||||
|
||||
// /*
|
||||
// ** Comparison and arithmetic functions
|
||||
// */
|
||||
// llgo:link (*State).Topointer C.lua_topointer
|
||||
func (L *State) Topointer(idx c.Int) c.Pointer { return nil }
|
||||
|
||||
/*
|
||||
* Comparison and arithmetic functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* push functions (C -> stack)
|
||||
*/
|
||||
|
||||
// /*
|
||||
// ** push functions (C -> stack)
|
||||
// */
|
||||
// llgo:link (*State).Pushnil C.lua_pushnil
|
||||
func (L *State) Pushnil() {}
|
||||
|
||||
@@ -277,11 +276,12 @@ func (L *State) Pushboolean(b c.Int) {}
|
||||
// llgo:link (*State).Pushlightuserdata C.lua_pushlightuserdata
|
||||
func (L *State) Pushlightuserdata(p c.Pointer) {}
|
||||
|
||||
//int (lua_pushthread) (State *L);
|
||||
// llgo:link (*State).Pushthread C.lua_pushthread
|
||||
func (L *State) Pushthread() c.Int { return 0 }
|
||||
|
||||
// /*
|
||||
// ** get functions (Lua -> stack)
|
||||
// */
|
||||
/*
|
||||
* get functions (Lua -> stack)
|
||||
*/
|
||||
|
||||
// llgo:link (*State).Getglobal C.lua_getglobal
|
||||
func (L *State) Getglobal(name *c.Char) c.Int { return 0 }
|
||||
@@ -292,10 +292,17 @@ func (L *State) Gettable(idx c.Int) c.Int { return 0 }
|
||||
// llgo:link (*State).Getfield C.lua_getfield
|
||||
func (L *State) Getfield(idx c.Int, k *c.Char) c.Int { return 0 }
|
||||
|
||||
// LUA_API int (lua_geti) (State *L, int idx, lua_Integer n);
|
||||
// LUA_API int (lua_rawget) (State *L, int idx);
|
||||
// LUA_API int (lua_rawgeti) (State *L, int idx, lua_Integer n);
|
||||
// LUA_API int (lua_rawgetp) (State *L, int idx, const void *p);
|
||||
// llgo:link (*State).Geti C.lua_geti
|
||||
func (L *State) Geti(idx c.Int, n Integer) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Rawget C.lua_rawget
|
||||
func (L *State) Rawget(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Rawgeti C.lua_rawgeti
|
||||
func (L *State) Rawgeti(idx c.Int, n Integer) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Rawgetp C.lua_rawgetp
|
||||
func (L *State) Rawgetp(idx c.Int, p c.Pointer) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Createtable C.lua_createtable
|
||||
func (L *State) Createtable(narr c.Int, nrec c.Int) {}
|
||||
@@ -306,11 +313,12 @@ func (L *State) Newuserdatauv(sz uintptr, nuvalue c.Int) c.Pointer { return nil
|
||||
// llgo:link (*State).Getmetatable C.lua_getmetatable
|
||||
func (L *State) Getmetatable(objindex c.Int) c.Int { return 0 }
|
||||
|
||||
// LUA_API int (lua_getiuservalue) (State *L, int idx, int n);
|
||||
// llgo:link (*State).Getiuservalue C.lua_getiuservalue
|
||||
func (L *State) Getiuservalue(idx c.Int, n c.Int) c.Int { return 0 }
|
||||
|
||||
// /*
|
||||
// ** set functions (stack -> Lua)
|
||||
// */
|
||||
/*
|
||||
* set functions (stack -> Lua)
|
||||
*/
|
||||
|
||||
// llgo:link (*State).Setglobal C.lua_setglobal
|
||||
func (L *State) Setglobal(name *c.Char) {}
|
||||
@@ -321,19 +329,27 @@ func (L *State) Settable(idx c.Int) {}
|
||||
// llgo:link (*State).Setfield C.lua_setfield
|
||||
func (L *State) Setfield(idx c.Int, k *c.Char) {}
|
||||
|
||||
//void (lua_seti) (State *L, int idx, lua_Integer n);
|
||||
//void (lua_rawset) (State *L, int idx);
|
||||
//void (lua_rawseti) (State *L, int idx, lua_Integer n);
|
||||
//void (lua_rawsetp) (State *L, int idx, const void *p);
|
||||
// llgo:link (*State).Seti C.lua_seti
|
||||
func (L *State) Seti(idx c.Int, n Integer) {}
|
||||
|
||||
// llgo:link (*State).Rawset C.lua_rawset
|
||||
func (L *State) Rawset(idx c.Int) {}
|
||||
|
||||
// llgo:link (*State).Rawseti C.lua_rawseti
|
||||
func (L *State) Rawseti(idx c.Int, n Integer) {}
|
||||
|
||||
// llgo:link (*State).Rawsetp C.lua_rawsetp
|
||||
func (L *State) Rawsetp(idx c.Int, p c.Pointer) {}
|
||||
|
||||
// llgo:link (*State).Setmetatable C.lua_setmetatable
|
||||
func (L *State) Setmetatable(objindex c.Int) c.Int { return 0 }
|
||||
|
||||
//int (lua_setiuservalue) (State *L, int idx, int n);
|
||||
// llgo:link (*State).Setiuservalue C.lua_setiuservalue
|
||||
func (L *State) Setiuservalue(idx c.Int, n c.Int) c.Int { return 0 }
|
||||
|
||||
// /*
|
||||
// ** 'load' and 'call' functions (load and run Lua code)
|
||||
// */
|
||||
/*
|
||||
* 'load' and 'call' functions (load and run Lua code)
|
||||
*/
|
||||
|
||||
// llgo:link (*State).Callk C.lua_callk
|
||||
func (L *State) Callk(nargs c.Int, nresults c.Int, ctx KContext, k KFunction) c.Int {
|
||||
@@ -359,9 +375,9 @@ func (L *State) Load(reader Reader, dt c.Pointer, chunkname *c.Char, mode *c.Cha
|
||||
// llgo:link (*State).Dump C.lua_dump
|
||||
func (L *State) Dump(writer Writer, data c.Pointer, strip c.Int) c.Int { return 0 }
|
||||
|
||||
// /*
|
||||
// ** coroutine functions
|
||||
// */
|
||||
/*
|
||||
* coroutine functions
|
||||
*/
|
||||
|
||||
// llgo:link (*State).Resume C.lua_resume
|
||||
func (L *State) Resume(from *State, narg c.Int, nres *c.Int) c.Int { return 0 }
|
||||
@@ -376,16 +392,19 @@ func (L *State) Isyieldable() c.Int { return 0 }
|
||||
func (L *State) Yieldk(nresults c.Int, ctx KContext, k KFunction) c.Int { return 0 }
|
||||
func (L *State) Yield(nresults c.Int) c.Int { return L.Yieldk(nresults, nil, nil) }
|
||||
|
||||
// /*
|
||||
// ** Warning-related functions
|
||||
// */
|
||||
/*
|
||||
* Warning-related functions
|
||||
*/
|
||||
|
||||
//void (lua_setwarnf) (State *L, lua_WarnFunction f, void *ud);
|
||||
//void (lua_warning) (State *L, const char *msg, int tocont);
|
||||
// llgo:link (*State).Setwarnf C.lua_setwarnf
|
||||
func (L *State) Setwarnf(f WarnFunction, ud c.Pointer) {}
|
||||
|
||||
// /*
|
||||
// ** garbage-collection function and options
|
||||
// */
|
||||
// llgo:link (*State).Warning C.lua_warning
|
||||
func (L *State) Warning(msg *c.Char, tocont c.Int) {}
|
||||
|
||||
/*
|
||||
* garbage-collection function and options
|
||||
*/
|
||||
|
||||
const (
|
||||
GCSTOP = 0
|
||||
@@ -401,36 +420,49 @@ const (
|
||||
GCINC = 11
|
||||
)
|
||||
|
||||
// LUA_API int (lua_gc) (State *L, int what, ...);
|
||||
// llgo:link (*State).Gc C.lua_gc
|
||||
func (L *State) Gc(what c.Int, __llgo_va_list ...any) c.Int { return 0 }
|
||||
|
||||
/*
|
||||
* miscellaneous functions
|
||||
*/
|
||||
|
||||
// /*
|
||||
// ** miscellaneous functions
|
||||
// */
|
||||
// llgo:link (*State).Next C.lua_next
|
||||
func (L *State) Next(idx c.Int) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Error C.lua_error
|
||||
func (L *State) Error() c.Int { return 0 }
|
||||
|
||||
// LUA_API void (lua_concat) (State *L, int n);
|
||||
// LUA_API void (lua_len) (State *L, int idx);
|
||||
// llgo:link (*State).Concat C.lua_concat
|
||||
func (L *State) Concat(n c.Int) {}
|
||||
|
||||
// LUA_API size_t (lua_stringtonumber) (State *L, const char *s);
|
||||
// llgo:link (*State).Len C.lua_len
|
||||
func (L *State) Len(idx c.Int) {}
|
||||
|
||||
// LUA_API lua_Alloc (lua_getallocf) (State *L, void **ud);
|
||||
// LUA_API void (lua_setallocf) (State *L, lua_Alloc f, void *ud);
|
||||
// llgo:link (*State).Stringtonumber C.lua_stringtonumber
|
||||
func (L *State) Stringtonumber(s *c.Char) c.Ulong { return 0 }
|
||||
|
||||
// LUA_API void (lua_toclose) (State *L, int idx);
|
||||
// LUA_API void (lua_closeslot) (State *L, int idx);
|
||||
// llgo:link (*State).Getallocf C.lua_getallocf
|
||||
func (L *State) Getallocf(ud *c.Pointer) Alloc { return nil }
|
||||
|
||||
// /*
|
||||
// ** {==============================================================
|
||||
// ** some useful macros
|
||||
// ** ===============================================================
|
||||
// */
|
||||
// llgo:link (*State).Setallocf C.lua_setallocf
|
||||
func (L *State) Setallocf(f Alloc, ud c.Pointer) Alloc { return nil }
|
||||
|
||||
// #define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
|
||||
// llgo:link (*State).Toclose C.lua_toclose
|
||||
func (L *State) Toclose(idx c.Int) {}
|
||||
|
||||
// llgo:link (*State).Closeslot C.lua_closeslot
|
||||
func (L *State) Closeslot(idx c.Int) {}
|
||||
|
||||
/*
|
||||
** {==============================================================
|
||||
** some useful macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
func (L *State) Getextraspace() c.Pointer {
|
||||
return c.Pointer(uintptr(c.Pointer(L)) - EXTRASPACE)
|
||||
}
|
||||
func (L *State) Tonumber(idx c.Int) Number { return L.Tonumberx(idx, nil) }
|
||||
func (L *State) Tostring(idx c.Int) *c.Char { return L.Tolstring(idx, nil) }
|
||||
func (L *State) Tointeger(idx c.Int) Integer { return L.Tointegerx(idx, nil) }
|
||||
@@ -451,9 +483,13 @@ func (L *State) Isboolean(n c.Int) bool { return L.Type(n) == c.Int(BOOLEA
|
||||
func (L *State) Isthread(n c.Int) bool { return L.Type(n) == c.Int(THREAD) }
|
||||
func (L *State) Isnone(n c.Int) bool { return L.Type(n) == c.Int(NONE) }
|
||||
func (L *State) Isnoneornil(n c.Int) bool { return L.Type(n) <= 0 }
|
||||
func (L *State) Pushliteral(s *c.Char) *c.Char {
|
||||
return L.Pushstring(s)
|
||||
}
|
||||
|
||||
// #define lua_pushliteral(L, s) lua_pushstring(L, "" s)
|
||||
// #define lua_pushglobaltable(L) ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
|
||||
func (L *State) Pushglobaltable() c.Int {
|
||||
return L.Rawgeti(REGISTRYINDEX, RIDX_GLOBALS)
|
||||
}
|
||||
|
||||
func (L *State) Insert(idx c.Int) {
|
||||
L.Rotate(idx, 1)
|
||||
@@ -469,33 +505,41 @@ func (L *State) Replace(idx c.Int) {
|
||||
L.Pop(1)
|
||||
}
|
||||
|
||||
// /* }============================================================== */
|
||||
/* }============================================================== */
|
||||
|
||||
// /*
|
||||
// ** {==============================================================
|
||||
// ** compatibility macros
|
||||
// ** ===============================================================
|
||||
// */
|
||||
/*
|
||||
** {==============================================================
|
||||
** compatibility macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
func (L *State) Newuserdata(sz uintptr) c.Pointer {
|
||||
return L.Newuserdatauv(sz, 1)
|
||||
}
|
||||
|
||||
// #define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
||||
// #define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
|
||||
func (L *State) Getuservalue(idx c.Int) c.Int {
|
||||
return L.Getiuservalue(idx, 1)
|
||||
}
|
||||
|
||||
// #define LUA_NUMTAGS LUA_NUMTYPES
|
||||
func (L *State) Setuservalue(idx c.Int) c.Int {
|
||||
return L.Setiuservalue(idx, 1)
|
||||
}
|
||||
|
||||
// /* }============================================================== */
|
||||
const (
|
||||
NUMTAGS = NUMTYPES
|
||||
)
|
||||
|
||||
// /*
|
||||
// ** {======================================================================
|
||||
// ** Debug API
|
||||
// ** =======================================================================
|
||||
// */
|
||||
// /*
|
||||
// ** Event codes
|
||||
// */
|
||||
/* }============================================================== */
|
||||
|
||||
/*
|
||||
** {======================================================================
|
||||
** Debug API
|
||||
** =======================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Event codes
|
||||
*/
|
||||
|
||||
const (
|
||||
HOOKCALL = 0
|
||||
@@ -505,9 +549,9 @@ const (
|
||||
HOOKTAILCALL = 4
|
||||
)
|
||||
|
||||
// /*
|
||||
// ** Event masks
|
||||
// */
|
||||
/*
|
||||
* Event masks
|
||||
*/
|
||||
|
||||
const (
|
||||
MASKCALL = 1 << HOOKCOUNT
|
||||
@@ -516,22 +560,68 @@ const (
|
||||
MASKCOUNT = 1 << HOOKCOUNT
|
||||
)
|
||||
|
||||
// LUA_API int (lua_getstack) (State *L, int level, lua_Debug *ar);
|
||||
// LUA_API int (lua_getinfo) (State *L, const char *what, lua_Debug *ar);
|
||||
// LUA_API const char *(lua_getlocal) (State *L, const lua_Debug *ar, int n);
|
||||
// LUA_API const char *(lua_setlocal) (State *L, const lua_Debug *ar, int n);
|
||||
// LUA_API const char *(lua_getupvalue) (State *L, int funcindex, int n);
|
||||
// LUA_API const char *(lua_setupvalue) (State *L, int funcindex, int n);
|
||||
// llgo:link (*State).Getstack C.lua_getstack
|
||||
func (L *State) Getstack(level c.Int, ar *Debug) c.Int { return 0 }
|
||||
|
||||
// LUA_API void *(lua_upvalueid) (State *L, int fidx, int n);
|
||||
// LUA_API void (lua_upvaluejoin) (State *L, int fidx1, int n1, int fidx2, int n2);
|
||||
// llgo:link (*State).Getinfo C.lua_getinfo
|
||||
func (L *State) Getinfo(what *c.Char, ar *Debug) c.Int { return 0 }
|
||||
|
||||
// LUA_API void (lua_sethook) (State *L, lua_Hook func, int mask, int count);
|
||||
// LUA_API lua_Hook (lua_gethook) (State *L);
|
||||
// LUA_API int (lua_gethookmask) (State *L);
|
||||
// LUA_API int (lua_gethookcount) (State *L);
|
||||
// llgo:link (*State).Getlocal C.lua_getlocal
|
||||
func (L *State) Getlocal(ar *Debug, n c.Int) *c.Char { return nil }
|
||||
|
||||
// LUA_API int (lua_setcstacklimit) (State *L, unsigned int limit);
|
||||
// llgo:link (*State).Setlocal C.lua_setlocal
|
||||
func (L *State) Setlocal(ar *Debug, n c.Int) *c.Char { return nil }
|
||||
|
||||
// struct lua_Debug
|
||||
// /* }====================================================================== */
|
||||
// llgo:link (*State).Getupvalue C.lua_getupvalue
|
||||
func (L *State) Getupvalue(funcindex c.Int, n c.Int) *c.Char { return nil }
|
||||
|
||||
// llgo:link (*State).Setupvalue C.lua_setupvalue
|
||||
func (L *State) Setupvalue(funcindex c.Int, n c.Int) *c.Char { return nil }
|
||||
|
||||
// llgo:link (*State).Upvalueid C.lua_upvalueid
|
||||
func (L *State) Upvalueid(fidx c.Int, n c.Int) c.Pointer { return nil }
|
||||
|
||||
// llgo:link (*State).Upvaluejoin C.lua_upvaluejoin
|
||||
func (L *State) Upvaluejoin(fidx1 c.Int, n1 c.Int, fidx2 c.Int, n2 c.Int) {}
|
||||
|
||||
// llgo:link (*State).Sethook C.lua_sethook
|
||||
func (L *State) Sethook(fn Hook, mask c.Int, count c.Int) {}
|
||||
|
||||
// llgo:link (*State).Gethook C.lua_gethook
|
||||
func (L *State) Gethook() Hook { return nil }
|
||||
|
||||
// llgo:link (*State).Gethookmask C.lua_gethookmask
|
||||
func (L *State) Gethookmask() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Gethookcount C.lua_gethookcount
|
||||
func (L *State) Gethookcount() c.Int { return 0 }
|
||||
|
||||
// llgo:link (*State).Setcstacklimit C.lua_setcstacklimit
|
||||
func (L *State) Setcstacklimit(limit c.Uint) c.Int { return 0 }
|
||||
|
||||
type CallInfo struct {
|
||||
Unused [8]byte
|
||||
}
|
||||
|
||||
type Debug struct {
|
||||
Event c.Int
|
||||
Name *c.Char /* (n) */
|
||||
Namewhat *c.Char /* (n) 'global', 'local', 'field', 'method' */
|
||||
What *c.Char /* (S) 'Lua', 'C', 'main', 'tail' */
|
||||
Source *c.Char /* (S) */
|
||||
Srclen uintptr /* (S) */
|
||||
Currentline c.Int /* (l) */
|
||||
Linedefined c.Int /* (S) */
|
||||
Lastlinedefined c.Int /* (S) */
|
||||
Nups byte /* (u) number of upvalues */
|
||||
Nparams byte /* (u) number of parameters */
|
||||
Isvararg c.Char /* (u) */
|
||||
Istailcall c.Char /* (t) */
|
||||
Ftransfer uint16 /* (r) index of first value transferred */
|
||||
Ntransfer uint16 /* (r) number of transferred values */
|
||||
ShortSrc [IDSIZE]c.Char /* (S) */
|
||||
/* private part */
|
||||
ICi *CallInfo
|
||||
}
|
||||
|
||||
/* }====================================================================== */
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package lua
|
||||
|
||||
import "unsafe"
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Macros that affect the API and must be stable (that is, must be the
|
||||
@@ -19,3 +21,21 @@ package lua
|
||||
const (
|
||||
MAXSTACK = 1000000
|
||||
)
|
||||
|
||||
/*
|
||||
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
||||
** a Lua state with very fast access.
|
||||
** CHANGE it if you need a different size.
|
||||
*/
|
||||
const (
|
||||
EXTRASPACE = unsafe.Sizeof(uintptr(0))
|
||||
)
|
||||
|
||||
/*
|
||||
@@ LUA_IDSIZE gives the maximum size for the description of the source
|
||||
** of a function in debug information.
|
||||
** CHANGE it if you want a different size.
|
||||
*/
|
||||
const (
|
||||
IDSIZE = 60
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
int llgoClearenv() {
|
||||
extern char **environ;
|
||||
@@ -7,3 +8,5 @@ int llgoClearenv() {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int llgoErrno() { return errno; }
|
||||
|
||||
@@ -70,8 +70,8 @@ type (
|
||||
StatT = syscall.Stat_t
|
||||
)
|
||||
|
||||
//go:linkname Errno errno
|
||||
var Errno c.Int
|
||||
//go:linkname Errno C.llgoErrno
|
||||
func Errno() c.Int
|
||||
|
||||
//go:linkname Umask C.umask
|
||||
func Umask(cmask ModeT) ModeT
|
||||
|
||||
@@ -21,7 +21,8 @@ package os
|
||||
import "C"
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
LLGoFiles = "_os/os.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
//go:linkname Clearenv C.clearenv
|
||||
|
||||
@@ -61,7 +61,9 @@ func printType(t clang.Type, data *Data) {
|
||||
case clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray, clang.TypeConstantArray:
|
||||
printType(t.ArrayElementType(), data)
|
||||
case clang.TypeTypedef:
|
||||
printType(t.CanonicalType(), data)
|
||||
printType(t.TypeDeclaration().TypedefDeclUnderlyingType(), data)
|
||||
case clang.TypeElaborated:
|
||||
printType(t.NamedType(), data)
|
||||
case clang.TypeFunctionProto:
|
||||
printType(t.ResultType(), data)
|
||||
for i := 0; i < int(t.NumArgTypes()); i++ {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// TODO(xsw): implement llcppsigfetch tool
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/cjson"
|
||||
"github.com/goplus/llgo/chore/llcppg/types"
|
||||
)
|
||||
|
||||
type Conf struct {
|
||||
*cjson.JSON
|
||||
*types.Config
|
||||
}
|
||||
|
||||
func GetConf(data []byte) (Conf, error) {
|
||||
parsedConf := cjson.ParseBytes(data)
|
||||
if parsedConf == nil {
|
||||
return Conf{}, errors.New("failed to parse config")
|
||||
}
|
||||
|
||||
config := &types.Config{
|
||||
Name: GetStringItem(parsedConf, "name", ""),
|
||||
CFlags: GetStringItem(parsedConf, "cflags", ""),
|
||||
Libs: GetStringItem(parsedConf, "libs", ""),
|
||||
Include: GetStringArrayItem(parsedConf, "include"),
|
||||
TrimPrefixes: GetStringArrayItem(parsedConf, "trimPrefixes"),
|
||||
}
|
||||
|
||||
return Conf{
|
||||
JSON: parsedConf,
|
||||
Config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetString(obj *cjson.JSON) (value string) {
|
||||
str := obj.GetStringValue()
|
||||
return unsafe.String((*byte)(unsafe.Pointer(str)), c.Strlen(str))
|
||||
}
|
||||
|
||||
func GetStringItem(obj *cjson.JSON, key string, defval string) (value string) {
|
||||
item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key))
|
||||
if item == nil {
|
||||
return defval
|
||||
}
|
||||
return GetString(item)
|
||||
}
|
||||
|
||||
func GetStringArrayItem(obj *cjson.JSON, key string) (value []string) {
|
||||
item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key))
|
||||
if item == nil {
|
||||
return
|
||||
}
|
||||
value = make([]string, item.GetArraySize())
|
||||
for i := range value {
|
||||
value[i] = GetString(item.GetArrayItem(c.Int(i)))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/cjson"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config"
|
||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
||||
"github.com/goplus/llgo/chore/llcppg/types"
|
||||
"github.com/goplus/llgo/cpp/llvm"
|
||||
"github.com/goplus/llgo/xtool/nm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfgFile := "llcppg.cfg"
|
||||
if len(os.Args) > 1 {
|
||||
cfgFile = os.Args[1]
|
||||
}
|
||||
|
||||
var data []byte
|
||||
var err error
|
||||
if cfgFile == "-" {
|
||||
data, err = io.ReadAll(os.Stdin)
|
||||
} else {
|
||||
data, err = os.ReadFile(cfgFile)
|
||||
}
|
||||
check(err)
|
||||
|
||||
conf, err := config.GetConf(data)
|
||||
check(err)
|
||||
defer conf.Delete()
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile)
|
||||
}
|
||||
symbols, err := parseDylibSymbols(conf.Libs)
|
||||
|
||||
check(err)
|
||||
|
||||
filepaths := genHeaderFilePath(conf.CFlags, conf.Include)
|
||||
headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes)
|
||||
check(err)
|
||||
|
||||
symbolInfo := getCommonSymbols(symbols, headerInfos, conf.TrimPrefixes)
|
||||
|
||||
err = genSymbolTableFile(symbolInfo)
|
||||
check(err)
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func parseDylibSymbols(lib string) ([]*nm.Symbol, error) {
|
||||
dylibPath, err := genDylibPath(lib)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to generate dylib path")
|
||||
}
|
||||
|
||||
files, err := nm.New("").List(dylibPath)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to list symbols in dylib")
|
||||
}
|
||||
|
||||
var symbols []*nm.Symbol
|
||||
for _, file := range files {
|
||||
symbols = append(symbols, file.Symbols...)
|
||||
}
|
||||
|
||||
return symbols, nil
|
||||
}
|
||||
|
||||
func genDylibPath(lib string) (string, error) {
|
||||
output := lib
|
||||
libPath := ""
|
||||
libName := ""
|
||||
for _, part := range strings.Fields(string(output)) {
|
||||
if strings.HasPrefix(part, "-L") {
|
||||
libPath = part[2:]
|
||||
} else if strings.HasPrefix(part, "-l") {
|
||||
libName = part[2:]
|
||||
}
|
||||
}
|
||||
|
||||
if libPath == "" || libName == "" {
|
||||
return "", fmt.Errorf("failed to parse pkg-config output: %s", output)
|
||||
}
|
||||
|
||||
dylibPath := filepath.Join(libPath, "lib"+libName+".dylib")
|
||||
return dylibPath, nil
|
||||
}
|
||||
|
||||
func decodeSymbol(symbolName string) string {
|
||||
if symbolName == "" {
|
||||
return ""
|
||||
}
|
||||
demangled := llvm.ItaniumDemangle(symbolName, true)
|
||||
if demangled == nil {
|
||||
return symbolName
|
||||
}
|
||||
defer c.Free(unsafe.Pointer(demangled))
|
||||
demangleName := c.GoString(demangled)
|
||||
return strings.TrimSpace(demangleName)
|
||||
}
|
||||
|
||||
func genHeaderFilePath(cflags string, files []string) []string {
|
||||
prefixPath := cflags
|
||||
prefixPath = strings.TrimPrefix(prefixPath, "-I")
|
||||
var includePaths []string
|
||||
for _, file := range files {
|
||||
includePaths = append(includePaths, filepath.Join(prefixPath, "/"+file))
|
||||
}
|
||||
return includePaths
|
||||
}
|
||||
|
||||
func getCommonSymbols(dylibSymbols []*nm.Symbol, symbolMap map[string]string, prefix []string) []*types.SymbolInfo {
|
||||
var commonSymbols []*types.SymbolInfo
|
||||
for _, dylibSym := range dylibSymbols {
|
||||
symName := strings.TrimPrefix(dylibSym.Name, "_")
|
||||
if goName, ok := symbolMap[symName]; ok {
|
||||
symbolInfo := &types.SymbolInfo{
|
||||
Mangle: symName,
|
||||
CPP: decodeSymbol(dylibSym.Name),
|
||||
Go: goName,
|
||||
}
|
||||
commonSymbols = append(commonSymbols, symbolInfo)
|
||||
}
|
||||
}
|
||||
return commonSymbols
|
||||
}
|
||||
|
||||
func genSymbolTableFile(symbolInfos []*types.SymbolInfo) error {
|
||||
fileName := "llcppg.symb.json"
|
||||
existingSymbols, err := readExistingSymbolTable(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range symbolInfos {
|
||||
if existingSymbol, exists := existingSymbols[symbolInfos[i].Mangle]; exists {
|
||||
symbolInfos[i].Go = existingSymbol.Go
|
||||
}
|
||||
}
|
||||
|
||||
root := cjson.Array()
|
||||
defer root.Delete()
|
||||
|
||||
for _, symbol := range symbolInfos {
|
||||
item := cjson.Object()
|
||||
item.SetItem(c.Str("mangle"), cjson.String(c.AllocaCStr(symbol.Mangle)))
|
||||
item.SetItem(c.Str("c++"), cjson.String(c.AllocaCStr(symbol.CPP)))
|
||||
item.SetItem(c.Str("go"), cjson.String(c.AllocaCStr(symbol.Go)))
|
||||
root.AddItem(item)
|
||||
}
|
||||
|
||||
cStr := root.Print()
|
||||
if cStr == nil {
|
||||
return errors.New("symbol table is empty")
|
||||
}
|
||||
defer c.Free(unsafe.Pointer(cStr))
|
||||
|
||||
data := unsafe.Slice((*byte)(unsafe.Pointer(cStr)), c.Strlen(cStr))
|
||||
|
||||
if err := os.WriteFile(fileName, data, 0644); err != nil {
|
||||
return errors.New("failed to write symbol table file")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readExistingSymbolTable(fileName string) (map[string]types.SymbolInfo, error) {
|
||||
existingSymbols := make(map[string]types.SymbolInfo)
|
||||
|
||||
if _, err := os.Stat(fileName); err != nil {
|
||||
return existingSymbols, nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to read symbol table file")
|
||||
}
|
||||
|
||||
parsedJSON := cjson.ParseBytes(data)
|
||||
if parsedJSON == nil {
|
||||
return nil, errors.New("failed to parse JSON")
|
||||
}
|
||||
|
||||
arraySize := parsedJSON.GetArraySize()
|
||||
|
||||
for i := 0; i < int(arraySize); i++ {
|
||||
item := parsedJSON.GetArrayItem(c.Int(i))
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
symbol := types.SymbolInfo{
|
||||
Mangle: config.GetStringItem(item, "mangle", ""),
|
||||
CPP: config.GetStringItem(item, "c++", ""),
|
||||
Go: config.GetStringItem(item, "go", ""),
|
||||
}
|
||||
existingSymbols[symbol.Mangle] = symbol
|
||||
}
|
||||
|
||||
return existingSymbols, nil
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/clang"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
namespaceName string
|
||||
className string
|
||||
prefixes []string
|
||||
symbolMap map[string]string
|
||||
currentFile string
|
||||
nameCounts map[string]int
|
||||
}
|
||||
|
||||
func newContext(prefixes []string) *Context {
|
||||
return &Context{
|
||||
prefixes: prefixes,
|
||||
symbolMap: make(map[string]string),
|
||||
nameCounts: make(map[string]int),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) setNamespaceName(name string) {
|
||||
c.namespaceName = name
|
||||
}
|
||||
|
||||
func (c *Context) setClassName(name string) {
|
||||
c.className = name
|
||||
}
|
||||
|
||||
func (c *Context) setCurrentFile(filename string) {
|
||||
c.currentFile = filename
|
||||
}
|
||||
|
||||
func (c *Context) removePrefix(str string) string {
|
||||
for _, prefix := range c.prefixes {
|
||||
if strings.HasPrefix(str, prefix) {
|
||||
return strings.TrimPrefix(str, prefix)
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (c *Context) genGoName(name string) string {
|
||||
class := c.removePrefix(c.className)
|
||||
name = c.removePrefix(name)
|
||||
|
||||
var baseName string
|
||||
if class == "" {
|
||||
baseName = name
|
||||
} else {
|
||||
baseName = c.genMethodName(class, name)
|
||||
}
|
||||
|
||||
return c.addSuffix(baseName)
|
||||
}
|
||||
|
||||
func (c *Context) genMethodName(class, name string) string {
|
||||
prefix := "(*" + class + ")."
|
||||
if class == name {
|
||||
return prefix + "Init"
|
||||
}
|
||||
if name == "~"+class {
|
||||
return prefix + "Dispose"
|
||||
}
|
||||
return prefix + name
|
||||
}
|
||||
|
||||
func (c *Context) addSuffix(name string) string {
|
||||
c.nameCounts[name]++
|
||||
count := c.nameCounts[name]
|
||||
if count > 1 {
|
||||
return name + "__" + strconv.Itoa(count-1)
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
var context = newContext([]string{})
|
||||
|
||||
func collectFuncInfo(cursor clang.Cursor) {
|
||||
cursorStr := cursor.String()
|
||||
symbol := cursor.Mangling()
|
||||
|
||||
name := c.GoString(cursorStr.CStr())
|
||||
symbolName := c.GoString(symbol.CStr())
|
||||
if len(symbolName) >= 1 && symbolName[0] == '_' {
|
||||
symbolName = symbolName[1:]
|
||||
}
|
||||
defer symbol.Dispose()
|
||||
defer cursorStr.Dispose()
|
||||
|
||||
goName := context.genGoName(name)
|
||||
context.symbolMap[symbolName] = goName
|
||||
}
|
||||
|
||||
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
|
||||
if cursor.Kind == clang.CursorNamespace {
|
||||
nameStr := cursor.String()
|
||||
defer nameStr.Dispose()
|
||||
|
||||
context.setNamespaceName(c.GoString(nameStr.CStr()))
|
||||
clang.VisitChildren(cursor, visit, nil)
|
||||
context.setNamespaceName("")
|
||||
} else if cursor.Kind == clang.CursorClassDecl {
|
||||
nameStr := cursor.String()
|
||||
defer nameStr.Dispose()
|
||||
|
||||
context.setClassName(c.GoString(nameStr.CStr()))
|
||||
clang.VisitChildren(cursor, visit, nil)
|
||||
context.setClassName("")
|
||||
} else if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorFunctionDecl || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor {
|
||||
loc := cursor.Location()
|
||||
var file clang.File
|
||||
var line, column c.Uint
|
||||
|
||||
loc.SpellingLocation(&file, &line, &column, nil)
|
||||
filename := file.FileName()
|
||||
|
||||
if c.Strcmp(filename.CStr(), c.AllocaCStr(context.currentFile)) == 0 {
|
||||
collectFuncInfo(cursor)
|
||||
}
|
||||
|
||||
defer filename.Dispose()
|
||||
}
|
||||
|
||||
return clang.ChildVisit_Continue
|
||||
}
|
||||
|
||||
func ParseHeaderFile(filepaths []string, prefixes []string) (map[string]string, error) {
|
||||
index := clang.CreateIndex(0, 0)
|
||||
args := make([]*c.Char, 3)
|
||||
args[0] = c.Str("-x")
|
||||
args[1] = c.Str("c++")
|
||||
args[2] = c.Str("-std=c++11")
|
||||
context = newContext(prefixes)
|
||||
|
||||
for _, filename := range filepaths {
|
||||
unit := index.ParseTranslationUnit(
|
||||
c.AllocaCStr(filename),
|
||||
unsafe.SliceData(args), 3,
|
||||
nil, 0,
|
||||
clang.TranslationUnit_None,
|
||||
)
|
||||
|
||||
if unit == nil {
|
||||
return nil, errors.New("Unable to parse translation unit for file " + filename)
|
||||
}
|
||||
|
||||
cursor := unit.Cursor()
|
||||
context.setCurrentFile(filename)
|
||||
|
||||
clang.VisitChildren(cursor, visit, nil)
|
||||
|
||||
unit.Dispose()
|
||||
}
|
||||
|
||||
index.Dispose()
|
||||
|
||||
return context.symbolMap, nil
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func main() {
|
||||
items := cjson.Array()
|
||||
mod := py.ImportModule(pyLib)
|
||||
keys := mod.ModuleGetDict().DictKeys()
|
||||
for i, n := uintptr(0), keys.ListLen(); i < n; i++ {
|
||||
for i, n := 0, keys.ListLen(); i < n; i++ {
|
||||
key := keys.ListItem(i)
|
||||
val := mod.GetAttr(key)
|
||||
doc := val.GetAttrString(c.Str("__doc__"))
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/goplus/llgo/internal/llgen"
|
||||
"github.com/goplus/llgo/ssa"
|
||||
"github.com/goplus/mod"
|
||||
)
|
||||
|
||||
@@ -30,18 +29,15 @@ func main() {
|
||||
dir, _, err := mod.FindGoMod(".")
|
||||
check(err)
|
||||
|
||||
ssa.Initialize(ssa.InitAll | ssa.InitNative)
|
||||
llgen.Verbose = false
|
||||
|
||||
llgenDir(dir + "/cl/_testlibc")
|
||||
llgenDir(dir + "/cl/_testlibgo")
|
||||
llgenDir(dir + "/cl/_testrt")
|
||||
llgenDir(dir + "/cl/_testgo")
|
||||
llgenDir(dir+"/cl/_testpy", "")
|
||||
llgenDir(dir+"/cl/_testdata", "")
|
||||
llgenDir(dir + "/cl/_testpy")
|
||||
llgenDir(dir + "/cl/_testdata")
|
||||
}
|
||||
|
||||
func llgenDir(dir string, pkgPath ...string) {
|
||||
func llgenDir(dir string) {
|
||||
fis, err := os.ReadDir(dir)
|
||||
check(err)
|
||||
for _, fi := range fis {
|
||||
@@ -51,8 +47,8 @@ func llgenDir(dir string, pkgPath ...string) {
|
||||
}
|
||||
testDir := dir + "/" + name
|
||||
fmt.Fprintln(os.Stderr, "llgen", testDir)
|
||||
os.Chdir(testDir)
|
||||
llgen.SmartDoFile("in.go", pkgPath...)
|
||||
check(os.Chdir(testDir))
|
||||
llgen.SmartDoFile(testDir)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// TODO(xsw): implement gogensig tool
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
llcppg - Autogen tool for C/C++ libraries
|
||||
====
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
llcppg [config-file]
|
||||
```
|
||||
|
||||
If `config-file` is not specified, a `llcppg.cfg` file is used in current directory. The configuration file format is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inireader",
|
||||
"cflags": "$(pkg-config --cflags inireader)",
|
||||
"include": [
|
||||
"INIReader.h",
|
||||
"AnotherHeaderFile.h"
|
||||
],
|
||||
"libs": "$(pkg-config --libs inireader)",
|
||||
"trimPrefixes": ["Ini", "INI"]
|
||||
}
|
||||
```
|
||||
|
||||
## Design
|
||||
|
||||
See [llcppg Design](design.md).
|
||||
@@ -1,378 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ast
|
||||
|
||||
import "github.com/goplus/llgo/chore/llcppg/token"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
type Node interface {
|
||||
}
|
||||
|
||||
type Expr interface {
|
||||
Node
|
||||
exprNode()
|
||||
}
|
||||
|
||||
type Decl interface {
|
||||
Node
|
||||
declNode()
|
||||
}
|
||||
|
||||
type Stmt interface {
|
||||
Node
|
||||
stmtNode()
|
||||
}
|
||||
|
||||
type PPD interface { // preprocessing directive
|
||||
Node
|
||||
ppdNode()
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
type AccessSpecifier uint
|
||||
|
||||
const (
|
||||
Invalid AccessSpecifier = iota
|
||||
Public
|
||||
Protected
|
||||
Private
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// Expressions (Types are also expressions)
|
||||
|
||||
type BasicLitKind uint
|
||||
|
||||
const (
|
||||
IntLit BasicLitKind = iota
|
||||
FloatLit
|
||||
CharLit
|
||||
StringLit
|
||||
)
|
||||
|
||||
type BasicLit struct {
|
||||
Kind BasicLitKind
|
||||
Value string
|
||||
}
|
||||
|
||||
func (*BasicLit) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type TypeKind uint
|
||||
|
||||
const (
|
||||
Void TypeKind = iota
|
||||
Bool
|
||||
Char
|
||||
Char16
|
||||
Char32
|
||||
WChar
|
||||
Int
|
||||
Int128
|
||||
Float
|
||||
Float16
|
||||
Float128
|
||||
Complex
|
||||
)
|
||||
|
||||
type TypeFlag uint
|
||||
|
||||
const (
|
||||
Signed TypeFlag = 1 << iota
|
||||
Unsigned
|
||||
Long
|
||||
LongLong
|
||||
Double
|
||||
Short
|
||||
)
|
||||
|
||||
// [signed/unsigned/short/long/long long/double] [int]/char/float/complex/bool
|
||||
type BuiltinType struct {
|
||||
Kind TypeKind
|
||||
Flags TypeFlag
|
||||
}
|
||||
|
||||
func (*BuiltinType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Name
|
||||
type Ident struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (*Ident) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Tag int
|
||||
|
||||
const (
|
||||
Struct Tag = iota
|
||||
Union
|
||||
Enum
|
||||
Class
|
||||
)
|
||||
|
||||
// struct/union/enum/class (A::B::)Name
|
||||
type TagExpr struct {
|
||||
Tag Tag
|
||||
Name Expr // ScopingExpr, Ident
|
||||
}
|
||||
|
||||
func (*TagExpr) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// type a, ...
|
||||
type Variadic struct {
|
||||
}
|
||||
|
||||
func (*Variadic) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// (X)
|
||||
type ParenExpr struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*ParenExpr) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Parent::X
|
||||
type ScopingExpr struct {
|
||||
Parent Expr
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*ScopingExpr) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// X*
|
||||
type PointerType struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*PointerType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// X&
|
||||
type LvalueRefType struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*LvalueRefType) exprNode() {}
|
||||
|
||||
// X&&
|
||||
type RvalueRefType struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*RvalueRefType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Elt[Len]
|
||||
// Elt[]
|
||||
type ArrayType struct {
|
||||
Elt Expr
|
||||
Len Expr // optional
|
||||
}
|
||||
|
||||
func (*ArrayType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Comment struct {
|
||||
Text string // comment text (excluding '\n' for //-style comments)
|
||||
}
|
||||
|
||||
func (*Comment) exprNode() {}
|
||||
|
||||
type CommentGroup struct {
|
||||
List []*Comment // len(List) > 0
|
||||
}
|
||||
|
||||
func (*CommentGroup) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Field struct {
|
||||
Doc *CommentGroup // associated documentation; or nil
|
||||
Type Expr // field/method/parameter type; or nil
|
||||
Names []*Ident // field/method/(type) parameter names; or nil
|
||||
Comment *CommentGroup // line comments; or nil
|
||||
Access AccessSpecifier // field access(Record Type); Struct Field default is Public,Class Field default is Private
|
||||
IsStatic bool // static field
|
||||
}
|
||||
|
||||
func (*Field) exprNode() {}
|
||||
|
||||
type FieldList struct {
|
||||
List []*Field // field list; or nil
|
||||
}
|
||||
|
||||
func (*FieldList) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Ret (*)(Params)
|
||||
type FuncType struct {
|
||||
Params *FieldList
|
||||
Ret Expr
|
||||
}
|
||||
|
||||
func (*FuncType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type RecordType struct {
|
||||
Tag Tag
|
||||
Fields *FieldList
|
||||
Methods []*FuncDecl
|
||||
}
|
||||
|
||||
func (*RecordType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Template<Arg1, Arg2, ...>
|
||||
type InstantiationType struct {
|
||||
Template Expr
|
||||
Args *FieldList
|
||||
}
|
||||
|
||||
func (*InstantiationType) exprNode() {}
|
||||
|
||||
// =============================================================================
|
||||
// Declarations
|
||||
|
||||
type Location struct {
|
||||
File string
|
||||
}
|
||||
|
||||
type DeclBase struct {
|
||||
Doc *CommentGroup // associated documentation; or nil
|
||||
Loc *Location
|
||||
Parent Expr // namespace or class
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// typedef Type Name;
|
||||
type TypedefDecl struct {
|
||||
DeclBase
|
||||
Type Expr
|
||||
Name *Ident
|
||||
}
|
||||
|
||||
func (*TypedefDecl) declNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type EnumItem struct {
|
||||
Name *Ident
|
||||
Value Expr // optional
|
||||
}
|
||||
|
||||
func (*EnumItem) exprNode() {}
|
||||
|
||||
type EnumType struct {
|
||||
Items []*EnumItem
|
||||
}
|
||||
|
||||
func (*EnumType) exprNode() {}
|
||||
|
||||
// enum Name { Item1, Item2, ... };
|
||||
type EnumTypeDecl struct {
|
||||
DeclBase
|
||||
Name *Ident
|
||||
Type *EnumType
|
||||
}
|
||||
|
||||
func (*EnumTypeDecl) declNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Ret Name(Params);
|
||||
type FuncDecl struct {
|
||||
DeclBase
|
||||
Name *Ident
|
||||
Type *FuncType
|
||||
IsInline bool
|
||||
IsStatic bool
|
||||
|
||||
// Class method specific fields
|
||||
IsConst bool // const member function
|
||||
IsExplicit bool // explicit constructor
|
||||
IsConstructor bool
|
||||
IsDestructor bool
|
||||
IsVirtual bool
|
||||
IsOverride bool
|
||||
}
|
||||
|
||||
func (*FuncDecl) declNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// struct/union/class Name { Field1, Field2, ... };
|
||||
type TypeDecl struct {
|
||||
DeclBase
|
||||
Name *Ident
|
||||
Type *RecordType
|
||||
}
|
||||
|
||||
func (*TypeDecl) declNode() {}
|
||||
|
||||
// =============================================================================
|
||||
// AST File
|
||||
|
||||
type Include struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
func (*Include) ppdNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Token struct {
|
||||
Token token.Token
|
||||
Lit string
|
||||
}
|
||||
|
||||
type Macro struct {
|
||||
Name string
|
||||
Tokens []*Token // Tokens[0].Lit is the macro name
|
||||
}
|
||||
|
||||
func (*Macro) ppdNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type File struct {
|
||||
Decls []Decl `json:"decls"`
|
||||
Includes []*Include `json:"includes,omitempty"`
|
||||
Macros []*Macro `json:"macros,omitempty"`
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -1,84 +0,0 @@
|
||||
llcppg Design
|
||||
=====
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
llcppg [config-file]
|
||||
```
|
||||
|
||||
If `config-file` is not specified, a `llcppg.cfg` file is used in current directory. The configuration file format is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inih",
|
||||
"cflags": "$(pkg-config --cflags inireader)",
|
||||
"include": [
|
||||
"INIReader.h",
|
||||
"AnotherHeaderFile.h"
|
||||
],
|
||||
"libs": "$(pkg-config --libs inireader)",
|
||||
"trimPrefixes": ["Ini", "INI"]
|
||||
}
|
||||
```
|
||||
|
||||
## Steps
|
||||
|
||||
1. llcppsymg: Generate symbol table for a C/C++ library
|
||||
2. Manually modify the desired Go symbols in symbol table
|
||||
3. llcppsigfetch: Fetch information of C/C++ symbols
|
||||
4. gogensig: Generate a go package by information of symbols
|
||||
|
||||
|
||||
### llcppsymg
|
||||
|
||||
```sh
|
||||
llcppsymg config-file
|
||||
llcppsymg - # read config from stdin
|
||||
```
|
||||
|
||||
It generates a symbol table file named `llcppg.symb.json`. Its file format is as follows:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"mangle": "_ZN9INIReaderC1EPKcm",
|
||||
"c++": "INIReader::INIReader(char const*, unsigned long)",
|
||||
"go": "(*Reader).Init__0"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
### llcppsigfetch
|
||||
|
||||
```sh
|
||||
llcppsigfetch config-file
|
||||
llcppsigfetch - # read config from stdin
|
||||
```
|
||||
|
||||
It fetches information of C/C++ symbols and print to stdout. Its format is as follows:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"path": "/path/to/file.h",
|
||||
"doc": {
|
||||
"decls": [],
|
||||
"macros": [],
|
||||
"includes": [
|
||||
{
|
||||
"path": "incfile.h"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### gogensig
|
||||
|
||||
```sh
|
||||
gogensig ast-file
|
||||
gogensig - # read AST from stdin
|
||||
```
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/goplus/llgo/chore/llcppg/types"
|
||||
"github.com/goplus/llgo/xtool/env"
|
||||
)
|
||||
|
||||
func llcppsymg(conf []byte) error {
|
||||
cmd := exec.Command("llcppsymg", "-")
|
||||
cmd.Stdin = bytes.NewReader(conf)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func llcppsigfetch(conf []byte, out io.Writer) {
|
||||
cmd := exec.Command("llcppsigfetch", "-")
|
||||
cmd.Stdin = bytes.NewReader(conf)
|
||||
cmd.Stdout = out
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
check(err)
|
||||
}
|
||||
|
||||
func gogensig(in io.Reader) error {
|
||||
cmd := exec.Command("gogensig", "-")
|
||||
cmd.Stdin = in
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfgFile := "llcppg.cfg"
|
||||
if len(os.Args) > 1 {
|
||||
cfgFile = os.Args[1]
|
||||
}
|
||||
if cfgFile == "-h" || cfgFile == "--help" {
|
||||
fmt.Fprintln(os.Stderr, "Usage: llcppg [config-file]")
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open(cfgFile)
|
||||
check(err)
|
||||
defer f.Close()
|
||||
|
||||
var conf types.Config
|
||||
json.NewDecoder(f).Decode(&conf)
|
||||
conf.CFlags = env.ExpandEnv(conf.CFlags)
|
||||
conf.Libs = env.ExpandEnv(conf.Libs)
|
||||
|
||||
b, err := json.MarshalIndent(&conf, "", " ")
|
||||
check(err)
|
||||
|
||||
err = llcppsymg(b)
|
||||
check(err)
|
||||
|
||||
r, w := io.Pipe()
|
||||
go llcppsigfetch(b, w)
|
||||
|
||||
err = gogensig(r)
|
||||
check(err)
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package token
|
||||
|
||||
type Token uint
|
||||
|
||||
const (
|
||||
ILLEGAL Token = iota
|
||||
|
||||
/**
|
||||
* A token that contains some kind of punctuation.
|
||||
*/
|
||||
PUNCT
|
||||
|
||||
/**
|
||||
* A language keyword.
|
||||
*/
|
||||
KEYWORD
|
||||
|
||||
/**
|
||||
* An identifier (that is not a keyword).
|
||||
*/
|
||||
IDENT
|
||||
|
||||
/**
|
||||
* A numeric, string, or character literal.
|
||||
*/
|
||||
LITERAL
|
||||
|
||||
/**
|
||||
* A comment.
|
||||
*/
|
||||
COMMENT
|
||||
)
|
||||
@@ -17,6 +17,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@@ -24,11 +25,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: llgen <pkg> [pkgPath]")
|
||||
flag.Parse()
|
||||
if len(flag.Args()) != 1 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: llgen [flags] <pkg>")
|
||||
return
|
||||
}
|
||||
|
||||
llgen.Init()
|
||||
llgen.SmartDoFile(os.Args[1], os.Args[2:]...)
|
||||
llgen.SmartDoFile(flag.Args()[0])
|
||||
}
|
||||
|
||||
@@ -22,25 +22,41 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/xtool/env/llvm"
|
||||
nmtool "github.com/goplus/llgo/xtool/nm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: nmdump libfile")
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: nmdump [flags] libfile")
|
||||
return
|
||||
}
|
||||
|
||||
nm := llvm.New("").Nm()
|
||||
items, err := nm.List(os.Args[1])
|
||||
|
||||
var flags []string
|
||||
libfile := os.Args[len(os.Args)-1]
|
||||
if len(os.Args) > 2 {
|
||||
flags = os.Args[1 : len(os.Args)-1]
|
||||
}
|
||||
|
||||
items, err := nm.List(libfile, flags...)
|
||||
|
||||
for _, item := range items {
|
||||
if item.File != "" {
|
||||
fmt.Printf("\n%s:\n", item.File)
|
||||
}
|
||||
for _, sym := range item.Symbols {
|
||||
var versionInfo string
|
||||
switch sym.VersionType {
|
||||
case nmtool.VersionSpecific:
|
||||
versionInfo = fmt.Sprintf("@%s", sym.Version)
|
||||
case nmtool.VersionDefault:
|
||||
versionInfo = fmt.Sprintf("@@%s", sym.Version)
|
||||
}
|
||||
if sym.FAddr {
|
||||
fmt.Printf("%016x %c %s\n", sym.Addr, sym.Type, sym.Name)
|
||||
fmt.Printf("%016x %c %s%s\n", sym.Addr, sym.Type, sym.Name, versionInfo)
|
||||
} else {
|
||||
fmt.Printf("%16s %c %s\n", "", sym.Type, sym.Name)
|
||||
fmt.Printf("%16s %c %s%s\n", "", sym.Type, sym.Name, versionInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
; ModuleID = 'apkg'
|
||||
source_filename = "apkg"
|
||||
; ModuleID = 'github.com/goplus/llgo/cl/_testdata/apkg'
|
||||
source_filename = "github.com/goplus/llgo/cl/_testdata/apkg"
|
||||
|
||||
@"apkg.init$guard" = global i1 false, align 1
|
||||
@"github.com/goplus/llgo/cl/_testdata/apkg.init$guard" = global i1 false, align 1
|
||||
|
||||
define double @apkg.Max(double %0, double %1) {
|
||||
define double @"github.com/goplus/llgo/cl/_testdata/apkg.Max"(double %0, double %1) {
|
||||
_llgo_0:
|
||||
%2 = fcmp ogt double %0, %1
|
||||
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||
@@ -15,13 +15,13 @@ _llgo_2: ; preds = %_llgo_0
|
||||
ret double %1
|
||||
}
|
||||
|
||||
define void @apkg.init() {
|
||||
define void @"github.com/goplus/llgo/cl/_testdata/apkg.init"() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"apkg.init$guard", align 1
|
||||
%0 = load i1, ptr @"github.com/goplus/llgo/cl/_testdata/apkg.init$guard", align 1
|
||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
store i1 true, ptr @"apkg.init$guard", align 1
|
||||
store i1 true, ptr @"github.com/goplus/llgo/cl/_testdata/apkg.init$guard", align 1
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
|
||||
1
cl/_testdata/debug/flags.txt
Normal file
1
cl/_testdata/debug/flags.txt
Normal file
@@ -0,0 +1 @@
|
||||
-dbg
|
||||
569
cl/_testdata/debug/in.go
Normal file
569
cl/_testdata/debug/in.go
Normal file
@@ -0,0 +1,569 @@
|
||||
package main
|
||||
|
||||
import "errors"
|
||||
|
||||
type Base struct {
|
||||
name string
|
||||
}
|
||||
|
||||
type E struct {
|
||||
// Base
|
||||
i int
|
||||
}
|
||||
type StructWithAllTypeFields struct {
|
||||
i8 int8
|
||||
i16 int16
|
||||
i32 int32
|
||||
i64 int64
|
||||
i int
|
||||
u8 uint8
|
||||
u16 uint16
|
||||
u32 uint32
|
||||
u64 uint64
|
||||
u uint
|
||||
f32 float32
|
||||
f64 float64
|
||||
b bool
|
||||
c64 complex64
|
||||
c128 complex128
|
||||
slice []int
|
||||
arr [3]int
|
||||
arr2 [3]E
|
||||
s string
|
||||
e E
|
||||
pf *StructWithAllTypeFields // resursive
|
||||
pi *int
|
||||
intr Interface
|
||||
m map[string]uint64
|
||||
c chan int
|
||||
err error
|
||||
fn func(string) (int, error)
|
||||
pad1 int
|
||||
pad2 int
|
||||
}
|
||||
|
||||
type Interface interface {
|
||||
Foo(a []int, b string) int
|
||||
}
|
||||
|
||||
type Struct struct{}
|
||||
|
||||
func (s *Struct) Foo(a []int, b string) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func FuncWithAllTypeStructParam(s StructWithAllTypeFields) {
|
||||
println(&s)
|
||||
// Expected:
|
||||
// all variables: s
|
||||
// s.i8: '\x01'
|
||||
// s.i16: 2
|
||||
// s.i32: 3
|
||||
// s.i64: 4
|
||||
// s.i: 5
|
||||
// s.u8: '\x06'
|
||||
// s.u16: 7
|
||||
// s.u32: 8
|
||||
// s.u64: 9
|
||||
// s.u: 10
|
||||
// s.f32: 11
|
||||
// s.f64: 12
|
||||
// s.b: true
|
||||
// s.c64: complex64{real = 13, imag = 14}
|
||||
// s.c128: complex128{real = 15, imag = 16}
|
||||
// s.slice: []int{21, 22, 23}
|
||||
// s.arr: [3]int{24, 25, 26}
|
||||
// s.arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
|
||||
// s.s: "hello"
|
||||
// s.e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||
// s.pad1: 100
|
||||
// s.pad2: 200
|
||||
s.i8 = '\b'
|
||||
// Expected:
|
||||
// s.i8: '\b'
|
||||
// s.i16: 2
|
||||
println(len(s.s), s.i8)
|
||||
}
|
||||
|
||||
// Params is a function with all types of parameters.
|
||||
func FuncWithAllTypeParams(
|
||||
i8 int8,
|
||||
i16 int16,
|
||||
i32 int32,
|
||||
i64 int64,
|
||||
i int,
|
||||
u8 uint8,
|
||||
u16 uint16,
|
||||
u32 uint32,
|
||||
u64 uint64,
|
||||
u uint,
|
||||
f32 float32,
|
||||
f64 float64,
|
||||
b bool,
|
||||
c64 complex64,
|
||||
c128 complex128,
|
||||
slice []int,
|
||||
arr [3]int,
|
||||
arr2 [3]E,
|
||||
s string,
|
||||
e E,
|
||||
f StructWithAllTypeFields,
|
||||
pf *StructWithAllTypeFields,
|
||||
pi *int,
|
||||
intr Interface,
|
||||
m map[string]uint64,
|
||||
c chan int,
|
||||
err error,
|
||||
fn func(string) (int, error),
|
||||
) (int, error) {
|
||||
// Expected:
|
||||
// all variables: i8 i16 i32 i64 i u8 u16 u32 u64 u f32 f64 b c64 c128 slice arr arr2 s e f pf pi intr m c err fn
|
||||
// i32: 3
|
||||
// i64: 4
|
||||
// i: 5
|
||||
// u32: 8
|
||||
// u64: 9
|
||||
// u: 10
|
||||
// f32: 11
|
||||
// f64: 12
|
||||
// slice: []int{21, 22, 23}
|
||||
// arr: [3]int{24, 25, 26}
|
||||
// arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
|
||||
// slice[0]: 21
|
||||
// slice[1]: 22
|
||||
// slice[2]: 23
|
||||
// arr[0]: 24
|
||||
// arr[1]: 25
|
||||
// arr[2]: 26
|
||||
// arr2[0].i: 27
|
||||
// arr2[1].i: 28
|
||||
// arr2[2].i: 29
|
||||
// e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||
|
||||
// Expected(skip):
|
||||
// i8: '\b'
|
||||
// i16: 2
|
||||
// u8: '\x06'
|
||||
// u16: 7
|
||||
// b: true
|
||||
println(
|
||||
i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
||||
f32, f64, b,
|
||||
c64, c128,
|
||||
slice, arr[0:],
|
||||
s,
|
||||
&e,
|
||||
&f, pf, pi, intr, m,
|
||||
c,
|
||||
err,
|
||||
fn,
|
||||
)
|
||||
i8 = 9
|
||||
i16 = 10
|
||||
i32 = 11
|
||||
i64 = 12
|
||||
i = 13
|
||||
u8 = 14
|
||||
u16 = 15
|
||||
u32 = 16
|
||||
u64 = 17
|
||||
u = 18
|
||||
f32 = 19
|
||||
f64 = 20
|
||||
b = false
|
||||
c64 = 21 + 22i
|
||||
c128 = 23 + 24i
|
||||
slice = []int{31, 32, 33}
|
||||
arr = [3]int{34, 35, 36}
|
||||
arr2 = [3]E{{i: 37}, {i: 38}, {i: 39}}
|
||||
s = "world"
|
||||
e = E{i: 40}
|
||||
|
||||
println(i8, i16, i32, i64, i, u8, u16, u32, u64, u,
|
||||
f32, f64, b,
|
||||
c64, c128,
|
||||
slice, arr[0:], &arr2,
|
||||
s,
|
||||
&e,
|
||||
&f, pf, pi, intr, m,
|
||||
c,
|
||||
err,
|
||||
fn,
|
||||
)
|
||||
// Expected:
|
||||
// i8: '\t'
|
||||
// i16: 10
|
||||
// i32: 11
|
||||
// i64: 12
|
||||
// i: 13
|
||||
// u8: '\x0e'
|
||||
// u16: 15
|
||||
// u32: 16
|
||||
// u64: 17
|
||||
// u: 18
|
||||
// f32: 19
|
||||
// f64: 20
|
||||
// b: false
|
||||
// c64: complex64{real = 21, imag = 22}
|
||||
// c128: complex128{real = 23, imag = 24}
|
||||
// slice: []int{31, 32, 33}
|
||||
// arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 37}, {i = 38}, {i = 39}}
|
||||
// s: "world"
|
||||
// e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 40}
|
||||
|
||||
// Expected(skip):
|
||||
// arr: [3]int{34, 35, 36}
|
||||
return 1, errors.New("some error")
|
||||
}
|
||||
|
||||
type TinyStruct struct {
|
||||
I int
|
||||
}
|
||||
|
||||
type SmallStruct struct {
|
||||
I int
|
||||
J int
|
||||
}
|
||||
|
||||
type MidStruct struct {
|
||||
I int
|
||||
J int
|
||||
K int
|
||||
}
|
||||
|
||||
type BigStruct struct {
|
||||
I int
|
||||
J int
|
||||
K int
|
||||
L int
|
||||
M int
|
||||
N int
|
||||
O int
|
||||
P int
|
||||
Q int
|
||||
R int
|
||||
}
|
||||
|
||||
func FuncStructParams(t TinyStruct, s SmallStruct, m MidStruct, b BigStruct) {
|
||||
// println(&t, &s, &m, &b)
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 1
|
||||
// s.I: 2
|
||||
// s.J: 3
|
||||
// m.I: 4
|
||||
// m.J: 5
|
||||
// m.K: 6
|
||||
// b.I: 7
|
||||
// b.J: 8
|
||||
// b.K: 9
|
||||
// b.L: 10
|
||||
// b.M: 11
|
||||
// b.N: 12
|
||||
// b.O: 13
|
||||
// b.P: 14
|
||||
// b.Q: 15
|
||||
// b.R: 16
|
||||
println(t.I, s.I, s.J, m.I, m.J, m.K, b.I, b.J, b.K, b.L, b.M, b.N, b.O, b.P, b.Q, b.R)
|
||||
t.I = 10
|
||||
s.I = 20
|
||||
s.J = 21
|
||||
m.I = 40
|
||||
m.J = 41
|
||||
m.K = 42
|
||||
b.I = 70
|
||||
b.J = 71
|
||||
b.K = 72
|
||||
b.L = 73
|
||||
b.M = 74
|
||||
b.N = 75
|
||||
b.O = 76
|
||||
b.P = 77
|
||||
b.Q = 78
|
||||
b.R = 79
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 10
|
||||
// s.I: 20
|
||||
// s.J: 21
|
||||
// m.I: 40
|
||||
// m.J: 41
|
||||
// m.K: 42
|
||||
// b.I: 70
|
||||
// b.J: 71
|
||||
// b.K: 72
|
||||
// b.L: 73
|
||||
// b.M: 74
|
||||
// b.N: 75
|
||||
// b.O: 76
|
||||
// b.P: 77
|
||||
// b.Q: 78
|
||||
// b.R: 79
|
||||
println("done")
|
||||
}
|
||||
|
||||
func FuncStructPtrParams(t *TinyStruct, s *SmallStruct, m *MidStruct, b *BigStruct) {
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 1
|
||||
// s.I: 2
|
||||
// s.J: 3
|
||||
// m.I: 4
|
||||
// m.J: 5
|
||||
// m.K: 6
|
||||
// b.I: 7
|
||||
// b.J: 8
|
||||
// b.K: 9
|
||||
// b.L: 10
|
||||
// b.M: 11
|
||||
// b.N: 12
|
||||
// b.O: 13
|
||||
// b.P: 14
|
||||
// b.Q: 15
|
||||
// b.R: 16
|
||||
println(t, s, m, b)
|
||||
t.I = 10
|
||||
s.I = 20
|
||||
s.J = 21
|
||||
m.I = 40
|
||||
m.J = 41
|
||||
m.K = 42
|
||||
b.I = 70
|
||||
b.J = 71
|
||||
b.K = 72
|
||||
b.L = 73
|
||||
b.M = 74
|
||||
b.N = 75
|
||||
b.O = 76
|
||||
b.P = 77
|
||||
b.Q = 78
|
||||
b.R = 79
|
||||
// Expected:
|
||||
// all variables: t s m b
|
||||
// t.I: 10
|
||||
// s.I: 20
|
||||
// s.J: 21
|
||||
// m.I: 40
|
||||
// m.J: 41
|
||||
// m.K: 42
|
||||
// b.I: 70
|
||||
// b.J: 71
|
||||
// b.K: 72
|
||||
// b.L: 73
|
||||
// b.M: 74
|
||||
// b.N: 75
|
||||
// b.O: 76
|
||||
// b.P: 77
|
||||
// b.Q: 78
|
||||
// b.R: 79
|
||||
println(t.I, s.I, s.J, m.I, m.J, m.K, b.I, b.J, b.K, b.L, b.M, b.N, b.O, b.P, b.Q, b.R)
|
||||
println("done")
|
||||
}
|
||||
|
||||
func ScopeIf(branch int) {
|
||||
a := 1
|
||||
// Expected:
|
||||
// all variables: a branch
|
||||
// a: 1
|
||||
if branch == 1 {
|
||||
b := 2
|
||||
c := 3
|
||||
// Expected:
|
||||
// all variables: a b c branch
|
||||
// a: 1
|
||||
// b: 2
|
||||
// c: 3
|
||||
// branch: 1
|
||||
println(a, b, c)
|
||||
} else {
|
||||
c := 3
|
||||
d := 4
|
||||
// Expected:
|
||||
// all variables: a c d branch
|
||||
// a: 1
|
||||
// c: 3
|
||||
// d: 4
|
||||
// branch: 0
|
||||
println(a, c, d)
|
||||
}
|
||||
// Expected:
|
||||
// all variables: a branch
|
||||
// a: 1
|
||||
println("a:", a)
|
||||
}
|
||||
|
||||
func ScopeFor() {
|
||||
a := 1
|
||||
for i := 0; i < 10; i++ {
|
||||
switch i {
|
||||
case 0:
|
||||
println("i is 0")
|
||||
// Expected:
|
||||
// all variables: i a
|
||||
// i: 0
|
||||
// a: 1
|
||||
println("i:", i)
|
||||
case 1:
|
||||
println("i is 1")
|
||||
// Expected:
|
||||
// all variables: i a
|
||||
// i: 1
|
||||
// a: 1
|
||||
println("i:", i)
|
||||
default:
|
||||
println("i is", i)
|
||||
}
|
||||
}
|
||||
println("a:", a)
|
||||
}
|
||||
|
||||
func ScopeSwitch(i int) {
|
||||
a := 0
|
||||
switch i {
|
||||
case 1:
|
||||
b := 1
|
||||
println("i is 1")
|
||||
// Expected:
|
||||
// all variables: i a b
|
||||
// i: 1
|
||||
// a: 0
|
||||
// b: 1
|
||||
println("i:", i, "a:", a, "b:", b)
|
||||
case 2:
|
||||
c := 2
|
||||
println("i is 2")
|
||||
// Expected:
|
||||
// all variables: i a c
|
||||
// i: 2
|
||||
// a: 0
|
||||
// c: 2
|
||||
println("i:", i, "a:", a, "c:", c)
|
||||
default:
|
||||
d := 3
|
||||
println("i is", i)
|
||||
// Expected:
|
||||
// all variables: i a d
|
||||
// i: 3
|
||||
// a: 0
|
||||
// d: 3
|
||||
println("i:", i, "a:", a, "d:", d)
|
||||
}
|
||||
// Expected:
|
||||
// all variables: a i
|
||||
// a: 0
|
||||
println("a:", a)
|
||||
}
|
||||
|
||||
func main() {
|
||||
FuncStructParams(TinyStruct{I: 1}, SmallStruct{I: 2, J: 3}, MidStruct{I: 4, J: 5, K: 6}, BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
|
||||
FuncStructPtrParams(&TinyStruct{I: 1}, &SmallStruct{I: 2, J: 3}, &MidStruct{I: 4, J: 5, K: 6}, &BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
|
||||
i := 100
|
||||
s := StructWithAllTypeFields{
|
||||
i8: 1,
|
||||
i16: 2,
|
||||
i32: 3,
|
||||
i64: 4,
|
||||
i: 5,
|
||||
u8: 6,
|
||||
u16: 7,
|
||||
u32: 8,
|
||||
u64: 9,
|
||||
u: 10,
|
||||
f32: 11,
|
||||
f64: 12,
|
||||
b: true,
|
||||
c64: 13 + 14i,
|
||||
c128: 15 + 16i,
|
||||
slice: []int{21, 22, 23},
|
||||
arr: [3]int{24, 25, 26},
|
||||
arr2: [3]E{{i: 27}, {i: 28}, {i: 29}},
|
||||
s: "hello",
|
||||
e: E{i: 30},
|
||||
pf: &StructWithAllTypeFields{i16: 100},
|
||||
pi: &i,
|
||||
intr: &Struct{},
|
||||
m: map[string]uint64{"a": 31, "b": 32},
|
||||
c: make(chan int),
|
||||
err: errors.New("Test error"),
|
||||
fn: func(s string) (int, error) {
|
||||
println("fn:", s)
|
||||
i = 201
|
||||
return 1, errors.New("fn error")
|
||||
},
|
||||
pad1: 100,
|
||||
pad2: 200,
|
||||
}
|
||||
// Expected:
|
||||
// all variables: s i err
|
||||
// s.i8: '\x01'
|
||||
// s.i16: 2
|
||||
// s.i32: 3
|
||||
// s.i64: 4
|
||||
// s.i: 5
|
||||
// s.u8: '\x06'
|
||||
// s.u16: 7
|
||||
// s.u32: 8
|
||||
// s.u64: 9
|
||||
// s.u: 10
|
||||
// s.f32: 11
|
||||
// s.f64: 12
|
||||
// s.b: true
|
||||
// s.c64: complex64{real = 13, imag = 14}
|
||||
// s.c128: complex128{real = 15, imag = 16}
|
||||
// s.slice: []int{21, 22, 23}
|
||||
// s.arr: [3]int{24, 25, 26}
|
||||
// s.arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
|
||||
// s.s: "hello"
|
||||
// s.e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
|
||||
// s.pf.i16: 100
|
||||
// *(s.pf).i16: 100
|
||||
// *(s.pi): 100
|
||||
globalStructPtr = &s
|
||||
globalStruct = s
|
||||
println("globalInt:", globalInt)
|
||||
// Expected(skip):
|
||||
// all variables: globalInt globalStruct globalStructPtr s i err
|
||||
println("s:", &s)
|
||||
FuncWithAllTypeStructParam(s)
|
||||
println("called function with struct")
|
||||
i, err := FuncWithAllTypeParams(
|
||||
s.i8, s.i16, s.i32, s.i64, s.i, s.u8, s.u16, s.u32, s.u64, s.u,
|
||||
s.f32, s.f64, s.b,
|
||||
s.c64, s.c128,
|
||||
s.slice, s.arr, s.arr2,
|
||||
s.s,
|
||||
s.e, s,
|
||||
s.pf, s.pi,
|
||||
s.intr,
|
||||
s.m,
|
||||
s.c,
|
||||
s.err,
|
||||
s.fn,
|
||||
)
|
||||
println(i, err)
|
||||
ScopeIf(1)
|
||||
ScopeIf(0)
|
||||
ScopeFor()
|
||||
ScopeSwitch(1)
|
||||
ScopeSwitch(2)
|
||||
ScopeSwitch(3)
|
||||
println(globalStructPtr)
|
||||
println(&globalStruct)
|
||||
s.i8 = 0x12
|
||||
println(s.i8)
|
||||
// Expected:
|
||||
// all variables: s i err
|
||||
// s.i8: '\x12'
|
||||
|
||||
// Expected(skip):
|
||||
// globalStruct.i8: '\x01'
|
||||
println((*globalStructPtr).i8)
|
||||
println("done")
|
||||
println("")
|
||||
println(&s, &globalStruct, globalStructPtr.i16, globalStructPtr)
|
||||
globalStructPtr = nil
|
||||
}
|
||||
|
||||
var globalInt int = 301
|
||||
var globalStruct StructWithAllTypeFields
|
||||
var globalStructPtr *StructWithAllTypeFields
|
||||
1
cl/_testdata/debug/out.ll
Normal file
1
cl/_testdata/debug/out.ll
Normal file
@@ -0,0 +1 @@
|
||||
;
|
||||
7
cl/_testdata/llgotag/in.go
Normal file
7
cl/_testdata/llgotag/in.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build llgo
|
||||
// +build llgo
|
||||
|
||||
package llgotag
|
||||
|
||||
func Foo() {
|
||||
}
|
||||
22
cl/_testdata/llgotag/out.ll
Normal file
22
cl/_testdata/llgotag/out.ll
Normal file
@@ -0,0 +1,22 @@
|
||||
; ModuleID = 'github.com/goplus/llgo/cl/_testdata/llgotag'
|
||||
source_filename = "github.com/goplus/llgo/cl/_testdata/llgotag"
|
||||
|
||||
@"github.com/goplus/llgo/cl/_testdata/llgotag.init$guard" = global i1 false, align 1
|
||||
|
||||
define void @"github.com/goplus/llgo/cl/_testdata/llgotag.Foo"() {
|
||||
_llgo_0:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @"github.com/goplus/llgo/cl/_testdata/llgotag.init"() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"github.com/goplus/llgo/cl/_testdata/llgotag.init$guard", align 1
|
||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
store i1 true, ptr @"github.com/goplus/llgo/cl/_testdata/llgotag.init$guard", align 1
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,41 +52,27 @@ _llgo_0:
|
||||
br label %_llgo_3
|
||||
|
||||
_llgo_1: ; preds = %_llgo_3
|
||||
%2 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 0
|
||||
store ptr @0, ptr %3, align 8
|
||||
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 1
|
||||
store i64 7, ptr %4, align 4
|
||||
%5 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %2, align 8
|
||||
%6 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %5, 1
|
||||
%7 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" %5, i64 %15, i64 %6)
|
||||
%8 = call { i32, i64 } @"unicode/utf8.DecodeRuneInString"(%"github.com/goplus/llgo/internal/runtime.String" %7)
|
||||
%9 = extractvalue { i32, i64 } %8, 0
|
||||
%10 = extractvalue { i32, i64 } %8, 1
|
||||
%11 = add i64 %15, %10
|
||||
%12 = sext i32 %9 to i64
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %12)
|
||||
%2 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringSlice"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @0, i64 7 }, i64 %10, i64 7)
|
||||
%3 = call { i32, i64 } @"unicode/utf8.DecodeRuneInString"(%"github.com/goplus/llgo/internal/runtime.String" %2)
|
||||
%4 = extractvalue { i32, i64 } %3, 0
|
||||
%5 = extractvalue { i32, i64 } %3, 1
|
||||
%6 = add i64 %10, %5
|
||||
%7 = sext i32 %4 to i64
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %7)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
br label %_llgo_3
|
||||
|
||||
_llgo_2: ; preds = %_llgo_3
|
||||
%13 = call i8 @main.index(i8 2)
|
||||
%14 = icmp eq i8 %13, 3
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %14)
|
||||
%8 = call i8 @main.index(i8 2)
|
||||
%9 = icmp eq i8 %8, 3
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %9)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
ret i32 0
|
||||
|
||||
_llgo_3: ; preds = %_llgo_1, %_llgo_0
|
||||
%15 = phi i64 [ 0, %_llgo_0 ], [ %11, %_llgo_1 ]
|
||||
%16 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%17 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %16, i32 0, i32 0
|
||||
store ptr @0, ptr %17, align 8
|
||||
%18 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %16, i32 0, i32 1
|
||||
store i64 7, ptr %18, align 4
|
||||
%19 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %16, align 8
|
||||
%20 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %19, 1
|
||||
%21 = icmp slt i64 %15, %20
|
||||
br i1 %21, label %_llgo_1, label %_llgo_2
|
||||
%10 = phi i64 [ 0, %_llgo_0 ], [ %6, %_llgo_1 ]
|
||||
%11 = icmp slt i64 %10, 7
|
||||
br i1 %11, label %_llgo_1, label %_llgo_2
|
||||
}
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1)
|
||||
|
||||
@@ -36,40 +36,23 @@ _llgo_0:
|
||||
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 48)
|
||||
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 0
|
||||
%4 = load ptr, ptr @_llgo_int, align 8
|
||||
%5 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8
|
||||
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %5, i32 0, i32 0
|
||||
store ptr %4, ptr %6, align 8
|
||||
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %5, i32 0, i32 1
|
||||
store ptr inttoptr (i64 1 to ptr), ptr %7, align 8
|
||||
%8 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %5, align 8
|
||||
store %"github.com/goplus/llgo/internal/runtime.eface" %8, ptr %3, align 8
|
||||
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 1
|
||||
%10 = load ptr, ptr @_llgo_int, align 8
|
||||
%11 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8
|
||||
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %11, i32 0, i32 0
|
||||
store ptr %10, ptr %12, align 8
|
||||
%13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %11, i32 0, i32 1
|
||||
store ptr inttoptr (i64 2 to ptr), ptr %13, align 8
|
||||
%14 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %11, align 8
|
||||
store %"github.com/goplus/llgo/internal/runtime.eface" %14, ptr %9, align 8
|
||||
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 2
|
||||
%16 = load ptr, ptr @_llgo_int, align 8
|
||||
%17 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8
|
||||
%18 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %17, i32 0, i32 0
|
||||
store ptr %16, ptr %18, align 8
|
||||
%19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %17, i32 0, i32 1
|
||||
store ptr inttoptr (i64 3 to ptr), ptr %19, align 8
|
||||
%20 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %17, align 8
|
||||
store %"github.com/goplus/llgo/internal/runtime.eface" %20, ptr %15, align 8
|
||||
%21 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
||||
%22 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %21, i32 0, i32 0
|
||||
store ptr %2, ptr %22, align 8
|
||||
%23 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %21, i32 0, i32 1
|
||||
store i64 3, ptr %23, align 4
|
||||
%24 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %21, i32 0, i32 2
|
||||
store i64 3, ptr %24, align 4
|
||||
%25 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %21, align 8
|
||||
call void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %25)
|
||||
%5 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %4, 0
|
||||
%6 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %5, ptr inttoptr (i64 1 to ptr), 1
|
||||
store %"github.com/goplus/llgo/internal/runtime.eface" %6, ptr %3, align 8
|
||||
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 1
|
||||
%8 = load ptr, ptr @_llgo_int, align 8
|
||||
%9 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %8, 0
|
||||
%10 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %9, ptr inttoptr (i64 2 to ptr), 1
|
||||
store %"github.com/goplus/llgo/internal/runtime.eface" %10, ptr %7, align 8
|
||||
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 2
|
||||
%12 = load ptr, ptr @_llgo_int, align 8
|
||||
%13 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %12, 0
|
||||
%14 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %13, ptr inttoptr (i64 3 to ptr), 1
|
||||
store %"github.com/goplus/llgo/internal/runtime.eface" %14, ptr %11, align 8
|
||||
%15 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" undef, ptr %2, 0
|
||||
%16 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %15, i64 3, 1
|
||||
%17 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %16, i64 3, 2
|
||||
call void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %17)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
@@ -108,22 +91,12 @@ _llgo_4: ; preds = %_llgo_2
|
||||
br label %_llgo_1
|
||||
|
||||
_llgo_5: ; preds = %_llgo_2
|
||||
%18 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 0
|
||||
store ptr @1, ptr %19, align 8
|
||||
%20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 1
|
||||
store i64 21, ptr %20, align 4
|
||||
%21 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %18, align 8
|
||||
%22 = load ptr, ptr @_llgo_string, align 8
|
||||
%23 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" %21, ptr %23, align 8
|
||||
%24 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8
|
||||
%25 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %24, i32 0, i32 0
|
||||
store ptr %22, ptr %25, align 8
|
||||
%26 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %24, i32 0, i32 1
|
||||
store ptr %23, ptr %26, align 8
|
||||
%27 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %24, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %27)
|
||||
%18 = load ptr, ptr @_llgo_string, align 8
|
||||
%19 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @1, i64 21 }, ptr %19, align 8
|
||||
%20 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %18, 0
|
||||
%21 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %20, ptr %19, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %21)
|
||||
unreachable
|
||||
}
|
||||
|
||||
|
||||
17
cl/_testgo/allocinloop/in.go
Normal file
17
cl/_testgo/allocinloop/in.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
func Foo(s string) int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func Test() {
|
||||
j := 0
|
||||
for i := 0; i < 10000000; i++ {
|
||||
j += Foo("hello")
|
||||
}
|
||||
println(j)
|
||||
}
|
||||
|
||||
func main() {
|
||||
Test()
|
||||
}
|
||||
66
cl/_testgo/allocinloop/out.ll
Normal file
66
cl/_testgo/allocinloop/out.ll
Normal file
@@ -0,0 +1,66 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
||||
|
||||
@"main.init$guard" = global i1 false, align 1
|
||||
@0 = private unnamed_addr constant [5 x i8] c"hello", align 1
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
|
||||
define i64 @main.Foo(%"github.com/goplus/llgo/internal/runtime.String" %0) {
|
||||
_llgo_0:
|
||||
%1 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %0, 1
|
||||
ret i64 %1
|
||||
}
|
||||
|
||||
define void @main.Test() {
|
||||
_llgo_0:
|
||||
br label %_llgo_3
|
||||
|
||||
_llgo_1: ; preds = %_llgo_3
|
||||
%0 = call i64 @main.Foo(%"github.com/goplus/llgo/internal/runtime.String" { ptr @0, i64 5 })
|
||||
%1 = add i64 %3, %0
|
||||
%2 = add i64 %4, 1
|
||||
br label %_llgo_3
|
||||
|
||||
_llgo_2: ; preds = %_llgo_3
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %3)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
ret void
|
||||
|
||||
_llgo_3: ; preds = %_llgo_1, %_llgo_0
|
||||
%3 = phi i64 [ 0, %_llgo_0 ], [ %1, %_llgo_1 ]
|
||||
%4 = phi i64 [ 0, %_llgo_0 ], [ %2, %_llgo_1 ]
|
||||
%5 = icmp slt i64 %4, 10000000
|
||||
br i1 %5, label %_llgo_1, label %_llgo_2
|
||||
}
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"main.init$guard", align 1
|
||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
store i1 true, ptr @"main.init$guard", align 1
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %0, ptr %1) {
|
||||
_llgo_0:
|
||||
store i32 %0, ptr @__llgo_argc, align 4
|
||||
store ptr %1, ptr @__llgo_argv, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
call void @main.init()
|
||||
call void @main.Test()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
@@ -31,49 +31,24 @@ _llgo_0:
|
||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
call void @main.init()
|
||||
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16)
|
||||
%3 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 0
|
||||
store ptr @0, ptr %4, align 8
|
||||
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 1
|
||||
store i64 3, ptr %5, align 4
|
||||
%6 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %3, align 8
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" %6, ptr %2, align 8
|
||||
%7 = alloca %main.T, align 8
|
||||
%8 = getelementptr inbounds %main.T, ptr %7, i32 0, i32 0
|
||||
store ptr @"__llgo_stub.main.main$1", ptr %8, align 8
|
||||
%9 = getelementptr inbounds %main.T, ptr %7, i32 0, i32 1
|
||||
store ptr null, ptr %9, align 8
|
||||
%10 = load %main.T, ptr %7, align 8
|
||||
%11 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
|
||||
%12 = getelementptr inbounds { ptr }, ptr %11, i32 0, i32 0
|
||||
store ptr %2, ptr %12, align 8
|
||||
%13 = alloca { ptr, ptr }, align 8
|
||||
%14 = getelementptr inbounds { ptr, ptr }, ptr %13, i32 0, i32 0
|
||||
store ptr @"main.main$2", ptr %14, align 8
|
||||
%15 = getelementptr inbounds { ptr, ptr }, ptr %13, i32 0, i32 1
|
||||
store ptr %11, ptr %15, align 8
|
||||
%16 = load { ptr, ptr }, ptr %13, align 8
|
||||
%17 = alloca %main.T, align 8
|
||||
store { ptr, ptr } %16, ptr %17, align 8
|
||||
%18 = load %main.T, ptr %17, align 8
|
||||
%19 = extractvalue %main.T %10, 1
|
||||
%20 = extractvalue %main.T %10, 0
|
||||
call void %20(ptr %19, i64 100)
|
||||
%21 = extractvalue %main.T %18, 1
|
||||
%22 = extractvalue %main.T %18, 0
|
||||
call void %22(ptr %21, i64 200)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @0, i64 3 }, ptr %2, align 8
|
||||
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
|
||||
%4 = getelementptr inbounds { ptr }, ptr %3, i32 0, i32 0
|
||||
store ptr %2, ptr %4, align 8
|
||||
%5 = insertvalue { ptr, ptr } { ptr @"main.main$2", ptr undef }, ptr %3, 1
|
||||
%6 = alloca %main.T, align 8
|
||||
store { ptr, ptr } %5, ptr %6, align 8
|
||||
%7 = load %main.T, ptr %6, align 8
|
||||
call void @"__llgo_stub.main.main$1"(ptr null, i64 100)
|
||||
%8 = extractvalue %main.T %7, 1
|
||||
%9 = extractvalue %main.T %7, 0
|
||||
call void %9(ptr %8, i64 200)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define void @"main.main$1"(i64 %0) {
|
||||
_llgo_0:
|
||||
%1 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %1, i32 0, i32 0
|
||||
store ptr @1, ptr %2, align 8
|
||||
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %1, i32 0, i32 1
|
||||
store i64 4, ptr %3, align 4
|
||||
%4 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %1, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %4)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @1, i64 4 })
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %0)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
@@ -85,13 +60,7 @@ _llgo_0:
|
||||
%2 = load { ptr }, ptr %0, align 8
|
||||
%3 = extractvalue { ptr } %2, 0
|
||||
%4 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %3, align 8
|
||||
%5 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %5, i32 0, i32 0
|
||||
store ptr @2, ptr %6, align 8
|
||||
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %5, i32 0, i32 1
|
||||
store i64 7, ptr %7, align 4
|
||||
%8 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %5, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %8)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @2, i64 7 })
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %1)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
|
||||
11
cl/_testgo/closure2/in.go
Normal file
11
cl/_testgo/closure2/in.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
x := 1
|
||||
f := func(i int) func(int) {
|
||||
return func(i int) {
|
||||
println("closure", i, x)
|
||||
}
|
||||
}
|
||||
f(1)(2)
|
||||
}
|
||||
80
cl/_testgo/closure2/out.ll
Normal file
80
cl/_testgo/closure2/out.ll
Normal file
@@ -0,0 +1,80 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
|
||||
|
||||
@"main.init$guard" = global i1 false, align 1
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
@0 = private unnamed_addr constant [7 x i8] c"closure", align 1
|
||||
|
||||
define void @main.init() {
|
||||
_llgo_0:
|
||||
%0 = load i1, ptr @"main.init$guard", align 1
|
||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_0
|
||||
store i1 true, ptr @"main.init$guard", align 1
|
||||
br label %_llgo_2
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main(i32 %0, ptr %1) {
|
||||
_llgo_0:
|
||||
store i32 %0, ptr @__llgo_argc, align 4
|
||||
store ptr %1, ptr @__llgo_argv, align 8
|
||||
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
call void @main.init()
|
||||
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 8)
|
||||
store i64 1, ptr %2, align 4
|
||||
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
|
||||
%4 = getelementptr inbounds { ptr }, ptr %3, i32 0, i32 0
|
||||
store ptr %2, ptr %4, align 8
|
||||
%5 = insertvalue { ptr, ptr } { ptr @"main.main$1", ptr undef }, ptr %3, 1
|
||||
%6 = extractvalue { ptr, ptr } %5, 1
|
||||
%7 = extractvalue { ptr, ptr } %5, 0
|
||||
%8 = call { ptr, ptr } %7(ptr %6, i64 1)
|
||||
%9 = extractvalue { ptr, ptr } %8, 1
|
||||
%10 = extractvalue { ptr, ptr } %8, 0
|
||||
call void %10(ptr %9, i64 2)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define { ptr, ptr } @"main.main$1"(ptr %0, i64 %1) {
|
||||
_llgo_0:
|
||||
%2 = load { ptr }, ptr %0, align 8
|
||||
%3 = extractvalue { ptr } %2, 0
|
||||
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
|
||||
%5 = getelementptr inbounds { ptr }, ptr %4, i32 0, i32 0
|
||||
store ptr %3, ptr %5, align 8
|
||||
%6 = insertvalue { ptr, ptr } { ptr @"main.main$1$1", ptr undef }, ptr %4, 1
|
||||
ret { ptr, ptr } %6
|
||||
}
|
||||
|
||||
define void @"main.main$1$1"(ptr %0, i64 %1) {
|
||||
_llgo_0:
|
||||
%2 = load { ptr }, ptr %0, align 8
|
||||
%3 = extractvalue { ptr } %2, 0
|
||||
%4 = load i64, ptr %3, align 4
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @0, i64 7 })
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %1)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %4)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64)
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user