summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.html85
-rw-r--r--README.md36
-rw-r--r--docs/00.html7
-rw-r--r--docs/01.html4
-rw-r--r--infer.c8
-rw-r--r--main.c4
-rw-r--r--test.toc58
-rw-r--r--types.c13
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.</strong>
I would recommend against using it for anything big or important.
Many parts of it may change in the future.</p>
-<p><code>toc</code> improves on C's syntax (and semantics) in many ways,
+<p><code>toc</code> improves on C&rsquo;s syntax (and semantics) in many ways,
To declare <code>x</code> as an integer and set it to 5,
you can do:</p>
<p><code>
-x := 5; // Declare x and set x to 5 (infer type) <br />
-x : int = 5; // Explicitly make the type int. <br />
-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.
</code></p>
-<p><code>toc</code> is statically typed and has many of C's features, but
+<p><code>toc</code> is statically typed and has many of C&rsquo;s features, but
it is nearly as fast in theory.</p>
<p>See <code>docs</code> for more information (in progress).</p>
<p><code>tests</code> has some test programs written in <code>toc</code>.</p>
-<p>To compile the compiler on a Unix-y system, just run <code>build.sh</code>. You can supply a compiler by running <code>CC=tcc build.sh</code>, or built it in release mode with <code>./build.sh release</code> (which will help speed up compiling large programs). </p>
+<p>To compile the compiler on a Unix-y system, just run <code>./build.sh release</code>. You can supply a compiler by running <code>CC=tcc ./build.sh release</code>, or build it in debug mode without the <code>release</code>.</p>
+
+<p>On other systems, you can just compile main.c with a C compiler. <code>toc</code> 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 <code>clang</code>, <code>gcc</code>, and <code>tcc</code>. 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 <em>outputted</em> code should be C99-compliant.</p>
+
+<h4>Why it compiles to C</h4>
+
+<p><code>toc</code> compiles to C for three reasons:</p>
+
+<ul>
+<li>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).</li>
+<li>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.</li>
+<li>Laziness. I don&rsquo;t really want to deal with writing something which outputs machine code, and it would certainly be more buggy than something which outputs C.</li>
+</ul>
-<p>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 <code>clang</code>, <code>gcc</code>, and <code>tcc</code>. 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 <em>outputted</em> code should be C99-compliant.</p>
<hr />
@@ -40,35 +51,77 @@ it is nearly as fast in theory.</p>
<h4>Build system</h4>
-<p><code>toc</code> is set up as a unity build, meaning that there is only one translation unit. So, <code>main.c</code> <code>#include</code>s <code>toc.c</code>, which <code>#include</code>s all of <code>toc</code>'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 <code>#include &lt;map&gt;</code> 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 <code>map</code>. It also obviates the need for fancy build systems like CMake.</p>
+<p><code>toc</code> is set up as a unity build, meaning that there is only one translation unit. So, <code>main.c</code> <code>#include</code>s <code>toc.c</code>, which <code>#include</code>s all of <code>toc</code>&rsquo;s files.</p>
+
+<h5>Why?</h5>
+
+<p>This improves compilation speeds (especially from scratch), since you don&rsquo;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 <code>#include &lt;map&gt;</code> ends up turning into 25,000 lines after preprocessing. All of toc&rsquo;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 <code>map</code>. It also obviates the need for fancy build systems like CMake.</p>
<h4>New features</h4>
-<p>Here are all the C99 features which <code>toc</code> depends on (I might have forgotten some...):</p>
+<p>Here are all the C99 features which <code>toc</code> depends on (I might have forgotten some&hellip;):</p>
<ul>
<li>Declare anywhere</li>
-<li><code>stdint.h</code></li>
+<li><code>inttypes.h</code></li>
<li>Non-constant struct literal initializers (e.g. <code>int x[2] = {y, z};</code>)</li>
-<li>Variadic macros and <code>__VA_ARGS__</code></li>
<li>Flexible array members</li>
</ul>
-<p>The last three of those could all be removed fairly easily.</p>
+
+<p>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).</p>
<p>And here are all of its C11 features:</p>
<ul>
<li>Anonymous structures/unions</li>
-<li><code>max_align_t</code> and <code>alignof</code> - It can still compile without these but it won't technically be standard-compliant</li>
+<li><code>max_align_t</code> and <code>alignof</code> - It can still compile without these but it won&rsquo;t technically be standard-compliant</li>
</ul>
+
<h4>More</h4>
<p>See <code>main.c</code> for a bit more information.</p>
<hr />
+<h3>Version history</h3>
+
+<p>Here are the major versions of <code>toc</code>.</p>
+
+<table>
+<thead>
+<tr>
+<th> Version </th>
+<th> Description </th>
+<th> Date </th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td> 0.0 </td>
+<td> Initial version. </td>
+<td> 2019 Dec 6 </td>
+</tr>
+<tr>
+<td> 0.1 </td>
+<td> Constant parameter inference. </td>
+<td> 2019 Dec 15 </td>
+</tr>
+</tbody>
+</table>
+
+
+<hr />
+
+<h3>Report a bug</h3>
+
+<p>If you find a bug, you can report it through <a href="https://github.com/pommicket/toc/issues">GitHub&rsquo;s issue tracker</a>, or by emailing pommicket@gmail.com.</p>
+
+<p>Just send me the <code>toc</code> source code which results in the bug, and I&rsquo;ll try to fix it.</p>
+
+<hr />
+
<p>* for those curious, it has to do with <code>goto</code>. In C, this program:</p>
<pre><code>
@@ -80,7 +133,8 @@ int main() {
}
</code></pre>
-<p>Is completely fine. <code>x</code> 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</p>
+
+<p>Is completely fine. <code>x</code> will hold an unspecified value after the jump (but it isn&rsquo;t used so it doesn&rsquo;t really matter). Apparently, in C++, this is an ill-formed program. This is a bit ridiculous since</p>
<pre><code>
int main() {
@@ -91,4 +145,5 @@ int main() {
}
</code></pre>
-<p>is fine. So that's an interesting little "fun fact": <code>int x = 5;</code> isn't always the same as <code>int x; x = 5;</code> in C++.</p>
+
+<p>is fine. So that&rsquo;s an interesting little &ldquo;fun fact&rdquo;: <code>int x = 5;</code> isn&rsquo;t always the same as <code>int x; x = 5;</code> in C++.</p>
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 <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` `#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 <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
@@ -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:
<pre><code>
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 <code>int</code>, whereas <code>0.0</code>
defaults to a <code>float</code>.</p>
-<p>Here are all of toc's builtin types and their ranges of values:</p>
+<p>Here are all of toc&rsquo;s builtin types and their ranges of values:</p>
<ul>
<li><code>int</code> - A 64-bit signed integer (always), -9223372036854775808 to 9223372036854775807</li>
@@ -49,13 +49,14 @@ defaults to a <code>float</code>.</p>
<li><code>char</code> - A character. The specific values are technically platform-dependent, but usually there are 256 of them.</li>
</ul>
+
<p>At the moment, it is not technically guaranteed that <code>f32</code>/<code>float</code> is actually 32-bit and that <code>f64</code> 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.</p>
<p>To make declarations constant, use <code>::</code> instead of <code>:</code>. e.g.</p>
<p><code>
-x ::= 5+3; <br />
+x ::= 5+3;
y :: float = 5.123;
</code></p>
-<p>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 <code>x ::= some_function();</code> runs <code>some_function</code> at compile time, not at run time.</p>
+<p>Here, &ldquo;constant&rdquo; 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 <code>x ::= some_function();</code> runs <code>some_function</code> at compile time, not at run time.</p>
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() {
};
</code></p>
-<p>It declares a constant, <code>main</code>, 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 <code>fn main() { ... }</code>).</p>
+<p>It declares a constant, <code>main</code>, 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&rsquo;t something like <code>fn main() { ... }</code>).</p>
<p>Assuming you have compiled the compiler (see <code>README.md</code> for instructions about that), you can compile it with</p>
@@ -15,4 +15,4 @@ main ::= fn() {
toc &lt;your filename&gt;
</code></p>
-<p>You will get a file called <code>out.c</code>, 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.</p>
+<p>You will get a file called <code>out.c</code>, which you can then put through your C compiler to get an executable file which does nothing. Congratulations! You&rsquo;ve written your first toc program.</p>
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;