summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-10-14 19:20:46 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-10-14 19:20:46 -0400
commit089b01e0849b9eb01b5ab542b0baabe2d6ce1865 (patch)
treecb0d28c62763e18a25bef683d08a6cd0a29bd96a
parentc687651c6d6ece2db2afe6ad0083bfec6c497e52 (diff)
made parameters immutable; fixed other things involving immutability
-rw-r--r--abbrevs.txt1
-rwxr-xr-xbuild.sh10
-rw-r--r--cgen.c16
-rw-r--r--eval.c4
-rw-r--r--main.c1
-rw-r--r--out.c45
-rw-r--r--parse.c33
-rw-r--r--test.toc37
-rw-r--r--tokenizer.c4
-rw-r--r--types.c90
-rw-r--r--types.h28
11 files changed, 175 insertions, 94 deletions
diff --git a/abbrevs.txt b/abbrevs.txt
index d907681..49d29ce 100644
--- a/abbrevs.txt
+++ b/abbrevs.txt
@@ -11,6 +11,7 @@ expr - expression
fn - function
ident - identifier
kw - keyword
+mut - mutable
num - number
op - operator
param - parameter
diff --git a/build.sh b/build.sh
index 619252b..9290a15 100755
--- a/build.sh
+++ b/build.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-if [[ $CC == "" ]]; then
+#!/bin/sh
+if [ "$CC" = "" ]; then
CC=gcc
fi
@@ -12,10 +12,10 @@ fi
ADDITIONAL_FLAGS='-Wno-unused-function'
-if [[ $CC == "clang" ]]; then
- WARNINGS='-Wall -Wextra -Wpedantic -Wshadow -Wimplicit-fallthrough -Wno-unused-parameter'
+if [ "$CC" = "clang" ]; then
+ WARNINGS='-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wimplicit-fallthrough -Wno-unused-parameter'
else
- WARNINGS='-Wall -Wextra -Wpedantic -Wshadow -Wno-pointer-to-int-cast -Wno-unused-parameter'
+ WARNINGS='-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wno-pointer-to-int-cast -Wno-unused-parameter'
fi
DEBUG_FLAGS="-O0 -g3 $WARNINGS -std=c11 -DTOC_DEBUG"
diff --git a/cgen.c b/cgen.c
index 0650ca2..27fb0cf 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1,13 +1,3 @@
-typedef struct {
- FILE *outc;
- unsigned long ident_counter;
- ParsedFile *file;
- Block *block;
- FnExpr *fn; /* which function are we in? (NULL for none) - not used during decls */
- Evaluator *evalr;
- Identifier main_ident;
-} CGenerator;
-
static bool cgen_stmt(CGenerator *g, Statement *s);
static bool cgen_block(CGenerator *g, Block *b);
static bool cgen_expr(CGenerator *g, Expression *e);
@@ -89,8 +79,8 @@ static void cgen_ident(CGenerator *g, Identifier i) {
}
}
-static void cgen_ident_id(CGenerator *g, unsigned long id) {
- cgen_write(g, "a%lu_", id);
+static void cgen_ident_id(CGenerator *g, IdentID id) {
+ cgen_write(g, "a%lu_", (unsigned long)id);
}
static bool cgen_type_post(CGenerator *g, Type *t, Location where);
@@ -522,7 +512,7 @@ static bool cgen_decl(CGenerator *g, Declaration *d) {
cgen_write(g, "{");
cgen_nl(g);
if (!cgen_type_pre(g, &d->expr.type, d->expr.where)) return false;
- cgen_write(g, "expr__");
+ cgen_write(g, " expr__");
if (!cgen_type_post(g, &d->expr.type, d->expr.where)) return false;
cgen_write(g, "; ");
if (!cgen_set(g, NULL, "expr__", &d->expr, NULL))
diff --git a/eval.c b/eval.c
index 71f8888..b9d948f 100644
--- a/eval.c
+++ b/eval.c
@@ -436,7 +436,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
/* WARNING: macros ahead */
#define eval_unary_op_one(low, up, op) \
case BUILTIN_##up: \
- v->low = op of.low; break
+ v->low = (up)(op of.low); break
#define eval_unary_op_nums(builtin, op) \
eval_unary_op_one(i8, I8, op); \
eval_unary_op_one(i16, I16, op); \
@@ -457,7 +457,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
#define eval_binary_op_one(low, up, op) \
case BUILTIN_##up: \
- v->low = lhs.low op rhs.low; break
+ v->low = (up)(lhs.low op rhs.low); break
#define eval_binary_op_nums(builtin, op) \
eval_binary_op_one(i8, I8, op); \
diff --git a/main.c b/main.c
index 00b95a7..05a41b6 100644
--- a/main.c
+++ b/main.c
@@ -3,6 +3,7 @@ TODO:
re-do cgen
arrs are pointers
make sure initializers for global variables are compile-time constants
+allow, e.g.: x := "foo"; x[0] = 'g';
any odd number of "s for a string
*/
#include "toc.c"
diff --git a/out.c b/out.c
index 2bfb426..024b9fa 100644
--- a/out.c
+++ b/out.c
@@ -16,8 +16,8 @@ typedef unsigned char bool;
/* declarations */
-void puti(i64 i);
-void asdf(i64 i, i64( (*ret__)[3]));
+i64 puti(i64 i);
+void dbl(i64((* x)[3]));
void main__();
/* code */
int main() {
@@ -25,43 +25,20 @@ int main() {
return 0;
}
-void puti(i64 i) {
+i64 puti(i64 i) {
printf("%ld\n", i);
}
-void asdf(i64 i, i64( (*ret__)[3])) {
-i64( ret[3]) = {0};
-i64( asdf[3]) = {0};
-(ret[0]) = (0*i);;
-(ret[1]) = (1*i);;
-(ret[2]) = (2*i);;
-{
-size_t i;i64(*arr__in) = asdf; i64(*arr__out) = ret;
-for (i = 0; i < 3; i++) arr__out[i] = arr__in[i];
-};
-{
-size_t i;i64(*arr__in) = *ret__; i64(*arr__out) = asdf;
-for (i = 0; i < 3; i++) arr__out[i] = arr__in[i];
-}return;
+void dbl(i64((* x)[3])) {
+((*x)[0]) = (((*x)[0])*2);;
+((*x)[1]) = (((*x)[1])*2);;
+((*x)[2]) = (((*x)[2])*2);;
}
void main__() {
-i64(* x); {
-i64(*expr__); expr__ = ((i64(*))calloc(1, sizeof(i64)));x = expr__;}
-(*x) = 17;;
-if (((*x)==0)) {
-(*x) = ((1+2)+(3-(5/62)));;
-} else {
-(*x) = ((4+5)+6);;
-};
-(puti((*x)));
-(free(x));
-void (* fptr)(i64, i64((*)[3])); {
-void (*expr__)(i64, i64((*)[3])); expr__ = asdf;fptr = expr__;}
+i64( a[3]) = {0};
+(a[0]) = 1;;
+(dbl((&a)));
+(puti((a[0])));
}
-i64 foo = 5;
-char( bar[5]) = "\x48\x65\x6c\x6c\x6f";
-i64 a = 123; i64 b = 123;
-char x = ((char)97);
-i64 sadkfj = (-1293812);
diff --git a/parse.c b/parse.c
index f949794..01f8096 100644
--- a/parse.c
+++ b/parse.c
@@ -3,6 +3,30 @@ 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, DeclEndKind ends_with, uint16_t flags);
+static const char *expr_kind_to_str(ExprKind k) {
+ switch (k) {
+ case EXPR_LITERAL_FLOAT: return "float literal";
+ case EXPR_LITERAL_INT: return "integer literal";
+ case EXPR_LITERAL_STR: return "string literal";
+ case EXPR_LITERAL_BOOL: return "boolean literal";
+ case EXPR_LITERAL_CHAR: return "character literal";
+ case EXPR_IF: return "if expression";
+ case EXPR_WHILE: return "while expression";
+ case EXPR_CALL: return "function call";
+ case EXPR_DIRECT: return "directive";
+ case EXPR_NEW: return "new expression";
+ case EXPR_CAST: return "cast expression";
+ case EXPR_UNARY_OP: return "unary operator";
+ case EXPR_BINARY_OP: return "binary operator";
+ case EXPR_FN: return "function expression";
+ case EXPR_TUPLE: return "tuple";
+ case EXPR_BLOCK: return "block";
+ case EXPR_IDENT: return "identifier";
+ }
+ assert(0);
+ return "";
+}
+
static const char *unary_op_to_str(UnaryOp u) {
switch (u) {
case UNARY_MINUS: return "-";
@@ -459,7 +483,8 @@ static bool parse_block(Parser *p, Block *b) {
}
static bool is_decl(Tokenizer *t);
-
+static inline bool ends_decl(Token *t, DeclEndKind ends_with);
+
static bool parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end) {
Tokenizer *t = p->tokr;
bool ret = true;
@@ -472,8 +497,8 @@ static bool parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end
Declaration *decl = parser_arr_add(p, 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))
+ /* skip to end of list */
+ while (t->token->kind != TOKEN_EOF && !ends_decl(t->token, decl_end))
t->token++;
break;
}
@@ -499,6 +524,8 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
} else {
if (!parse_decl_list(p, &f->params, DECL_END_RPAREN_COMMA))
return false;
+ arr_foreach(f->params, Declaration, pdecl)
+ pdecl->flags |= DECL_FLAG_PARAM;
}
if (t->token->kind == TOKEN_EOF) {
diff --git a/test.toc b/test.toc
index 1aeca39..148c6de 100644
--- a/test.toc
+++ b/test.toc
@@ -1,33 +1,18 @@
-puti @= fn(i: int) {
+puti @= fn(i: int) int {
#C("printf(\"%ld\\n\", i)");
+ i
};
-asdf @= fn(i: int) [3]int {
- ret : [3]int;
- asdf : [3]int;
- ret[0] = 0*i;
- ret[1] = 1*i;
- ret[2] = 2*i;
- asdf = ret;
- return asdf;
+dbl @= fn(x: &[3]int) {
+ (*x)[0] = (*x)[0] * 2;
+ (*x)[1] = (*x)[1] * 2;
+ (*x)[2] = (*x)[2] * 2;
};
main @= fn() {
- x := new int;
- *x = 17;
- if *x == 0 {
- *x = 1+2+3-5/62;
- } else {
- *x = 4+5+6;
- }
- puti(*x);
-del x;
- fptr := asdf;
-};
-
-foo := 5;
-bar := "Hello";
-a, b := 123;
-x := 'a';
-sadkfj := -1293812;
+ a : [3]int;
+ a[0] = 1;
+ dbl(&a);
+ puti(a[0]);
+}; \ No newline at end of file
diff --git a/tokenizer.c b/tokenizer.c
index a665ca5..1a4f5dd 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -374,7 +374,7 @@ static bool tokenize_string(Tokenizer *t, char *str) {
switch (n.kind) {
case NUM_LITERAL_INT:
if (n.intval > UINTEGER_MAX / (UInteger)base ||
- n.intval * (UInteger)base > ULLONG_MAX - (UInteger)digit) {
+ n.intval * (UInteger)base > UINT_MAX - (UInteger)digit) {
/* too big! */
tokenization_err(t, "Number too big to fit in a numeric literal.");
goto err;
@@ -464,7 +464,7 @@ static bool tokenize_string(Tokenizer *t, char *str) {
}
*strptr = 0;
token->kind = TOKEN_STR_LITERAL;
- token->str.len = strptr - strlit;
+ token->str.len = (size_t)(strptr - strlit);
token->str.str = strlit;
tokr_nextchar(t); /* move past closing " */
continue;
diff --git a/types.c b/types.c
index 8426b3b..39de36a 100644
--- a/types.c
+++ b/types.c
@@ -80,7 +80,61 @@ static bool type_must_eq(Location where, Type *expected, Type *got) {
return true;
}
-/* sometimes prints an error and returns false if the given expression is not an l-value */
+
+/*
+this expression, which is an array, must be mutable (otherwise print an error,
+return false)!
+*/
+static bool expr_arr_must_mut(Expression *e) {
+ switch (e->kind) {
+ case EXPR_IDENT: {
+ IdentDecl *idecl = ident_decl(e->ident);
+ Declaration *d = idecl->decl;
+ if (d->flags & DECL_FLAG_CONST) {
+ err_print(e->where, "Cannot modify a constant array.");
+ return false;
+ }
+ if (d->flags & DECL_FLAG_PARAM) {
+ err_print(e->where, "Parameters are immutable.");
+ return false;
+ }
+ } return true;
+ case EXPR_CAST:
+ case EXPR_CALL:
+ case EXPR_NEW:
+ case EXPR_UNARY_OP:
+ return true;
+ case EXPR_WHILE:
+ assert(e->while_.body.ret_expr);
+ return expr_arr_must_mut(e->while_.body.ret_expr);
+ case EXPR_IF:
+ for (IfExpr *i = &e->if_; i; i->next_elif ? i = &i->next_elif->if_ : (i = NULL)) {
+ assert(i->body.ret_expr);
+ if (!expr_arr_must_mut(i->body.ret_expr))
+ return false;
+ }
+ return true;
+ case EXPR_BLOCK:
+ assert(e->block.ret_expr);
+ return expr_arr_must_mut(e->block.ret_expr);
+ case EXPR_LITERAL_STR:
+ err_print(e->where, "String constants are immutable.");
+ return false;
+ case EXPR_LITERAL_BOOL:
+ case EXPR_FN:
+ case EXPR_TUPLE:
+ case EXPR_LITERAL_FLOAT:
+ case EXPR_LITERAL_CHAR:
+ case EXPR_LITERAL_INT:
+ case EXPR_BINARY_OP:
+ case EXPR_DIRECT:
+ break;
+ }
+ assert(0);
+ return false;
+}
+
+/* prints an error and returns false if the given expression is not an l-value */
static bool expr_must_lval(Expression *e) {
/* NOTE: make sure you update eval when you change this */
switch (e->kind) {
@@ -94,6 +148,11 @@ static bool expr_must_lval(Expression *e) {
info_print(d->where, "%s was declared here.", istr);
return false;
}
+ if (d->flags & DECL_FLAG_PARAM) {
+ char *istr = ident_to_str(e->ident);
+ err_print(e->where, "You cannot modify or take the address of a parameter (%s).", istr);
+ return false;
+ }
return true;
}
@@ -102,7 +161,7 @@ static bool expr_must_lval(Expression *e) {
break;
case EXPR_BINARY_OP:
switch (e->binary.op) {
- case BINARY_AT_INDEX: return true;
+ case BINARY_AT_INDEX: return expr_arr_must_mut(e->binary.lhs);
default: break;
}
break;
@@ -114,9 +173,24 @@ static bool expr_must_lval(Expression *e) {
}
return true;
} break;
- default:
- break;
+ case EXPR_CAST:
+ case EXPR_NEW:
+ case EXPR_FN:
+ case EXPR_LITERAL_FLOAT:
+ case EXPR_LITERAL_CHAR:
+ case EXPR_LITERAL_STR:
+ case EXPR_LITERAL_INT:
+ case EXPR_LITERAL_BOOL:
+ case EXPR_IF:
+ case EXPR_WHILE:
+ case EXPR_CALL:
+ case EXPR_DIRECT:
+ case EXPR_BLOCK: {
+ err_print(e->where, "Cannot use %s as l-value.", expr_kind_to_str(e->kind));
+ return false;
}
+ }
+ assert(0);
return false;
}
@@ -622,11 +696,16 @@ static bool types_expr(Typer *tr, Expression *e) {
if (!types_expr(tr, &arg->val))
return false;
}
+ if (f->type.kind == TYPE_UNKNOWN) {
+ e->type.kind = TYPE_UNKNOWN;
+ return true;
+ }
if (f->type.kind != TYPE_FN) {
char *type = type_to_str(&f->type);
err_print(e->where, "Calling non-function (type %s).", type);
return false;
}
+
Type *ret_type = f->type.fn.types;
Type *param_types = ret_type + 1;
Argument *args = c->args;
@@ -831,7 +910,6 @@ static bool types_expr(Typer *tr, Expression *e) {
switch (e->binary.op) {
case BINARY_SET:
if (!expr_must_lval(e->binary.lhs)) {
- err_print(e->where, "You can only assign to an lvalue."); /* FEATURE: better err */
return false;
}
/* fallthrough */
@@ -988,7 +1066,7 @@ static bool types_decl(Typer *tr, Declaration *d) {
goto ret;
}
d->type = d->expr.type;
- d->type.flags &= ~TYPE_FLAG_FLEXIBLE; /* x := 5; => x is not flexible */
+ d->type.flags &= (uint16_t)~(uint16_t)TYPE_FLAG_FLEXIBLE; /* x := 5; => x is not flexible */
}
if (d->flags & DECL_FLAG_CONST) {
if (!(d->flags & DECL_FLAG_FOUND_VAL)) {
diff --git a/types.h b/types.h
index 6c65a0a..f21ff3f 100644
--- a/types.h
+++ b/types.h
@@ -25,6 +25,8 @@ typedef int64_t I64;
typedef float F32;
typedef double F64;
+typedef U32 IdentID; /* identifier ID for cgen (anonymous variables) */
+
typedef uint32_t LineNo;
typedef struct {
LineNo line;
@@ -342,11 +344,17 @@ typedef struct {
typedef struct {
struct Expression *cond; /* NULL = this is an else */
struct Expression *next_elif; /* next elif/else of this statement */
+ struct {
+ IdentID id;
+ } c;
Block body;
} IfExpr;
typedef struct {
struct Expression *cond;
+ struct {
+ IdentID id;
+ } c;
Block body;
} WhileExpr;
@@ -358,7 +366,7 @@ typedef struct FnExpr {
struct {
/* if name = NULL, this is an anonymous function, and id will be the ID of the fn. */
Identifier name;
- unsigned long id;
+ IdentID id;
} c;
} FnExpr; /* an expression such as fn(x: int) int { 2 * x } */
@@ -370,12 +378,13 @@ typedef struct {
#define EXPR_FLAG_FOUND_TYPE 0x01
typedef struct Expression {
+ Type type;
Location where;
ExprKind kind;
uint16_t flags;
- Type type;
union {
Floating floatl;
+ /* Floating floatl; */
UInteger intl;
StrLiteral strl;
bool booll;
@@ -402,7 +411,10 @@ typedef struct Expression {
WhileExpr while_;
FnExpr fn;
CastExpr cast;
- Block block;
+ struct {
+ Block block;
+ IdentID block_ret_id;
+ };
struct Expression *tuple;
};
} Expression;
@@ -419,6 +431,7 @@ typedef struct Argument {
#define DECL_FLAG_FOUND_TYPE 0x08
#define DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE 0x10 /* has there been an error about this decl referencing itself? */
#define DECL_FLAG_FOUND_VAL 0x20
+#define DECL_FLAG_PARAM 0x40 /* is this a parameter declaration? (needed because parameters are immutable) */
/* OPTIM: Instead of using dynamic arrays, do two passes. */
typedef struct Declaration {
@@ -483,3 +496,12 @@ typedef struct Typer {
Type ret_type; /* the return type of the function we're currently parsing. */
} Typer;
+typedef struct {
+ FILE *outc;
+ IdentID ident_counter;
+ ParsedFile *file;
+ Block *block;
+ FnExpr *fn; /* which function are we in? (NULL for none) - not used during decls */
+ Evaluator *evalr;
+ Identifier main_ident;
+} CGenerator;