summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-09-27 16:41:45 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-09-27 16:41:45 -0400
commit010e0cc777e77e0668e0b9d1acb5859f8c2a364c (patch)
treebb1f8635035aba71bd2e784451730f59f83367f1
parentd795c15a008a89aa2de86f83f7b01d996757fdbe (diff)
started to add named return values
-rw-r--r--main.c3
-rw-r--r--parse.c89
-rw-r--r--test.toc8
-rw-r--r--tokenizer.c24
-rw-r--r--types.c11
-rw-r--r--util/err.c22
-rw-r--r--util/location.c1
7 files changed, 103 insertions, 55 deletions
diff --git a/main.c b/main.c
index 7e5f93f..bba3a36 100644
--- a/main.c
+++ b/main.c
@@ -39,11 +39,10 @@ int main(int argc, char **argv) {
}
fclose(in);
- err_filename = in_filename;
Identifiers file_idents;
idents_create(&file_idents);
Tokenizer t;
- tokr_create(&t, &file_idents);
+ tokr_create(&t, &file_idents, in_filename);
if (!tokenize_string(&t, contents)) {
err_fprint(TEXT_IMPORTANT("Errors occured while preprocessing.\n"));
return EXIT_FAILURE;
diff --git a/parse.c b/parse.c
index 4e4f5e3..8d6230c 100644
--- a/parse.c
+++ b/parse.c
@@ -124,6 +124,7 @@ typedef struct {
typedef struct {
Array params; /* declarations of the parameters to this function */
+ Array ret_decls; /* array of decls, if this has named return values. otherwise, len & data will be 0. */
Type ret_type;
Block body;
} FnExpr; /* an expression such as fn(x: int) int { 2 * x } */
@@ -217,13 +218,14 @@ typedef struct {
typedef enum {
DECL_END_SEMICOLON,
- DECL_END_RPAREN_COMMA
-} DeclEndType;
+ DECL_END_RPAREN_COMMA,
+ DECL_END_LBRACE_COMMA
+} DeclEndKind;
static bool parse_expr(Parser *p, Expression *e, Token *end);
#define PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR 0x01
-static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_t flags);
+static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags);
static const char *unary_op_to_str(UnaryOp u) {
switch (u) {
@@ -655,8 +657,33 @@ static bool parse_block(Parser *p, Block *b) {
return ret;
}
+static bool is_decl(Tokenizer *t);
+
+static bool parse_decl_list(Parser *p, Array *decls, DeclEndKind decl_end) {
+ Tokenizer *t = p->tokr;
+ bool ret = true;
+ bool first = true;
+ while (t->token->kind != TOKEN_EOF &&
+ (first || (
+ !token_is_kw(t->token - 1, KW_RPAREN) &&
+ !token_is_kw(t->token - 1, KW_LBRACE)))) {
+ first = false;
+ Declaration *decl = arr_add(decls);
+ if (!parse_decl(p, decl, decl_end, PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR)) {
+ ret = false;
+ /* skip to end of param list */
+ while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_RPAREN))
+ t->token++;
+ break;
+ }
+ }
+ return ret;
+}
+
static bool parse_fn_expr(Parser *p, FnExpr *f) {
Tokenizer *t = p->tokr;
+ f->ret_decls.len = 0;
+ f->ret_decls.data = NULL;
/* only called when token is fn */
assert(token_is_kw(t->token, KW_FN));
t->token++;
@@ -670,16 +697,8 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
if (token_is_kw(t->token, KW_RPAREN)) {
t->token++;
} else {
- while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token - 1, KW_RPAREN)) {
- Declaration *decl = arr_add(&f->params);
- if (!parse_decl(p, decl, DECL_END_RPAREN_COMMA, PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR)) {
- ret = false;
- /* skip to end of param list */
- while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_RPAREN))
- t->token++;
- break;
- }
- }
+ if (!parse_decl_list(p, &f->params, DECL_END_RPAREN_COMMA))
+ return false;
}
if (t->token->kind == TOKEN_EOF) {
@@ -691,6 +710,25 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
/* void function */
f->ret_type.kind = TYPE_VOID;
f->ret_type.flags = 0;
+ } else if (is_decl(t)) {
+ arr_create(&f->ret_decls, sizeof(Declaration));
+ if (!parse_decl_list(p, &f->ret_decls, DECL_END_LBRACE_COMMA))
+ return false;
+ t->token--; /* move back to { */
+ assert(f->ret_decls.len);
+ if (f->ret_decls.len > 1 || ((Declaration *)f->ret_decls.data)[0].idents.len) {
+ f->ret_type.kind = TYPE_TUPLE;
+ f->ret_type.flags = 0;
+ arr_create(&f->ret_type.tuple, sizeof(Type));
+ arr_foreach(&f->ret_decls, Declaration, decl) {
+ for (size_t i = 0; i < decl->idents.len; i++) {
+ Type *tuple_type = arr_add(&f->ret_type.tuple);
+ *tuple_type = decl->type;
+ }
+ }
+ } else {
+ f->ret_type = ((Declaration *)f->ret_decls.data)[0].type;
+ }
} else {
if (!parse_type(p, &f->ret_type)) {
ret = false;
@@ -735,17 +773,17 @@ static void fprint_expr(FILE *out, Expression *e);
#define NOT_AN_OP -1
-#define CAST_PRECEDENCE 1
+#define CAST_PRECEDENCE 2
static int op_precedence(Keyword op) {
switch (op) {
case KW_EQ: return 0;
+ case KW_COMMA: return 1;
case KW_LT: return 3;
case KW_GT: return 3;
case KW_LE: return 3;
case KW_GE: return 3;
case KW_EQEQ: return 3;
case KW_NE: return 3;
- case KW_COMMA: return 5;
case KW_PLUS: return 10;
case KW_MINUS: return 20;
case KW_AMPERSAND: return 25;
@@ -1246,18 +1284,20 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
}
}
-static inline bool ends_decl(Token *t, DeclEndType ends_with) {
+static inline bool ends_decl(Token *t, DeclEndKind ends_with) {
if (t->kind != TOKEN_KW) return false;
switch (ends_with) {
case DECL_END_SEMICOLON:
return t->kw == KW_SEMICOLON;
case DECL_END_RPAREN_COMMA:
return t->kw == KW_RPAREN || t->kw == KW_COMMA;
+ case DECL_END_LBRACE_COMMA:
+ return t->kw == KW_LBRACE || t->kw == KW_COMMA;
default: assert(0); return false;
}
}
-static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_t flags) {
+static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags) {
d->val = NULL;
d->where = p->tokr->token->where;
arr_create(&d->idents, sizeof(Identifier));
@@ -1305,8 +1345,13 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_
}
d->type = type;
}
- char end_char = ends_with == DECL_END_SEMICOLON ? ';' : ')';
-
+ const char *end_str;
+ switch (ends_with) {
+ case DECL_END_SEMICOLON: end_str = "';'"; break;
+ case DECL_END_RPAREN_COMMA: end_str = "')' or ','"; break;
+ case DECL_END_LBRACE_COMMA: end_str = "'{' or ','"; break;
+ }
+
if (token_is_kw(t->token, KW_EQ)) {
t->token++;
d->flags |= DECL_FLAG_HAS_EXPR;
@@ -1315,7 +1360,7 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_
expr_flags |= EXPR_CAN_END_WITH_COMMA;
Token *end = expr_find_end(p, expr_flags, NULL);
if (!end || !ends_decl(end, ends_with)) {
- tokr_err(t, "Expected '%c' at end of declaration.", end_char);
+ tokr_err(t, "Expected %s at end of declaration.", end_str);
goto ret_false;
}
if (!parse_expr(p, &d->expr, end)) {
@@ -1325,13 +1370,13 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with, uint16_
if (ends_decl(t->token, ends_with)) {
t->token++;
} else {
- tokr_err(t, "Expected '%c' at end of declaration.", end_char);
+ tokr_err(t, "Expected %s at end of declaration.", end_str);
goto ret_false;
}
} else if (ends_decl(t->token, ends_with)) {
t->token++;
} else {
- tokr_err(t, "Expected '%c' or '=' at end of delaration.", end_char);
+ tokr_err(t, "Expected %s or '=' at end of delaration.", end_str);
goto ret_false;
}
diff --git a/test.toc b/test.toc
index b876e96..e93cfb4 100644
--- a/test.toc
+++ b/test.toc
@@ -1,10 +1,6 @@
main @= fn() {
- // b := !(5 > 3 && 4 <= 3 && 3 >= 2 || 0 == 1 || 5 != 3);
- N, M @= 2;
- foo := 3;
- bar : float = foo as float;
- test @= fn(x : i64, y : i32, z,w: i64) i32 {
- x + (y as i64) + z + w + x as i32
+ test @= fn(x : i64, y : i32, z,w: i64) ret1 : i64, ret2 : i64 {
+ ret1 = x;
};
};
diff --git a/tokenizer.c b/tokenizer.c
index 02194c5..0ed7f5a 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -151,6 +151,7 @@ typedef struct {
typedef struct {
Array tokens;
char *s; /* string being parsed */
+ const char *filename;
LineNo line;
Token *token; /* token currently being processed */
Identifiers *idents;
@@ -214,13 +215,6 @@ static void fprint_token(FILE *out, Token *t) {
}
}
-static Token *tokr_add(Tokenizer *t) {
- Token *token = arr_add(&t->tokens);
- token->where.line = t->line;
- token->where.code = t->s;
- return token;
-}
-
static inline void tokr_nextchar(Tokenizer *t) {
if (*(t->s) == '\n') {
t->line++;
@@ -252,7 +246,7 @@ static char tokr_esc_seq(Tokenizer *t) {
/* to be used during tokenization */
static void tokenization_err(Tokenizer *t, const char *fmt, ...) {
va_list args;
- Location where = {t->line, t->s};
+ Location where = {t->line, t->s, t->filename};
va_start(args, fmt);
err_vprint(where, fmt, args);
va_end(args);
@@ -279,6 +273,7 @@ static void tokr_err_(const char *src_file, int src_line, Tokenizer *t, const ch
static void tokr_put_location(Tokenizer *tokr, Token *t) {
t->where.line = tokr->line;
t->where.code = tokr->s;
+ t->where.filename = tokr->filename;
}
static void tokr_get_location(Tokenizer *tokr, Token *t) {
@@ -286,10 +281,17 @@ static void tokr_get_location(Tokenizer *tokr, Token *t) {
tokr->s = t->where.code;
}
-static void tokr_create(Tokenizer *t, Identifiers *idents) {
+static void tokr_create(Tokenizer *t, Identifiers *idents, const char *filename) {
arr_create(&t->tokens, sizeof(Token));
arr_reserve(&t->tokens, 256);
t->idents = idents;
+ t->filename = filename;
+}
+
+static Token *tokr_add(Tokenizer *t) {
+ Token *token = arr_add(&t->tokens);
+ tokr_put_location(t, token);
+ return token;
}
static bool tokenize_string(Tokenizer *t, char *str) {
@@ -350,7 +352,7 @@ static bool tokenize_string(Tokenizer *t, char *str) {
if (direct != DIRECT_COUNT) {
/* it's a directive */
Token *token = tokr_add(t);
- token->where.line = t->line;
+ tokr_put_location(t, token);
token->where.code = start_s;
token->kind = TOKEN_DIRECT;
token->direct = direct;
@@ -367,7 +369,7 @@ static bool tokenize_string(Tokenizer *t, char *str) {
if (kw != KW_COUNT) {
/* it's a keyword */
Token *token = tokr_add(t);
- token->where.line = t->line;
+ tokr_put_location(t, token);
token->where.code = start_s;
token->kind = TOKEN_KW;
token->kw = kw;
diff --git a/types.c b/types.c
index 5c1ed9d..7ca8cf6 100644
--- a/types.c
+++ b/types.c
@@ -176,6 +176,9 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Type *t) {
*param_type = decl->type;
}
}
+ arr_foreach(&f->ret_decls, Declaration, decl) {
+ if (!types_decl(tr, decl)) return false;
+ }
return true;
}
@@ -233,7 +236,9 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
err_print(where, "Use of identifier %s before its declaration.\nNote that it is only possible to use a constant function before it is directly declared (e.g. x @= fn() {}).", s);
info_print(d->where, "%s will be declared here.", s);
free(s);
- } /* else, there should have been an error earlier */
+ } else {
+ err_print(d->where, "Declaration type not found yet, even though it has passed.\nThis should not happen.");
+ }
return false;
}
}
@@ -320,10 +325,14 @@ static bool types_expr(Typer *tr, Expression *e) {
tr->ret_type = t->fn.types.data;
arr_foreach(&f->params, Declaration, decl)
add_ident_decls(&f->body, decl);
+ arr_foreach(&f->ret_decls, Declaration, decl)
+ add_ident_decls(&f->body, decl);
bool block_success = true;
block_success = types_block(tr, &e->fn.body);
arr_foreach(&f->params, Declaration, decl)
remove_ident_decls(&f->body, decl);
+ arr_foreach(&f->ret_decls, Declaration, decl)
+ remove_ident_decls(&f->body, decl);
if (!block_success) {
success = false;
goto fn_ret;
diff --git a/util/err.c b/util/err.c
index cc642d4..ac620ec 100644
--- a/util/err.c
+++ b/util/err.c
@@ -21,10 +21,6 @@ static inline const char *ordinals(size_t x) {
}
}
-/* file name of file being processed */
-/* TODO: remove this */
-static const char *err_filename;
-
/* Write directly to the error file */
static void err_fwrite(const void *data, size_t size, size_t n) {
fwrite(data, size, n, stderr);
@@ -41,16 +37,16 @@ static void err_vfprint(const char *fmt, va_list args) {
vfprintf(stderr, fmt, args);
}
-static void err_print_header_(LineNo line) {
- err_fprint(TEXT_ERROR("error:") " at line %lu of %s:\n", (unsigned long)line, err_filename);
+static void err_print_header_(Location where) {
+ err_fprint(TEXT_ERROR("error:") " at line %lu of %s:\n", (unsigned long)where.line, where.filename);
}
-static void info_print_header_(LineNo line) {
- err_fprint(TEXT_INFO("info:") " at line %lu of %s:\n", (unsigned long)line, err_filename);
+static void info_print_header_(Location where) {
+ err_fprint(TEXT_INFO("info:") " at line %lu of %s:\n", (unsigned long)where.line, where.filename);
}
-static void warn_print_header_(LineNo line) {
- err_fprint(TEXT_WARN("warning:") " at line %lu of %s:\n", (unsigned long)line, err_filename);
+static void warn_print_header_(Location where) {
+ err_fprint(TEXT_WARN("warning:") " at line %lu of %s:\n", (unsigned long)where.line, where.filename);
}
static void err_print_footer_(const char *context) {
@@ -70,7 +66,7 @@ static void err_print_footer_(const char *context) {
static void err_vprint(Location where, const char *fmt, va_list args) {
- err_print_header_(where.line);
+ err_print_header_(where);
err_vfprint(fmt, args);
err_print_footer_(where.code);
}
@@ -89,7 +85,7 @@ static void err_print_(int line, const char *file, Location where, const char *f
static void info_print(Location where, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
- info_print_header_(where.line);
+ info_print_header_(where);
err_vfprint(fmt, args);
err_print_footer_(where.code);
va_end(args);
@@ -98,7 +94,7 @@ static void info_print(Location where, const char *fmt, ...) {
static void warn_print(Location where, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
- warn_print_header_(where.line);
+ warn_print_header_(where);
err_vfprint(fmt, args);
err_print_footer_(where.code);
va_end(args);
diff --git a/util/location.c b/util/location.c
index 9a8beb8..4b450ce 100644
--- a/util/location.c
+++ b/util/location.c
@@ -2,6 +2,7 @@ typedef uint32_t LineNo;
typedef struct {
LineNo line;
char *code;
+ const char *filename;
} Location;
bool location_after(Location a, Location b) { /* a is after b? */