Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various "C+" improvements #5

Open
sgraham opened this issue Oct 19, 2023 · 7 comments
Open

Various "C+" improvements #5

sgraham opened this issue Oct 19, 2023 · 7 comments
Labels
enhancement New feature or request

Comments

@sgraham
Copy link
Owner

sgraham commented Oct 19, 2023

Some possibilities:

  • import instead of #include when not referring to system headers
  • string type with helper syntax
  • basic polymorphic containers (dist, list, slice)
  • range based for loop to go with containers
  • range notation

Obviously first would need way to opt in per file/per section, and a way of cleanly integrating/generating down to normal C.

@sgraham sgraham added the enhancement New feature or request label Oct 19, 2023
@sgraham
Copy link
Owner Author

sgraham commented Oct 19, 2023

I didn't try it, but https://github.com/red0124/sgc looks straightforward, and could be not-too-verbose with some helper syntax sugar.

@sgraham
Copy link
Owner Author

sgraham commented Oct 19, 2023

Some random scribblings on that idea (user syntax at bottom)

#pragma luv
// #includes all of SGC.
// reserves: `vector, `str, `list, `map, `set, `hashmap, `hashset, ...
// 
// at parse time `vector(int) v:
// 1. inserts SGC_INIT_HEADERS(VECTOR, int, _luv_vector__int_) at top level
// 2. adds SGC_INIT_DEFINITIONS(VECTOR, int, _luv_vector__int_) in a temporary ltcg.c
// 3. declares _luv_vector__int_ v
// 4. calls v..init();
//
// where .. syntax is also specially handled and does:
//
//   x..something(a, b, c) <==> <static_type_of_x>_something(&x, a, b, c)
//
// e.g.
//
//   v..push_back(1)  ==>  _luv_vector_int__push_back(&v, 1)
//
// .. is chosen because it's not too ugly, and works with clang-format.
//
// :: also mostly works, makes me think of static calls (sort of what it is, so maybe good?)
// doesn't format quite as reliably as ..

// :, @, #, ! don't work for format
// $ doesn't work because it's sorta an identifier character in C
// ^ and | maybe plausible but always get spaces which looks a bit weird
//
// Single . could maybe be made to work since we have to know the static type of the lhs anyway
// - ambiguous for member access, but prettier
// - possibly more confusing what's happening?
// - ? if rhs of . exists on structure, then it's just a field access, otherwise member invoke
//
// What about pointers? declaration seems fine, but then more magic required in
// ., .., -> etc.

#if 0
SGC_INIT(VECTOR, int, vec)

int main(void) {
  vec v;
  vec_init(&v);

  vec_push_back(&v, 1);
  vec_push_back(&v, 5);

  *vec_at(&v, 0) = 2;

  for_each(i IN v AS vec) { printf("%d ", *i); }

  vec_free(&v);
  return 0;
}
#endif  // Would be written as vvv

int main() {
  `vector(int) v;

  v.push_back(1);
  v.push_back(5);

  v.at(0) = 2;

  foreach (i, v) {
    printf("%d ", *i);
  }

  v.free();
}

@sgraham
Copy link
Owner Author

sgraham commented Oct 22, 2023

No need for #pragma, or wacky backtick prefixes. Instead, just use _Vec, _Str, etc. Those could almost be macros but not quite because some stuff it would expand to needs to be injected at top-level or in a single translation unit.

I think the operator overloading for . is fine too then because we have a bunch of known types so we can just not have any "public" fields, or special case any if necessary.

@sgraham
Copy link
Owner Author

sgraham commented Oct 23, 2023

apparently reserving _Str isn't going to work so well since we want to use Microsoft's std*.h:

C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include/vcruntime_string.h:71:     _In_z_ char const* _Str,
                                                                                                                                        ^ error: expected ','

One of __str, @str, $str, __Str, @Str, $Str maybe.

@sgraham
Copy link
Owner Author

sgraham commented Oct 29, 2023

I started by implementing an __attribute__ on structs that makes them callable method-like: 496d31c#diff-5b99019f6d3db6895298385f15e166a8f07ed2b61cffb0b3fc7d0569571f6f62 .

Then I thought the rest might just be a matter of having the preprocessor map $vec(int) (the user syntax) to _Vec$int (the generated instantiated container) and then as a side-effect, doing the #include of the container type (as in something like https://github.com/stclib/STC#usage which seems like a nice container library), along with a bit of caching/unique-ing/whatever.

And that was almost enough for it to work! One problem that comes up is where to insert the header when it's magically instantiated. Since the preprocessor is doing the work, the only two possible locations at the head and tail of the current file (because we have no lexical context to know where "global scope" is). The tail seemed wrong because we need (e.g.) the struct definition early. So the head seemed like it'd work, but the problem is that by the time we see $vec(int) other files have been included, say, stdint.h that might be needed by the container. But when the container header sees an #include of stdint.h the include guard will avoid the contents of stdint being included again. So if the tokens for the container are injected at the head of the file they won't be in the correct order. So we sort of want the container injected ... at global scope ... after "some stuff" ... and before "some other stuff". Which doesn't sound great.

I could force include some headers (but it'd probably have to be always, not only when containers are in use, which is no good).

Perhaps rewrite the containers to need to include any files?

A related problem that I haven't thought too much about is what to do when the $vec(int) is in a header/forward-declaration situation where it shouldn't be defining anything yet. Or at least not re-defining when done multiple-y. It might not matter (if each definition only gets instantiated once per translation unit) or... if it does, maybe some sort of hacky attribute that allows struct redefinition, as long as it matches the previous one (which feels like encroaching on C++ ODR nose-demon territory 🤮).

@sgraham
Copy link
Owner Author

sgraham commented Oct 30, 2023

Containers are actually working (?) in a branch now. This code 3c3ad8e doesn't feel too awful, though the implementation is maybe a bit unpleasant (and of course ignoring the lack of wisdom in extending C at the syntax level)!

The extensions are:

  • __attribute__((methodcall(PREFIX))) which allows the .. syntax that adds the "self" and follows pointers if necessary
  • supporting and baking in $vec(T) and $map(K,V) which are the first two container types supported (embedded hacked versions of https://github.com/stclib/STC)

@sgraham
Copy link
Owner Author

sgraham commented Jan 25, 2024

(I think I'm probably going to remove this as it's too hacky even for me, and put this type of functionality into a more extensive alternate "front-end".)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant