summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--abbrevs.txt1
-rw-r--r--cgen.c9
-rw-r--r--parse.c79
-rw-r--r--test.toc20
-rw-r--r--tokenizer.c23
-rw-r--r--types.h12
6 files changed, 90 insertions, 54 deletions
diff --git a/abbrevs.txt b/abbrevs.txt
index d694268..1075c21 100644
--- a/abbrevs.txt
+++ b/abbrevs.txt
@@ -20,5 +20,6 @@ ptr - pointer
ret - return
stmt - statement
str - string
+tdecl - type declaration
tokr - tokenizer
val - value
diff --git a/cgen.c b/cgen.c
index aede98d..6ba6cad 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1260,6 +1260,15 @@ static bool cgen_stmt(CGenerator *g, Statement *s) {
cgen_write(g, ";");
cgen_nl(g);
break;
+ case STMT_TDECL:
+ cgen_write(g, "typedef ");
+ if (!cgen_type_pre(g, &s->tdecl.type, s->where)) return false;
+ cgen_write(g, " ");
+ cgen_ident(g, s->tdecl.name);
+ if (!cgen_type_post(g, &s->tdecl.type, s->where)) return false;
+ cgen_write(g, ";");
+ cgen_nl(g);
+ break;
case STMT_RET:
if (!cgen_ret(g, s->ret.flags & RET_FLAG_EXPR ? &s->ret.expr : NULL))
return false;
diff --git a/parse.c b/parse.c
index a8ffa93..c3a0694 100644
--- a/parse.c
+++ b/parse.c
@@ -1,5 +1,5 @@
static bool parse_expr(Parser *p, Expression *e, Token *end);
-
+static bool parse_stmt(Parser *p, Statement *s);
#define PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR 0x01
static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags);
@@ -237,7 +237,7 @@ static inline Expression *parser_new_expr(Parser *p) {
#define EXPR_CAN_END_WITH_LBRACE 0x02
#define EXPR_CAN_END_WITH_COLON 0x04
/* is_vbs can be NULL */
-static Token *expr_find_end(Parser *p, uint16_t flags, bool *is_vbs) {
+static Token *expr_find_end(Parser *p, U16 flags, bool *is_vbs) {
Tokenizer *t = p->tokr;
int paren_level = 0;
int brace_level = 0;
@@ -459,7 +459,6 @@ static bool parse_type(Parser *p, Type *type) {
}
-static bool parse_stmt(Parser *p, Statement *s);
static bool parse_block(Parser *p, Block *b) {
b->flags = 0;
@@ -1304,7 +1303,6 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_
Tokenizer *t = p->tokr;
d->flags = 0;
- /* OPTIM: Maybe don't use a dynamic array or use parser allocator. */
while (1) {
Identifier *ident = parser_arr_add(p, &d->idents);
if (t->token->kind != TOKEN_IDENT) {
@@ -1391,12 +1389,7 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_
ret_false:
/* move past end of decl */
- while (t->token->kind != TOKEN_EOF && !token_is_kw(t->token, KW_SEMICOLON)) {
- t->token++;
- }
- if (token_is_kw(t->token, KW_SEMICOLON)) {
- t->token++; /* move past ; */
- }
+ tokr_skip_semicolon(t);
return false;
}
@@ -1419,30 +1412,46 @@ static bool parse_stmt(Parser *p, Statement *s) {
if (t->token->kind == TOKEN_EOF)
tokr_err(t, "Expected statement.");
s->where = t->token->where;
-
- if (token_is_kw(t->token, KW_RETURN)) {
- s->kind = STMT_RET;
- t->token++;
- s->ret.flags = 0;
- if (token_is_kw(t->token, KW_SEMICOLON)) {
- /* return with no expr */
+ if (t->token->kind == TOKEN_KW) {
+ switch (t->token->kw) {
+ case KW_RETURN: {
+ s->kind = STMT_RET;
t->token++;
- return true;
- }
- s->ret.flags |= RET_FLAG_EXPR;
- Token *end = expr_find_end(p, 0, NULL);
- if (!end) {
- while (t->token->kind != TOKEN_EOF) t->token++; /* move to end of file */
- return false;
+ s->ret.flags = 0;
+ if (token_is_kw(t->token, KW_SEMICOLON)) {
+ /* return with no expr */
+ t->token++;
+ return true;
+ }
+ s->ret.flags |= RET_FLAG_EXPR;
+ Token *end = expr_find_end(p, 0, NULL);
+ if (!end) {
+ while (t->token->kind != TOKEN_EOF) t->token++; /* move to end of file */
+ return false;
+ }
+ if (!token_is_kw(end, KW_SEMICOLON)) {
+ err_print(end->where, "Expected ';' at end of return statement.");
+ t->token = end->kind == TOKEN_EOF ? end : end + 1;
+ return false;
+ }
+ bool success = parse_expr(p, &s->ret.expr, end);
+ t->token = end + 1;
+ return success;
}
- if (!token_is_kw(end, KW_SEMICOLON)) {
- err_print(end->where, "Expected ';' at end of return statement.");
- t->token = end->kind == TOKEN_EOF ? end : end + 1;
- return false;
+ case KW_NEWTYPE:
+ s->kind = STMT_TDECL;
+ t->token++;
+ if (t->token->kind != TOKEN_IDENT) {
+ tokr_err(t, "Expected identifier after \"newtype\".");
+ tokr_skip_semicolon(t);
+ }
+ s->tdecl.name = t->token->ident;
+ t->token++;
+ if (!parse_type(p, &s->tdecl.type))
+ return false;
+ return true;
+ default: break;
}
- bool success = parse_expr(p, &s->ret.expr, end);
- t->token = end + 1;
- return success;
}
if (is_decl(t)) {
s->kind = STMT_DECL;
@@ -1695,9 +1704,7 @@ static void fprint_stmt(FILE *out, Statement *s) {
PARSE_PRINT_LOCATION(s->where);
if (s->flags & STMT_FLAG_VOIDED_EXPR)
fprintf(out, "(void)");
-
switch (s->kind) {
-
case STMT_DECL:
fprint_decl(out, &s->decl);
fprintf(out, ";\n");
@@ -1712,6 +1719,12 @@ static void fprint_stmt(FILE *out, Statement *s) {
fprint_expr(out, &s->ret.expr);
fprintf(out, ";\n");
break;
+ case STMT_TDECL:
+ fprintf(out, "newtype ");
+ fprint_ident(out, s->tdecl.name);
+ fprintf(out, " ");
+ fprint_type(out, &s->tdecl.type);
+ break;
}
}
diff --git a/test.toc b/test.toc
index b9c1909..0304979 100644
--- a/test.toc
+++ b/test.toc
@@ -13,24 +13,8 @@ putf @= fn(x: float) {
");
};
-foo @= fn() [3]int {
- x : [3]int;
- x[0] = 1;
- x[1] = 2;
- x[2] = 3;
- x
-};
-
-getASDF @= fn(i: int) int {
- ASDF @= foo();
- ASDF[i]
-};
+newtype Foo int
main @= fn() {
- // ptriangle @= pascal();
- // puti(ptriangle[49][25]);
- puti(getASDF(2));
- puti(getASDF(1));
- puti(getASDF(0));
-
+ // x : Foo;
};
diff --git a/tokenizer.c b/tokenizer.c
index 2e6bb4d..315379d 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -3,7 +3,7 @@ static const char *keywords[KW_COUNT] =
"+", "-", "*", "!", "&", "/",
"=",
"if", "elif", "else", "while", "return", "fn", "as",
- "new", "del",
+ "new", "del", "newtype",
"int", "i8", "i16", "i32", "i64",
"u8", "u16", "u32", "u64", "float", "f32", "f64",
"char", "bool", "true", "false"};
@@ -490,6 +490,27 @@ static bool tokenize_string(Tokenizer *t, char *str) {
return !has_err;
}
+/*
+ skip to one token past the next semicolon not in braces (or the end of the file).
+*/
+static void tokr_skip_semicolon(Tokenizer *t) {
+ int brace_level = 0;
+ while (t->token->kind != TOKEN_EOF) {
+ if (t->token->kind == TOKEN_KW) switch (t->token->kw) {
+ case KW_LBRACE: brace_level++; break;
+ case KW_RBRACE: brace_level--; break;
+ case KW_SEMICOLON:
+ if (brace_level == 0) {
+ t->token++;
+ return;
+ }
+ break;
+ default: break;
+ }
+ t->token++;
+ }
+}
+
/* ONLY frees tokens, not string literals. You can call this followed by tokr_free. */
static void tokr_free_tokens(Tokenizer *t) {
arr_clear(&t->tokens);
diff --git a/types.h b/types.h
index 2d4e7e4..537c845 100644
--- a/types.h
+++ b/types.h
@@ -169,6 +169,7 @@ typedef enum {
KW_AS,
KW_NEW,
KW_DEL,
+ KW_NEWTYPE,
KW_INT,
KW_I8,
KW_I16,
@@ -470,7 +471,8 @@ typedef struct Declaration {
typedef enum {
STMT_DECL,
STMT_EXPR,
- STMT_RET
+ STMT_RET,
+ STMT_TDECL
} StatementKind;
#define RET_FLAG_EXPR 0x01
@@ -479,12 +481,18 @@ typedef struct {
Expression expr;
} Return;
+typedef struct {
+ Identifier name;
+ Type type;
+} TypeDecl;
+
#define STMT_FLAG_VOIDED_EXPR 0x01 /* the "4;" in fn () { 4; } is a voided expression, but the "4" in fn () int { 4 } is not */
typedef struct Statement {
Location where;
StatementKind kind;
- unsigned short flags;
+ U16 flags;
union {
+ TypeDecl tdecl;
Declaration decl;
Expression expr;
Return ret;