summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--cgen.c7
-rw-r--r--eval.c19
-rw-r--r--foreign64.c20
-rw-r--r--main.c1
-rw-r--r--parse.c1
-rw-r--r--std/base.toc13
-rw-r--r--std/io.toc115
-rw-r--r--std/mem.toc15
-rw-r--r--test.toc23
-rw-r--r--toc.c1
-rw-r--r--tokenizer.c4
-rw-r--r--types.c20
13 files changed, 188 insertions, 52 deletions
diff --git a/.gitignore b/.gitignore
index c5f345e..450a731 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ std/*.o
*.obj
*.exe
.vs
+test.txt
diff --git a/cgen.c b/cgen.c
index c4427e1..2fd5cbf 100644
--- a/cgen.c
+++ b/cgen.c
@@ -277,11 +277,12 @@ static void cgen_type_post(CGenerator *g, Type *t) {
}
static void cgen_ctype(CGenerator *g, CType *c) {
- if (c->kind & CTYPE_UNSIGNED) {
- c->kind &= (CTypeKind)~(CTypeKind)CTYPE_UNSIGNED;
+ CTypeKind k = c->kind;
+ if (k & CTYPE_UNSIGNED) {
+ k &= (CTypeKind)~(CTypeKind)CTYPE_UNSIGNED;
cgen_write(g, "unsigned ");
}
- switch (c->kind) {
+ switch (k) {
case CTYPE_CHAR:
cgen_write(g, "char");
break;
diff --git a/eval.c b/eval.c
index e4b5313..69b2785 100644
--- a/eval.c
+++ b/eval.c
@@ -1035,7 +1035,8 @@ static Status eval_ident(Evaluator *ev, Identifier ident, Value *v, Location whe
if (!success) return false;
assert(d->type.flags & TYPE_IS_RESOLVED);
#else
- err_print(where, "Use of identifier at compile time before it is declared. This isn't allowed. Sorry.");
+ if (!where.file->ctx->have_errored)
+ err_print(where, "Use of identifier at compile time before it is declared. This isn't allowed. Sorry.");
return false;
#endif
}
@@ -1338,7 +1339,16 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
return false;
}
if (fn->ret_decls) {
+ size_t nret_decls = 0;
+ arr_foreach(fn->ret_decls, Declaration, d) {
+ nret_decls += arr_len(d->idents);
+ }
+
Value *tuple = NULL;
+ if (nret_decls > 1)
+ tuple = err_malloc(nret_decls * sizeof *tuple);
+ size_t tuple_idx = 0;
+
arr_foreach(fn->ret_decls, Declaration, d) {
int i = 0;
arr_foreach(d->idents, Identifier, ident) {
@@ -1349,16 +1359,13 @@ static Status eval_expr(Evaluator *ev, Expression *e, Value *v) {
expr.ident = *ident;
if (!eval_expr(ev, &expr, &this_one))
return false;
- Value *element = arr_add_ptr(tuple);
+ Value *element = tuple ? &tuple[tuple_idx++] : v;
Type *type = decl_type_at_index(d, i);
copy_val(NULL, element, this_one, type);
++i;
}
}
- if (arr_len(tuple) == 1) {
- *v = tuple[0];
- arr_clear(tuple);
- } else {
+ if (tuple) {
v->tuple = tuple;
}
}
diff --git a/foreign64.c b/foreign64.c
index 0a0fc40..5aaf574 100644
--- a/foreign64.c
+++ b/foreign64.c
@@ -96,6 +96,14 @@ static Status val_to_word(Value v, Type *t, Location where, U64 *w) {
static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type, Type *arg_types, size_t arg_types_stride, Value *args, size_t nargs, Location call_where, Value *ret) {
possibly_static_assert(sizeof(double) == 8); /* if either of these assertions fails, you'll need to use libffcall */
possibly_static_assert(sizeof(float) == 4);
+
+#if 0
+#define FOREIGN_DEBUGGING 1
+#endif
+#if FOREIGN_DEBUGGING
+ printf("Foreign call: %s(", fn->foreign.name);
+#endif
+
FnPtr fn_ptr = foreign_get_fn_ptr(ffmgr, fn, call_where);
if (!fn_ptr) return false;
/* @OPTIM: use alloca/_malloca if available */
@@ -104,6 +112,10 @@ static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type,
U64 *word = words;
char *type = (char *)arg_types;
for (size_t i = 0; i < nargs; ++i) {
+ #if FOREIGN_DEBUGGING
+ if (i) printf(", ");
+ fprint_val(stdout, args[i], (Type *)type);
+ #endif
if (!val_to_word(args[i], (Type *)type, call_where, word))
return false;
is_float[i] = type_is_float((Type *)type);
@@ -181,6 +193,14 @@ static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type,
ret->f64 = foreign_calld(fn_ptr, words, (I64)nargs, is_float);
break;
}
+#if FOREIGN_DEBUGGING
+ printf(") => ");
+ fprint_val(stdout, *ret, ret_type);
+#if 1
+ printf(" (errno: %d)", errno);
+#endif
+ printf("\n");
+#endif
free(words);
free(is_float);
return true;
diff --git a/main.c b/main.c
index fbd6029..1fb6f34 100644
--- a/main.c
+++ b/main.c
@@ -9,6 +9,7 @@
/*
@TODO:
if we do #include "foo.toc", bar; and foo.toc fails, bar should be declared as TYPE_UNKNOWN (right now it's undeclared)
+fix #foreign not at global scope - right now the cgen'd definition doesn't use the proper type
improve type_to_str:
Foo ::= struct(t::Type) {}
type_to_str(Foo(int))
diff --git a/parse.c b/parse.c
index 53df60f..b723db0 100644
--- a/parse.c
+++ b/parse.c
@@ -2007,6 +2007,7 @@ static inline bool ends_decl(Token *t, U16 flags) {
static Status parse_decl(Parser *p, Declaration *d, U16 flags) {
Tokenizer *t = p->tokr;
d->where = parser_mk_loc(p);
+ parser_set_end_to_token(p, &d->where, t->token+1); /* set temporary end in case this fails and we need to know the location of this declaration */
d->idents = NULL;
d->flags = 0;
d->val_stack = NULL;
diff --git a/std/base.toc b/std/base.toc
index 54d64d6..950f817 100644
--- a/std/base.toc
+++ b/std/base.toc
@@ -23,4 +23,17 @@ PLATFORM ::= #builtin("platform");
PLATFORM_IS_UNIX :: bool = PLATFORM == PLATFORM_LINUX || PLATFORM == PLATFORM_OSX || PLATFORM == PLATFORM_FREEBSD
|| PLATFORM == PLATFORM_OPENBSD || PLATFORM == PLATFORM_MISC_UNIX;
+fwrite ::= #foreign("fwrite", libc) fn(#C &"const void", #C size_t, #C size_t, &void) #C size_t;
+stderr_write ::= fn(s: []char) {
+ fwrite(&s[0], 1, s.len as #C size_t, #builtin("stderr"));
+}
+
+exit ::= #foreign("exit", libc) fn(#C int);
+error ::= fn(s: []char) {
+ stderr_write("Fatal error: ");
+ stderr_write(s);
+ // @TODO: backtrace
+ stderr_write("\nExiting.\n");
+ exit(1);
+}
diff --git a/std/io.toc b/std/io.toc
index acba673..932cf45 100644
--- a/std/io.toc
+++ b/std/io.toc
@@ -1,16 +1,36 @@
+
#include "std/base.toc", base;
#include "std/mem.toc", mem;
str_to_cstr ::= fn(s: []char) []char {
ret := mem.news(char, s.len+1);
mem.mem_copy(&ret[0], &s[0], s.len);
- ret
+ return ret;
}
+// @TODO(eventually): enum
+FileError ::= int;
+FILE_ERR_OK ::= 0;
+FILE_ERR_MISC ::= 1;
+// @TODO: more of these
+
+/*
+the raw file interface:
+raw_stdout - standard output
+raw_stderr - standard error
+raw_file_write - write to a raw file
+raw_file_open_write - open a raw file for writing
+raw_file_close - flush and close a raw file
+*/
+
+
#if base.PLATFORM_IS_UNIX {
- // @TODO: use syscall instead
+ // @TODO: use syscall instead (it'll allow other functions called write)
write ::= #foreign("write", base.libc) fn(#C int, #C &"const void", #C size_t) #C long;
- open ::= #foreign("open", base.libc) fn (#C &"const char", #C int) #C int;
+ open ::= #foreign("open", base.libc) fn (#C &"const char", #C int, #C unsigned) #C int;
+ close ::= #foreign("close", base.libc) fn (#C int) #C int;
+
+ DEFAULT_MODE ::= 0o644;
O_RDONLY ::= 0x00;
O_WRONLY ::= 0x01;
@@ -26,20 +46,27 @@ str_to_cstr ::= fn(s: []char) []char {
size -= bytes_written;
buf += bytes_written;
}
- true
+ return true;
}
raw_stdout ::= fn() RawFile {
- 1
+ return 1;
}
raw_stderr ::= fn() RawFile {
- 2
+ return 2;
}
- file_open_write ::= fn(name: []char) f: RawFile, success: bool {
+ raw_file_open_write ::= fn(name: []char) f: RawFile, err := FILE_ERR_OK {
cstr := str_to_cstr(name);
defer mem.dels(cstr);
// @TODO: switch to bitwise or when that exists
- f = open(&cstr[0], (O_WRONLY + O_CREAT) as #C int) as RawFile;
- success = f != -1;
+ f = open(&cstr[0], (O_WRONLY + O_CREAT) as #C int, DEFAULT_MODE as #C unsigned) as RawFile;
+ if f == -1 {
+ err = FILE_ERR_MISC; // @TODO
+ }
+ }
+ raw_file_close ::= fn(f: RawFile) err := FILE_ERR_OK {
+ if close(f as #C int) == -1 {
+ err = FILE_ERR_MISC; // @TODO
+ }
}
} else {
// @TODO: on windows, use WriteFile
@@ -47,65 +74,97 @@ str_to_cstr ::= fn(s: []char) []char {
RawFile ::= &void;
raw_file_write ::= fn(file: RawFile, buf: &void, size: int) bool {
bytes_written := fwrite(buf, 1, size, file) as int;
- bytes_written == size
+ return bytes_written == size;
}
raw_stdout ::= fn() RawFile {
- #builtin("stdout")
+ return #builtin("stdout");
}
raw_stderr ::= fn() RawFile {
- #builtin("stdout")
+ return #builtin("stderr");
}
- file_open_write ::= fn(name: []char) f: RawFile, success: bool {
+ raw_file_open_write ::= fn(name: []char) f: RawFile, err := FILE_ERR_OK {
cstr := base.str_to_cstr(name);
defer mem.dels(cstr);
mode := "w\0";
f = fopen(&cstr[0], &mode[0]);
- success = f != null;
+ if f == null {
+ err = FILE_ERR_MISC; // @TODO
+ }
+ }
+ raw_file_close ::= fn(f: RawFile) err := FILE_ERR_OK {
+ if fclose(f) != 0 {
+ err = FILE_ERR_MISC; // @TODO
+ }
}
}
-
File ::= struct {
BUFSZ ::= 4096;
raw : RawFile;
- written : int; // ranges from 0 to FILE_BUFSZ-1
+ buffer_used : int; // ranges from 0 to FILE_BUFSZ-1
nobuffer : bool; // if true, flush after every write
buffer : [BUFSZ]char;
}
-raw_file_to_file ::= fn(raw : RawFile) f: File {
+raw_file_to_file ::= fn(raw : RawFile, f: &File) {
f.raw = raw;
}
std_out, std_err : File;
-file_flush ::= fn(use f: &File) {
- raw_file_write(raw, &buffer[0], written);
- written = 0;
+fopen_write ::= fn(name: []char) f: &File, error: FileError {
+ raw : RawFile;
+ raw, error = raw_file_open_write(name);
+ if !error {
+ f = mem.new(File);
+ raw_file_to_file(raw, f);
+ }
+}
+
+flush ::= fn(use f: &File) {
+ raw_file_write(raw, &buffer[0], buffer_used);
+ buffer_used = 0;
+}
+
+fclose ::= fn(f: &File) err: FileError {
+ err = raw_file_close(f.raw);
+ mem.del(f);
}
-file_writes ::= fn(use f: &File, s : []char) {
+fwrites ::= fn(use f: &File, s : []char) {
if f.nobuffer {
raw_file_write(raw, &s[0], s.len);
return;
}
- if written + s.len > BUFSZ {
- file_flush(f);
+ if buffer_used + s.len > BUFSZ {
+ flush(f);
if s.len > BUFSZ {
raw_file_write(raw, &s[0], s.len);
} else {
mem.mem_copy(&buffer[0], &s[0], s.len);
- written = s.len;
+ buffer_used = s.len;
}
} else {
- mem.mem_copy(&buffer[written], &s[0], s.len);
- written += s.len;
+ mem.mem_copy(&buffer[buffer_used], &s[0], s.len);
+ buffer_used += s.len;
}
}
+fputs ::= fn(f: &File, s: []char) {
+ fwrites(f, s);
+ fwrites(f, "\n");
+}
+
+puts ::= fn(s: []char) {
+ fputs(&std_out, s);
+}
+
+
io_init ::= fn() {
- std_out = raw_file_to_file(raw_stdout());
+ raw_file_to_file(raw_stdout(), &std_out);
std_out.nobuffer = true;
- std_err = raw_file_to_file(raw_stderr());
+ raw_file_to_file(raw_stderr(), &std_err);
std_err.nobuffer = true;
}
+
+#init io_init();
diff --git a/std/mem.toc b/std/mem.toc
index 9ea9b12..b6af0fe 100644
--- a/std/mem.toc
+++ b/std/mem.toc
@@ -1,6 +1,6 @@
#include "std/base.toc", base;
-// TODO: check for failed calloc
+// @TODO: check for failed calloc
calloc ::= #foreign("calloc", base.libc) fn(#C size_t, #C size_t) #C &"void";
free ::= #foreign("free", base.libc) fn(#C &"void");
@@ -15,7 +15,6 @@ news ::= fn(t :: Type, n : int) []t {
return s;
}
-// TODO(eventually): use type information to make this just one function
del ::= fn(t::=, x: &t) {
free(x);
}
@@ -23,3 +22,15 @@ del ::= fn(t::=, x: &t) {
dels ::= fn(t::=, x: []t) {
free(x.data);
}
+
+
+// @OPTIM @OPTIM @OPTIM
+mem_copy ::= fn(out: &void, in: &void, n : int) {
+ out_u8 : &u8 = out;
+ in_u8 : &u8 = in;
+ for i := 0..n-1 {
+ *out_u8 = *in_u8;
+ out_u8 += 1;
+ in_u8 += 1;
+ }
+}
diff --git a/test.toc b/test.toc
index d79f526..8523940 100644
--- a/test.toc
+++ b/test.toc
@@ -1,5 +1,22 @@
-f();
+#include "std/io.toc", io;
+#include "std/base.toc", base;
-f ::= fn( ) int {
- return 3;
+main ::= fn() {
+ file, err := io.fopen_write("test.txt");
+ if err {
+ base.error("Couldn't open file!");
+ }
+ io.fputs(file, "This file has some stuff in it.");
+ io.puts("Hello!");
+ io.puts("yes");
+ io.fputs(file, "here is more stuff for the file.");
+ for i := 1..1000 {
+ io.fwrites(file, "Here's a line in the file");
+ for j := 1..i {
+ io.fwrites(file, "!");
+ }
+ io.fwrites(file, "\n");
+ }
+ io.fclose(file);
}
+main();
diff --git a/toc.c b/toc.c
index 2afbc1c..c63dc36 100644
--- a/toc.c
+++ b/toc.c
@@ -15,6 +15,7 @@
#include <limits.h>
#include <float.h>
#include <inttypes.h>
+#include <errno.h>
#ifndef COMPILE_TIME_FOREIGN_FN_SUPPORT
#define COMPILE_TIME_FOREIGN_FN_SUPPORT 1
diff --git a/tokenizer.c b/tokenizer.c
index 6b4cc1b..3f83e6f 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -375,6 +375,10 @@ static Status tokenize_file(Tokenizer *t, File *file) {
base = 16;
tokr_nextchar(t);
break;
+ case 'o':
+ base = 8;
+ tokr_nextchar(t);
+ break;
default:
/* it's 0/0.something etc. */
break;
diff --git a/types.c b/types.c
index f103f5d..f50bebd 100644
--- a/types.c
+++ b/types.c
@@ -768,7 +768,6 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) {
/* doesn't do any translation on ident or check if it's declared or anything, so make sure it's in the right scope */
static Status type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
-top:;
Declaration *d = i->decl;
assert(d);
if (!(d->flags & DECL_IS_CONST)) {
@@ -838,6 +837,7 @@ top:;
free(s);
return false;
}
+ #if 0
Block *decl_block = i->idents->scope;
if (block_is_at_top_level(decl_block)) {
/*
@@ -855,12 +855,12 @@ top:;
tr->block = prev_block;
goto top;
} else {
- char *s = ident_to_str(i);
- err_print(where, "Use of %s before its declaration.", s);
- info_print(d->where, "%s will be declared here.", s);
- free(s);
- return false;
- }
+ #endif
+ char *s = ident_to_str(i);
+ err_print(where, "Use of %s before its declaration.", s);
+ info_print(d->where, "%s will be declared here.", s);
+ free(s);
+ return false;
}
}
return true;
@@ -2856,7 +2856,7 @@ static Status types_expr(Typer *tr, Expression *e) {
Identifier i = rhs->ident = ident_get_with_len(&nms->body.idents, str.str, str.len);
if (!i) {
char *s = cstr(str.str, str.len);
- err_print(e->where, "\"%s\" is not a member of this namespace.", s);
+ err_print(e->where, "'%s' is not a member of this namespace.", s);
free(s);
return false;
}
@@ -3194,7 +3194,7 @@ static Status types_decl(Typer *tr, Declaration *d) {
d->expr.fn->flags |= FN_EXPR_EXPORT;
}
- if (typer_is_at_top_level(tr)) {
+ if (tr->block == NULL || tr->block->kind == BLOCK_NMS) {
DeclWithCtx dctx = {d, tr->nms, tr->block};
typer_arr_add(tr, tr->all_globals, dctx);
}
@@ -3948,7 +3948,7 @@ top:
}
success:
s->flags |= STMT_TYPED;
- if (tr->block == NULL) {
+ if (tr->block == NULL || tr->block->kind == BLOCK_NMS) {
/* evaluate statements at global scope */
switch (s->kind) {
case STMT_DECL: