Compare commits
387 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 | ||
|
|
0484d4bb77 |
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:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "*" ]
|
branches: [ "**" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "*" ]
|
branches: [ "**" ]
|
||||||
|
|
||||||
jobs:
|
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:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
@@ -26,7 +42,8 @@ jobs:
|
|||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
run: |
|
run: |
|
||||||
brew update
|
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
|
echo "$(brew --prefix llvm@${{matrix.llvm}})/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
# Install optional deps for demos.
|
# 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
|
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 -
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
sudo apt-get update
|
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
|
echo "/usr/lib/llvm-${{matrix.llvm}}/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
# Install optional deps for demos.
|
# Install optional deps for demos.
|
||||||
@@ -65,7 +82,7 @@ jobs:
|
|||||||
numpy # for github.com/goplus/llgo/py/numpy
|
numpy # for github.com/goplus/llgo/py/numpy
|
||||||
torch # for github.com/goplus/llgo/py/torch
|
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
|
- name: Clang information
|
||||||
run: |
|
run: |
|
||||||
@@ -81,6 +98,9 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: go build -v ./...
|
run: go build -v ./...
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: go install ./...
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
if: ${{!startsWith(matrix.os, 'macos')}}
|
if: ${{!startsWith(matrix.os, 'macos')}}
|
||||||
run: go test -v ./...
|
run: go test -v ./...
|
||||||
@@ -89,31 +109,48 @@ jobs:
|
|||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
||||||
|
|
||||||
- name: Install
|
|
||||||
run: go install ./...
|
|
||||||
|
|
||||||
- name: LLGO tests
|
- name: LLGO tests
|
||||||
if: ${{!startsWith(matrix.os, 'ubuntu')}}
|
if: ${{!startsWith(matrix.os, 'ubuntu')}}
|
||||||
run: |
|
run: |
|
||||||
echo "Test result on ${{matrix.os}} with LLVM ${{matrix.llvm}}" > result.md
|
echo "Test result on ${{matrix.os}} with LLVM ${{matrix.llvm}}" > result.md
|
||||||
bash .github/workflows/test_llgo.sh
|
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
|
- name: Test demos
|
||||||
continue-on-error: true
|
run: |
|
||||||
run: bash .github/workflows/test_demo.sh
|
# 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
|
- name: Show test result
|
||||||
run: cat result.md
|
run: cat result.md
|
||||||
|
|
||||||
- name: PR comment with test result
|
- name: PR comment with test result
|
||||||
uses: thollander/actions-comment-pull-request@v2
|
uses: thollander/actions-comment-pull-request@v3
|
||||||
if: false
|
if: false
|
||||||
with:
|
with:
|
||||||
filePath: result.md
|
filePath: result.md
|
||||||
comment_tag: test-result-on-${{matrix.os}}-with-llvm-${{matrix.llvm}}
|
comment_tag: test-result-on-${{matrix.os}}-with-llvm-${{matrix.llvm}}
|
||||||
|
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
token: ${{secrets.CODECOV_TOKEN}}
|
token: ${{secrets.CODECOV_TOKEN}}
|
||||||
slug: goplus/llgo
|
slug: goplus/llgo
|
||||||
|
|||||||
4
.github/workflows/test_demo.sh
vendored
4
.github/workflows/test_demo.sh
vendored
@@ -1,13 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# llgo run subdirectories under _demo and _pydemo
|
# llgo run subdirectories under _demo and _pydemo that contain *.go files
|
||||||
total=0
|
total=0
|
||||||
failed=0
|
failed=0
|
||||||
failed_cases=""
|
failed_cases=""
|
||||||
for d in ./_demo/* ./_pydemo/*; do
|
for d in ./_demo/* ./_pydemo/*; do
|
||||||
|
if [ -d "$d" ] && [ -n "$(ls "$d"/*.go 2>/dev/null)" ]; then
|
||||||
total=$((total+1))
|
total=$((total+1))
|
||||||
if [ -d "$d" ]; then
|
|
||||||
echo "Testing $d"
|
echo "Testing $d"
|
||||||
if ! (cd "$d" && llgo run .); then
|
if ! (cd "$d" && llgo run .); then
|
||||||
echo "FAIL"
|
echo "FAIL"
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,6 +26,9 @@ build.dir/
|
|||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
# Debug symbols
|
||||||
|
*.dSYM
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
*.swp
|
*.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:
|
Here is a simple example:
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/llgo_simple/simple.go -->
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -77,6 +79,8 @@ llgo run .
|
|||||||
|
|
||||||
LLGo use `go:linkname` to link an extern symbol througth its ABI:
|
LLGo use `go:linkname` to link an extern symbol througth its ABI:
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/llgo_call_c/call_c.go#L3-L6 -->
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import _ "unsafe" // for go:linkname
|
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):
|
You can directly integrate it into [your own code](_demo/linkname/linkname.go):
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/llgo_call_c/call_c.go -->
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -101,6 +107,8 @@ func main() {
|
|||||||
|
|
||||||
Or put it into a package (see [c/math](c/math/math.go)):
|
Or put it into a package (see [c/math](c/math/math.go)):
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/llgo_call_cmath/call_cmath.go -->
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -135,6 +143,8 @@ Note: For third-party libraries (such as pandas and pytorch), you still need to
|
|||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/llgo_call_py/call_py.go -->
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -152,6 +162,8 @@ func main() {
|
|||||||
|
|
||||||
It is equivalent to the following Python code:
|
It is equivalent to the following Python code:
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/llgo_call_py/call_math.py -->
|
||||||
|
|
||||||
```py
|
```py
|
||||||
import math
|
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:
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -340,20 +354,26 @@ Follow these steps to generate the `llgo` command (its usage is the same as the
|
|||||||
|
|
||||||
### on macOS
|
### on macOS
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/scripts/install_macos.sh#L2-L1000 -->
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew update
|
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 install python@3.12 # optional
|
||||||
|
brew link --force libffi
|
||||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### on Linux (Debian/Ubuntu)
|
### on Linux (Debian/Ubuntu)
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/scripts/install_ubuntu.sh#L2-L1000 -->
|
||||||
|
|
||||||
```sh
|
```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
|
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 -
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
sudo apt-get update
|
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
|
sudo apt-get install -y python3.12-dev # optional
|
||||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||||
```
|
```
|
||||||
@@ -373,9 +393,12 @@ TODO
|
|||||||
|
|
||||||
How do I generate these tools?
|
How do I generate these tools?
|
||||||
|
|
||||||
|
<!-- embedme doc/_readme/scripts/install_llgo.sh#L2-L1000 -->
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/goplus/llgo.git
|
git clone https://github.com/goplus/llgo.git
|
||||||
cd llgo
|
cd llgo
|
||||||
|
go install -v ./cmd/...
|
||||||
go install -v ./chore/... # compile all tools except pydump
|
go install -v ./chore/... # compile all tools except pydump
|
||||||
cd chore/_xtool
|
cd chore/_xtool
|
||||||
llgo install ./... # compile pydump
|
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
|
//go:linkname Free C.free
|
||||||
func Free(ptr Pointer)
|
func Free(ptr Pointer)
|
||||||
|
|
||||||
|
//go:linkname Realloc C.realloc
|
||||||
|
func Realloc(ptr Pointer, size uintptr) Pointer
|
||||||
|
|
||||||
//go:linkname Memcpy C.memcpy
|
//go:linkname Memcpy C.memcpy
|
||||||
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
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
|
func GetoptLongOnly(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//go:linkname Sysconf C.sysconf
|
||||||
|
func Sysconf(name Int) Long
|
||||||
|
|||||||
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" {
|
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) {
|
void wrap_clang_getTranslationUnitCursor(CXTranslationUnit uint, CXCursor *cur) {
|
||||||
*cur = clang_getTranslationUnitCursor(uint);
|
*cur = clang_getTranslationUnitCursor(uint);
|
||||||
}
|
}
|
||||||
@@ -33,6 +41,12 @@ void wrap_clang_getOverriddenCursors(CXCursor *cursor, CXCursor **overridden, un
|
|||||||
clang_getOverriddenCursors(*cursor, overridden, num_overridden);
|
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_getCursorLocation(CXCursor *cur, CXSourceLocation *loc) { *loc = clang_getCursorLocation(*cur); }
|
||||||
|
|
||||||
void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); }
|
void wrap_clang_getCursorExtent(CXCursor *cur, CXSourceRange *range) { *range = clang_getCursorExtent(*cur); }
|
||||||
@@ -113,8 +127,18 @@ CXString wrap_clang_getCursorUSR(CXCursor *cur) { return clang_getCursorUSR(*cur
|
|||||||
|
|
||||||
CXString wrap_clang_getCursorSpelling(CXCursor *cur) { return clang_getCursorSpelling(*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); }
|
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_getRawCommentText(CXCursor *cursor) { return clang_Cursor_getRawCommentText(*cursor); }
|
||||||
|
|
||||||
CXString wrap_clang_Cursor_getMangling(CXCursor *cur) { return clang_Cursor_getMangling(*cur); }
|
CXString wrap_clang_Cursor_getMangling(CXCursor *cur) { return clang_Cursor_getMangling(*cur); }
|
||||||
@@ -178,6 +202,8 @@ unsigned wrap_clang_visitChildren(CXCursor *parent, wrap_CXCursorVisitor visitor
|
|||||||
return clang_visitChildren(*parent, wrap_visitor, CXClientData(&data));
|
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,
|
void wrap_clang_getSpellingLocation(CXSourceLocation *loc, CXFile *file, unsigned *line, unsigned *column,
|
||||||
unsigned *offset) {
|
unsigned *offset) {
|
||||||
clang_getSpellingLocation(*loc, file, line, column, offset);
|
clang_getSpellingLocation(*loc, file, line, column, offset);
|
||||||
|
|||||||
140
c/clang/clang.go
140
c/clang/clang.go
@@ -1157,6 +1157,30 @@ type UnsavedFile struct {
|
|||||||
Length c.Ulong
|
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
|
* An "index" that consists of a set of translation units that would
|
||||||
* typically be linked together into an executable or library.
|
* 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
|
// llgo:link (*Cursor).DisposeOverriddenCursors C.clang_disposeOverriddenCursors
|
||||||
func (c *Cursor) 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
|
* Retrieve the physical location of the source constructor referenced
|
||||||
* by the given cursor.
|
* by the given cursor.
|
||||||
@@ -2196,6 +2257,39 @@ func (c Cursor) String() (ret String) {
|
|||||||
return c.wrapString()
|
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.
|
* Returns non-zero if the given cursor is a variadic function or method.
|
||||||
*/
|
*/
|
||||||
@@ -2204,6 +2298,19 @@ func (*Cursor) wrapIsVariadic() (ret c.Uint) { return 0 }
|
|||||||
|
|
||||||
func (c Cursor) IsVariadic() (ret c.Uint) { return c.wrapIsVariadic() }
|
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
|
* Given a cursor that represents a declaration, return the associated
|
||||||
* comment text, including comment markers.
|
* comment text, including comment markers.
|
||||||
@@ -2596,6 +2703,29 @@ func VisitChildren(
|
|||||||
//llgo:type C
|
//llgo:type C
|
||||||
type Visitor func(cursor, parent Cursor, clientData ClientData) ChildVisitResult
|
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
|
* Tokenize the source code described by the given range into raw
|
||||||
* lexical tokens.
|
* lexical tokens.
|
||||||
@@ -2626,6 +2756,16 @@ func (t *TranslationUnit) Tokenize(ran SourceRange, tokens **Token, numTokens *c
|
|||||||
// llgo:link (*TranslationUnit).DisposeTokens C.clang_disposeTokens
|
// llgo:link (*TranslationUnit).DisposeTokens C.clang_disposeTokens
|
||||||
func (t *TranslationUnit) DisposeTokens(tokens *Token, numTokens c.Uint) {}
|
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
|
* Retrieve the file, line, column, and offset represented by
|
||||||
* the given source location.
|
* the given source location.
|
||||||
|
|||||||
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
|
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
|
// llgo:link (*Loop).Now C.uv_now
|
||||||
func (loop *Loop) Now() c.UlongLong {
|
func (loop *Loop) Now() c.UlongLong {
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -265,6 +265,11 @@ func (req *Req) GetType() ReqType {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// llgo:link (*Req).Cancel C.uv_cancel
|
||||||
|
func (req *Req) Cancel() c.Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
|
|
||||||
/* Stream related function and method */
|
/* 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() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func coroutineFunc(L *lua.State) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func createCountdown(L *lua.State) c.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
L.Register(c.Str("create_countdown"), createCountdown)
|
L.Register(c.Str("create_countdown"), createCountdown)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func customPanic(L *lua.State) c.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
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() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func writer(L *lua.State, p c.Pointer, sz c.Ulong, ud c.Pointer) c.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
if res := L.Loadstring(c.Str("function doubleNumber(x) ! return x * 2 end")); res != lua.OK {
|
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() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
if res := L.Dostring(c.Str("print('hello world')")); res != lua.OK {
|
if res := L.Dostring(c.Str("print('hello world')")); res != lua.OK {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func printStack(L *lua.State, message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func printStack(L *lua.State, stateName *c.Char) {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create a new Lua state and open libraries
|
// Create a new Lua state and open libraries
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ func main() {
|
|||||||
printStack(L, c.Str("L1"))
|
printStack(L, c.Str("L1"))
|
||||||
|
|
||||||
// Create a second Lua state
|
// Create a second Lua state
|
||||||
L1 := lua.Newstate()
|
L1 := lua.Newstate__1()
|
||||||
defer L1.Close()
|
defer L1.Close()
|
||||||
|
|
||||||
// Move two elements to the new state
|
// 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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/c/lua"
|
"github.com/goplus/llgo/c/lua"
|
||||||
)
|
)
|
||||||
@@ -8,53 +10,91 @@ import (
|
|||||||
func printTable(L *lua.State) {
|
func printTable(L *lua.State) {
|
||||||
L.Pushnil()
|
L.Pushnil()
|
||||||
for L.Next(-2) != 0 {
|
for L.Next(-2) != 0 {
|
||||||
key := L.Tostring(-2)
|
|
||||||
value := L.Tostring(-1)
|
value := L.Tostring(-1)
|
||||||
|
switch L.Type(-2) {
|
||||||
|
case lua.STRING:
|
||||||
|
key := L.Tostring(-2)
|
||||||
c.Printf(c.Str("%s - %s\n"), key, value)
|
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)
|
||||||
}
|
}
|
||||||
L.Pop(1)
|
L.Pop(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|
||||||
L.Newtable()
|
L.Newtable()
|
||||||
|
|
||||||
|
// set table name:John
|
||||||
L.Pushstring(c.Str("name"))
|
L.Pushstring(c.Str("name"))
|
||||||
L.Pushstring(c.Str("John"))
|
L.Pushstring(c.Str("John"))
|
||||||
L.Settable(-3)
|
L.Settable(-3)
|
||||||
|
|
||||||
|
// set table age:30
|
||||||
L.Pushstring(c.Str("age"))
|
L.Pushstring(c.Str("age"))
|
||||||
L.Pushnumber(30)
|
L.Pushnumber(30)
|
||||||
L.Settable(-3)
|
L.Settable(-3)
|
||||||
|
|
||||||
|
// set table field fullname:John Doe
|
||||||
L.Pushstring(c.Str("John Doe"))
|
L.Pushstring(c.Str("John Doe"))
|
||||||
L.Setfield(-2, c.Str("fullname"))
|
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"))
|
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)
|
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.Pushstring(c.Str("age"))
|
||||||
L.Gettable(-2)
|
L.Gettable(-2)
|
||||||
age := int(L.Tonumber(-1))
|
age := int(L.Tonumber(-1))
|
||||||
c.Printf(c.Str("Age: %d\n"), age)
|
c.Printf(c.Str("Age: %d\n"), age)
|
||||||
L.Pop(1)
|
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"))
|
c.Printf(c.Str("All entries in the table:\n"))
|
||||||
printTable(L)
|
printTable(L)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expected output:
|
/* Expected output:
|
||||||
John
|
name: John
|
||||||
|
fullname: John Doe
|
||||||
Age: 30
|
Age: 30
|
||||||
|
Index[1] value: 123
|
||||||
All entries in the table:
|
All entries in the table:
|
||||||
age - 30.0
|
[1] - 123
|
||||||
fullname - John Doe
|
|
||||||
name - John
|
name - John
|
||||||
|
[pointer] - pointer value
|
||||||
|
fullname - John Doe
|
||||||
|
age - 30.0
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func pushThread(state *lua.State, name string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
|
|
||||||
L.Openlibs()
|
L.Openlibs()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type lightdata struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
L := lua.Newstate()
|
L := lua.Newstate__1()
|
||||||
defer L.Close()
|
defer L.Close()
|
||||||
L.Openlibs()
|
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
|
// llgo:link (*State).Loadstring C.luaL_loadstring
|
||||||
func (L *State) Loadstring(s *c.Char) c.Int { return 0 }
|
func (L *State) Loadstring(s *c.Char) c.Int { return 0 }
|
||||||
|
|
||||||
//go:linkname Newstate C.luaL_newstate
|
//go:linkname Newstate__1 C.luaL_newstate
|
||||||
func Newstate() *State
|
func Newstate__1() *State
|
||||||
|
|
||||||
// /*
|
// /*
|
||||||
// ** ===============================================================
|
// ** ===============================================================
|
||||||
|
|||||||
399
c/lua/lua.go
399
c/lua/lua.go
@@ -10,18 +10,18 @@ const (
|
|||||||
LLGoPackage = "link: $(pkg-config --libs lua); -llua -lm"
|
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 (
|
const (
|
||||||
MULTRET = -1
|
MULTRET = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** Pseudo-indices
|
* Pseudo-indices
|
||||||
// ** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
* (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
||||||
// ** space after that to help overflow detection)
|
* space after that to help overflow detection)
|
||||||
// */
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
REGISTRYINDEX = -MAXSTACK - 1000
|
REGISTRYINDEX = -MAXSTACK - 1000
|
||||||
@@ -31,7 +31,7 @@ func Upvalueindex(i c.Int) c.Int {
|
|||||||
return c.Int(REGISTRYINDEX) - i
|
return c.Int(REGISTRYINDEX) - i
|
||||||
}
|
}
|
||||||
|
|
||||||
// /* thread status */
|
/* thread status */
|
||||||
const (
|
const (
|
||||||
OK = 0
|
OK = 0
|
||||||
YIELD = 1
|
YIELD = 1
|
||||||
@@ -45,9 +45,9 @@ type State struct {
|
|||||||
Unused [8]byte
|
Unused [8]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** basic types
|
* basic types
|
||||||
// */
|
*/
|
||||||
const (
|
const (
|
||||||
NONE c.Int = -1
|
NONE c.Int = -1
|
||||||
NIL c.Int = 0
|
NIL c.Int = 0
|
||||||
@@ -59,50 +59,50 @@ const (
|
|||||||
FUNCTION c.Int = 6
|
FUNCTION c.Int = 6
|
||||||
USERDATA c.Int = 7
|
USERDATA c.Int = 7
|
||||||
THREAD c.Int = 8
|
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 (
|
const (
|
||||||
MINSTACK = 20
|
MINSTACK = 20
|
||||||
)
|
)
|
||||||
|
|
||||||
// /* predefined values in the registry */
|
/* predefined values in the registry */
|
||||||
const (
|
const (
|
||||||
RIDX_MAINTHREAD = 1
|
RIDX_MAINTHREAD = 1
|
||||||
RIDX_GLOBALS = 2
|
RIDX_GLOBALS = 2
|
||||||
RIDX_LAST = RIDX_GLOBALS
|
RIDX_LAST = RIDX_GLOBALS
|
||||||
)
|
)
|
||||||
|
|
||||||
// /* type of numbers in Lua */
|
/* type of numbers in Lua */
|
||||||
type Number = c.Double
|
type Number = c.Double
|
||||||
|
|
||||||
// /* type for integer functions */
|
/* type for integer functions */
|
||||||
type Integer = c.Int
|
type Integer = c.Int
|
||||||
|
|
||||||
// /* unsigned integer type */
|
/* unsigned integer type */
|
||||||
type Unsigned = c.Uint
|
type Unsigned = c.Uint
|
||||||
|
|
||||||
// /* type for continuation-function contexts */
|
/* type for continuation-function contexts */
|
||||||
type KContext = c.Pointer
|
type KContext = c.Pointer
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** Type for C functions registered with Lua
|
* Type for C functions registered with Lua
|
||||||
// */
|
*/
|
||||||
|
|
||||||
// llgo:type C
|
// llgo:type C
|
||||||
type CFunction func(L *State) c.Int
|
type CFunction func(L *State) c.Int
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** Type for continuation functions
|
* Type for continuation functions
|
||||||
// */
|
*/
|
||||||
|
|
||||||
// llgo:type C
|
// llgo:type C
|
||||||
type KFunction func(L *State, status c.Int, ctx KContext) c.Int
|
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
|
// llgo:type C
|
||||||
type Reader func(L *State, ud c.Pointer, sz *c.Ulong) *c.Char
|
type Reader func(L *State, ud c.Pointer, sz *c.Ulong) *c.Char
|
||||||
@@ -110,51 +110,42 @@ type Reader func(L *State, ud c.Pointer, sz *c.Ulong) *c.Char
|
|||||||
// llgo:type C
|
// llgo:type C
|
||||||
type Writer func(L *State, p c.Pointer, sz c.Ulong, ud c.Pointer) c.Int
|
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
|
* RCS ident string
|
||||||
// */
|
*/
|
||||||
|
|
||||||
// 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
|
|
||||||
// */
|
|
||||||
|
|
||||||
// extern const char lua_ident[];
|
// extern const char lua_ident[];
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** state manipulation
|
** state manipulation
|
||||||
// */
|
*/
|
||||||
|
|
||||||
// llgo:link (*State).Close C.lua_close
|
// llgo:link (*State).Close C.lua_close
|
||||||
func (L *State) 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
|
// llgo:link (*State).Newthread C.lua_newthread
|
||||||
func (L *State) Newthread() *State { return nil }
|
func (L *State) Newthread() *State { return nil }
|
||||||
@@ -171,9 +162,9 @@ func (L *State) Atpanic(panicf CFunction) CFunction { return nil }
|
|||||||
// llgo:link (*State).Version C.lua_version
|
// llgo:link (*State).Version C.lua_version
|
||||||
func (L *State) Version() Number { return 0 }
|
func (L *State) Version() Number { return 0 }
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** basic stack manipulation
|
* basic stack manipulation
|
||||||
// */
|
*/
|
||||||
|
|
||||||
// llgo:link (*State).Absindex C.lua_absindex
|
// llgo:link (*State).Absindex C.lua_absindex
|
||||||
func (L *State) Absindex(idx c.Int) c.Int { return 0 }
|
func (L *State) Absindex(idx c.Int) c.Int { return 0 }
|
||||||
@@ -199,9 +190,9 @@ func (L *State) Checkstack(n c.Int) c.Int { return 0 }
|
|||||||
// llgo:link (*State).Xmove C.lua_xmove
|
// llgo:link (*State).Xmove C.lua_xmove
|
||||||
func (L *State) Xmove(to *State, n c.Int) {}
|
func (L *State) Xmove(to *State, n c.Int) {}
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** access functions (stack -> C)
|
* access functions (stack -> C)
|
||||||
// */
|
*/
|
||||||
|
|
||||||
// llgo:link (*State).Isnumber C.lua_isnumber
|
// llgo:link (*State).Isnumber C.lua_isnumber
|
||||||
func (L *State) Isnumber(idx c.Int) c.Int { return 0 }
|
func (L *State) Isnumber(idx c.Int) c.Int { return 0 }
|
||||||
@@ -247,15 +238,17 @@ func (L *State) Touserdata(idx c.Int) c.Pointer { return nil }
|
|||||||
// llgo:link (*State).Tothread C.lua_tothread
|
// llgo:link (*State).Tothread C.lua_tothread
|
||||||
func (L *State) Tothread(idx c.Int) *State { return nil }
|
func (L *State) Tothread(idx c.Int) *State { return nil }
|
||||||
|
|
||||||
// LUA_API const void *(lua_topointer) (State *L, int idx);
|
// llgo:link (*State).Topointer C.lua_topointer
|
||||||
|
func (L *State) Topointer(idx c.Int) c.Pointer { return nil }
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** Comparison and arithmetic functions
|
* Comparison and arithmetic functions
|
||||||
// */
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* push functions (C -> stack)
|
||||||
|
*/
|
||||||
|
|
||||||
// /*
|
|
||||||
// ** push functions (C -> stack)
|
|
||||||
// */
|
|
||||||
// llgo:link (*State).Pushnil C.lua_pushnil
|
// llgo:link (*State).Pushnil C.lua_pushnil
|
||||||
func (L *State) Pushnil() {}
|
func (L *State) Pushnil() {}
|
||||||
|
|
||||||
@@ -286,9 +279,9 @@ func (L *State) Pushlightuserdata(p c.Pointer) {}
|
|||||||
// llgo:link (*State).Pushthread C.lua_pushthread
|
// llgo:link (*State).Pushthread C.lua_pushthread
|
||||||
func (L *State) Pushthread() c.Int { return 0 }
|
func (L *State) Pushthread() c.Int { return 0 }
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** get functions (Lua -> stack)
|
* get functions (Lua -> stack)
|
||||||
// */
|
*/
|
||||||
|
|
||||||
// llgo:link (*State).Getglobal C.lua_getglobal
|
// llgo:link (*State).Getglobal C.lua_getglobal
|
||||||
func (L *State) Getglobal(name *c.Char) c.Int { return 0 }
|
func (L *State) Getglobal(name *c.Char) c.Int { return 0 }
|
||||||
@@ -299,10 +292,17 @@ func (L *State) Gettable(idx c.Int) c.Int { return 0 }
|
|||||||
// llgo:link (*State).Getfield C.lua_getfield
|
// llgo:link (*State).Getfield C.lua_getfield
|
||||||
func (L *State) Getfield(idx c.Int, k *c.Char) c.Int { return 0 }
|
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);
|
// llgo:link (*State).Geti C.lua_geti
|
||||||
// LUA_API int (lua_rawget) (State *L, int idx);
|
func (L *State) Geti(idx c.Int, n Integer) c.Int { return 0 }
|
||||||
// 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).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
|
// llgo:link (*State).Createtable C.lua_createtable
|
||||||
func (L *State) Createtable(narr c.Int, nrec c.Int) {}
|
func (L *State) Createtable(narr c.Int, nrec c.Int) {}
|
||||||
@@ -313,11 +313,12 @@ func (L *State) Newuserdatauv(sz uintptr, nuvalue c.Int) c.Pointer { return nil
|
|||||||
// llgo:link (*State).Getmetatable C.lua_getmetatable
|
// llgo:link (*State).Getmetatable C.lua_getmetatable
|
||||||
func (L *State) Getmetatable(objindex c.Int) c.Int { return 0 }
|
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
|
// llgo:link (*State).Setglobal C.lua_setglobal
|
||||||
func (L *State) Setglobal(name *c.Char) {}
|
func (L *State) Setglobal(name *c.Char) {}
|
||||||
@@ -328,19 +329,27 @@ func (L *State) Settable(idx c.Int) {}
|
|||||||
// llgo:link (*State).Setfield C.lua_setfield
|
// llgo:link (*State).Setfield C.lua_setfield
|
||||||
func (L *State) Setfield(idx c.Int, k *c.Char) {}
|
func (L *State) Setfield(idx c.Int, k *c.Char) {}
|
||||||
|
|
||||||
//void (lua_seti) (State *L, int idx, lua_Integer n);
|
// llgo:link (*State).Seti C.lua_seti
|
||||||
//void (lua_rawset) (State *L, int idx);
|
func (L *State) Seti(idx c.Int, n Integer) {}
|
||||||
//void (lua_rawseti) (State *L, int idx, lua_Integer n);
|
|
||||||
//void (lua_rawsetp) (State *L, int idx, const void *p);
|
// 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
|
// llgo:link (*State).Setmetatable C.lua_setmetatable
|
||||||
func (L *State) Setmetatable(objindex c.Int) c.Int { return 0 }
|
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
|
// llgo:link (*State).Callk C.lua_callk
|
||||||
func (L *State) Callk(nargs c.Int, nresults c.Int, ctx KContext, k KFunction) c.Int {
|
func (L *State) Callk(nargs c.Int, nresults c.Int, ctx KContext, k KFunction) c.Int {
|
||||||
@@ -366,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
|
// llgo:link (*State).Dump C.lua_dump
|
||||||
func (L *State) Dump(writer Writer, data c.Pointer, strip c.Int) c.Int { return 0 }
|
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
|
// llgo:link (*State).Resume C.lua_resume
|
||||||
func (L *State) Resume(from *State, narg c.Int, nres *c.Int) c.Int { return 0 }
|
func (L *State) Resume(from *State, narg c.Int, nres *c.Int) c.Int { return 0 }
|
||||||
@@ -383,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) 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) }
|
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);
|
// llgo:link (*State).Setwarnf C.lua_setwarnf
|
||||||
//void (lua_warning) (State *L, const char *msg, int tocont);
|
func (L *State) Setwarnf(f WarnFunction, ud c.Pointer) {}
|
||||||
|
|
||||||
// /*
|
// llgo:link (*State).Warning C.lua_warning
|
||||||
// ** garbage-collection function and options
|
func (L *State) Warning(msg *c.Char, tocont c.Int) {}
|
||||||
// */
|
|
||||||
|
/*
|
||||||
|
* garbage-collection function and options
|
||||||
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GCSTOP = 0
|
GCSTOP = 0
|
||||||
@@ -408,36 +420,49 @@ const (
|
|||||||
GCINC = 11
|
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
|
// llgo:link (*State).Next C.lua_next
|
||||||
func (L *State) Next(idx c.Int) c.Int { return 0 }
|
func (L *State) Next(idx c.Int) c.Int { return 0 }
|
||||||
|
|
||||||
// llgo:link (*State).Error C.lua_error
|
// llgo:link (*State).Error C.lua_error
|
||||||
func (L *State) Error() c.Int { return 0 }
|
func (L *State) Error() c.Int { return 0 }
|
||||||
|
|
||||||
// LUA_API void (lua_concat) (State *L, int n);
|
// llgo:link (*State).Concat C.lua_concat
|
||||||
// LUA_API void (lua_len) (State *L, int idx);
|
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);
|
// llgo:link (*State).Stringtonumber C.lua_stringtonumber
|
||||||
// LUA_API void (lua_setallocf) (State *L, lua_Alloc f, void *ud);
|
func (L *State) Stringtonumber(s *c.Char) c.Ulong { return 0 }
|
||||||
|
|
||||||
// LUA_API void (lua_toclose) (State *L, int idx);
|
// llgo:link (*State).Getallocf C.lua_getallocf
|
||||||
// LUA_API void (lua_closeslot) (State *L, int idx);
|
func (L *State) Getallocf(ud *c.Pointer) Alloc { return nil }
|
||||||
|
|
||||||
// /*
|
// llgo:link (*State).Setallocf C.lua_setallocf
|
||||||
// ** {==============================================================
|
func (L *State) Setallocf(f Alloc, ud c.Pointer) Alloc { return nil }
|
||||||
// ** some useful macros
|
|
||||||
// ** ===============================================================
|
|
||||||
// */
|
|
||||||
|
|
||||||
// #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) 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) Tostring(idx c.Int) *c.Char { return L.Tolstring(idx, nil) }
|
||||||
func (L *State) Tointeger(idx c.Int) Integer { return L.Tointegerx(idx, nil) }
|
func (L *State) Tointeger(idx c.Int) Integer { return L.Tointegerx(idx, nil) }
|
||||||
@@ -458,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) 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) 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) 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)
|
func (L *State) Pushglobaltable() c.Int {
|
||||||
// #define lua_pushglobaltable(L) ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
|
return L.Rawgeti(REGISTRYINDEX, RIDX_GLOBALS)
|
||||||
|
}
|
||||||
|
|
||||||
func (L *State) Insert(idx c.Int) {
|
func (L *State) Insert(idx c.Int) {
|
||||||
L.Rotate(idx, 1)
|
L.Rotate(idx, 1)
|
||||||
@@ -476,33 +505,41 @@ func (L *State) Replace(idx c.Int) {
|
|||||||
L.Pop(1)
|
L.Pop(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// /* }============================================================== */
|
/* }============================================================== */
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** {==============================================================
|
** {==============================================================
|
||||||
// ** compatibility macros
|
** compatibility macros
|
||||||
// ** ===============================================================
|
** ===============================================================
|
||||||
// */
|
*/
|
||||||
|
|
||||||
func (L *State) Newuserdata(sz uintptr) c.Pointer {
|
func (L *State) Newuserdata(sz uintptr) c.Pointer {
|
||||||
return L.Newuserdatauv(sz, 1)
|
return L.Newuserdatauv(sz, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
func (L *State) Getuservalue(idx c.Int) c.Int {
|
||||||
// #define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
|
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
|
/*
|
||||||
// ** =======================================================================
|
** {======================================================================
|
||||||
// */
|
** Debug API
|
||||||
// /*
|
** =======================================================================
|
||||||
// ** Event codes
|
*/
|
||||||
// */
|
|
||||||
|
/*
|
||||||
|
* Event codes
|
||||||
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HOOKCALL = 0
|
HOOKCALL = 0
|
||||||
@@ -512,9 +549,9 @@ const (
|
|||||||
HOOKTAILCALL = 4
|
HOOKTAILCALL = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
// /*
|
/*
|
||||||
// ** Event masks
|
* Event masks
|
||||||
// */
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MASKCALL = 1 << HOOKCOUNT
|
MASKCALL = 1 << HOOKCOUNT
|
||||||
@@ -523,22 +560,68 @@ const (
|
|||||||
MASKCOUNT = 1 << HOOKCOUNT
|
MASKCOUNT = 1 << HOOKCOUNT
|
||||||
)
|
)
|
||||||
|
|
||||||
// LUA_API int (lua_getstack) (State *L, int level, lua_Debug *ar);
|
// llgo:link (*State).Getstack C.lua_getstack
|
||||||
// LUA_API int (lua_getinfo) (State *L, const char *what, lua_Debug *ar);
|
func (L *State) Getstack(level c.Int, ar *Debug) c.Int { return 0 }
|
||||||
// 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);
|
|
||||||
|
|
||||||
// LUA_API void *(lua_upvalueid) (State *L, int fidx, int n);
|
// llgo:link (*State).Getinfo C.lua_getinfo
|
||||||
// LUA_API void (lua_upvaluejoin) (State *L, int fidx1, int n1, int fidx2, int n2);
|
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);
|
// llgo:link (*State).Getlocal C.lua_getlocal
|
||||||
// LUA_API lua_Hook (lua_gethook) (State *L);
|
func (L *State) Getlocal(ar *Debug, n c.Int) *c.Char { return nil }
|
||||||
// LUA_API int (lua_gethookmask) (State *L);
|
|
||||||
// LUA_API int (lua_gethookcount) (State *L);
|
|
||||||
|
|
||||||
// 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
|
package lua
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {==================================================================
|
** {==================================================================
|
||||||
** Macros that affect the API and must be stable (that is, must be the
|
** Macros that affect the API and must be stable (that is, must be the
|
||||||
@@ -19,3 +21,21 @@ package lua
|
|||||||
const (
|
const (
|
||||||
MAXSTACK = 1000000
|
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 <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
int llgoClearenv() {
|
int llgoClearenv() {
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
@@ -7,3 +8,5 @@ int llgoClearenv() {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int llgoErrno() { return errno; }
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ type (
|
|||||||
StatT = syscall.Stat_t
|
StatT = syscall.Stat_t
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:linkname Errno errno
|
//go:linkname Errno C.llgoErrno
|
||||||
var Errno c.Int
|
func Errno() c.Int
|
||||||
|
|
||||||
//go:linkname Umask C.umask
|
//go:linkname Umask C.umask
|
||||||
func Umask(cmask ModeT) ModeT
|
func Umask(cmask ModeT) ModeT
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ package os
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LLGoPackage = "decl"
|
LLGoFiles = "_os/os.c"
|
||||||
|
LLGoPackage = "link"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:linkname Clearenv C.clearenv
|
//go:linkname Clearenv C.clearenv
|
||||||
|
|||||||
@@ -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,72 +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"),
|
|
||||||
Cplusplus: GetBoolItem(parsedConf, "cplusplus"),
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBoolItem(obj *cjson.JSON, key string) bool {
|
|
||||||
item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key))
|
|
||||||
if item == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if item.IsBool() != 0 {
|
|
||||||
return item.IsTrue() != 0
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -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()
|
items := cjson.Array()
|
||||||
mod := py.ImportModule(pyLib)
|
mod := py.ImportModule(pyLib)
|
||||||
keys := mod.ModuleGetDict().DictKeys()
|
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)
|
key := keys.ListItem(i)
|
||||||
val := mod.GetAttr(key)
|
val := mod.GetAttr(key)
|
||||||
doc := val.GetAttrString(c.Str("__doc__"))
|
doc := val.GetAttrString(c.Str("__doc__"))
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goplus/llgo/internal/llgen"
|
"github.com/goplus/llgo/internal/llgen"
|
||||||
"github.com/goplus/llgo/ssa"
|
|
||||||
"github.com/goplus/mod"
|
"github.com/goplus/mod"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,18 +29,15 @@ func main() {
|
|||||||
dir, _, err := mod.FindGoMod(".")
|
dir, _, err := mod.FindGoMod(".")
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
ssa.Initialize(ssa.InitAll | ssa.InitNative)
|
|
||||||
llgen.Verbose = false
|
|
||||||
|
|
||||||
llgenDir(dir + "/cl/_testlibc")
|
llgenDir(dir + "/cl/_testlibc")
|
||||||
llgenDir(dir + "/cl/_testlibgo")
|
llgenDir(dir + "/cl/_testlibgo")
|
||||||
llgenDir(dir + "/cl/_testrt")
|
llgenDir(dir + "/cl/_testrt")
|
||||||
llgenDir(dir + "/cl/_testgo")
|
llgenDir(dir + "/cl/_testgo")
|
||||||
llgenDir(dir+"/cl/_testpy", "")
|
llgenDir(dir + "/cl/_testpy")
|
||||||
llgenDir(dir+"/cl/_testdata", "")
|
llgenDir(dir + "/cl/_testdata")
|
||||||
}
|
}
|
||||||
|
|
||||||
func llgenDir(dir string, pkgPath ...string) {
|
func llgenDir(dir string) {
|
||||||
fis, err := os.ReadDir(dir)
|
fis, err := os.ReadDir(dir)
|
||||||
check(err)
|
check(err)
|
||||||
for _, fi := range fis {
|
for _, fi := range fis {
|
||||||
@@ -51,8 +47,8 @@ func llgenDir(dir string, pkgPath ...string) {
|
|||||||
}
|
}
|
||||||
testDir := dir + "/" + name
|
testDir := dir + "/" + name
|
||||||
fmt.Fprintln(os.Stderr, "llgen", testDir)
|
fmt.Fprintln(os.Stderr, "llgen", testDir)
|
||||||
os.Chdir(testDir)
|
check(os.Chdir(testDir))
|
||||||
llgen.SmartDoFile("in.go", pkgPath...)
|
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,85 +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"],
|
|
||||||
"cplusplus":true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@@ -24,11 +25,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
flag.Parse()
|
||||||
fmt.Fprintln(os.Stderr, "Usage: llgen <pkg> [pkgPath]")
|
if len(flag.Args()) != 1 {
|
||||||
|
fmt.Fprintln(os.Stderr, "Usage: llgen [flags] <pkg>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
llgen.SmartDoFile(flag.Args()[0])
|
||||||
llgen.Init()
|
|
||||||
llgen.SmartDoFile(os.Args[1], os.Args[2:]...)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,25 +22,41 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/goplus/llgo/xtool/env/llvm"
|
"github.com/goplus/llgo/xtool/env/llvm"
|
||||||
|
nmtool "github.com/goplus/llgo/xtool/nm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) != 2 {
|
if len(os.Args) < 2 {
|
||||||
fmt.Fprintln(os.Stderr, "Usage: nmdump libfile")
|
fmt.Fprintln(os.Stderr, "Usage: nmdump [flags] libfile")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nm := llvm.New("").Nm()
|
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 {
|
for _, item := range items {
|
||||||
if item.File != "" {
|
if item.File != "" {
|
||||||
fmt.Printf("\n%s:\n", item.File)
|
fmt.Printf("\n%s:\n", item.File)
|
||||||
}
|
}
|
||||||
for _, sym := range item.Symbols {
|
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 {
|
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 {
|
} 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'
|
; ModuleID = 'github.com/goplus/llgo/cl/_testdata/apkg'
|
||||||
source_filename = "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:
|
_llgo_0:
|
||||||
%2 = fcmp ogt double %0, %1
|
%2 = fcmp ogt double %0, %1
|
||||||
br i1 %2, label %_llgo_1, label %_llgo_2
|
br i1 %2, label %_llgo_1, label %_llgo_2
|
||||||
@@ -15,13 +15,13 @@ _llgo_2: ; preds = %_llgo_0
|
|||||||
ret double %1
|
ret double %1
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @apkg.init() {
|
define void @"github.com/goplus/llgo/cl/_testdata/apkg.init"() {
|
||||||
_llgo_0:
|
_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
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
_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
|
br label %_llgo_2
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_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 @@
|
|||||||
|
;
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
; ModuleID = 'llgotag'
|
; ModuleID = 'github.com/goplus/llgo/cl/_testdata/llgotag'
|
||||||
source_filename = "llgotag"
|
source_filename = "github.com/goplus/llgo/cl/_testdata/llgotag"
|
||||||
|
|
||||||
@"llgotag.init$guard" = global i1 false, align 1
|
@"github.com/goplus/llgo/cl/_testdata/llgotag.init$guard" = global i1 false, align 1
|
||||||
|
|
||||||
define void @llgotag.Foo() {
|
define void @"github.com/goplus/llgo/cl/_testdata/llgotag.Foo"() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @llgotag.init() {
|
define void @"github.com/goplus/llgo/cl/_testdata/llgotag.init"() {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%0 = load i1, ptr @"llgotag.init$guard", align 1
|
%0 = load i1, ptr @"github.com/goplus/llgo/cl/_testdata/llgotag.init$guard", align 1
|
||||||
br i1 %0, label %_llgo_2, label %_llgo_1
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_0
|
_llgo_1: ; preds = %_llgo_0
|
||||||
store i1 true, ptr @"llgotag.init$guard", align 1
|
store i1 true, ptr @"github.com/goplus/llgo/cl/_testdata/llgotag.init$guard", align 1
|
||||||
br label %_llgo_2
|
br label %_llgo_2
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -52,41 +52,27 @@ _llgo_0:
|
|||||||
br label %_llgo_3
|
br label %_llgo_3
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_3
|
_llgo_1: ; preds = %_llgo_3
|
||||||
%2 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
%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 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 0
|
%3 = call { i32, i64 } @"unicode/utf8.DecodeRuneInString"(%"github.com/goplus/llgo/internal/runtime.String" %2)
|
||||||
store ptr @0, ptr %3, align 8
|
%4 = extractvalue { i32, i64 } %3, 0
|
||||||
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 1
|
%5 = extractvalue { i32, i64 } %3, 1
|
||||||
store i64 7, ptr %4, align 4
|
%6 = add i64 %10, %5
|
||||||
%5 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %2, align 8
|
%7 = sext i32 %4 to i64
|
||||||
%6 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %5, 1
|
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %7)
|
||||||
%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)
|
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
br label %_llgo_3
|
br label %_llgo_3
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_3
|
_llgo_2: ; preds = %_llgo_3
|
||||||
%13 = call i8 @main.index(i8 2)
|
%8 = call i8 @main.index(i8 2)
|
||||||
%14 = icmp eq i8 %13, 3
|
%9 = icmp eq i8 %8, 3
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %14)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %9)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
ret i32 0
|
ret i32 0
|
||||||
|
|
||||||
_llgo_3: ; preds = %_llgo_1, %_llgo_0
|
_llgo_3: ; preds = %_llgo_1, %_llgo_0
|
||||||
%15 = phi i64 [ 0, %_llgo_0 ], [ %11, %_llgo_1 ]
|
%10 = phi i64 [ 0, %_llgo_0 ], [ %6, %_llgo_1 ]
|
||||||
%16 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
%11 = icmp slt i64 %10, 7
|
||||||
%17 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %16, i32 0, i32 0
|
br i1 %11, label %_llgo_1, label %_llgo_2
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1)
|
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)
|
%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
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 0
|
||||||
%4 = load ptr, ptr @_llgo_int, align 8
|
%4 = load ptr, ptr @_llgo_int, align 8
|
||||||
%5 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8
|
%5 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %4, 0
|
||||||
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %5, i32 0, i32 0
|
%6 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %5, ptr inttoptr (i64 1 to ptr), 1
|
||||||
store ptr %4, ptr %6, align 8
|
store %"github.com/goplus/llgo/internal/runtime.eface" %6, ptr %3, align 8
|
||||||
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %5, i32 0, i32 1
|
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 1
|
||||||
store ptr inttoptr (i64 1 to ptr), ptr %7, align 8
|
%8 = load ptr, ptr @_llgo_int, align 8
|
||||||
%8 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %5, align 8
|
%9 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %8, 0
|
||||||
store %"github.com/goplus/llgo/internal/runtime.eface" %8, ptr %3, align 8
|
%10 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %9, ptr inttoptr (i64 2 to ptr), 1
|
||||||
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 1
|
store %"github.com/goplus/llgo/internal/runtime.eface" %10, ptr %7, align 8
|
||||||
%10 = load ptr, ptr @_llgo_int, align 8
|
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 2
|
||||||
%11 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8
|
%12 = load ptr, ptr @_llgo_int, align 8
|
||||||
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %11, i32 0, i32 0
|
%13 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %12, 0
|
||||||
store ptr %10, ptr %12, align 8
|
%14 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %13, ptr inttoptr (i64 3 to ptr), 1
|
||||||
%13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %11, i32 0, i32 1
|
store %"github.com/goplus/llgo/internal/runtime.eface" %14, ptr %11, align 8
|
||||||
store ptr inttoptr (i64 2 to ptr), ptr %13, align 8
|
%15 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" undef, ptr %2, 0
|
||||||
%14 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %11, align 8
|
%16 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %15, i64 3, 1
|
||||||
store %"github.com/goplus/llgo/internal/runtime.eface" %14, ptr %9, align 8
|
%17 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %16, i64 3, 2
|
||||||
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %2, i64 2
|
call void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %17)
|
||||||
%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)
|
|
||||||
ret i32 0
|
ret i32 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,22 +91,12 @@ _llgo_4: ; preds = %_llgo_2
|
|||||||
br label %_llgo_1
|
br label %_llgo_1
|
||||||
|
|
||||||
_llgo_5: ; preds = %_llgo_2
|
_llgo_5: ; preds = %_llgo_2
|
||||||
%18 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
%18 = load ptr, ptr @_llgo_string, align 8
|
||||||
%19 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 0
|
%19 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||||
store ptr @1, ptr %19, align 8
|
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @1, i64 21 }, ptr %19, align 8
|
||||||
%20 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %18, i32 0, i32 1
|
%20 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %18, 0
|
||||||
store i64 21, ptr %20, align 4
|
%21 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %20, ptr %19, 1
|
||||||
%21 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %18, align 8
|
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %21)
|
||||||
%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)
|
|
||||||
unreachable
|
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 @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
call void @main.init()
|
call void @main.init()
|
||||||
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16)
|
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 16)
|
||||||
%3 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @0, i64 3 }, ptr %2, align 8
|
||||||
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 0
|
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
|
||||||
store ptr @0, ptr %4, align 8
|
%4 = getelementptr inbounds { ptr }, ptr %3, i32 0, i32 0
|
||||||
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 1
|
store ptr %2, ptr %4, align 8
|
||||||
store i64 3, ptr %5, align 4
|
%5 = insertvalue { ptr, ptr } { ptr @"main.main$2", ptr undef }, ptr %3, 1
|
||||||
%6 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %3, align 8
|
%6 = alloca %main.T, align 8
|
||||||
store %"github.com/goplus/llgo/internal/runtime.String" %6, ptr %2, align 8
|
store { ptr, ptr } %5, ptr %6, align 8
|
||||||
%7 = alloca %main.T, align 8
|
%7 = load %main.T, ptr %6, align 8
|
||||||
%8 = getelementptr inbounds %main.T, ptr %7, i32 0, i32 0
|
call void @"__llgo_stub.main.main$1"(ptr null, i64 100)
|
||||||
store ptr @"__llgo_stub.main.main$1", ptr %8, align 8
|
%8 = extractvalue %main.T %7, 1
|
||||||
%9 = getelementptr inbounds %main.T, ptr %7, i32 0, i32 1
|
%9 = extractvalue %main.T %7, 0
|
||||||
store ptr null, ptr %9, align 8
|
call void %9(ptr %8, i64 200)
|
||||||
%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)
|
|
||||||
ret i32 0
|
ret i32 0
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @"main.main$1"(i64 %0) {
|
define void @"main.main$1"(i64 %0) {
|
||||||
_llgo_0:
|
_llgo_0:
|
||||||
%1 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @1, i64 4 })
|
||||||
%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.PrintByte"(i8 32)
|
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.PrintInt"(i64 %0)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
@@ -85,13 +60,7 @@ _llgo_0:
|
|||||||
%2 = load { ptr }, ptr %0, align 8
|
%2 = load { ptr }, ptr %0, align 8
|
||||||
%3 = extractvalue { ptr } %2, 0
|
%3 = extractvalue { ptr } %2, 0
|
||||||
%4 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %3, align 8
|
%4 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %3, align 8
|
||||||
%5 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @2, i64 7 })
|
||||||
%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.PrintByte"(i8 32)
|
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.PrintInt"(i64 %1)
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
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)
|
||||||
9
cl/_testgo/constconv/in.go
Normal file
9
cl/_testgo/constconv/in.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var i64 int64 = 1
|
||||||
|
var u64 uint64 = 1
|
||||||
|
var c int64 = i64 + (1.0 / (1.0 / 10))
|
||||||
|
var d uint64 = u64 + (1.0 / (1.0 / 10))
|
||||||
|
println(u64, i64, c, d)
|
||||||
|
}
|
||||||
44
cl/_testgo/constconv/out.ll
Normal file
44
cl/_testgo/constconv/out.ll
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@"main.init$guard" = global i1 false, align 1
|
||||||
|
@__llgo_argc = global i32 0, align 4
|
||||||
|
@__llgo_argv = global ptr null, align 8
|
||||||
|
|
||||||
|
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 @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 1)
|
||||||
|
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 11)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 11)
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||||
|
ret i32 0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64)
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user