From 94f7c1d47a98d5cb827e0c9f2d5b04fc9ee9e476 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sun, 15 Dec 2019 18:34:58 -0500 Subject: updated readme --- README.html | 85 +++++++++++++++++++++++++++++++++++++++++++++++++----------- README.md | 36 ++++++++++++++++++++++--- docs/00.html | 7 ++--- docs/01.html | 4 +-- infer.c | 8 +++--- main.c | 4 +-- test.toc | 58 ++++++----------------------------------- types.c | 13 ++++++++++ 8 files changed, 136 insertions(+), 79 deletions(-) diff --git a/README.html b/README.html index e34ab71..ae11187 100644 --- a/README.html +++ b/README.html @@ -11,26 +11,37 @@ and there are almost definitely bugs right now. I would recommend against using it for anything big or important. Many parts of it may change in the future.

-

toc improves on C's syntax (and semantics) in many ways, +

toc improves on C’s syntax (and semantics) in many ways, To declare x as an integer and set it to 5, you can do:

-x := 5; // Declare x and set x to 5 (infer type)
-x : int = 5; // Explicitly make the type int.
-x : int; x = 5; // Declare x as an integer, then set it to 5. +x := 5; // Declare x and set x to 5 (infer type) +x : int = 5; // Explicitly make the type int. +x : int; x = 5; // Declare x as an integer, then set it to 5.

-

toc is statically typed and has many of C's features, but +

toc is statically typed and has many of C’s features, but it is nearly as fast in theory.

See docs for more information (in progress).

tests has some test programs written in toc.

-

To compile the compiler on a Unix-y system, just run build.sh. You can supply a compiler by running CC=tcc build.sh, or built it in release mode with ./build.sh release (which will help speed up compiling large programs).

+

To compile the compiler on a Unix-y system, just run ./build.sh release. You can supply a compiler by running CC=tcc ./build.sh release, or build it in debug mode without the release.

+ +

On other systems, you can just compile main.c with a C compiler. toc uses several C99 and a couple of C11 features, so it might not work on all compilers. But it does compile on quite a few, including clang, gcc, and tcc. It can also be compiled as if it were C++, but it does break the standard in a few places*. So, MSVC can also compile it. The outputted code should be C99-compliant.

+ +

Why it compiles to C

+ +

toc compiles to C for three reasons:

+ + -

On other systems, you can just compile main.c with a C compiler. toc uses several C99 and a couple of C11 features, so it might not work on all compilers. But it does compile on quite a few, including clang, gcc, and tcc. It can also be compiled as if it were C++, but it does break the standard in a few places*. So, MSVC can also compile it. The outputted code should be C99-compliant.


@@ -40,35 +51,77 @@ it is nearly as fast in theory.

Build system

-

toc is set up as a unity build, meaning that there is only one translation unit. So, main.c #includes toc.c, which #includes all of toc's files. This improves (from scratch) compilation speeds, since you don't have to include headers a bunch of times for each translation unit. This is more of a problem in C++, where, for example, doing #include <map> ends up turning into 25,000 lines after preprocessing. All of toc's source code, which includes most of the C standard library, at the time of this writing (Dec 2019) is only 22,000 lines after preprocessing; imagine including all of that once for each translation unit which includes map. It also obviates the need for fancy build systems like CMake.

+

toc is set up as a unity build, meaning that there is only one translation unit. So, main.c #includes toc.c, which #includes all of toc’s files.

+ +
Why?
+ +

This improves compilation speeds (especially from scratch), since you don’t have to include headers a bunch of times for each translation unit. This is more of a problem in C++, where, for example, doing #include <map> ends up turning into 25,000 lines after preprocessing. All of toc’s source code, which includes most of the C standard library, at the time of this writing (Dec 2019) is only 22,000 lines after preprocessing; imagine including all of that once for each translation unit which includes map. It also obviates the need for fancy build systems like CMake.

New features

-

