Fixing bugs, pointer arithmetic checking, better for, working on first program
This commit is contained in:
14
ccodegen.cpp
14
ccodegen.cpp
@@ -66,7 +66,7 @@ gen_simple_decl(Ast_Resolved_Type *ast, Intern_String name){
|
||||
|
||||
function void
|
||||
gen_value(Value a){
|
||||
gen("%s", docname(a.type));
|
||||
// gen("%s", docname(a.type));
|
||||
switch(a.type->kind){
|
||||
CASE_INT: {
|
||||
Scratch scratch;
|
||||
@@ -94,10 +94,12 @@ gen_expr(Ast_Expr *ast){
|
||||
}
|
||||
|
||||
CASE(INDEX, Index){
|
||||
gen("(");
|
||||
gen_expr(node->expr);
|
||||
gen("[");
|
||||
gen_expr(node->index);
|
||||
gen("]");
|
||||
gen(")");
|
||||
BREAK();
|
||||
}
|
||||
|
||||
@@ -335,7 +337,7 @@ gen_ast(Ast *ast){
|
||||
if(sym->type_val->kind == TYPE_STRUCT){
|
||||
Ast_Struct *agg = (Ast_Struct *)sym->type_val->ast;
|
||||
if(node->value->kind == AST_STRUCT){
|
||||
gen("struct %s{", node->name.str);
|
||||
gen("typedef struct %s{", node->name.str);
|
||||
global_indent++;
|
||||
For(agg->members){
|
||||
genln("");
|
||||
@@ -347,7 +349,7 @@ gen_ast(Ast *ast){
|
||||
gen_ast(it);
|
||||
}
|
||||
global_indent--;
|
||||
genln("};");
|
||||
genln("}%s;", node->name.str);
|
||||
}
|
||||
else{
|
||||
// Type alias
|
||||
@@ -428,12 +430,18 @@ typedef U64 SizeU;
|
||||
typedef S64 SizeS;
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
typedef S32 Bool;
|
||||
|
||||
typedef struct String{
|
||||
U8 *str;
|
||||
S64 len;
|
||||
}String;
|
||||
#define LIT(x) (String){.str=(U8 *)x, .len=sizeof(x)-1}
|
||||
|
||||
void entry();
|
||||
int main(){
|
||||
entry();
|
||||
}
|
||||
)==");
|
||||
|
||||
F64 resolve_begin = os_time();
|
||||
|
||||
9
main.cpp
9
main.cpp
@@ -77,7 +77,6 @@ Expr:
|
||||
|
||||
|
||||
@todo
|
||||
[ ] - Fix casting
|
||||
[ ] - Make sure pointer arithmetic works
|
||||
[ ] - Passing down program to compile through command line
|
||||
[ ] - More for loop variations
|
||||
@@ -108,10 +107,12 @@ Expr:
|
||||
[ ] - Compound that zeros values - .{} , Compound that assumes defaults from struct definition - {}
|
||||
|
||||
@donzo
|
||||
[x] - We are parsing wrong here: (t.str=(&string_to_lex.str)[i]);
|
||||
[x] - Test new operators, add constant eval for them
|
||||
[x] - lvalue, rvalue concept so we cant assign value to some arbitrary weird expression
|
||||
[x] - More basic types
|
||||
[x] - Implementing required operations int128
|
||||
[x] - Fix casting
|
||||
[x] - Add basic support for floats
|
||||
[x] - Converting from U64 token to S64 Atom introduces unnanounced error (negates) - probably need big int
|
||||
[x] - Add basic setup for new type system
|
||||
@@ -167,7 +168,7 @@ int main(){
|
||||
|
||||
|
||||
String result = {};
|
||||
#if 1
|
||||
#if 0
|
||||
result = compile_file("globals.kl"_s);
|
||||
printf("%s", result.str);
|
||||
result = compile_file("enums.kl"_s);
|
||||
@@ -178,12 +179,12 @@ int main(){
|
||||
printf("%s", result.str);
|
||||
result = compile_file("lambdas.kl"_s);
|
||||
printf("%s", result.str);
|
||||
#endif
|
||||
result = compile_file("new_types.kl"_s);
|
||||
printf("%s", result.str);
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
result = compile_file("program.kl"_s);
|
||||
FILE *f = fopen("program.c", "w");
|
||||
assert(f);
|
||||
|
||||
@@ -118,7 +118,9 @@ function Ast_Expr *parse_expr(S64 minbp = 0);
|
||||
function Ast_Expr *
|
||||
parse_init_stmt(Ast_Expr *expr){
|
||||
Token *token = token_get();
|
||||
if(token->kind == TK_ColonAssign && expr->kind != AST_IDENT) parsing_error(expr->pos, "Binding with [:=] to something that is not an identifier");
|
||||
if(token->kind == TK_ColonAssign && expr->kind != AST_IDENT)
|
||||
parsing_error(expr->pos, "Binding with [:=] to something that is not an identifier");
|
||||
|
||||
if(token_is_assign(token)){
|
||||
token_next();
|
||||
Ast_Expr *value = parse_expr();
|
||||
@@ -359,7 +361,7 @@ binding_power(Binding binding, Token_Kind kind){
|
||||
Postfix: switch(kind){
|
||||
case TK_OpenBracket:
|
||||
case TK_OpenParen:
|
||||
return {20, -2};
|
||||
return {21, -2};
|
||||
default: return{-1,-1};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ unary_test :: ()
|
||||
var2: S64 = 20
|
||||
var_bool: Bool = !var1 == !var2
|
||||
|
||||
pointer: *S64
|
||||
pointer += 10
|
||||
// pointer = pointer + pointer
|
||||
|
||||
// uns: U64 = -int_val
|
||||
// int_float: S64 = float_val
|
||||
|
||||
26
program.c
26
program.c
@@ -16,6 +16,7 @@ typedef U64 SizeU;
|
||||
typedef S64 SizeS;
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
typedef S32 Bool;
|
||||
|
||||
typedef struct String{
|
||||
U8 *str;
|
||||
@@ -23,13 +24,28 @@ typedef struct String{
|
||||
}String;
|
||||
#define LIT(x) (String){.str=(U8 *)x, .len=sizeof(x)-1}
|
||||
|
||||
struct Lex_Stream{
|
||||
U8 *stream;
|
||||
U8 *end;
|
||||
};
|
||||
void entry();
|
||||
int main(){
|
||||
entry();
|
||||
}
|
||||
|
||||
typedef struct Token{
|
||||
U8 *str;
|
||||
S64 len;
|
||||
}Token;
|
||||
Bool is_numeric(U8 c){
|
||||
Bool result = ((c>=48)&&(c<=57));
|
||||
return result;
|
||||
}
|
||||
void entry(){
|
||||
String string_to_lex = LIT("Identifier 2425525 Not_Number");
|
||||
Token t;
|
||||
for(S64 i = 0;(i<string_to_lex.len);(i+=1)){
|
||||
(string_to_lex.str[0]=64);
|
||||
if(is_numeric((string_to_lex.str[i]))){
|
||||
(t.str=(&(string_to_lex.str[i])));
|
||||
for(;is_numeric((string_to_lex.str[i]));){
|
||||
(i+=1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
program.kl
22
program.kl
@@ -1,11 +1,21 @@
|
||||
|
||||
Lex_Stream :: struct
|
||||
stream: *U8
|
||||
end : *U8
|
||||
Token :: struct
|
||||
str: *U8
|
||||
len: S64
|
||||
|
||||
main :: (): int
|
||||
|
||||
is_numeric :: (c: U8): Bool
|
||||
result := c >= '0 && c <= '9
|
||||
return result
|
||||
|
||||
entry :: ()
|
||||
string_to_lex := "Identifier 2425525 Not_Number"
|
||||
|
||||
|
||||
t: Token
|
||||
for i := 0, i < string_to_lex.len, i+=1
|
||||
string_to_lex.str[0] = 64
|
||||
if is_numeric(string_to_lex.str[i])
|
||||
t.str = &string_to_lex.str[i]
|
||||
for is_numeric(string_to_lex.str[i])
|
||||
i+=1
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ convert_untyped_to_typed(Token *pos, Value a, Ast_Resolved_Type *new_type){
|
||||
assert(a.type == untyped_int);
|
||||
else if(is_int(a.type) && is_float(new_type))
|
||||
a.f64_val = bigint_as_float(&a.big_int_val); // @leak bigint
|
||||
else if(is_int(a.type) && is_pointer(new_type))
|
||||
;
|
||||
else if(is_float(a.type) && is_float(new_type))
|
||||
; // nothing to do
|
||||
else if(is_bool(a.type) && is_bool(new_type))
|
||||
@@ -67,11 +69,18 @@ convert_untyped_to_typed(Token *pos, Value a, Ast_Resolved_Type *new_type){
|
||||
|
||||
function void
|
||||
make_sure_types_are_compatible(Token *pos, Value *a, Value *b){
|
||||
if(is_typed(a->type) && is_typed(b->type)){
|
||||
if((is_pointer(a->type) && is_int(b->type)) || (is_pointer(b->type) && is_int(a->type))){
|
||||
return;
|
||||
}
|
||||
else if(is_pointer(a->type) && is_pointer(b->type)){
|
||||
goto fail;
|
||||
}
|
||||
else if(is_typed(a->type) && is_typed(b->type)){
|
||||
if(a->type != b->type){
|
||||
parsing_error(pos, "Type mismatch in make_sure_types_are_compatible - left: %s right: %s", docname(a->type), docname(b->type));
|
||||
fail: parsing_error(pos, "Type mismatch in make_sure_types_are_compatible - left: %s right: %s", docname(a->type), docname(b->type));
|
||||
}
|
||||
}
|
||||
|
||||
if(is_untyped(a->type) && is_typed(b->type)){
|
||||
assert(is_typed(b->type));
|
||||
*a = convert_untyped_to_typed(pos, *a, b->type);
|
||||
@@ -80,7 +89,6 @@ make_sure_types_are_compatible(Token *pos, Value *a, Value *b){
|
||||
assert(is_typed(a->type));
|
||||
*b = convert_untyped_to_typed(pos, *b, a->type);
|
||||
}
|
||||
|
||||
else if(is_int(a->type) && is_float(b->type)){
|
||||
*a = value_float(a->big_int_val);
|
||||
}
|
||||
@@ -92,7 +100,7 @@ make_sure_types_are_compatible(Token *pos, Value *a, Value *b){
|
||||
function Value
|
||||
compare_values(Token *pos, Token_Kind op, Value a, Value b, bool is_const){
|
||||
if(!(is_numeric(a.type) && is_numeric(b.type)))
|
||||
parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
|
||||
parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(b.type));
|
||||
|
||||
make_sure_types_are_compatible(pos, &a, &b);
|
||||
|
||||
@@ -146,7 +154,7 @@ eval_binary(Token *pos, Token_Kind op, Value a, Value b, bool is_const){
|
||||
return compare_values(pos, op, a, b, is_const);
|
||||
|
||||
if(!(is_numeric(a.type) && is_numeric(b.type)))
|
||||
parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
|
||||
parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(b.type));
|
||||
|
||||
make_sure_types_are_compatible(pos, &a, &b);
|
||||
|
||||
@@ -261,30 +269,45 @@ eval_unary(Token *pos, Token_Kind op, Value *a, bool is_const){
|
||||
}
|
||||
|
||||
function void
|
||||
convert_untyped_to_typed_default(Operand *op){
|
||||
if(!op) return;
|
||||
try_converting_untyped_to_typed(Operand *op){
|
||||
if(is_untyped(op->type)){
|
||||
if(op->type->kind == TYPE_UNTYPED_INT) op->type = type_s64;
|
||||
else if(op->type->kind == TYPE_UNTYPED_BOOL) op->type = type_bool;
|
||||
else if(op->type->kind == TYPE_UNTYPED_STRING) op->type = type_string;
|
||||
else if(op->type->kind == TYPE_UNTYPED_FLOAT) op->type = type_f64;
|
||||
else invalid_codepath;
|
||||
switch(op->type->kind){
|
||||
case TYPE_UNTYPED_INT: op->type = type_s64; break;
|
||||
case TYPE_UNTYPED_BOOL: op->type = type_bool; break;
|
||||
case TYPE_UNTYPED_STRING: op->type = type_string; break;
|
||||
case TYPE_UNTYPED_FLOAT: op->type = type_f64; break;
|
||||
default: invalid_codepath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum{
|
||||
TYPE_AND_EXPR_REQUIRED = 0,
|
||||
TYPE_CAN_BE_NULL = 1,
|
||||
EXPR_CAN_BE_NULL = 2
|
||||
};
|
||||
|
||||
function void
|
||||
make_sure_types_are_compatible_for_assignment(Token *pos, Operand *expr, Ast_Resolved_Type *type = 0){
|
||||
make_sure_value_is_compatible_with_type(Token *pos, Operand *expr, Ast_Resolved_Type *type, U64 debug_flag){
|
||||
if(type == expr->type){
|
||||
assert(type);
|
||||
assert(expr->type);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!type)
|
||||
convert_untyped_to_typed_default(expr);
|
||||
else if(!expr->type)
|
||||
if(!type){
|
||||
assert(is_flag_set(debug_flag, TYPE_CAN_BE_NULL));
|
||||
assert(expr->type);
|
||||
try_converting_untyped_to_typed(expr);
|
||||
}
|
||||
else if(!expr->type){
|
||||
assert(is_flag_set(debug_flag, EXPR_CAN_BE_NULL));
|
||||
assert(type);
|
||||
expr->type = type;
|
||||
else if(is_untyped(expr->type))
|
||||
}
|
||||
else if(is_untyped(expr->type)){
|
||||
expr->value = convert_untyped_to_typed(pos, expr->value, type);
|
||||
}
|
||||
|
||||
if(type && expr->type != type){
|
||||
parsing_error(pos, "Assigning but incompatible types, expression: %s expected var type: %s", docname(expr->type), docname(type));
|
||||
@@ -362,10 +385,16 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
||||
}
|
||||
|
||||
CASE(FOR, For){
|
||||
if(node->init && node->cond == 0 && node->iter == 0){
|
||||
if(!is_flag_set(node->init->flags, AST_STMT)){
|
||||
node->cond = node->init;
|
||||
node->init = 0;
|
||||
}
|
||||
}
|
||||
|
||||
resolve_expr(node->init, ret);
|
||||
Operand cond = resolve_expr(node->cond); // @todo: typechecking
|
||||
resolve_expr(node->cond, ret);
|
||||
resolve_expr(node->iter, ret);
|
||||
unused(cond);
|
||||
resolve_stmt_block(node->block, ret);
|
||||
BREAK();
|
||||
}
|
||||
@@ -392,10 +421,16 @@ resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
||||
function Operand
|
||||
require_const_int(Ast_Expr *expr, B32 ast_can_be_null){
|
||||
Operand op = resolve_expr(expr);
|
||||
if(expr == 0 && ast_can_be_null) return op;
|
||||
else if(expr == 0) parsing_error(expr->pos, "This field cannot be null");
|
||||
if(!op.is_const) parsing_error(expr->pos, "Expected a const value");
|
||||
if(!is_int(op.type)) parsing_error(expr->pos, "Expected a constant integer got instead %s", docname(op.type));
|
||||
|
||||
if(expr == 0 && ast_can_be_null)
|
||||
return op;
|
||||
else if(expr == 0)
|
||||
parsing_error(expr->pos, "This field cannot be null");
|
||||
|
||||
if(!op.is_const)
|
||||
parsing_error(expr->pos, "Expected a const value");
|
||||
if(!is_int(op.type))
|
||||
parsing_error(expr->pos, "Expected a constant integer got instead %s", docname(op.type));
|
||||
|
||||
return op;
|
||||
}
|
||||
@@ -410,7 +445,7 @@ resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
|
||||
Ast_Resolved_Type *type =
|
||||
resolve_typespec(it->typespec, AST_CANT_BE_NULL);
|
||||
Operand default_value = resolve_expr(it->default_value, type);
|
||||
make_sure_types_are_compatible_for_assignment(it->pos, &default_value, type);
|
||||
make_sure_value_is_compatible_with_type(it->pos, &default_value, type, EXPR_CAN_BE_NULL);
|
||||
args.add(type);
|
||||
}
|
||||
|
||||
@@ -700,7 +735,9 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
||||
}
|
||||
else{ parsing_error(node->pos, "Dereferencing expression %s that is not a [Pointer] or [Type]", type_names[value.type->kind]); return {}; }
|
||||
}break;
|
||||
case TK_Dereference:{return operand_lvalue(type_pointer(value.type));}break;
|
||||
case TK_Dereference:{
|
||||
return operand_lvalue(type_pointer(value.type));
|
||||
}break;
|
||||
case TK_Neg:case TK_Not:case TK_Add:case TK_Sub:{
|
||||
Operand op = resolve_expr(node->expr);
|
||||
eval_unary(node->pos, node->op, &op.value, op.is_const);
|
||||
@@ -724,7 +761,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
||||
assert(node->left->kind == AST_IDENT);
|
||||
|
||||
Operand right = resolve_expr(node->right);
|
||||
make_sure_types_are_compatible_for_assignment(node->pos, &right);
|
||||
make_sure_value_is_compatible_with_type(node->pos, &right, 0, TYPE_CAN_BE_NULL);
|
||||
assert(right.type);
|
||||
|
||||
auto atom = (Ast_Atom *)node->left;
|
||||
@@ -840,7 +877,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
|
||||
rewrite_into_const(node, Ast_Binary, value);
|
||||
result = operand_const_rvalue(value);
|
||||
}
|
||||
else result = operand_rvalue(left.type);
|
||||
else result = operand_rvalue(value.type);
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -903,7 +940,7 @@ resolve_binding(Ast *ast, Sym *sym){
|
||||
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
|
||||
Operand expr = resolve_expr(node->expr, type);
|
||||
assert(expr.type != 0 || type != 0);
|
||||
make_sure_types_are_compatible_for_assignment(node->pos, &expr, type);
|
||||
make_sure_value_is_compatible_with_type(node->pos, &expr, type, EXPR_CAN_BE_NULL|TYPE_CAN_BE_NULL);
|
||||
assert(expr.type);
|
||||
return expr;
|
||||
BREAK();
|
||||
|
||||
Reference in New Issue
Block a user