aboutsummaryrefslogtreecommitdiff
path: root/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap')
-rw-r--r--bootstrap/compiler.h3
-rw-r--r--bootstrap/out.c9
-rw-r--r--bootstrap/outexpr.c2
-rw-r--r--bootstrap/outstmt.c2
-rw-r--r--bootstrap/parsedecl.c127
-rw-r--r--bootstrap/parsestmt.c6
-rw-r--r--bootstrap/token.c10
-rw-r--r--bootstrap/token.h31
8 files changed, 175 insertions, 15 deletions
diff --git a/bootstrap/compiler.h b/bootstrap/compiler.h
index 1aafb6e..e892df6 100644
--- a/bootstrap/compiler.h
+++ b/bootstrap/compiler.h
@@ -152,14 +152,15 @@ struct TypeRefNumeric {
enum TypeRefKind {
TR_UNKNOWN,
- TR_NUMERIC,
TR_BOOL,
+ TR_INT,
TR_STRING,
TR_CLASS
};
struct TypeRef {
enum TypeRefKind kind;
+ unsigned quals;
union {
struct TypeRefNumeric *num;
struct Type *class_;
diff --git a/bootstrap/out.c b/bootstrap/out.c
index f5bfcca..845a875 100644
--- a/bootstrap/out.c
+++ b/bootstrap/out.c
@@ -30,16 +30,19 @@ void emit_ident(struct Ident *ident)
outf("%.*s", ident->node.length, ident->node.name);
}
-/* FIXME int, bool, array... ?? currently it only supports "classes" */
+/* FIXME arrays, optional types, generics... */
void emit_typeref_prefix(struct TypeRef *tr)
{
/* TODO output parantheses for nested types e.g. array of pointer etc. */
switch (tr->kind) {
case TR_UNKNOWN:
ast_error("TR_UNKNOWN encountered at codegen time");
- case TR_NUMERIC:
case TR_BOOL:
- /* No suffix */
+ outf("bool ");
+ break;
+ case TR_INT:
+ /* TODO unsigned and uint64 */
+ outf("int ");
break;
case TR_STRING:
case TR_CLASS:
diff --git a/bootstrap/outexpr.c b/bootstrap/outexpr.c
index a5916ba..c6e6f36 100644
--- a/bootstrap/outexpr.c
+++ b/bootstrap/outexpr.c
@@ -140,8 +140,10 @@ static void declare_expr_temps(struct Expr *expr,
share the ID with the preceding E_SEQPOINT and and hence
already declared at this point. */
outf("int");/* TODO use expr->tr */
+ /*emit_typeref_prefix(expr->typeref);*/
outc(' ');
emit_subexpr_varname(expr, target_ident, target_num);
+ /*emit_typeref_suffix(expr->typeref);*/
outf(";\n");
}
}
diff --git a/bootstrap/outstmt.c b/bootstrap/outstmt.c
index bfc82bc..d5286b5 100644
--- a/bootstrap/outstmt.c
+++ b/bootstrap/outstmt.c
@@ -28,7 +28,7 @@ static void emit_compare(struct TypeRef *tr, const char *res_name, int res_id,
static void emit_bool(struct Stmt *stmt, struct Expr *expr)
{
- static const struct TypeRef booltr = { TR_BOOL, { NULL } };
+ static const struct TypeRef booltr = { TR_BOOL, 0, { NULL } };
emit_expr(&booltr, "b", stmt->id, expr);
}
diff --git a/bootstrap/parsedecl.c b/bootstrap/parsedecl.c
index aedf274..7c01886 100644
--- a/bootstrap/parsedecl.c
+++ b/bootstrap/parsedecl.c
@@ -414,8 +414,18 @@ static enum Token parse_paramlist(struct Var **list_out, size_t *count_out)
struct Var *var;
t = tokenize(&li);
- /* TODO var/out parameters */
- if (t != T_UpperIdent) {
+ /* TODO var/out parameters
+ (again, there's a difference between modifying an
+ object and replacing it...) */
+ switch ((int)t) {
+ case T_UpperIdent:
+ case T_KW_bool:
+ case T_KW_byte:
+ case T_KW_int:
+ case T_KW_long:
+ TOKEN_CASES_QUALIFIERS
+ break;
+ default:
if (count_out) {
*count_out = count;
}
@@ -441,22 +451,121 @@ static enum Token parse_paramlist(struct Var **list_out, size_t *count_out)
&current_type->inner_types : &module->types);
- generic types */
+struct QualifierInfo {
+ unsigned qual;
+ int position;
+};
+
static struct TypeRef *parse_type_usage(void)
{
enum Token tok;
struct LexemeInfo li;
struct TypeRef *tr = malloc(sizeof(struct TypeRef));
+ int qualifier_position = 0;
+ static const struct QualifierInfo qualinfos[NUM_QUALIFIERS] = {
+ /* TODO "modifiable object" vs "replaceable object"
+ could use <- vs = operators for "replaceable",
+ but that doens't work inside structs! */
+ { Q_VAR, 1 },
+ { Q_ALIASED, 2 },
+ { Q_VOLATILE, 2 },
+ { Q_WRAPPING, 3 },
+ { Q_SIGNED, 4 },
+ { Q_UNSIGNED, 4 }
+ };
+ unsigned quals = 0;
NO_NULL(tr);
- /* TODO needs to handle different types (identifier, array, etc.) */
- /* TODO needs to handle generic types */
- tok = tokenize(&li);
- if (tok == T_UpperIdent) {
- tr->kind = TR_CLASS;
- tr->u.class_ = map_named_type(li.string, li.len);
+ /* TODO needs to handle:
+ - arrays
+ - optional types
+ - generic types */
+ for (;;) {
+ tok = tokenize(&li);
+ switch ((int)tok) {
+ /* Types */
+ case T_UpperIdent:
+ tr->kind = TR_CLASS;
+ tr->u.class_ = map_named_type(li.string, li.len);
+ goto done;
+ case T_LowerIdent:
+ if ((quals & (Q_WRAPPING|Q_SIGNED|Q_UNSIGNED)) == 0) {
+ error("Expected a type");
+ }
+ unread_token();
+ goto implicit_int;
+ case T_KW_bool:
+ tr->kind = TR_BOOL;
+ goto done;
+ case T_KW_byte:
+ if ((quals & Q_UNSIGNED) != 0) {
+ error("The `byte` type always has the full unsigned range");
+ }
+ tr->kind = TR_INT;
+ /* TODO set range */
+ goto done;
+ case T_KW_int:
+ if ((quals & (Q_WRAPPING|Q_SIGNED|Q_UNSIGNED)) != 0) {
+ error("Redundant `int` keyword after wrapping/signed/unsigned");
+ }
+ implicit_int:
+ tr->kind = TR_INT;
+ /* TODO set range */
+ goto done;
+ /* XXX separate size_t type?
+ - but the platform dependence makes it trickier
+ (behaviour should be the same across platforms)
+ - maybe the size_t type could trap on overflow?
+ (basically, a variant of OoM, except it's the address space)
+ - a size type also makes sense for constraining the length
+ to up to the system size, even if the "logical" maximum
+ is larger (e.g. if the application allows up to e.g. 2^40
+ but is compiled on a 32 bit platform.
+ - BUT with an unknown range of size types, it beomes
+ inconvenient, because size can't be converted to int
+ without an assert/if.
+ - have a "large-array" type? which could optionally
+ be compressed and/or "windowed memory mapped"?
+ - a size_t type could also serve as documentation */
+ case T_KW_long:
+ tr->kind = TR_INT;
+ /* TODO set range */
+ goto done;
+ TOKEN_CASES_QUALIFIERS {
+ struct QualifierInfo info = qualinfos[tok - FIRST_QUALIFIER];
+ if (qualifier_position >= info.position) {
+fprintf(stderr, "qp=%d, ip=%d\n", qualifier_position, info.position);
+ error(info.position == qualifier_position ?
+ "Conflicting type qualifier" :
+ "Wrong order of type qualifiers");
+ } else if (info.position == 4 && (quals&Q_WRAPPING) != 0) {
+ error("wrapping integers are implicitly unsigned");
+ }
+ qualifier_position = info.position;
+ quals |= info.qual;
+ break; }
+ default:
+ error("Expected a type here");
+ }
+ }
+ done:
+ if (tr->kind == TR_BOOL) {
+ if ((quals & (unsigned)~Q_VAR) != 0) {
+ error("bool cannot have any qualifiers other than `var`");
+ }
+ } else if (tr->kind == TR_CLASS) { /* TODO also arrays etc. */
+ if ((quals & (Q_WRAPPING|Q_SIGNED|Q_UNSIGNED)) != 0) {
+ error("wrapping/signed/unsigned are not applicable for objects");
+ }
} else {
- error("Expected a type here");
+ if ((quals & (Q_ALIASED|Q_VOLATILE)) != 0) {
+ error("aliased/volatile are not applicable for int/bool/long");
+ }
+ }
+ if ((quals & Q_WRAPPING) != 0) {
+ quals |= Q_UNSIGNED;
}
+ tr->quals = quals;
return tr;
}
diff --git a/bootstrap/parsestmt.c b/bootstrap/parsestmt.c
index 3daba26..1e3bd9f 100644
--- a/bootstrap/parsestmt.c
+++ b/bootstrap/parsestmt.c
@@ -243,7 +243,11 @@ static enum Token parse_stmt_block(struct Stmt **stmt_out)
error(msg);
}
break; }
- case T_KW_var:
+ TOKEN_CASES_QUALIFIERS
+ case T_KW_bool:
+ case T_KW_byte:
+ case T_KW_int:
+ case T_KW_long:
case T_UpperIdent: {
/* Variable definition */
struct Var *var;
diff --git a/bootstrap/token.c b/bootstrap/token.c
index d1223f0..197fbd0 100644
--- a/bootstrap/token.c
+++ b/bootstrap/token.c
@@ -155,12 +155,16 @@ static enum Token tok_alphanum(struct LexemeInfo *li_out)
CMP_KW(3, and)
CMP_KW(3, end)
CMP_KW(3, for)
+ CMP_KW(3, int)
CMP_KW(3, mod)
CMP_KW(3, not)
/* XXX should there be `and`/`or`, or `all_of`/`any_of`/`none_of`?
maybe there should be a T... safe-vararg, like in Java. */
+ CMP_KW(3, var)
break;
case 4:
+ CMP_KW(4, bool)
+ CMP_KW(4, byte)
CMP_KW(4, case)
CMP_KW(4, code)
CMP_KW(4, elif)
@@ -168,6 +172,7 @@ static enum Token tok_alphanum(struct LexemeInfo *li_out)
CMP_KW(4, enum)
CMP_KW(4, from)
CMP_KW(4, func)
+ CMP_KW(4, long)
CMP_KW(4, none)
CMP_KW(4, sets)
CMP_KW(4, true)
@@ -186,9 +191,11 @@ static enum Token tok_alphanum(struct LexemeInfo *li_out)
CMP_KW(6, export)
CMP_KW(6, record)
CMP_KW(6, return)
+ CMP_KW(6, signed)
CMP_KW(6, switch)
break;
case 7:
+ CMP_KW(7, aliased)
CMP_KW(7, default)
CMP_KW(7, loopend)
CMP_KW(7, returns)
@@ -197,6 +204,9 @@ static enum Token tok_alphanum(struct LexemeInfo *li_out)
case 8:
CMP_KW(8, continue)
CMP_KW(8, modifies)
+ CMP_KW(8, unsigned)
+ CMP_KW(8, volatile)
+ CMP_KW(8, wrapping)
break;
case 9:
CMP_KW(9, loopempty)
diff --git a/bootstrap/token.h b/bootstrap/token.h
index 06a5048..d3a906a 100644
--- a/bootstrap/token.h
+++ b/bootstrap/token.h
@@ -44,8 +44,18 @@ enum Token {
T_KW_record,
T_KW_templates,
T_KW_trait,
+ /* Builtin types */
+ T_KW_bool,
+ T_KW_byte,
+ T_KW_int,
+ T_KW_long,
/* Qualifiers */
T_KW_var,
+ T_KW_aliased,
+ T_KW_volatile,
+ T_KW_wrapping,
+ T_KW_signed,
+ T_KW_unsigned,
/* Generics */
T_KW_of,
T_KW_to,
@@ -88,6 +98,18 @@ enum Token {
T_KW_none
};
+#define FIRST_QUALIFIER T_KW_var
+#define LAST_QUALIFIER T_KW_unsigned
+#define NUM_QUALIFIERS (LAST_QUALIFIER+1 - FIRST_QUALIFIER)
+#define TOKEN_CASES_QUALIFIERS \
+ case T_KW_var: \
+ case T_KW_aliased: \
+ case T_KW_volatile: \
+ case T_KW_wrapping: \
+ case T_KW_signed: \
+ case T_KW_unsigned:
+
+
#define TOKEN_CASES_VALUE_START \
case T_LowerIdent: \
case T_Integer: \
@@ -100,6 +122,15 @@ enum Token {
case T_KW_true: \
case T_KW_none:
+/* Type qualifiers */
+#define Q_VAR 0x01
+#define Q_ALIASED 0x02
+#define Q_VOLATILE 0x04
+#define Q_SIGNED 0x08
+#define Q_UNSIGNED 0x10
+#define Q_WRAPPING 0x20
+
+
struct LexemeInfo {
size_t len;