diff --git a/c/clang/_demo/castdump/astdump.go b/c/clang/_demo/castdump/astdump.go new file mode 100644 index 000000000..336c8d6f5 --- /dev/null +++ b/c/clang/_demo/castdump/astdump.go @@ -0,0 +1,49 @@ +package main + +import ( + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/clang" +) + +func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult { + depth := *(*c.Uint)(clientData) + printAST(cursor, depth+1) + return clang.ChildVisit_Continue +} + +func printAST(cursor clang.Cursor, depth c.Uint) { + cursorKind := cursor.Kind.String() + cursorSpelling := cursor.String() + + for i := c.Uint(0); i < depth; i++ { + c.Fputs(c.Str(" "), c.Stdout) + } + + c.Printf(c.Str("%s: %s\n"), cursorKind.CStr(), cursorSpelling.CStr()) + + cursorKind.Dispose() + cursorSpelling.Dispose() + + clang.VisitChildren(cursor, visit, c.Pointer(&depth)) +} + +func main() { + index := clang.CreateIndex(0, 0) + unit := index.ParseTranslationUnit( + c.Str("todo"), + nil, 0, + nil, 0, + clang.TranslationUnit_None, + ) + + if unit == nil { + println("Unable to parse translation unit. Quitting.") + c.Exit(1) + } + + cursor := unit.Cursor() + printAST(cursor, 0) + + unit.Dispose() + index.Dispose() +} diff --git a/c/clang/basic.go b/c/clang/basic.go new file mode 100644 index 000000000..1d33d1fe9 --- /dev/null +++ b/c/clang/basic.go @@ -0,0 +1,59 @@ +/* + * 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 clang + +import ( + _ "unsafe" + + "github.com/goplus/llgo/c" +) + +/** + * A character string. + * + * The \c CXString type is used to return strings from the interface when + * the ownership of that string might differ from one call to the next. + * Use \c clang_getCString() to retrieve the string data and, once finished + * with the string data, call \c clang_disposeString() to free the string. + */ +type String struct { + Data c.Pointer + PrivateFlags c.Uint +} + +/** + * Retrieve the character data associated with the given string. + */ +// llgo:link C.clang_getCString +func (String) CStr() *c.Char { return nil } + +/** + * Free the given string. + */ +// llgo:link C.clang_disposeString +func (String) Dispose() {} + +type StringSet struct { + Strings *String + Count c.Uint +} + +/** + * Free the given string set. + */ +// llgo:link C.clang_disposeStringSet +func (*StringSet) Dispose() {} diff --git a/c/clang/clang.go b/c/clang/clang.go new file mode 100644 index 000000000..52a981f3b --- /dev/null +++ b/c/clang/clang.go @@ -0,0 +1,262 @@ +/* + * 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 clang + +import ( + _ "unsafe" + + "github.com/goplus/llgo/c" +) + +/** + * Opaque pointer representing client data that will be passed through + * to various callbacks and visitors. + */ +type ClientData = c.Pointer + +/** + * Provides the contents of a file that has not yet been saved to disk. + * + * Each CXUnsavedFile instance provides the name of a file on the + * system along with the current contents of that file that have not + * yet been saved to disk. + */ +type UnsavedFile struct { + /** + * The file whose contents have not yet been saved. + * + * This file must already exist in the file system. + */ + Filename *c.Char + + /** + * A buffer containing the unsaved contents of this file. + */ + Contents *c.Char + + /** + * The length of the unsaved contents of this buffer. + */ + Length c.Ulong +} + +/** + * An "index" that consists of a set of translation units that would + * typically be linked together into an executable or library. + */ +type Index struct { + Unused [0]byte +} + +/** + * Provides a shared context for creating translation units. + * + * It provides two options: + * + * - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" + * declarations (when loading any new translation units). A "local" declaration + * is one that belongs in the translation unit itself and not in a precompiled + * header that was used by the translation unit. If zero, all declarations + * will be enumerated. + * + * Here is an example: + * + * \code + * // excludeDeclsFromPCH = 1, displayDiagnostics=1 + * Idx = clang_createIndex(1, 1); + * + * // IndexTest.pch was produced with the following command: + * // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch" + * TU = clang_createTranslationUnit(Idx, "IndexTest.pch"); + * + * // This will load all the symbols from 'IndexTest.pch' + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * + * // This will load all the symbols from 'IndexTest.c', excluding symbols + * // from 'IndexTest.pch'. + * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch" }; + * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args, + * 0, 0); + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * \endcode + * + * This process of creating the 'pch', loading it separately, and using it (via + * -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks + * (which gives the indexer the same performance benefit as the compiler). + */ +//go:linkname CreateIndex C.clang_createIndex +func CreateIndex(excludeDeclarationsFromPCH, displayDiagnostics c.Int) *Index + +/** + * Destroy the given index. + * + * The index must not be destroyed until all of the translation units created + * within that index have been destroyed. + */ +// llgo:link (*Index).Dispose C.clang_disposeIndex +func (*Index) Dispose() {} + +/** + * Flags that control the creation of translation units. + * + * The enumerators in this enumeration type are meant to be bitwise + * ORed together to specify which options should be used when + * constructing the translation unit. + */ +const ( + TranslationUnit_None = 0x0 +) + +/** + * Same as \c clang_parseTranslationUnit2, but returns + * the \c CXTranslationUnit instead of an error code. In case of an error this + * routine returns a \c NULL \c CXTranslationUnit, without further detailed + * error codes. + */ +// llgo:link (*Index).ParseTranslationUnit C.clang_parseTranslationUnit +func (*Index) ParseTranslationUnit( + sourceFilename *c.Char, commandLineArgs **c.Char, numCommandLineArgs c.Int, + unsavedFiles *UnsavedFile, numUnsavedFiles c.Uint, options c.Uint) *TranslationUnit { + return nil +} + +/** + * A single translation unit, which resides in an index. + */ +type TranslationUnit struct { + Unused [0]byte +} + +/** + * Destroy the specified CXTranslationUnit object. + */ +// llgo:linke (*TranslationUnit).Dispose C.clang_disposeTranslationUnit +func (*TranslationUnit) Dispose() {} + +/** + * Retrieve the cursor that represents the given translation unit. + * + * The translation unit cursor can be used to start traversing the + * various declarations within the given translation unit. + */ +// llgo:link (*TranslationUnit).Cursor C.clang_getTranslationUnitCursor +func (*TranslationUnit) Cursor() (ret Cursor) { + return +} + +/** + * Describes the kind of entity that a cursor refers to. + */ +type CursorKind c.Int + +/* for debug/testing */ +// llgo:link (CursorKind).String C.clang_getCursorKindSpelling +func (CursorKind) String() (ret String) { + return +} + +/** + * A cursor representing some element in the abstract syntax tree for + * a translation unit. + * + * The cursor abstraction unifies the different kinds of entities in a + * program--declaration, statements, expressions, references to declarations, + * etc.--under a single "cursor" abstraction with a common set of operations. + * Common operation for a cursor include: getting the physical location in + * a source file where the cursor points, getting the name associated with a + * cursor, and retrieving cursors for any child nodes of a particular cursor. + * + * Cursors can be produced in two specific ways. + * clang_getTranslationUnitCursor() produces a cursor for a translation unit, + * from which one can use clang_visitChildren() to explore the rest of the + * translation unit. clang_getCursor() maps from a physical source location + * to the entity that resides at that location, allowing one to map from the + * source code into the AST. + */ +type Cursor struct { + Kind CursorKind + Xdata c.Int + Data [3]c.Pointer +} + +/** + * Retrieve a name for the entity referenced by this cursor. + */ +// llgo:link C.clang_getCursorSpelling +func (Cursor) String() (ret String) { + return +} + +/** + * Describes how the traversal of the children of a particular + * cursor should proceed after visiting a particular child cursor. + * + * A value of this enumeration type should be returned by each + * \c CXCursorVisitor to indicate how clang_visitChildren() proceed. + */ +type ChildVisitResult c.Int + +const ( + /** + * Terminates the cursor traversal. + */ + ChildVisit_Break ChildVisitResult = iota + /** + * Continues the cursor traversal with the next sibling of + * the cursor just visited, without visiting its children. + */ + ChildVisit_Continue + /** + * Recursively traverse the children of this cursor, using + * the same visitor and client data. + */ + ChildVisit_Recurse +) + +/** + * Visit the children of a particular cursor. + * + * This function visits all the direct children of the given cursor, + * invoking the given \p visitor function with the cursors of each + * visited child. The traversal may be recursive, if the visitor returns + * \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if + * the visitor returns \c CXChildVisit_Break. + * + * \param parent the cursor whose child may be visited. All kinds of + * cursors can be visited, including invalid cursors (which, by + * definition, have no children). + * + * \param visitor the visitor function that will be invoked for each + * child of \p parent. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the visitor each time it is invoked. + * + * \returns a non-zero value if the traversal was terminated + * prematurely by the visitor returning \c CXChildVisit_Break. + */ +//go:linkname VisitChildren C.clang_visitChildren +func VisitChildren( + cusor Cursor, + visitor func(cursor, parent Cursor, clientData ClientData) ChildVisitResult, + clientData ClientData) c.Uint { + return 0 +} diff --git a/c/clang/llgo_autogen.lla b/c/clang/llgo_autogen.lla new file mode 100644 index 000000000..3a5e839a4 Binary files /dev/null and b/c/clang/llgo_autogen.lla differ diff --git a/c/raylib/_demo/raylibdemo/raydemo.go b/c/raylib/_demo/raylibdemo/raydemo.go new file mode 100644 index 000000000..62baabc19 --- /dev/null +++ b/c/raylib/_demo/raylibdemo/raydemo.go @@ -0,0 +1,18 @@ +package main + +import ( + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/raylib" +) + +func main() { + const screenWidth = 800 + const screenHeight = 450 + raylib.InitWindow(screenWidth, screenHeight, c.Str("Raylib DEMO")) + for !raylib.WindowShouldClose() { + raylib.BeginDrawing() + raylib.ClearBackground(raylib.RAYWHITE) + raylib.DrawRectangle(screenWidth/2-50, screenHeight/2-50, 100, 100, raylib.BLUE) + raylib.EndDrawing() + } +} diff --git a/c/raylib/llgo_autogen.lla b/c/raylib/llgo_autogen.lla new file mode 100644 index 000000000..634259475 Binary files /dev/null and b/c/raylib/llgo_autogen.lla differ diff --git a/c/raylib/raylib.go b/c/raylib/raylib.go index 8e2bbba95..d5dba1ca0 100644 --- a/c/raylib/raylib.go +++ b/c/raylib/raylib.go @@ -53,9 +53,39 @@ type Vector4 struct { type Quaternion = Vector4 // Color, 4 components, R8G8B8A8 (32bit) -type Color struct { - R, G, B, A uint8 -} +// R, G, B, A uint8 +type Color uint32 + +const ( + LIGHTGRAY = Color(200 | 200<<8 | 200<<16 | 255<<24) // Light Gray + GRAY = Color(130 | 130<<8 | 130<<16 | 255<<24) // Gray + DARKGRAY = Color(80 | 80<<8 | 80<<16 | 255<<24) // Dark Gray + YELLOW = Color(253 | 249<<8 | 0<<16 | 255<<24) // Yellow + GOLD = Color(255 | 203<<8 | 0<<16 | 255<<24) // Gold + ORANGE = Color(255 | 161<<8 | 0<<16 | 255<<24) // Orange + PINK = Color(255 | 109<<8 | 194<<16 | 255<<24) // Pink + RED = Color(230 | 41<<8 | 55<<16 | 255<<24) // Red + MAROON = Color(190 | 33<<8 | 55<<16 | 255<<24) // Maroon + GREEN = Color(0 | 228<<8 | 48<<16 | 255<<24) // Green + LIME = Color(0 | 158<<8 | 47<<16 | 255<<24) // Lime + DARKGREEN = Color(0 | 117<<8 | 44<<16 | 255<<24) // Dark Green + SKYBLUE = Color(102 | 191<<8 | 255<<16 | 255<<24) // Sky Blue + BLUE = Color(0 | 121<<8 | 241<<16 | 255<<24) // Blue + + DARKBLUE = Color(0 | 82<<8 | 172<<16 | 255<<24) // Dark Blue + PURPLE = Color(200 | 122<<8 | 255<<16 | 255<<24) // Purple + VIOLET = Color(135 | 60<<8 | 190<<16 | 255<<24) // Violet + DARKPURPLE = Color(112 | 31<<8 | 126<<16 | 255<<24) // Dark Purple + BEIGE = Color(211 | 176<<8 | 131<<16 | 255<<24) // Beige + BROWN = Color(127 | 106<<8 | 79<<16 | 255<<24) // Brown + DARKBROWN = Color(76 | 63<<8 | 47<<16 | 255<<24) // Dark Brown + + WHITE = Color(255 | 255<<8 | 255<<16 | 255<<24) // White + BLACK = Color(0 | 0<<8 | 0<<16 | 255<<24) // Black + BLANK = Color(0 | 0<<8 | 0<<16 | 0<<24) // Blank (Transparent) + MAGENTA = Color(255 | 0<<8 | 255<<16 | 255<<24) // Magenta + RAYWHITE = Color(245 | 245<<8 | 245<<16 | 255<<24) // My own White (raylib logo) +) // Image, pixel data stored in CPU memory (RAM) type Image struct { @@ -297,3 +327,10 @@ func BeginScissorMode(x, y, width, height c.Int) func EndScissorMode() // ----------------------------------------------------------------------------- + +// Draw a color-filled rectangle +// +//go:linkname DrawRectangle C.DrawRectangle +func DrawRectangle(posX, posY, width, height c.Int, color Color) + +// ----------------------------------------------------------------------------- diff --git a/chore/_xtool/astdump/astdump.cpp b/chore/_xtool/astdump/astdump.cpp new file mode 100644 index 000000000..e466fce80 --- /dev/null +++ b/chore/_xtool/astdump/astdump.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +CXChildVisitResult visit(CXCursor c, CXCursor parent, CXClientData client_data); + +void printAST(CXCursor cursor, unsigned int depth = 0) { + CXString cursorKind = clang_getCursorKindSpelling(clang_getCursorKind(cursor)); + CXString cursorSpelling = clang_getCursorSpelling(cursor); + + for (unsigned int i = 0; i < depth; ++i) { + std::cout << " "; + } + + std::cout << clang_getCString(cursorKind) << ": " + << clang_getCString(cursorSpelling) << std::endl; + + clang_disposeString(cursorKind); + clang_disposeString(cursorSpelling); + + CXCursor child; + clang_visitChildren( + cursor, + visit, + &depth + ); +} + +CXChildVisitResult visit(CXCursor c, CXCursor parent, CXClientData client_data) { + unsigned int* depth = (unsigned int*)client_data; + printAST(c, *depth + 1); + return CXChildVisit_Continue; +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + CXIndex index = clang_createIndex(0, 0); + CXTranslationUnit unit = clang_parseTranslationUnit( + index, + argv[1], + nullptr, 0, + nullptr, 0, + CXTranslationUnit_None + ); + + if (unit == nullptr) { + std::cerr << "Unable to parse translation unit. Quitting." << std::endl; + return 1; + } + + CXCursor cursor = clang_getTranslationUnitCursor(unit); + std::cout << "AST for " << argv[1] << ":" << std::endl; + printAST(cursor); + + clang_disposeTranslationUnit(unit); + clang_disposeIndex(index); + + return 0; +} \ No newline at end of file diff --git a/chore/_xtool/astdump/build.sh b/chore/_xtool/astdump/build.sh new file mode 100755 index 000000000..d255f327e --- /dev/null +++ b/chore/_xtool/astdump/build.sh @@ -0,0 +1,2 @@ +export LLVM_DIR=/opt/homebrew/Cellar/llvm@17/17.0.6 +clang -L$LLVM_DIR/lib -lclang -lc++ -I$LLVM_DIR/include astdump.cpp