summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c4
-rw-r--r--copy.c3
-rw-r--r--decls_cgen.c2
-rw-r--r--eval.c2
-rw-r--r--main.c9
-rw-r--r--parse.c43
-rw-r--r--sdecls_cgen.c2
-rw-r--r--test.toc34
-rw-r--r--types.c17
-rw-r--r--types.h23
10 files changed, 128 insertions, 11 deletions
diff --git a/cgen.c b/cgen.c
index ab65f30..7eebc08 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1997,6 +1997,8 @@ static void cgen_stmt(CGenerator *g, Statement *s) {
cgen_stmt(g, sub);
}
break;
+ case STMT_MESSAGE:
+ break;
}
}
@@ -2051,6 +2053,8 @@ static void cgen_defs_stmt(CGenerator *g, Statement *s) {
cgen_defs_stmt(g, sub);
}
break;
+ case STMT_MESSAGE:
+ break;
}
}
diff --git a/copy.c b/copy.c
index 00d3106..d03782c 100644
--- a/copy.c
+++ b/copy.c
@@ -441,6 +441,9 @@ static void copy_stmt(Copier *c, Statement *out, Statement *in) {
case STMT_DECL:
copy_decl(c, out->decl = allocr_malloc(c->allocr, sizeof *out->decl), in->decl);
break;
+ case STMT_MESSAGE:
+ copy_expr(c, &out->message.text, &in->message.text);
+ break;
}
}
diff --git a/decls_cgen.c b/decls_cgen.c
index 844db46..b9f7a04 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -268,6 +268,8 @@ static void cgen_decls_stmt(CGenerator *g, Statement *s) {
cgen_decls_stmt(g, sub);
}
break;
+ case STMT_MESSAGE:
+ break;
}
}
diff --git a/eval.c b/eval.c
index feb6796..2ca1a23 100644
--- a/eval.c
+++ b/eval.c
@@ -1687,6 +1687,8 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) {
}
eval_exit_stmts(stmt->inc.stmts, last_reached);
} break;
+ case STMT_MESSAGE:
+ break;
}
return true;
}
diff --git a/main.c b/main.c
index a5c8c22..4d5cb93 100644
--- a/main.c
+++ b/main.c
@@ -8,10 +8,8 @@
/*
TODO:
-fix foreign varargs
-user-generated errors
-#returns_code (struct body is a block, to be evaluated at compile time, which returns the actual statements)
- - struct varargs
+allow omission of trailing ; in foo ::= fn() {...} or foo ::= nms {...} or foo ::= struct { ... }
+- just end expressions when you get to a closing brace unless there's an elif, etc.
break
continue
switch
@@ -24,11 +22,12 @@ switch to / add as an alternative: libffi
X ::= newtype(int); or something
don't allow while {3; 5} or for 0..10 { 3; 5 } (once break is added)
any odd number of "s for a string
-allow omission of trailing ; in foo ::= fn() {...} or foo ::= nms {...} or foo ::= struct { ... }
consider- should #sizeof always take a Type? it would be more verbose, but we might not actually need
#sizeof that much, given that we have new.
it probably should, because #sizeof(x[0]) can't be evaluated at compile time if x is not a constant
---
+#returns_code (struct body is a block, to be evaluated at compile time, which returns the actual statements)
+ - struct varargs
macros
*/
diff --git a/parse.c b/parse.c
index a448c76..7a1e59e 100644
--- a/parse.c
+++ b/parse.c
@@ -2011,6 +2011,9 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
fn->where.end = t->token;
return true;
}
+ case DIRECT_ERROR:
+ case DIRECT_WARN:
+ case DIRECT_INFO:
case DIRECT_EXPORT:
case DIRECT_INCLUDE:
case DIRECT_FORCE:
@@ -2531,6 +2534,32 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
++t->token;
goto success;
} break;
+ case DIRECT_ERROR:
+ case DIRECT_WARN:
+ case DIRECT_INFO: {
+ MessageKind kind;
+ if (t->token->direct == DIRECT_ERROR) {
+ kind = MESSAGE_ERROR;
+ } else if (t->token->direct == DIRECT_WARN) {
+ kind = MESSAGE_WARN;
+ } else {
+ kind = MESSAGE_INFO;
+ }
+ ++t->token;
+ s->kind = STMT_MESSAGE;
+ Message *m = &s->message;
+ m->kind = kind;
+ if (!parse_expr(p, &m->text, expr_find_end(p, 0))) {
+ tokr_skip_semicolon(t);
+ return false;
+ }
+ if (!token_is_kw(t->token, KW_SEMICOLON)) {
+ tokr_err(t, "Expected ; at end of statement.");
+ tokr_skip_semicolon(t);
+ return false;
+ }
+ goto success;
+ }
default:
break;
}
@@ -2909,6 +2938,20 @@ static void fprint_stmt(FILE *out, Statement *s) {
fprintf(out, ";\n");
}
break;
+ case STMT_MESSAGE: {
+ Message *m = &s->message;
+ switch (m->kind) {
+ case MESSAGE_ERROR:
+ fprintf(out, "#error ");
+ break;
+ case MESSAGE_WARN:
+ fprintf(out, "#warn ");
+ break;
+ case MESSAGE_INFO:
+ fprintf(out, "#info ");
+ break;
+ }
+ } break;
}
}
diff --git a/sdecls_cgen.c b/sdecls_cgen.c
index f186792..0445851 100644
--- a/sdecls_cgen.c
+++ b/sdecls_cgen.c
@@ -146,6 +146,8 @@ static void cgen_sdecls_stmt(CGenerator *g, Statement *s) {
cgen_sdecls_stmt(g, sub);
}
break;
+ case STMT_MESSAGE:
+ break;
}
}
diff --git a/test.toc b/test.toc
index ba33c5d..db2f0b2 100644
--- a/test.toc
+++ b/test.toc
@@ -1,9 +1,35 @@
printf ::= #foreign("printf","libc.so.6") fn(#C &"const char", #C ..) #C int;
-main ::= fn() {
- x := "hey %ld %ld %ld %ld %ld\n\0";
- printf(&x[0], 5, 3, 8, 9, 4);
+// NOTE: this doesn't work (e.g. "%%%")
+tprintf_valid ::= fn(fmt :: []char, nargs: int) bool {
+ if fmt[fmt.len-1] != '\0' {
+ return false;
+ }
+ count := 0;
+ for x, i := fmt {
+ if x == '%' {
+ if i == fmt.len-1 {
+ count += 1;
+ } elif fmt[i+1] != '%' {
+ count += 1;
+ } else {
+ count -= 1;
+ }
+ }
+ }
+ count == nargs
+};
+
+
+tprintf ::= fn(fmt :: []char, args: ..) {
+ #if !tprintf_valid(fmt, args.len) {
+ #error "Invalid printf format";
+ }
+ f := fmt;
+ printf(&f[0], args);
};
-main(); \ No newline at end of file
+main ::= fn() {
+ tprintf("%d %d%%\n", 3, 4);
+};
diff --git a/types.c b/types.c
index 9f3d2c6..ce40a88 100644
--- a/types.c
+++ b/types.c
@@ -3385,6 +3385,23 @@ static Status types_stmt(Typer *tr, Statement *s) {
}
} break;
+ case STMT_MESSAGE: {
+ Message *m = &s->message;
+ char *text = eval_expr_as_cstr(tr, &m->text, "message");
+ if (!text)
+ return false;
+ switch (m->kind) {
+ case MESSAGE_INFO:
+ info_print(s->where, "%s", text);
+ break;
+ case MESSAGE_WARN:
+ warn_print(s->where, "%s", text);
+ break;
+ case MESSAGE_ERROR:
+ err_print(s->where, "%s", text);
+ return false;
+ }
+ } break;
}
s->flags |= STMT_TYPED;
return true;
diff --git a/types.h b/types.h
index aa50567..885d737 100644
--- a/types.h
+++ b/types.h
@@ -248,11 +248,15 @@ typedef enum {
DIRECT_INCLUDE,
DIRECT_FORCE,
DIRECT_IF,
+ DIRECT_ERROR,
+ DIRECT_WARN,
+ DIRECT_INFO,
DIRECT_COUNT
} Directive;
static const char *directives[DIRECT_COUNT] =
- {"C", "sizeof", "alignof", "export", "foreign", "builtin", "include", "force", "if"};
+ {"C", "sizeof", "alignof", "export", "foreign", "builtin", "include", "force", "if", "error", "warn",
+ "info"};
typedef enum {
KW_SEMICOLON,
@@ -786,10 +790,12 @@ typedef struct Namespace {
} c;
} Namespace;
+
enum {
EXPR_FOUND_TYPE = 0x01
};
+
typedef U8 ExprFlags;
typedef struct Expression {
@@ -900,7 +906,8 @@ typedef enum {
STMT_DECL,
STMT_EXPR,
STMT_RET,
- STMT_INCLUDE
+ STMT_INCLUDE,
+ STMT_MESSAGE
} StatementKind;
enum {
@@ -937,6 +944,17 @@ typedef union {
IncludedFile *inc_file;
} Include;
+typedef enum {
+ MESSAGE_ERROR,
+ MESSAGE_WARN,
+ MESSAGE_INFO
+} MessageKind;
+
+typedef struct {
+ MessageKind kind;
+ Expression text;
+} Message;
+
enum {
STMT_EXPR_NO_SEMICOLON = 0x01,
STMT_INC_TO_NMS = 0x01,
@@ -951,6 +969,7 @@ typedef struct Statement {
Expression expr;
Return ret;
Include inc;
+ Message message; /* #error, #warn, #info */
};
} Statement;