aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorphillvancejr <phillipvancejr@gmail.com>2022-02-04 13:45:36 -0500
committerphillvancejr <phillipvancejr@gmail.com>2022-02-04 13:45:36 -0500
commita315e7c9628cc0b53c4504fa6432a75d5ecc2fd8 (patch)
tree03b7e181bd6fed85c8ed6b762660c8a02607b9ca
parent42364f2fcee1f0f588b006bf2b7e9bc6f88acb93 (diff)
Reverted experimental changes that were meant for a branch, in sync with master
-rw-r--r--Makefile2
-rw-r--r--core/bindgen/c-parser-evaluate.odin266
-rw-r--r--core/bindgen/c-parser-helpers.odin267
-rw-r--r--core/bindgen/c-parser-nodes.odin132
-rw-r--r--core/bindgen/c-parser.odin840
-rw-r--r--core/bindgen/errors.odin44
-rw-r--r--core/bindgen/generator-clean.odin284
-rw-r--r--core/bindgen/generator-export.odin166
-rw-r--r--core/bindgen/generator-helpers.odin392
-rw-r--r--core/bindgen/generator.odin205
l---------wasm-ld1
11 files changed, 1 insertions, 2598 deletions
diff --git a/Makefile b/Makefile
index df5fe0605..d3d3c6a2d 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ ifeq ($(OS), Darwin)
LLVM_VERSIONS = "13.%.%"
else
# allow for x86 / amd64 all llvm versions begining from 11
- LLVM_VERSIONS = "13.%.%" "12.0.1" "11.0.0"
+ LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0"
endif
LLVM_VERSION_PATTERN_SEPERATOR = )|(
diff --git a/core/bindgen/c-parser-evaluate.odin b/core/bindgen/c-parser-evaluate.odin
deleted file mode 100644
index 13cb5042c..000000000
--- a/core/bindgen/c-parser-evaluate.odin
+++ /dev/null
@@ -1,266 +0,0 @@
-package bindgen
-
-import "core:fmt"
-import "core:strconv"
-
-// Evaluates an expression to a i64, without checking.
-evaluate_i64 :: proc(data : ^ParserData) -> i64 {
- ok : bool;
- value : LiteralValue;
-
- value, ok = evaluate(data);
- return value.(i64);
-}
-
-// Evaluate an expression, returns whether it succeeded.
-evaluate :: proc(data : ^ParserData) -> (LiteralValue, bool) {
- return evaluate_level_5(data);
-}
-
-// @note Evaluate levels numbers are based on
-// https://en.cppreference.com/w/c/language/operator_precedence.
-
-// Bitwise shift level.
-evaluate_level_5 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) {
- value, ok = evaluate_level_4(data);
- if !ok do return;
-
- invalid_value : LiteralValue;
- token := peek_token(data);
-
- if token == "<<" {
- v : LiteralValue;
- eat_token(data);
-
- v, ok = evaluate_level_5(data);
- if is_i64(v) do value = value.(i64) << cast(u64) v.(i64);
- else do invalid_value = v;
- } else if token == ">>" {
- v : LiteralValue;
- eat_token(data);
-
- v, ok = evaluate_level_5(data);
- if is_i64(v) do value = value.(i64) >> cast(u64) v.(i64);
- else do invalid_value = v;
- }
-
- if invalid_value != nil {
- print_warning("Invalid operand for bitwise shift ", invalid_value);
- }
-
- return;
-}
-
-// Additive level.
-evaluate_level_4 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) {
- value, ok = evaluate_level_3(data);
- if !ok do return;
-
- token := peek_token(data);
- if token == "+" {
- v : LiteralValue;
- eat_token(data);
- v, ok = evaluate_level_4(data);
- if is_i64(v) do value = value.(i64) + v.(i64);
- else if is_f64(v) do value = value.(f64) + v.(f64);
- }
- else if token == "-" {
- v : LiteralValue;
- eat_token(data);
- v, ok = evaluate_level_4(data);
- if is_i64(v) do value = value.(i64) - v.(i64);
- else if is_f64(v) do value = value.(f64) - v.(f64);
- }
-
- return;
-}
-
-// Multiplicative level.
-evaluate_level_3 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) {
- value, ok = evaluate_level_2(data);
- if !ok do return;
-
- token := peek_token(data);
- if token == "*" {
- v : LiteralValue;
- eat_token(data);
- v, ok = evaluate_level_3(data);
- if is_i64(v) do value = value.(i64) * v.(i64);
- else if is_f64(v) do value = value.(f64) * v.(f64);
- }
- else if token == "/" {
- v : LiteralValue;
- eat_token(data);
- v, ok = evaluate_level_3(data);
- if is_i64(v) do value = value.(i64) / v.(i64);
- else if is_f64(v) do value = value.(f64) / v.(f64);
- }
-
- return;
-}
-
-// Prefix level.
-evaluate_level_2 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) {
- token := peek_token(data);
-
- // Bitwise not
- if token == "~" {
- check_and_eat_token(data, "~");
- value, ok = evaluate_level_2(data);
- value = ~value.(i64);
- }
- else {
- // @note Should call evaluate_level_1, but we don't have that because we do not dereferenciation.
- value, ok = evaluate_level_0(data);
- }
-
- return;
-}
-
-// Does not try to compose with arithmetics, it just evaluates one single expression.
-evaluate_level_0 :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) {
- ok = true;
- value = 0;
- token := peek_token(data);
-
- // Parentheses
- if token == "(" {
- value, ok = evaluate_parentheses(data);
- } // Number literal
- else if (token[0] == '-') || (token[0] >= '0' && token[0] <= '9') {
- value, ok = evaluate_number_literal(data);
- } // String literal
- else if token[0] == '"' {
- value = evaluate_string_literal(data);
- } // Function-like
- else if token == "sizeof" {
- value = evaluate_sizeof(data);
- } // Knowned literal
- else if token in data.knownedLiterals {
- value = evaluate_knowned_literal(data);
- } // Custom expression
- else if token in data.options.customExpressionHandlers {
- value = data.options.customExpressionHandlers[token](data);
- }
- else {
- print_warning("Unknown token ", token, " for expression evaluation.");
- ok = false;
- }
-
- return;
-}
-
-evaluate_sizeof :: proc(data : ^ParserData) -> LiteralValue {
- print_warning("Using 'sizeof()'. Currently not able to precompute that. Please check generated code.");
-
- check_and_eat_token(data, "sizeof");
- check_and_eat_token(data, "(");
- for data.bytes[data.offset] != ')' {
- data.offset += 1;
- }
- check_and_eat_token(data, ")");
- return 1;
-}
-
-evaluate_parentheses :: proc(data : ^ParserData) -> (value : LiteralValue, ok : bool) {
- check_and_eat_token(data, "(");
-
- // Cast to int (via "(int)" syntax)
- token := peek_token(data);
- if token == "int" {
- check_and_eat_token(data, "int");
- check_and_eat_token(data, ")");
- value, ok = evaluate(data);
- return;
- } // Cast to enum value (via "(enum XXX)" syntax)
- else if token == "enum" {
- check_and_eat_token(data, "enum");
- eat_token(data);
- check_and_eat_token(data, ")");
- value, ok = evaluate(data);
- return;
- }
-
- value, ok = evaluate(data);
- check_and_eat_token(data, ")");
- return;
-}
-
-evaluate_number_literal :: proc(data : ^ParserData, loc := #caller_location) -> (value : LiteralValue, ok : bool) {
- token := parse_any(data);
-
- // Unary - before numbers
- numberLitteral := token;
- for token == "-" {
- token = parse_any(data);
- numberLitteral = tcat(numberLitteral, token);
- }
- token = numberLitteral;
-
- // Check if any point or scientific notation in number
- foundPointOrExp := false;
- for c in token {
- if c == '.' || c == 'e' || c == 'E' {
- foundPointOrExp = true;
- break;
- }
- }
-
- isHexadecimal := len(token) >= 2 && token[:2] == "0x";
-
- // Computing postfix
- tokenLength := len(token);
- l := tokenLength - 1;
- for l > 0 {
- c := token[l];
- if c >= '0' && c <= '9' { break; }
- if isHexadecimal && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { break; }
- l -= 1;
- }
-
- postfix : string;
- if l != tokenLength - 1 {
- postfix = token[l+1:];
- token = token[:l+1];
- }
-
- if postfix != "" && (postfix[0] == 'u' || postfix[0] == 'U') {
- print_warning("Found number litteral '", token, "' with unsigned postfix, we cast it to an int64 internally.");
- }
-
- // Floating point
- if !isHexadecimal && (foundPointOrExp || postfix == "f") {
- value, ok = strconv.parse_f64(token);
- } // Integer
- else {
- value, ok = strconv.parse_i64(token);
- }
-
- if !ok {
- print_error(data, loc, "Expected number litteral but got '", token, "'.");
- }
-
- return value, ok;
-}
-
-evaluate_string_literal :: proc(data : ^ParserData) -> string {
- token := parse_any(data);
- return token;
-}
-
-evaluate_knowned_literal :: proc(data : ^ParserData) -> LiteralValue {
- token := parse_any(data);
- return data.knownedLiterals[token];
-}
-
-is_i64 :: proc(value : LiteralValue) -> (ok : bool) {
- v : i64;
- v, ok = value.(i64);
- return ok;
-}
-
-is_f64 :: proc(value : LiteralValue) -> (ok : bool) {
- v : f64;
- v, ok = value.(f64);
- return ok;
-}
diff --git a/core/bindgen/c-parser-helpers.odin b/core/bindgen/c-parser-helpers.odin
deleted file mode 100644
index a99d83dd2..000000000
--- a/core/bindgen/c-parser-helpers.odin
+++ /dev/null
@@ -1,267 +0,0 @@
-package bindgen
-
-import "core:os"
-import "core:fmt"
-import "core:strings"
-import "core:strconv"
-
-// Extract from start (included) to end (excluded) offsets
-extract_string :: proc(data : ^ParserData, startOffset : u32, endOffset : u32) -> string {
- return strings.string_from_ptr(&data.bytes[startOffset], cast(int) (endOffset - startOffset));
-}
-
-// Peek the end offset of the next token
-peek_token_end :: proc(data : ^ParserData) -> u32 {
- offset : u32;
-
- for true {
- eat_whitespaces_and_comments(data);
- if data.offset >= data.bytesLength {
- return data.bytesLength;
- }
- offset = data.offset;
-
- // Identifier
- if (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'z') ||
- (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'Z') ||
- (data.bytes[offset] == '_') {
- offset += 1;
- for (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'z') ||
- (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'Z') ||
- (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') ||
- (data.bytes[offset] == '_') {
- offset += 1;
- }
- }
- if offset != data.offset {
- // Nothing to do: we found an identifier
- } // Number literal
- else if (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') {
- offset += 1;
- // Hexademical literal
- if data.bytes[offset - 1] == '0' && data.bytes[offset] == 'x' {
- offset += 1;
- for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') ||
- (data.bytes[offset] >= 'a' && data.bytes[offset] <= 'f') ||
- (data.bytes[offset] >= 'A' && data.bytes[offset] <= 'F') {
- offset += 1;
- }
- } // Basic number literal
- else {
- for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') ||
- data.bytes[offset] == '.' {
- offset += 1;
- }
-
- if (data.bytes[offset] == 'e' || data.bytes[offset] == 'E') {
- offset += 1;
- if data.bytes[offset] == '-' {
- offset += 1;
- }
- }
-
- for (data.bytes[offset] >= '0' && data.bytes[offset] <= '9') {
- offset += 1;
- }
- }
-
- // Number suffix?
- for (data.bytes[offset] == 'u' || data.bytes[offset] == 'U') ||
- (data.bytes[offset] == 'l' || data.bytes[offset] == 'L') ||
- (data.bytes[offset] == 'f') {
- offset += 1;
- }
- } // String literal
- else if data.bytes[offset] == '"' {
- offset += 1;
- for data.bytes[offset-1] == '\\' || data.bytes[offset] != '"' {
- offset += 1;
- }
- offset += 1;
- } // Possible shifts
- else if data.bytes[offset] == '<' || data.bytes[offset] == '>' {
- offset += 1;
- if data.bytes[offset] == data.bytes[offset-1] {
- offset += 1;
- }
- } // Single character
- else {
- offset += 1;
- }
-
- token := extract_string(data, data.offset, offset);
-
- // Ignore __attribute__
- if token == "__attribute__" {
- print_warning("__attribute__ is ignored.");
-
- for data.bytes[offset] != '(' {
- offset += 1;
- }
-
- parenthesesCount := 1;
- for true {
- offset += 1;
- if data.bytes[offset] == '(' do parenthesesCount += 1;
- else if data.bytes[offset] == ')' do parenthesesCount -= 1;
- if parenthesesCount == 0 do break;
- }
- offset += 1;
-
- data.offset = offset;
- } // Ignore certain keywords
- else if (token == "inline" || token == "__inline" || token == "static"
- || token == "restrict" || token == "__restrict"
- || token == "volatile"
- || token == "__extension__") {
- data.offset = offset;
- } // Ignore ignored tokens ;)
- else {
- for ignoredToken in data.options.ignoredTokens {
- if token == ignoredToken {
- data.offset = offset;
- break;
- }
- }
- }
-
- if data.offset != offset {
- break;
- }
- }
-
- return offset;
-}
-
-// Peek the next token (just eating whitespaces and comment)
-peek_token :: proc(data : ^ParserData) -> string {
- tokenEnd := peek_token_end(data);
- if tokenEnd == data.bytesLength {
- return "EOF";
- }
- return extract_string(data, data.offset, tokenEnd);
-}
-
-// Find the end of the define directive (understanding endline backslashes)
-// @note Tricky cases like comments hiding a backslash effect are not handled.
-peek_define_end :: proc(data : ^ParserData) -> u32 {
- defineEndOffset := data.offset;
- for data.bytes[defineEndOffset-1] == '\\' || data.bytes[defineEndOffset] != '\n' {
- defineEndOffset += 1;
- }
- return defineEndOffset;
-}
-
-eat_comment :: proc(data : ^ParserData) {
- if data.offset >= data.bytesLength || data.bytes[data.offset] != '/' {
- return;
- }
-
- // Line comment
- if data.bytes[data.offset + 1] == '/' {
- eat_line(data);
- } // Range comment
- else if data.bytes[data.offset + 1] == '*' {
- data.offset += 2;
- for data.bytes[data.offset] != '*' || data.bytes[data.offset + 1] != '/' {
- data.offset += 1;
- }
- data.offset += 2;
- }
-}
-
-// Eat whitespaces
-eat_whitespaces :: proc(data : ^ParserData) {
- // Effective whitespace
- for data.offset < data.bytesLength &&
- (data.bytes[data.offset] == ' ' || data.bytes[data.offset] == '\t' ||
- data.bytes[data.offset] == '\r' || data.bytes[data.offset] == '\n') {
- if data.bytes[data.offset] == '\n' && data.bytes[data.offset] != '\\' {
- data.foundFullReturn = true;
- }
- data.offset += 1;
- }
-}
-
-// Removes whitespaces and comments
-eat_whitespaces_and_comments :: proc(data : ^ParserData) {
- startOffset : u32 = 0xFFFFFFFF;
- for startOffset != data.offset {
- startOffset = data.offset;
- eat_whitespaces(data);
- eat_comment(data);
- }
-}
-
-// Eat full line
-eat_line :: proc(data : ^ParserData) {
- for ; data.bytes[data.offset] != '\n'; data.offset += 1 {
- }
-}
-
-// Eat a line, and repeat if it ends with a backslash
-eat_define_lines :: proc(data : ^ParserData) {
- for data.bytes[data.offset-1] == '\\' || data.bytes[data.offset] != '\n' {
- data.offset += 1;
- }
-}
-
-// Eat next token
-eat_token :: proc(data : ^ParserData) {
- data.offset = peek_token_end(data);
-}
-
-// Eat next token
-check_and_eat_token :: proc(data : ^ParserData, expectedToken : string, loc := #caller_location) {
- token := peek_token(data);
- if token != expectedToken {
- print_error(data, loc, "Expected ", expectedToken, " but found ", token, ".");
- }
- data.offset += cast(u32) len(token);
-}
-
-// Check whether the next token is outside #define range
-is_define_end :: proc(data : ^ParserData) -> bool {
- defineEnd := peek_define_end(data);
- tokenEnd := peek_token_end(data);
-
- return (defineEnd < tokenEnd);
-}
-
-// Check if the current #define is a macro definition
-is_define_macro :: proc(data : ^ParserData) -> bool {
- startOffset := data.offset;
- defer data.offset = startOffset;
-
- token := parse_any(data);
- if token != "(" do return false;
-
- // Find the other parenthesis
- parenthesesCount := 1;
- for parenthesesCount != 0 {
- token = parse_any(data);
- if token == "(" do parenthesesCount += 1;
- else if token == ")" do parenthesesCount -= 1;
- }
-
- // Its a macro if after the parentheses, it's not the end
- return !is_define_end(data);
-}
-
-// @note Very slow function to get line number,
-// use only for errors.
-// @todo Well, this does not seem to work properly, UTF-8 problem?
-get_line_column :: proc(data : ^ParserData) -> (u32, u32) {
- line : u32 = 1;
- column : u32 = 0;
- for i : u32 = 0; i < data.offset; i += 1 {
- if data.bytes[i] == '\n' {
- column = 0;
- line += 1;
- }
- else {
- column += 1;
- }
- }
- return line, column;
-}
diff --git a/core/bindgen/c-parser-nodes.odin b/core/bindgen/c-parser-nodes.odin
deleted file mode 100644
index 0620e0187..000000000
--- a/core/bindgen/c-parser-nodes.odin
+++ /dev/null
@@ -1,132 +0,0 @@
-package bindgen
-
-DefineNode :: struct {
- name : string,
- value : LiteralValue,
-}
-
-StructDefinitionNode :: struct {
- name : string,
- members : [dynamic]StructOrUnionMember,
- forwardDeclared : bool,
-}
-
-UnionDefinitionNode :: struct {
- name : string,
- members : [dynamic]StructOrUnionMember,
-}
-
-EnumDefinitionNode :: struct {
- name : string,
- members : [dynamic]EnumMember,
-}
-
-FunctionDeclarationNode :: struct {
- name : string,
- returnType : Type,
- parameters : [dynamic]FunctionParameter,
-}
-
-TypedefNode :: struct {
- name : string,
- type : Type,
-}
-
-Nodes :: struct {
- defines : [dynamic]DefineNode,
- enumDefinitions : [dynamic]EnumDefinitionNode,
- unionDefinitions : [dynamic]UnionDefinitionNode,
- structDefinitions : [dynamic]StructDefinitionNode,
- functionDeclarations : [dynamic]FunctionDeclarationNode,
- typedefs : [dynamic]TypedefNode,
-}
-
-LiteralValue :: union {
- i64,
- f64,
- string,
-}
-
-// Type, might be an array
-Type :: struct {
- base : BaseType,
- dimensions : [dynamic]u64, // Array dimensions
-}
-
-BaseType :: union {
- BuiltinType,
- PointerType,
- IdentifierType,
- FunctionType,
- FunctionPointerType,
-}
-
-BuiltinType :: enum {
- Unknown,
- Void,
- Int,
- UInt,
- LongInt,
- ULongInt,
- LongLongInt,
- ULongLongInt,
- ShortInt,
- UShortInt,
- Char,
- SChar,
- UChar,
- Float,
- Double,
- LongDouble,
-
- // Not defined by C language but in <stdint.h>
- Int8,
- Int16,
- Int32,
- Int64,
- UInt8,
- UInt16,
- UInt32,
- UInt64,
- Size,
- SSize,
- PtrDiff,
- UIntPtr,
- IntPtr,
-}
-
-PointerType :: struct {
- type : ^Type, // Pointer is there to prevent definition cycle. Null means void.
-}
-
-IdentifierType :: struct {
- name : string,
- anonymous : bool, // An anonymous identifier can be hard-given a name in some contexts.
-}
-
-FunctionType :: struct {
- returnType : ^Type, // Pointer is there to prevent definition cycle. Null means void.
- parameters : [dynamic]FunctionParameter,
-}
-
-FunctionPointerType :: struct {
- name : string,
- returnType : ^Type, // Pointer is there to prevent definition cycle. Null means void.
- parameters : [dynamic]FunctionParameter,
-}
-
-EnumMember :: struct {
- name : string,
- value : i64,
- hasValue : bool,
-}
-
-StructOrUnionMember :: struct {
- name : string,
- type : Type,
-}
-
-FunctionParameter :: struct {
- name : string,
- type : Type,
-}
diff --git a/core/bindgen/c-parser.odin b/core/bindgen/c-parser.odin
deleted file mode 100644
index c3ef4937f..000000000
--- a/core/bindgen/c-parser.odin
+++ /dev/null
@@ -1,840 +0,0 @@
-package bindgen
-
-import "core:os"
-import "core:fmt"
-import "core:strings"
-import "core:strconv"
-
-// Global counters
-anonymousStructCount := 0;
-anonymousUnionCount := 0;
-anonymousEnumCount := 0;
-
-knownTypeAliases : map[string]Type;
-
-CustomHandler :: proc(data : ^ParserData);
-CustomExpressionHandler :: proc(data : ^ParserData) -> LiteralValue;
-
-ParserOptions :: struct {
- ignoredTokens : []string,
-
- // Handlers
- customHandlers : map[string]CustomHandler,
- customExpressionHandlers : map[string]CustomExpressionHandler,
-}
-
-ParserData :: struct {
- bytes : []u8,
- bytesLength : u32,
- offset : u32,
-
- // References
- nodes : Nodes,
- options : ^ParserOptions,
-
- // Knowned values
- knownedLiterals : map[string]LiteralValue,
-
- // Whether we have eaten a '\n' character that has no backslash just before
- foundFullReturn : bool,
-}
-
-is_identifier :: proc(token : string) -> bool {
- return (token[0] >= 'a' && token[0] <= 'z') ||
- (token[0] >= 'A' && token[0] <= 'Z') ||
- (token[0] == '_');
-}
-
-parse :: proc(bytes : []u8, options : ParserOptions, loc := #caller_location) -> Nodes {
- options := options;
-
- data : ParserData;
- data.bytes = bytes;
- data.bytesLength = cast(u32) len(bytes);
- data.options = &options;
-
- for data.offset = 0; data.offset < data.bytesLength; {
- token := peek_token(&data);
- if data.offset == data.bytesLength do break;
-
- if token in options.customHandlers {
- options.customHandlers[token](&data);
- }
- else if token == "{" || token == "}" || token == ";" {
- eat_token(&data);
- }
- else if token == "extern" {
- check_and_eat_token(&data, "extern");
- }
- else if token == "\"C\"" {
- check_and_eat_token(&data, "\"C\"");
- }
- else if token == "#" {
- parse_directive(&data);
- }
- else if token == "typedef" {
- parse_typedef(&data);
- }
- else if is_identifier(token) {
- parse_variable_or_function_declaration(&data);
- }
- else {
- print_error(&data, loc, "Unexpected token: ", token, ".");
- return data.nodes;
- }
- }
-
- return data.nodes;
-}
-
-parse_any :: proc(data : ^ParserData) -> string {
- offset := peek_token_end(data);
- identifier := extract_string(data, data.offset, offset);
- data.offset = offset;
- return identifier;
-}
-
-parse_identifier :: proc(data : ^ParserData, loc := #caller_location) -> string {
- identifier := parse_any(data);
-
- if (identifier[0] < 'a' || identifier[0] > 'z') &&
- (identifier[0] < 'A' || identifier[0] > 'Z') &&
- (identifier[0] != '_') {
- print_error(data, loc, "Expected identifier but found ", identifier, ".");
- }
-
- return identifier;
-}
-
-parse_type_dimensions :: proc(data : ^ParserData, type : ^Type) {
- token := peek_token(data);
- for token == "[" {
- eat_token(data);
- token = peek_token(data);
- if token == "]" {
- pointerType : PointerType;
- pointerType.type = new(Type);
- pointerType.type^ = type^; // Copy
- type.base = pointerType;
- delete(type.dimensions);
- } else {
- dimension := evaluate_i64(data);
- append(&type.dimensions, cast(u64) dimension);
- }
- check_and_eat_token(data, "]");
- token = peek_token(data);
- }
-}
-
-// This will parse anything that look like a type:
-// Builtin: char/int/float/...
-// Struct-like: struct A/struct { ... }/enum E
-// Function pointer: void (*f)(...)
-//
-// Definition permitted: If a struct-like definition is found, it will generate
-// the according Node and return a corresponding type.
-parse_type :: proc(data : ^ParserData, definitionPermitted := false) -> Type {
- type : Type;
-
- // Eat qualifiers
- token := peek_token(data);
- if token == "const" {
- eat_token(data);
- token = peek_token(data);
- }
-
- // Parse main type
- if token == "struct" {
- type.base = parse_struct_type(data, definitionPermitted);
- }
- else if token == "union" {
- type.base = parse_union_type(data);
- }
- else if token == "enum" {
- type.base = parse_enum_type(data);
- }
- else {
- // Test builtin type
- type.base = parse_builtin_type(data);
- if type.base.(BuiltinType) == BuiltinType.Unknown {
- // Basic identifier type
- identifierType : IdentifierType;
- identifierType.name = parse_identifier(data);
- type.base = identifierType;
- }
- }
-
- // Eat qualifiers
- token = peek_token(data);
- if token == "const" {
- eat_token(data);
- token = peek_token(data);
- }
-
- // Check if pointer
- for token == "*" {
- check_and_eat_token(data, "*");
- token = peek_token(data);
-
- pointerType : PointerType;
- pointerType.type = new(Type);
- pointerType.type^ = type; // Copy
-
- type.base = pointerType;
-
- // Eat qualifiers
- if token == "const" {
- eat_token(data);
- token = peek_token(data);
- }
- }
-
- // Parse array dimensions if any.
- parse_type_dimensions(data, &type);
-
- // ----- Function pointer type
-
- if token == "(" {
- check_and_eat_token(data, "(");
- check_and_eat_token(data, "*");
-
- functionPointerType : FunctionPointerType;
- functionPointerType.returnType = new(Type);
- functionPointerType.returnType^ = type;
- functionPointerType.name = parse_identifier(data);
-
- check_and_eat_token(data, ")");
- parse_function_parameters(data, &functionPointerType.parameters);
-
- type.base = functionPointerType;
- }
-
- return type;
-}
-
-parse_builtin_type :: proc(data : ^ParserData) -> BuiltinType {
- previousBuiltinType := BuiltinType.Unknown;
- intFound := false;
- shortFound := false;
- signedFound := false;
- unsignedFound := false;
- longCount := 0;
-
- for true {
- token := peek_token(data);
-
- // Attribute
- attributeFound := true;
- if token == "long" do longCount += 1;
- else if token == "short" do shortFound = true;
- else if token == "unsigned" do unsignedFound = true;
- else if token == "signed" do signedFound = true;
- else do attributeFound = false;
- if attributeFound { eat_token(data); continue; }
-
- // Known type alias
- if token in knownTypeAliases {
- builtinType, ok := knownTypeAliases[token].base.(BuiltinType);
- if ok {
- eat_token(data);
- previousBuiltinType = builtinType;
- }
- break;
- }
-
- // Classic type and standard types
- if token == "void" { eat_token(data); return BuiltinType.Void; }
- else if token == "int" {
- eat_token(data);
- intFound = true;
- }
- else if token == "float" { eat_token(data); return BuiltinType.Float; }
- else if token == "double" {
- eat_token(data);
- if longCount == 0 do return BuiltinType.Double;
- else do return BuiltinType.LongDouble;
- }
- else if token == "char" {
- eat_token(data);
- if signedFound do return BuiltinType.SChar;
- else if unsignedFound do return BuiltinType.UChar;
- else do return BuiltinType.Char;
- }
- else if token == "__int8" {
- // @note :MicrosoftDumminess __intX are Microsoft's fixed-size integers
- // https://docs.microsoft.com/fr-fr/cpp/cpp/int8-int16-int32-int64
- // and for unsigned version, they prefixed it with "unsigned"...
- eat_token(data);
- if unsignedFound do return BuiltinType.UInt8;
- else do return BuiltinType.Int8;
- }
- else if token == "__int16" {
- eat_token(data);
- if unsignedFound do return BuiltinType.UInt16;
- else do return BuiltinType.Int16;
- }
- else if token == "__int32" {
- eat_token(data);
- if unsignedFound do return BuiltinType.UInt32;
- else do return BuiltinType.Int32;
- }
- else if token == "__int64" {
- eat_token(data);
- if unsignedFound do return BuiltinType.UInt64;
- else do return BuiltinType.Int64;
- }
- else if token == "int8_t" { eat_token(data); return BuiltinType.Int8; }
- else if token == "int16_t" { eat_token(data); return BuiltinType.Int16; }
- else if token == "int32_t" { eat_token(data); return BuiltinType.Int32; }
- else if token == "int64_t" { eat_token(data); return BuiltinType.Int64; }
- else if token == "uint8_t" { eat_token(data); return BuiltinType.UInt8; }
- else if token == "uint16_t" { eat_token(data); return BuiltinType.UInt16; }
- else if token == "uint32_t" { eat_token(data); return BuiltinType.UInt32; }
- else if token == "uint64_t" { eat_token(data); return BuiltinType.UInt64; }
- else if token == "size_t" { eat_token(data); return BuiltinType.Size; }
- else if token == "ssize_t" { eat_token(data); return BuiltinType.SSize; }
- else if token == "ptrdiff_t" { eat_token(data); return BuiltinType.PtrDiff; }
- else if token == "uintptr_t" { eat_token(data); return BuiltinType.UIntPtr; }
- else if token == "intptr_t" { eat_token(data); return BuiltinType.IntPtr; }
-
- break;
- }
-
- // Adapt previous builtin type
- if previousBuiltinType == BuiltinType.ShortInt {
- shortFound = true;
- }
- else if previousBuiltinType == BuiltinType.Int {
- intFound = true;
- }
- else if previousBuiltinType == BuiltinType.LongInt {
- longCount += 1;
- }
- else if previousBuiltinType == BuiltinType.LongLongInt {
- longCount += 2;
- }
- else if previousBuiltinType == BuiltinType.UShortInt {
- unsignedFound = true;
- shortFound = true;
- }
- else if previousBuiltinType == BuiltinType.UInt {
- unsignedFound = true;
- }
- else if previousBuiltinType == BuiltinType.ULongInt {
- unsignedFound = true;
- longCount += 1;
- }
- else if previousBuiltinType == BuiltinType.ULongLongInt {
- unsignedFound = true;
- longCount += 2;
- }
- else if (previousBuiltinType != BuiltinType.Unknown) {
- return previousBuiltinType; // float, void, etc.
- }
-
- // Implicit and explicit int
- if intFound || shortFound || unsignedFound || signedFound || longCount > 0 {
- if unsignedFound {
- if shortFound do return BuiltinType.UShortInt;
- if longCount == 0 do return BuiltinType.UInt;
- if longCount == 1 do return BuiltinType.ULongInt;
- if longCount == 2 do return BuiltinType.ULongLongInt;
- } else {
- if shortFound do return BuiltinType.ShortInt;
- if longCount == 0 do return BuiltinType.Int;
- if longCount == 1 do return BuiltinType.LongInt;
- if longCount == 2 do return BuiltinType.LongLongInt;
- }
- }
-
- return BuiltinType.Unknown;
-}
-
-parse_struct_type :: proc(data : ^ParserData, definitionPermitted : bool) -> IdentifierType {
- check_and_eat_token(data, "struct");
-
- type : IdentifierType;
- token := peek_token(data);
-
- if !definitionPermitted || token != "{" {
- type.name = parse_identifier(data);
- token = peek_token(data);
- } else {
- type.name = tcat("AnonymousStruct", anonymousStructCount);
- type.anonymous = true;
- anonymousStructCount += 1;
- }
-
- if token == "{" {
- node := parse_struct_definition(data);
- node.name = type.name;
- } else if definitionPermitted {
- // @note Whatever happens, we create a definition of the struct,
- // as it might be used to forward declare it and then use it only with a pointer.
- // This for instance the pattern for xcb_connection_t which definition
- // is never known from user API.
- node : StructDefinitionNode;
- node.forwardDeclared = false;
- node.name = type.name;
- append(&data.nodes.structDefinitions, node);
- }
-
- return type;
-}
-
-parse_union_type :: proc(data : ^ParserData) -> IdentifierType {
- check_and_eat_token(data, "union");
-
- type : IdentifierType;
- token := peek_token(data);
-
- if token != "{" {
- type.name = parse_identifier(data);
- token = peek_token(data);
- } else {
- type.name = tcat("AnonymousUnion", anonymousUnionCount);
- type.anonymous = true;
- anonymousUnionCount += 1;
- }
-
- if token == "{" {
- node := parse_union_definition(data);
- node.name = type.name;
- }
-
- return type;
-}
-
-parse_enum_type :: proc(data : ^ParserData) -> IdentifierType {
- check_and_eat_token(data, "enum");
-
- type : IdentifierType;
- token := peek_token(data);
-
- if token != "{" {
- type.name = parse_identifier(data);
- token = peek_token(data);
- } else {
- type.name = tcat("AnonymousEnum", anonymousEnumCount);
- type.anonymous = true;
- anonymousEnumCount += 1;
- }
-
- if token == "{" {
- node := parse_enum_definition(data);
- node.name = type.name;
- }
-
- return type;
-}
-
-/**
- * We only care about defines of some value
- */
-parse_directive :: proc(data : ^ParserData) {
- check_and_eat_token(data, "#");
-
- token := peek_token(data);
- if token == "define" {
- parse_define(data);
- } // We ignore all other directives
- else {
- eat_line(data);
- }
-}
-
-parse_define :: proc(data : ^ParserData) {
- check_and_eat_token(data, "define");
- data.foundFullReturn = false;
-
- node : DefineNode;
- node.name = parse_identifier(data);
-
- // Does it look like end? It might be a #define with no expression
- if is_define_end(data) {
- node.value = 1;
- append(&data.nodes.defines, node);
- data.knownedLiterals[node.name] = node.value;
- } // Macros are ignored
- else if is_define_macro(data) {
- print_warning("Ignoring define macro for ", node.name, ".");
- }
- else {
- literalValue, ok := evaluate(data);
- if ok {
- node.value = literalValue;
- append(&data.nodes.defines, node);
- data.knownedLiterals[node.name] = node.value;
- }
- else {
- print_warning("Ignoring define expression for ", node.name, ".");
- }
- }
-
- // Evaluating the expression, we might have already eaten a full return,
- // if so, do nothing.
- if !data.foundFullReturn {
- eat_define_lines(data);
- }
-}
-
-// @fixme Move
-change_anonymous_node_name :: proc (data : ^ParserData, oldName : string, newName : string) -> bool {
- for i := 0; i < len(data.nodes.structDefinitions); i += 1 {
- if data.nodes.structDefinitions[i].name == oldName {
- data.nodes.structDefinitions[i].name = newName;
- return true;
- }
- }
-
- for i := 0; i < len(data.nodes.enumDefinitions); i += 1 {
- if data.nodes.enumDefinitions[i].name == oldName {
- data.nodes.enumDefinitions[i].name = newName;
- return true;
- }
- }
-
- for i := 0; i < len(data.nodes.unionDefinitions); i += 1 {
- if data.nodes.unionDefinitions[i].name == oldName {
- data.nodes.unionDefinitions[i].name = newName;
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Type aliasing.
- * typedef <sourceType> <name>;
- */
-parse_typedef :: proc(data : ^ParserData) {
- check_and_eat_token(data, "typedef");
-
- // @note Struct-like definitions (and such)
- // are generated within type parsing.
- //
- // So that typedef struct { int foo; }* Ap; is valid.
-
- // Parsing type
- node : TypedefNode;
- node.type = parse_type(data, true);
-
- if sourceType, ok := node.type.base.(FunctionPointerType); ok {
- node.name = sourceType.name;
- } else {
- node.name = parse_identifier(data);
- }
-
- // Checking if function type
- token := peek_token(data);
- if token == "(" {
- functionType : FunctionType;
- functionType.returnType = new(Type);
- functionType.returnType^ = node.type;
-
- parse_function_parameters(data, &functionType.parameters);
-
- node.type.base = functionType;
- }
-
- // Checking if array
- parse_type_dimensions(data, &node.type);
-
- // If the underlying type is anonymous,
- // we just affect it the name.
- addTypedefNode := true;
- if identifierType, ok := node.type.base.(IdentifierType); ok {
- if identifierType.anonymous {
- addTypedefNode = !change_anonymous_node_name(data, identifierType.name, node.name);
- }
- }
-
- if addTypedefNode {
- knownTypeAliases[node.name] = node.type;
- append(&data.nodes.typedefs, node);
- }
-
- check_and_eat_token(data, ";");
-
- // @note Commented tool for debug
- // fmt.println("Typedef: ", node.type, node.name);
-}
-
-parse_struct_definition :: proc(data : ^ParserData) -> ^StructDefinitionNode {
- node : StructDefinitionNode;
- node.forwardDeclared = false;
- parse_struct_or_union_members(data, &node.members);
-
- append(&data.nodes.structDefinitions, node);
- return &data.nodes.structDefinitions[len(data.nodes.structDefinitions) - 1];
-}
-
-parse_union_definition :: proc(data : ^ParserData) -> ^UnionDefinitionNode {
- node : UnionDefinitionNode;
- parse_struct_or_union_members(data, &node.members);
-
- append(&data.nodes.unionDefinitions, node);
- return &data.nodes.unionDefinitions[len(data.nodes.unionDefinitions) - 1];
-}
-
-parse_enum_definition :: proc(data : ^ParserData) -> ^EnumDefinitionNode {
- node : EnumDefinitionNode;
- parse_enum_members(data, &node.members);
-
- append(&data.nodes.enumDefinitions, node);
- return &data.nodes.enumDefinitions[len(data.nodes.enumDefinitions) - 1];
-}
-
-/**
- * {
- * <name> = <value>,
- * <name>,
- * }
- */
-parse_enum_members :: proc(data : ^ParserData, members : ^[dynamic]EnumMember) {
- check_and_eat_token(data, "{");
-
- nextMemberValue : i64 = 0;
- token := peek_token(data);
- for token != "}" {
- member : EnumMember;
- member.name = parse_identifier(data);
- member.hasValue = false;
-
- token = peek_token(data);
- if token == "=" {
- check_and_eat_token(data, "=");
-
- member.hasValue = true;
- member.value = evaluate_i64(data);
- nextMemberValue = member.value;
- token = peek_token(data);
- } else {
- member.value = nextMemberValue;
- }
-
- data.knownedLiterals[member.name] = member.value;
- nextMemberValue += 1;
-
- // Eat until end, as this might be a complex expression that we couldn't understand
- if token != "," && token != "}" {
- print_warning("Parser cannot understand fully the expression of enum member ", member.name, ".");
- for token != "," && token != "}" {
- eat_token(data);
- token = peek_token(data);
- }
- }
- if token == "," {
- check_and_eat_token(data, ",");
- token = peek_token(data);
- }
-
- append(members, member);
- }
-
- check_and_eat_token(data, "}");
-}
-
-/**
- * {
- * <type> <name>;
- * <type> <name1>, <name2>;
- * <type> <name>[<dimension>];
- * }
- */
-parse_struct_or_union_members :: proc(data : ^ParserData, structOrUnionMembers : ^[dynamic]StructOrUnionMember) {
- check_and_eat_token(data, "{");
-
- // To ensure unique id
- unamedCount := 0;
-
- token := peek_token(data);
- for token != "}" {
- member : StructOrUnionMember;
- member.type = parse_type(data, true);
-
- for true {
- // In the case of function pointer types, the name has been parsed
- // during type inspection.
- if type, ok := member.type.base.(FunctionPointerType); ok {
- member.name = type.name;
- }
- else {
- // Unamed (struct or union)
- token = peek_token(data);
- if !is_identifier(token) {
- member.name = tcat("unamed", unamedCount);
- unamedCount += 1;
- }
- else {
- member.name = parse_identifier(data);
- }
- }
-
- parse_type_dimensions(data, &member.type);
-
- token = peek_token(data);
- if token == ":" {
- check_and_eat_token(data, ":");
- print_warning("Found bitfield in struct, which is not handled correctly.");
- evaluate_i64(data);
- token = peek_token(data);
- }
-
- append(structOrUnionMembers, member);
-
- // Multiple declarations on one line
- if token == "," {
- check_and_eat_token(data, ",");
- continue;
- }
-
- break;
- }
-
- check_and_eat_token(data, ";");
- token = peek_token(data);
- }
-
- check_and_eat_token(data, "}");
-}
-
-parse_variable_or_function_declaration :: proc(data : ^ParserData) {
- type := parse_type(data, true);
-
- // If it's just a type, it might be a struct definition
- token := peek_token(data);
- if token == ";" {
- check_and_eat_token(data, ";");
- return;
- }
-
- // Eat array declaration if any
- // @fixme The return type of a function declaration will be wrong!
- for data.bytes[data.offset] == '[' {
- for data.bytes[data.offset] != ']' {
- data.offset += 1;
- }
- data.offset += 1;
- }
-
- name := parse_identifier(data);
-
- token = peek_token(data);
- if token == "(" {
- functionDeclarationNode := parse_function_declaration(data);
- functionDeclarationNode.returnType = type;
- functionDeclarationNode.name = name;
- return;
- } else if token == "[" {
- // Eat whole array declaration
- for data.bytes[data.offset] == '[' {
- for data.bytes[data.offset] != ']' {
- data.offset += 1;
- }
- data.offset += 1;
- }
- }
-
- // Global variable declaration (with possible multiple declarations)
- token = peek_token(data);
-
- for true {
- if token == "," {
- print_warning("Found global variable declaration '", name, "', we won't generated any binding for it.");
- check_and_eat_token(data, ",");
-
- name = parse_identifier(data);
- token = peek_token(data);
- continue;
- }
- else if token == ";" {
- if name != "" {
- print_warning("Found global variable declaration '", name, "', we won't generated any binding for it.");
- }
- check_and_eat_token(data, ";");
- break;
- }
-
- // Global variable assignment, considered as constant define.
- node : DefineNode;
-
- check_and_eat_token(data, "=");
- literalValue, ok := evaluate(data);
- if ok {
- node.name = name;
- node.value = literalValue;
- append(&data.nodes.defines, node);
- }
- else {
- print_warning("Ignoring global variable expression for '", name, "'.");
- }
-
- name = "";
- token = peek_token(data);
- }
-}
-
-parse_function_declaration :: proc(data : ^ParserData) -> ^FunctionDeclarationNode {
- node : FunctionDeclarationNode;
-
- parse_function_parameters(data, &node.parameters);
-
- // Function definition? Ignore it.
- token := peek_token(data);
- if token == "{" {
- bracesCount := 1;
- for true {
- data.offset += 1;
- if data.bytes[data.offset] == '{' do bracesCount += 1;
- else if data.bytes[data.offset] == '}' do bracesCount -= 1;
- if bracesCount == 0 do break;
- }
- data.offset += 1;
- } // Function declaration
- else {
- check_and_eat_token(data, ";");
- }
-
- append(&data.nodes.functionDeclarations, node);
- return &data.nodes.functionDeclarations[len(data.nodes.functionDeclarations) - 1];
-}
-
-parse_function_parameters :: proc(data : ^ParserData, parameters : ^[dynamic]FunctionParameter) {
- check_and_eat_token(data, "(");
-
- token := peek_token(data);
- for token != ")" {
- parameter : FunctionParameter;
-
- token = peek_token(data);
- if token == "." {
- print_warning("A function accepts variadic arguments, this is currently not handled within generated code.");
-
- check_and_eat_token(data, ".");
- check_and_eat_token(data, ".");
- check_and_eat_token(data, ".");
- break;
- } else {
- parameter.type = parse_type(data);
- }
-
- // Check if named parameter
- token = peek_token(data);
- if token != ")" && token != "," {
- parameter.name = parse_identifier(data);
- parse_type_dimensions(data, &parameter.type);
- token = peek_token(data);
- }
-
- if token == "," {
- eat_token(data);
- token = peek_token(data);
- }
-
- append(parameters, parameter);
- }
-
- check_and_eat_token(data, ")");
-}
diff --git a/core/bindgen/errors.odin b/core/bindgen/errors.odin
deleted file mode 100644
index 9564c5244..000000000
--- a/core/bindgen/errors.odin
+++ /dev/null
@@ -1,44 +0,0 @@
-package bindgen
-
-import "core:fmt"
-import "core:os"
-
-seenWarnings : map[string]bool;
-
-print_warning :: proc(args : ..any) {
- message := tcat(..args);
-
- if !seenWarnings[message] {
- fmt.eprint("[bindgen] Warning: ", message, "\n");
- seenWarnings[message] = true;
- }
-}
-
-print_error :: proc(data : ^ParserData, loc := #caller_location, args : ..any) {
- message := tcat(..args);
-
- min : u32 = 0;
- for i := data.offset - 1; i > 0; i -= 1 {
- if data.bytes[i] == '\n' {
- min = i + 1;
- break;
- }
- }
-
- max := min + 200;
- for i := min + 1; i < max; i += 1 {
- if data.bytes[i] == '\n' {
- max = i;
- break;
- }
- }
-
- line, _ := get_line_column(data);
-
- fmt.eprint("[bindgen] Error: ", message, "\n");
- fmt.eprint("[bindgen] ... from ", loc.procedure, "\n");
- fmt.eprint("[bindgen] ... at line ", line, " within this context:\n");
- fmt.eprint("> ", extract_string(data, min, max), "\n");
-
- os.exit(1);
-}
diff --git a/core/bindgen/generator-clean.odin b/core/bindgen/generator-clean.odin
deleted file mode 100644
index 8dd837b10..000000000
--- a/core/bindgen/generator-clean.odin
+++ /dev/null
@@ -1,284 +0,0 @@
-package bindgen
-
-import "core:fmt"
-
-// Prevent keywords clashes and other tricky cases
-clean_identifier :: proc(name : string) -> string {
- name := name;
-
- if name == "" {
- return name;
- }
-
- // Starting with _? Try removing that.
- for true {
- if name[0] == '_' {
- name = name[1:];
- }
- else {
- break;
- }
- }
-
- // Number
- if name[0] >= '0' && name[0] <= '9' {
- return tcat("_", name);
- } // Keywords clash
- else if name == "map" || name == "proc" || name == "opaque" || name == "in" {
- return tcat("_", name);
- } // Jai keywords clash
- else if name == "context" ||
- name == "float32" || name == "float64" ||
- name == "s8" || name == "s16" || name == "s32" || name == "s64" ||
- name == "u8" || name == "u16" || name == "u32" || name == "u64" {
- return tcat("_", name);
- }
-
- return name;
-}
-
-clean_variable_name :: proc(name : string, options : ^GeneratorOptions) -> string {
- name := name;
- name = change_case(name, options.variableCase);
- return clean_identifier(name);
-}
-
-clean_pseudo_type_name :: proc(structName : string, options : ^GeneratorOptions) -> string {
- structName := structName;
- structName = remove_postfixes(structName, options.pseudoTypePostfixes, options.pseudoTypeTransparentPostfixes);
- structName = remove_prefixes(structName, options.pseudoTypePrefixes, options.pseudoTypeTransparentPrefixes);
- structName = change_case(structName, options.pseudoTypeCase);
- return structName;
-}
-
-// Clean up the enum name so that it can be used to remove the prefix from enum values.
-clean_enum_name_for_prefix_removal :: proc(enumName : string, options : ^GeneratorOptions) -> (string, [dynamic]string) {
- enumName := enumName;
-
- if !options.enumValueNameRemove {
- return enumName, nil;
- }
-
- // Remove postfix and use same case convention as the enum values
- removedPostfixes : [dynamic]string;
- enumName, removedPostfixes = remove_postfixes_with_removed(enumName, options.enumValueNameRemovePostfixes);
- enumName = change_case(enumName, options.enumValueCase);
- return enumName, removedPostfixes;
-}
-
-clean_enum_value_name :: proc(valueName : string, enumName : string, postfixes : []string, options : ^GeneratorOptions) -> string {
- valueName := valueName;
-
- valueName = remove_prefixes(valueName, options.enumValuePrefixes, options.enumValueTransparentPrefixes);
- valueName = remove_postfixes(valueName, postfixes, options.enumValueTransparentPostfixes);
-
- if options.enumValueNameRemove {
- valueName = remove_prefixes(valueName, []string{enumName});
- }
-
- valueName = change_case(valueName, options.enumValueCase);
-
- return clean_identifier(valueName);
-}
-
-clean_function_name :: proc(functionName : string, options : ^GeneratorOptions) -> string {
- functionName := functionName;
- functionName = remove_prefixes(functionName, options.functionPrefixes, options.functionTransparentPrefixes);
- functionName = remove_postfixes(functionName, options.definePostfixes, options.defineTransparentPostfixes);
- functionName = change_case(functionName, options.functionCase);
- return functionName;
-}
-
-clean_define_name :: proc(defineName : string, options : ^GeneratorOptions) -> string {
- defineName := defineName;
- defineName = remove_prefixes(defineName, options.definePrefixes, options.defineTransparentPrefixes);
- defineName = remove_postfixes(defineName, options.definePostfixes, options.defineTransparentPostfixes);
- defineName = change_case(defineName, options.defineCase);
- return defineName;
-}
-
-// Convert to Odin's types
-clean_type :: proc(data : ^GeneratorData, type : Type, baseTab : string = "", explicitSharpType := true) -> string {
- output := "";
-
- for dimension in type.dimensions {
- output = tcat(output, "[", dimension, "]");
- }
- output = tcat(output, clean_base_type(data, type.base, baseTab, explicitSharpType));
-
- return output;
-}
-
-clean_base_type :: proc(data : ^GeneratorData, baseType : BaseType, baseTab : string = "", explicitSharpType := true) -> string {
- options := data.options;
-
- if _type, ok := baseType.(BuiltinType); ok {
- if _type == BuiltinType.Void do return options.mode == "jai" ? "void" : "";
- else if _type == BuiltinType.Int do return options.mode == "jai" ? "s64" : "_c.int";
- else if _type == BuiltinType.UInt do return options.mode == "jai" ? "u64" :"_c.uint";
- else if _type == BuiltinType.LongInt do return options.mode == "jai" ? "s64" :"_c.long";
- else if _type == BuiltinType.ULongInt do return options.mode == "jai" ? "u64" :"_c.ulong";
- else if _type == BuiltinType.LongLongInt do return options.mode == "jai" ? "s64" :"_c.longlong";
- else if _type == BuiltinType.ULongLongInt do return options.mode == "jai" ? "u64" :"_c.ulonglong";
- else if _type == BuiltinType.ShortInt do return options.mode == "jai" ? "s16" :"_c.short";
- else if _type == BuiltinType.UShortInt do return options.mode == "jai" ? "u16" :"_c.ushort";
- else if _type == BuiltinType.Char do return options.mode == "jai" ? "u8" :"_c.char";
- else if _type == BuiltinType.SChar do return options.mode == "jai" ? "s8" :"_c.schar";
- else if _type == BuiltinType.UChar do return options.mode == "jai" ? "u8" :"_c.uchar";
- else if _type == BuiltinType.Float do return options.mode == "jai" ? "float32" :"_c.float";
- else if _type == BuiltinType.Double do return options.mode == "jai" ? "float64" :"_c.double";
- else if _type == BuiltinType.LongDouble {
- print_warning("Found long double which is currently not supported. Fallback to double in generated code.");
- return options.mode == "jai" ? "double" :"_c.double";
- }
- else if _type == BuiltinType.Int8 do return options.mode == "jai" ? "s8" :"i8";
- else if _type == BuiltinType.Int16 do return options.mode == "jai" ? "s16" :"i16";
- else if _type == BuiltinType.Int32 do return options.mode == "jai" ? "s32" :"i32";
- else if _type == BuiltinType.Int64 do return options.mode == "jai" ? "s64" :"i64";
- else if _type == BuiltinType.UInt8 do return options.mode == "jai" ? "u8" :"u8";
- else if _type == BuiltinType.UInt16 do return options.mode == "jai" ? "u16" :"u16";
- else if _type == BuiltinType.UInt32 do return options.mode == "jai" ? "u32" :"u32";
- else if _type == BuiltinType.UInt64 do return options.mode == "jai" ? "u64" :"u64";
- else if _type == BuiltinType.Size do return options.mode == "jai" ? "u64" :"_c.size_t";
- else if _type == BuiltinType.SSize do return options.mode == "jai" ? "u64" :"_c.ssize_t";
- else if _type == BuiltinType.PtrDiff do return options.mode == "jai" ? "s64" :"_c.ptrdiff_t";
- else if _type == BuiltinType.UIntPtr do return options.mode == "jai" ? "u64" :"_c.uintptr_t";
- else if _type == BuiltinType.IntPtr do return options.mode == "jai" ? "s64" :"_c.intptr_t";
- }
- else if _type, ok := baseType.(PointerType); ok {
- if options.mode == "jai" {
- // Hide pointers to types that were not declared.
- if !is_known_base_type(data, _type.type.base) {
- print_warning("*", _type.type.base.(IdentifierType).name, " replaced by *void as the pointed type is unknown.");
- return "*void";
- }
- } else {
- if __type, ok := _type.type.base.(BuiltinType); ok {
- if __type == BuiltinType.Void do return "rawptr";
- else if __type == BuiltinType.Char do return "cstring";
- }
- }
- name := clean_type(data, _type.type^, baseTab);
- return tcat(options.mode == "jai" ? "*" :"^", name);
- }
- else if _type, ok := baseType.(IdentifierType); ok {
- return clean_pseudo_type_name(_type.name, options);
- }
- else if _type, ok := baseType.(FunctionType); ok {
- output : string;
- if explicitSharpType {
- output = "#type ";
- }
- output = tcat(output, options.mode == "jai" ? "(" :"proc(");
- parameters := clean_function_parameters(data, _type.parameters, baseTab);
- output = tcat(output, parameters, ")");
-
- returnType := clean_type(data, _type.returnType^);
- if len(returnType) > 0 && returnType != "void" {
- output = tcat(output, " -> ", returnType);
- }
- return output;
- }
- else if _type, ok := baseType.(FunctionPointerType); ok {
- output : string;
- if explicitSharpType {
- output = "#type ";
- }
- output = tcat(output, options.mode == "jai" ? "(" :"proc(");
- parameters := clean_function_parameters(data, _type.parameters, baseTab);
- output = tcat(output, parameters, ")");
-
- returnType := clean_type(data, _type.returnType^);
- if len(returnType) > 0 && returnType != "void" {
- output = tcat(output, " -> ", returnType);
- }
-
- if options.mode == "jai" {
- output = tcat(output, " #foreign");
- }
- return output;
- }
-
- return "<niy>";
-}
-
-clean_function_parameters :: proc(data : ^GeneratorData, parameters : [dynamic]FunctionParameter, baseTab : string) -> string {
- output := "";
- options := data.options;
-
- // Special case: function(void) does not really have a parameter
- if len(parameters) == 1 {
- if _type, ok := parameters[0].type.base.(BuiltinType); ok {
- if _type == BuiltinType.Void {
- return "";
- }
- }
- }
-
- tab := "";
- if options.mode == "jai" { // @note :OdinCodingStyle Odin forces a coding style, now. Ugh.
- if (len(parameters) > 1) {
- output = tcat(output, "\n");
- tab = tcat(baseTab, " ");
- }
- }
-
- unamedParametersCount := 0;
- for parameter, i in parameters {
- type := clean_type(data, parameter.type);
-
- name : string;
- if len(parameter.name) != 0 {
- name = clean_variable_name(parameter.name, options);
- } else {
- name = tcat("unamed", unamedParametersCount);
- unamedParametersCount += 1;
- }
-
- output = tcat(output, tab, name, " : ", type);
-
- if i != len(parameters) - 1 {
- if options.mode == "jai" { // @note :OdinCodingStyle
- output = tcat(output, ",\n");
- } else {
- output = tcat(output, ", ");
- }
- }
- }
-
- if (len(parameters) > 1) {
- if options.mode == "jai" { // @note :OdinCodingStyle
- output = tcat(output, "\n", baseTab);
- }
- }
-
- return output;
-}
-
-is_known_base_type :: proc(data : ^GeneratorData, baseType : BaseType) -> bool {
- if _type, ok := baseType.(IdentifierType); ok {
- for it in data.nodes.typedefs {
- if _type.name == it.name {
- return true;
- }
- }
- for it in data.nodes.structDefinitions {
- if _type.name == it.name {
- return true;
- }
- }
- for it in data.nodes.enumDefinitions {
- if _type.name == it.name {
- return true;
- }
- }
- for it in data.nodes.unionDefinitions {
- if _type.name == it.name {
- return true;
- }
- }
- return false;
- }
-
- return true;
-}
diff --git a/core/bindgen/generator-export.odin b/core/bindgen/generator-export.odin
deleted file mode 100644
index a04113ed9..000000000
--- a/core/bindgen/generator-export.odin
+++ /dev/null
@@ -1,166 +0,0 @@
-package bindgen
-
-import "core:os"
-import "core:fmt"
-
-export_defines :: proc(data : ^GeneratorData) {
- for node in data.nodes.defines {
- defineName := clean_define_name(node.name, data.options);
-
- // @fixme fprint of float numbers are pretty badly handled,
- // just has a 10^-3 precision.
- fcat(data.handle, defineName, " :: ", node.value, ";\n");
- }
- fcat(data.handle, "\n");
-}
-
-export_typedefs :: proc(data : ^GeneratorData) {
- for node in data.nodes.typedefs {
- name := clean_pseudo_type_name(node.name, data.options);
- type := clean_type(data, node.type, "", true);
- if name == type do continue;
- fcat(data.handle, name, " :: ", type, ";\n");
- }
- fcat(data.handle, "\n");
-}
-
-export_enums :: proc(data : ^GeneratorData) {
- for node in data.nodes.enumDefinitions {
- enumName := clean_pseudo_type_name(node.name, data.options);
-
- if data.options.mode == "jai" {
- consideredFlags := false;
- for postfix in data.options.enumConsideredFlagsPostfixes {
- if ends_with(node.name, postfix) {
- consideredFlags = true;
- break;
- }
- }
-
- if consideredFlags {
- fcat(data.handle, enumName, " :: enum_flags u32 {");
- } else {
- fcat(data.handle, enumName, " :: enum s32 {");
- }
- } else {
- fcat(data.handle, enumName, " :: enum i32 {");
- }
-
- postfixes : [dynamic]string;
- enumName, postfixes = clean_enum_name_for_prefix_removal(enumName, data.options);
-
- // Changing the case of postfixes to the enum value one,
- // so that they can be removed.
- enumValueCase := find_case(node.members[0].name);
- for postfix, i in postfixes {
- postfixes[i] = change_case(postfix, enumValueCase);
- }
-
- // And changing the case of enumName to the enum value one
- enumName = change_case(enumName, enumValueCase);
-
- // Merging enum value postfixes with postfixes that have been removed from the enum name.
- for postfix in data.options.enumValuePostfixes {
- append(&postfixes, postfix);
- }
-
- export_enum_members(data, node.members, enumName, postfixes[:]);
- fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n");
- fcat(data.handle, "\n");
- }
-}
-
-export_structs :: proc(data : ^GeneratorData) {
- for node in data.nodes.structDefinitions {
- structName := clean_pseudo_type_name(node.name, data.options);
- fcat(data.handle, structName, " :: struct {");
- export_struct_or_union_members(data, node.members);
- fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n");
- fcat(data.handle, "\n");
- }
-}
-
-export_unions :: proc(data : ^GeneratorData) {
- for node in data.nodes.unionDefinitions {
- unionName := clean_pseudo_type_name(node.name, data.options);
- fcat(data.handle, unionName, data.options.mode == "jai" ? " :: union {" : " :: struct #raw_union {");
- export_struct_or_union_members(data, node.members);
- fcat(data.handle, data.options.mode == "jai" ? "}\n" : "};\n");
- fcat(data.handle, "\n");
- }
-}
-
-export_functions :: proc(data : ^GeneratorData) {
- for node in data.nodes.functionDeclarations {
- functionName := clean_function_name(node.name, data.options);
- if data.options.mode == "jai" {
- fcat(data.handle, functionName, " :: (");
- } else {
- fcat(data.handle, " @(link_name=\"", node.name, "\")\n");
- fcat(data.handle, " ", functionName, " :: proc(");
- }
- parameters := clean_function_parameters(data, node.parameters, data.options.mode == "jai" ? "" : " ");
- fcat(data.handle, parameters, ")");
- returnType := clean_type(data, node.returnType);
- if len(returnType) > 0 {
- fcat(data.handle, " -> ", returnType);
- }
- if data.options.mode == "jai" {
- fcat(data.handle, " #foreign ", data.foreignLibrary, " \"", node.name ,"\";\n");
- } else {
- fcat(data.handle, " ---;\n");
- }
- fcat(data.handle, "\n");
- }
-}
-
-export_enum_members :: proc(data : ^GeneratorData, members : [dynamic]EnumMember, enumName : string, postfixes : []string) {
- if (len(members) > 0) {
- fcat(data.handle, "\n");
- }
-
- cleanedMembers : [dynamic]EnumMember;
- for member in members {
- cleanedMember : EnumMember;
- cleanedMember.hasValue = member.hasValue;
- cleanedMember.value = member.value;
- cleanedMember.name = clean_enum_value_name(member.name, enumName, postfixes, data.options);
-
- if len(cleanedMember.name) == 0 {
- // print_warning("Enum member ", member.name, " resolves to an empty name. Ignoring it.");
- continue;
- }
-
- // Ensuring that we don't collide with an other enum member.
- foundCopy := false;
- for existingCleanedMember in cleanedMembers {
- if cleanedMember.name == existingCleanedMember.name &&
- cleanedMember.hasValue == existingCleanedMember.hasValue &&
- cleanedMember.value == existingCleanedMember.value {
- print_warning("Enum member ", member.name, " is duplicated once cleaned. Keeping only one copy.");
- foundCopy = true;
- break;
- }
- }
- if foundCopy do continue;
-
- fcat(data.handle, " ", cleanedMember.name);
- if member.hasValue {
- fcat(data.handle, data.options.mode == "jai" ? " :: " : " = ", member.value);
- }
- fcat(data.handle, data.options.mode == "jai" ? ";\n" : ",\n");
-
- append(&cleanedMembers, cleanedMember);
- }
-}
-
-export_struct_or_union_members :: proc(data : ^GeneratorData, members : [dynamic]StructOrUnionMember) {
- if (len(members) > 0) {
- fcat(data.handle, "\n");
- }
- for member in members {
- type := clean_type(data, member.type, " ");
- name := clean_variable_name(member.name, data.options);
- fcat(data.handle, " ", name, " : ", type, data.options.mode == "jai" ? ";\n" : ",\n");
- }
-}
diff --git a/core/bindgen/generator-helpers.odin b/core/bindgen/generator-helpers.odin
deleted file mode 100644
index a3b37f4f6..000000000
--- a/core/bindgen/generator-helpers.odin
+++ /dev/null
@@ -1,392 +0,0 @@
-package bindgen
-
-import "core:fmt"
-import "core:os"
-import "core:io"
-import "core:strings"
-import "core:unicode/utf8"
-
-Case :: enum {
- Unknown,
- Camel,
- Constant,
- Kebab,
- Pascal,
- Snake,
-}
-
-WordCase :: enum {
- Unknown,
- Up,
- Low,
- FirstUp,
- // When first upping, numbers are followed always by a capital
- FirstUpNumberReset,
-}
-
-// Change a character to a capital.
-to_uppercase :: proc(c : rune) -> rune {
- c := c;
- if c >= 'a' && c <= 'z' {
- c = c - 'a' + 'A';
- }
- return c;
-}
-
-// Change a character to lowercase.
-to_lowercase :: proc(c : rune) -> rune {
- c := c;
- if c >= 'A' && c <= 'Z' {
- c = c - 'A' + 'a';
- }
- return c;
-}
-
-// @note Stolen tprint and fprint from fmt package, because it was confusing due to args: ..any and sep default parameter.
-tcat :: proc(args: ..any) -> string {
- return fmt.tprint(args=args, sep="");
-}
-
-fcat :: proc(fd: os.Handle, args: ..any) -> int {
- return fmt.fprint(fd=fd, args=args, sep="");
-}
-
-// Change the case convention of a word.
-change_word_case :: proc(str : string, targetCase : WordCase) -> string {
- newStr : string;
- if targetCase == WordCase.Up {
- for c in str {
- newStr = tcat(newStr, to_uppercase(c));
- }
- }
- else if targetCase == WordCase.Low {
- for c in str {
- newStr = tcat(newStr, to_lowercase(c));
- }
- }
- else if targetCase == WordCase.FirstUp {
- for c, i in str {
- if i == 0 {
- newStr = tcat(newStr, to_uppercase(c));
- } else {
- newStr = tcat(newStr, to_lowercase(c));
- }
- }
- }
- else if targetCase == WordCase.FirstUpNumberReset {
- for c, i in str {
- if i == 0 || (str[i - 1] >= '0' && str[i - 1] <= '9') {
- newStr = tcat(newStr, to_uppercase(c));
- } else {
- newStr = tcat(newStr, to_lowercase(c));
- }
- }
- }
- return newStr;
-}
-
-// Change the case convention of a string by detecting original convention,
-// then splitting it into words.
-change_case :: proc(str : string, targetCase : Case) -> string {
- if targetCase == Case.Unknown {
- return str;
- }
-
- // Split
- parts := autosplit_string(str);
-
- // Join
- newStr : string;
- if targetCase == Case.Pascal {
- for part, i in parts {
- newStr = tcat(newStr, change_word_case(part, WordCase.FirstUpNumberReset));
- }
- }
- else if targetCase == Case.Snake {
- for part, i in parts {
- newStr = tcat(newStr, change_word_case(part, WordCase.Low), (i != len(parts) - 1) ? "_" : "");
- }
- }
- else if targetCase == Case.Kebab {
- for part, i in parts {
- newStr = tcat(newStr, change_word_case(part, WordCase.Low), (i != len(parts) - 1) ? "-" : "");
- }
- }
- else if targetCase == Case.Camel {
- for part, i in parts {
- if i == 0 {
- newStr = tcat(newStr, change_word_case(part, WordCase.Low));
- } else {
- newStr = tcat(newStr, change_word_case(part, WordCase.FirstUpNumberReset));
- }
- }
- }
- else if targetCase == Case.Constant {
- for part, i in parts {
- newStr = tcat(newStr, change_word_case(part, WordCase.Up), (i != len(parts) - 1) ? "_" : "");
- }
- }
-
- return newStr;
-}
-
-// Identify the case of the provided string.
-// Full lowercase with no separator is identified as camelCase.
-find_case :: proc(str : string) -> Case {
- refuted : bool;
-
- // CONSTANT_CASE
- refuted = false;
- for c in str {
- if (c != '_') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') {
- refuted = true;
- break;
- }
- }
- if !refuted do return Case.Constant;
-
- for c in str {
- // snake_case
- if c == '_' {
- return Case.Snake;
- } // kebab-case
- else if c == '-' {
- return Case.Kebab;
- }
- }
-
- // PascalCase
- if str[0] >= 'A' && str[0] <= 'Z' {
- return Case.Pascal;
- }
-
- // camelCase
- return Case.Camel;
-}
-
-// Splits the string according to detected case.
-// HeyBuddy -> {"Hey", "Buddy"}
-// hey-buddy -> {"hey", "buddy"}
-// _hey_buddy -> {"", "hey", "buddy"}
-// and such...
-autosplit_string :: proc(str : string) -> [dynamic]string {
- lowCount := 0;
- upCount := 0;
- for c in str {
- // If any '_', split according to that (CONSTANT_CASE or snake_case)
- if c == '_' {
- return split_from_separator(str, '_');
- } // If any '-', split according to that (kebab-case)
- else if c == '-' {
- return split_from_separator(str, '-');
- }
- else if c >= 'a' && c <= 'z' {
- lowCount += 1;
- }
- else if c >= 'A' && c <= 'Z' {
- upCount += 1;
- }
- }
-
- // If it seems to be only one word
- if lowCount == 0 || upCount == 0 {
- parts : [dynamic]string;
- append(&parts, str);
- return parts;
- }
-
- // Split at each uppercase letter (PascalCase or camelCase)
- return split_from_capital(str);
-}
-
-split_from_separator :: proc(str : string, sep : rune) -> [dynamic]string {
- parts : [dynamic]string;
-
- lastI := 0;
-
- // Empty strings for starting separators in string
- for c in str {
- if c == sep {
- append(&parts, "");
- lastI += 1;
- } else {
- break;
- }
- }
-
- // Ignore non letter prefix
- if lastI == 0 {
- for c in str {
- if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') {
- lastI += 1;
- }
- else {
- break;
- }
- }
- }
-
- for c, i in str {
- if i > lastI + 1 && c == sep {
- append(&parts, str[lastI:i]);
- lastI = i + 1;
- }
- }
-
- append(&parts, str[lastI:]);
-
- return parts;
-}
-
-split_from_capital :: proc(str : string) -> [dynamic]string {
- parts : [dynamic]string;
-
- // Ignore non letter prefix
- lastI := 0;
- for c in str {
- if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') {
- lastI += 1;
- }
- else {
- break;
- }
- }
-
- // We want to handle:
- // myBrainIsCRAZY -> my Brain Is Crazy
- // myCRAZYBrain -> my CRAZY Brain
- // SOLO -> SOLO
-
- // Do split
- for i := 1; i < len(str); i += 1 {
- if str[i] >= 'A' && str[i] <= 'Z' {
- // Do not split too much if it seems to be a capitalized word
- if (lastI == i - 1) && (str[lastI] >= 'A' && str[lastI] <= 'Z') {
- for ; i + 1 < len(str); i += 1 {
- if str[i + 1] < 'A' || str[i + 1] > 'Z' {
- break;
- }
- }
- if (i + 1 == len(str)) && (str[i] >= 'A' && str[i] <= 'Z') {
- i += 1;
- }
- }
-
- append(&parts, str[lastI:i]);
- lastI = i;
- }
- }
-
- if lastI != len(str) {
- append(&parts, str[lastI:]);
- }
-
- return parts;
-}
-
-// Check if str if prefixed with any of the provided strings,
-// even combinaisons of those, and remove them.
-remove_prefixes :: proc(str : string, prefixes : []string, transparentPrefixes : []string = nil) -> string {
- str := str;
- transparentStr := "";
-
- found := true;
- for found {
- found = false;
-
- // Remove effective prefixes
- for prefix in prefixes {
- if len(str) >= len(prefix) &&
- str[:len(prefix)] == prefix {
- str = str[len(prefix):];
- if len(str) != 0 && (str[0] == '_' || str[0] == '-') {
- str = str[1:];
- }
- found = true;
- break;
- }
- }
-
- if found do continue;
-
- // Remove transparent ones, only one by one,
- // as we want effective ones to be fully removed.
- for prefix in transparentPrefixes {
- if len(str) >= len(prefix) &&
- str[:len(prefix)] == prefix {
- str = str[len(prefix):];
- transparentStr = tcat(transparentStr, prefix);
- if len(str) != 0 && (str[0] == '_' || str[0] == '-') {
- str = str[1:];
- transparentStr = tcat(transparentStr, '_');
- }
- found = true;
- break;
- }
- }
- }
-
- return tcat(transparentStr, str);
-}
-
-// Check if str if postfixes with any of the provided strings,
-// even combinaisons of those, and remove them.
-remove_postfixes_with_removed :: proc(
- str : string,
- postfixes : []string,
- transparentPostfixes : []string = nil) -> (string, [dynamic]string) {
- str := str;
- removedPostfixes : [dynamic]string;
- transparentStr := "";
-
- found := true;
- for found {
- found = false;
-
- // Remove effective postfixes
- for postfix in postfixes {
- if ends_with(str, postfix) {
- str = str[:len(str) - len(postfix)];
- if len(str) != 0 && (str[len(str)-1] == '_' || str[len(str)-1] == '-') {
- str = str[:len(str)-1];
- }
- append(&removedPostfixes, postfix);
- found = true;
- break;
- }
- }
-
- if found do continue;
-
- // Remove transparent ones, only one by one,
- // as we want effective ones to be fully removed.
- for postfix in transparentPostfixes {
- if ends_with(str, postfix) {
- str = str[:len(str) - len(postfix)];
- transparentStr = tcat(postfix, transparentStr);
- if len(str) != 0 && (str[len(str)-1] == '_' || str[len(str)-1] == '-') {
- str = str[:len(str)-1];
- transparentStr = tcat('_', transparentStr);
- }
- found = true;
- break;
- }
- }
- }
-
- return tcat(str, transparentStr), removedPostfixes;
-}
-
-remove_postfixes :: proc(
- str : string,
- postfixes : []string,
- transparentPostfixes : []string = nil) -> string {
- str := str;
- removedPostfixes : [dynamic]string;
- str, removedPostfixes = remove_postfixes_with_removed(str, postfixes, transparentPostfixes);
- return str;
-}
-
-ends_with :: proc(str : string, postfix : string) -> bool {
- return len(str) >= len(postfix) && str[len(str) - len(postfix):] == postfix;
-}
diff --git a/core/bindgen/generator.odin b/core/bindgen/generator.odin
deleted file mode 100644
index 3ef3d69c0..000000000
--- a/core/bindgen/generator.odin
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * Odin binding generator from C header data.
- */
-
-package bindgen
-
-import "core:os"
-import "core:fmt"
-import "core:runtime"
-
-GeneratorOptions :: struct {
- mode : string, // "odin" or "jai"
-
- // Variable
- variableCase : Case,
-
- // Defines
- definePrefixes : []string,
- defineTransparentPrefixes : []string,
- definePostfixes : []string,
- defineTransparentPostfixes : []string,
- defineCase : Case,
-
- // Pseudo-types
- pseudoTypePrefixes : []string,
- pseudoTypeTransparentPrefixes : []string,
- pseudoTypePostfixes : []string,
- pseudoTypeTransparentPostfixes : []string,
- pseudoTypeCase : Case,
-
- // Enums
- enumConsideredFlagsPostfixes : []string,
-
- // Functions
- functionPrefixes : []string,
- functionTransparentPrefixes : []string,
- functionPostfixes : []string,
- functionTransparentPostfixes : []string,
- functionCase : Case,
-
- // Enum values
- enumValuePrefixes : []string,
- enumValueTransparentPrefixes : []string,
- enumValuePostfixes : []string,
- enumValueTransparentPostfixes : []string,
- enumValueCase : Case,
- enumValueNameRemove : bool,
- enumValueNameRemovePostfixes : []string,
-
- parserOptions : ParserOptions,
-}
-
-GeneratorData :: struct {
- handle : os.Handle,
- nodes : Nodes,
-
- // References
- foreignLibrary : string,
- options : ^GeneratorOptions,
-}
-
-generate :: proc(
- packageName : string,
- foreignLibrary : string,
- outputFile : string,
- headerFiles : []string,
- options : GeneratorOptions,
-) {
- options := options;
- data : GeneratorData;
- data.options = &options;
- data.foreignLibrary = foreignLibrary;
-
- if options.mode == "" {
- options.mode = "odin";
- }
-
- // Outputing odin file
- errno : os.Errno;
-
- // chmod 664 when creating file
- mode: int = 0;
- when os.OS == "linux" || os.OS == "darwin" {
- mode = os.S_IRUSR | os.S_IWUSR | os.S_IRGRP | os.S_IWGRP | os.S_IROTH;
- }
-
- data.handle, errno = os.open(outputFile, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, mode);
- if errno != 0 {
- fmt.eprint("[bindgen] Unable to write to output file ", outputFile, " (", errno ,")\n");
- return;
- }
- defer os.close(data.handle);
-
- if options.mode == "jai" {
- fcat(data.handle, foreignLibrary, " :: #foreign_library \"", foreignLibrary, "\";\n");
- fcat(data.handle, "\n");
- } else {
- fcat(data.handle, "package ", packageName, "\n");
- fcat(data.handle, "\n");
- fcat(data.handle, "foreign import \"", foreignLibrary, "\"\n");
- fcat(data.handle, "\n");
- fcat(data.handle, "import _c \"core:c\"\n");
- fcat(data.handle, "\n");
- }
-
- // Parsing header files
- anonymousStructCount = 0;
- anonymousUnionCount = 0;
- anonymousEnumCount = 0;
-
- for headerFile in headerFiles {
- bytes, ok := os.read_entire_file(headerFile);
- if !ok {
- fmt.eprint("[bindgen] Unable to read file ", headerFile, "\n");
- return;
- }
-
- // We fuse the SOAs
- headerNodes := parse(bytes, options.parserOptions);
- merge_generic_nodes(&data.nodes.defines, &headerNodes.defines);
- merge_generic_nodes(&data.nodes.enumDefinitions, &headerNodes.enumDefinitions);
- merge_generic_nodes(&data.nodes.unionDefinitions, &headerNodes.unionDefinitions);
- merge_forward_declared_nodes(&data.nodes.structDefinitions, &headerNodes.structDefinitions);
- merge_generic_nodes(&data.nodes.functionDeclarations, &headerNodes.functionDeclarations);
- merge_generic_nodes(&data.nodes.typedefs, &headerNodes.typedefs);
- }
-
- // Exporting
- export_defines(&data);
- export_typedefs(&data);
- export_enums(&data);
- export_structs(&data);
- export_unions(&data);
-
- // Foreign block for functions
- if options.mode != "jai" {
- foreignLibrarySimple := simplify_library_name(foreignLibrary);
- fcat(data.handle, "@(default_calling_convention=\"c\")\n");
- fcat(data.handle, "foreign ", foreignLibrarySimple, " {\n");
- fcat(data.handle, "\n");
- }
-
- export_functions(&data);
-
- if options.mode != "jai" {
- fcat(data.handle, "}\n");
- }
-}
-
-// system:foo.lib -> foo
-simplify_library_name :: proc(libraryName : string) -> string {
- startOffset := 0;
- endOffset := len(libraryName);
-
- for c, i in libraryName {
- if startOffset == 0 && c == ':' {
- startOffset = i + 1;
- }
- else if c == '.' {
- endOffset = i;
- break;
- }
- }
-
- return libraryName[startOffset:endOffset];
-}
-
-merge_generic_nodes :: proc(nodes : ^$T, headerNodes : ^T) {
- for headerNode in headerNodes {
- // Check that there are no duplicated nodes (due to forward declaration or such)
- duplicatedIndex := -1;
- for i := 0; i < len(nodes); i += 1 {
- node := nodes[i];
- if node.name == headerNode.name {
- duplicatedIndex = i;
- break;
- }
- }
-
- if duplicatedIndex < 0 {
- append(nodes, headerNode);
- }
- }
-}
-
-merge_forward_declared_nodes :: proc(nodes : ^$T, headerNodes : ^T) {
- for headerNode in headerNodes {
- // Check that there are no duplicated nodes (due to forward declaration or such)
- duplicatedIndex := -1;
- for i := 0; i < len(nodes); i += 1 {
- node := nodes[i];
- if node.name == headerNode.name {
- duplicatedIndex = i;
- break;
- }
- }
-
- if duplicatedIndex < 0 {
- append(nodes, headerNode);
- }
- else if !headerNode.forwardDeclared && len(headerNode.members) > 0 {
- nodes[duplicatedIndex] = headerNode;
- }
- }
-}
diff --git a/wasm-ld b/wasm-ld
deleted file mode 120000
index 01ef2a7e7..000000000
--- a/wasm-ld
+++ /dev/null
@@ -1 +0,0 @@
-/Volumes/Phill_Backup/pers/programming/sdk/emsdk/upstream/bin/lld \ No newline at end of file