Here are all the C99 features which toc depends on (I might have forgotten some...):

+

Here are all the C99 features which toc depends on (I might have forgotten some…):

-

The last three of those could all be removed fairly easily.

+ +

The last three of those could all be removed fairly easily (assuming the system actually has 8-, 16-, 32-, and 64-bit signed and unsigned types).

And here are all of its C11 features:

+

More

See main.c for a bit more information.


+

Version history

+ +

Here are the major versions of toc.

+ + + + + + + + + + + + + + + + + + + + + +
Version Description Date
0.0 Initial version. 2019 Dec 6
0.1 Constant parameter inference. 2019 Dec 15
+ + +
+ +

Report a bug

+ +

If you find a bug, you can report it through GitHub’s issue tracker, or by emailing pommicket@gmail.com.

+ +

Just send me the toc source code which results in the bug, and I’ll try to fix it.

+ +
+

* for those curious, it has to do with goto. In C, this program:


@@ -80,7 +133,8 @@ int main() {
 }
 
-

Is completely fine. x will hold an unspecified value after the jump (but it isn't used so it doesn't really matter). Apparently, in C++, this is an ill-formed program. This is a bit ridiculous since

+ +

Is completely fine. x will hold an unspecified value after the jump (but it isn’t used so it doesn’t really matter). Apparently, in C++, this is an ill-formed program. This is a bit ridiculous since


 int main() {  
@@ -91,4 +145,5 @@ int main() {
 }
 
-

is fine. So that's an interesting little "fun fact": int x = 5; isn't always the same as int x; x = 5; in C++.

+ +

is fine. So that’s an interesting little “fun fact”: int x = 5; isn’t always the same as int x; x = 5; in C++.

diff --git a/README.md b/README.md index be43683..9cbfa2b 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,17 @@ See `docs` for more information (in progress). `tests` has some test programs written in `toc`. -To compile the compiler on a Unix-y system, just run `./build.sh release`. You can supply a compiler by running `CC=tcc ./build.sh release`, or built it in debug mode without the `release`. +To compile the compiler on a Unix-y system, just run `./build.sh release`. You can supply a compiler by running `CC=tcc ./build.sh release`, or build it in debug mode without the `release`. -On other systems, you can just compile main.c with a C compiler. toc uses several C99 and a couple of C11 features, so it might not work on all compilers. But it does compile on quite a few, including `clang`, `gcc`, and `tcc`. It can also be compiled as if it were C++, but it does break the standard in a few places\*. So, MSVC can also compile it. The *outputted* code should be C99-compliant. +On other systems, you can just compile main.c with a C compiler. `toc` uses several C99 and a couple of C11 features, so it might not work on all compilers. But it does compile on quite a few, including `clang`, `gcc`, and `tcc`. It can also be compiled as if it were C++, but it does break the standard in a few places\*. So, MSVC can also compile it. The *outputted* code should be C99-compliant. + +#### Why it compiles to C + +`toc` compiles to C for three reasons: + +- Speed. C is one of the most performant programming languages out there. It also has compilers which are very good at optimizing (better than anything I could write). +- Portability. C is probably the most portable language. It has existed for >30 years and can run on practically anything. Furthermore, all major languages nowadays can call functions written in C. +- Laziness. I don't really want to deal with writing something which outputs machine code, and it would certainly be more buggy than something which outputs C. --- @@ -39,7 +47,9 @@ On other systems, you can just compile main.c with a C compiler. toc uses severa `toc` is written in C, for speed and portability. It has no dependencies, other than the C runtime library. #### Build system -`toc` is set up as a unity build, meaning that there is only one translation unit. So, `main.c` `#include`s `toc.c`, which `#include`s all of `toc`'s files. This improves (from scratch) compilation speeds, since you don't have to include headers a bunch of times for each translation unit. This is more of a problem in C++, where, for example, doing `#include ` ends up turning into 25,000 lines after preprocessing. All of toc's source code, which includes most of the C standard library, at the time of this writing (Dec 2019) is only 22,000 lines after preprocessing; imagine including all of that once for each translation unit which includes `map`. It also obviates the need for fancy build systems like CMake. +`toc` is set up as a unity build, meaning that there is only one translation unit. So, `main.c` `#include`s `toc.c`, which `#include`s all of `toc`'s files. +##### Why? +This improves compilation speeds (especially from scratch), since you don't have to include headers a bunch of times for each translation unit. This is more of a problem in C++, where, for example, doing `#include ` ends up turning into 25,000 lines after preprocessing. All of toc's source code, which includes most of the C standard library, at the time of this writing (Dec 2019) is only 22,000 lines after preprocessing; imagine including all of that once for each translation unit which includes `map`. It also obviates the need for fancy build systems like CMake. #### New features @@ -50,7 +60,7 @@ Here are all the C99 features which `toc` depends on (I might have forgotten som - Non-constant struct literal initializers (e.g. `int x[2] = {y, z};`) - Flexible array members -The last three of those could all be removed fairly easily. +The last three of those could all be removed fairly easily (assuming the system actually has 8-, 16-, 32-, and 64-bit signed and unsigned types). And here are all of its C11 features: @@ -63,6 +73,24 @@ See `main.c` for a bit more information. --- +### Version history + +Here are the major versions of `toc`. + +| Version | Description | Date | +| ------- | ----------- | ---- | +| 0.0 | Initial version. | 2019 Dec 6 | +| 0.1 | Constant parameter inference. | 2019 Dec 15 | + +--- + +### Report a bug + +If you find a bug, you can report it through [GitHub's issue tracker](https://github.com/pommicket/toc/issues), or by emailing pommicket@gmail.com. + +Just send me the `toc` source code which results in the bug, and I'll try to fix it. + +--- \* for those curious, it has to do with `goto`. In C, this program:

diff --git a/docs/00.html b/docs/00.html
index cd0c352..b8c961c 100644
--- a/docs/00.html
+++ b/docs/00.html
@@ -30,7 +30,7 @@ x := 0.0;
 when no type is specified, it defaults to an int, whereas 0.0
 defaults to a float.

-

Here are all of toc's builtin types and their ranges of values:

+

Here are all of toc’s builtin types and their ranges of values:

  • int - A 64-bit signed integer (always), -9223372036854775808 to 9223372036854775807
  • @@ -49,13 +49,14 @@ defaults to a float.

  • char - A character. The specific values are technically platform-dependent, but usually there are 256 of them.
+

At the moment, it is not technically guaranteed that f32/float is actually 32-bit and that f64 is actually 64-bit; they are platform dependent. Perhaps someday there will be a version of toc which does not compile to C, where that could be guaranteed.

To make declarations constant, use :: instead of :. e.g.

-x ::= 5+3;
+x ::= 5+3; y :: float = 5.123;

-

Here, "constant" means constant at compile time, not read-only as it does in C. One interesting thing about toc is that normal functions can run at compile time, so pretty much any expression is a valid initializer for a constant, e.g. doing x ::= some_function(); runs some_function at compile time, not at run time.

+

Here, “constant” means constant at compile time, not read-only as it does in C. One interesting thing about toc is that normal functions can run at compile time, so pretty much any expression is a valid initializer for a constant, e.g. doing x ::= some_function(); runs some_function at compile time, not at run time.

diff --git a/docs/01.html b/docs/01.html index 633295b..6dce358 100644 --- a/docs/01.html +++ b/docs/01.html @@ -7,7 +7,7 @@ main ::= fn() { };

-

It declares a constant, main, which is a function with an empty body. Note that the syntax for declaring functions is the same as the syntax for declaring constants (it isn't something like fn main() { ... }).

+

It declares a constant, main, which is a function with an empty body. Note that the syntax for declaring functions is the same as the syntax for declaring constants (it isn’t something like fn main() { ... }).

Assuming you have compiled the compiler (see README.md for instructions about that), you can compile it with

@@ -15,4 +15,4 @@ main ::= fn() { toc <your filename>

-

You will get a file called out.c, which you can then put through your C compiler to get an executable file which does nothing. Congratulations! You've written your first toc program.

+

You will get a file called out.c, which you can then put through your C compiler to get an executable file which does nothing. Congratulations! You’ve written your first toc program.

diff --git a/infer.c b/infer.c index 92c7ef8..02fd34c 100644 --- a/infer.c +++ b/infer.c @@ -47,9 +47,11 @@ static bool infer_from_expr(Typer *tr, Expression *match, Expression *to, Expres } else { t_arg = &t_args[i]; } - assert(t_arg->kind == EXPR_VAL); /* should have been evaluated */ - if (!infer_from_expr(tr, &m_arg->val, t_arg, t_arg, idents, vals, types)) - return false; + if (t_arg->kind == EXPR_VAL) { + /* was evaluated, because it's const */ + if (!infer_from_expr(tr, &m_arg->val, t_arg, t_arg, idents, vals, types)) + return false; + } } } break; default: break; diff --git a/main.c b/main.c index 5d755cc..a39d27c 100644 --- a/main.c +++ b/main.c @@ -19,10 +19,10 @@ /* TODO: -make sure all parameters to a function which returns a type are constant ---- get ArrInt to work with inference +--- packages +--- X ::= newtype(int); or something don't allow while {3; 5} (once break is added) better printing of types (take was_expr into account) diff --git a/test.toc b/test.toc index ea9ea79..55c20e6 100644 --- a/test.toc +++ b/test.toc @@ -6,58 +6,16 @@ putf ::= fn(x: float) { #C("printf(\"%f\\n\", (double)x); "); }; - -// it would be nice if Arr.data.len == Arr.len (: but this will require some C code... -Arr ::= fn (t :: Type) Type { - struct { - data : []t; - len, cap : int; - } -}; - -arr_add ::= fn(t ::=, a : &Arr(t), x : t) { - if a.len >= a.cap { - a.cap = a.cap * 2 + 2; - new_data := new(t, a.cap); - each i := 0..a.len-1 { - new_data[i] = a.data[i]; - } - a.data = new_data; - } - a.data[a.len] = x; - a.len += 1; -}; - -square ::= fn(t ::=, x : t) t { - a : Arr(t); - each i := 1,2..2*x-1 { - arr_add(&a, i); - }; - sum := 0 as t; - each i := 0..a.len-1 { - sum += a.data[i]; - }; - sum +f ::= fn(x : int) Type { + if x == 0 { int } else { float } }; - -// ArrInt ::= Arr(int); - -inc ::= fn(t ::=, x : t) t { - x + 1 +r ::= fn(n::=, a :f(n)) int { +n }; main ::= fn() { - arr : Arr(int); - farr : Arr(float); - each i := 1..100 { - arr_add(&arr, inc(square(i))); - arr_add(&farr, inc(square(i as float))); - } - each i := 0..arr.len - 1 { - puti(arr.data[i]); - } - each i := 0..farr.len - 1 { - putf(farr.data[i]); - } -}; + x :: = 3; + y : f(x); + puti(r(y)); +}; \ No newline at end of file diff --git a/types.c b/types.c index 47b0145..34e7b08 100644 --- a/types.c +++ b/types.c @@ -323,6 +323,19 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) } *ret_type = f->ret_type; + if (ret_type->kind == TYPE_TYPE) { + /* + a function which returns a type but has non-constant parameters is weird... + but might be useful, so let's warn + */ + arr_foreach(f->params, Declaration, param) { + if (!(param->flags & DECL_IS_CONST)) { + warn_print(param->where, "Non-constant parameter in function which returns Type. (You can't call functions which return types at run-time, y'know)"); + break; + } + } + } + ret: arr_remove_last(&tr->blocks); tr->block = prev_block; -- cgit v1.2.3