F32 is default float, operator overloads turn literals into default types
This commit is contained in:
@@ -114,7 +114,7 @@ Dot :: (a: Vec3, b: Vec3): F32 ;; return a.x*b.x + a.y*b.y + a.z*b.z
|
||||
|
||||
- [ ] Polymorphism
|
||||
- [x] C like void type
|
||||
- [x] Any with it's dynamic typing
|
||||
- [x] Dynamic typing using Any and operator overloading
|
||||
- [ ] Generics aka compile time polymorphism aka parametric polymorphism
|
||||
- [ ] Something akin to inheritence
|
||||
- [ ] Something akin to C unions or Rust's enums
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
pushd %~dp0
|
||||
rem cl main.cpp -I.. user32.lib
|
||||
clang core_main.cpp -O2 -Wall -Wno-unused-function -fno-exceptions -fdiagnostics-absolute-paths -g -o main.exe -Wl,user32.lib
|
||||
clang core_main.cpp -O0 -Wall -Wno-unused-function -fno-exceptions -fdiagnostics-absolute-paths -g -o main.exe -Wl,user32.lib
|
||||
popd
|
||||
|
||||
@@ -56,7 +56,6 @@ enum{
|
||||
AST_STRICT = bit_flag(3),
|
||||
AST_AGGREGATE = bit_flag(4),
|
||||
AST_AGGREGATE_CHILD = bit_flag(5),
|
||||
AST_ANY_VARGS = bit_flag(6),
|
||||
AST_ATOM = bit_flag(7),
|
||||
AST_FOREIGN = bit_flag(8),
|
||||
AST_DECL = bit_flag(9),
|
||||
|
||||
@@ -796,12 +796,8 @@ compile_to_c_code(){
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef Panic
|
||||
#define Panic(...) (*(volatile int *)0 = 0)
|
||||
#endif
|
||||
|
||||
#ifndef Assert
|
||||
#define Assert(x) do{if(!(x))Panic();}while(0)
|
||||
#define Assert(x) do{if(!(x))(*(volatile int *)0 = 0);}while(0)
|
||||
#endif
|
||||
|
||||
#ifndef AssertMessage
|
||||
|
||||
@@ -444,15 +444,9 @@ parse_lambda(Token *token){
|
||||
Ast_Decl *param = ast_new(Ast_Decl, AST_VAR, name, AST_DECL);
|
||||
param->name = name->intern_val;
|
||||
|
||||
if(token_match(TK_TwoDots)){
|
||||
set_flag(param->flags, AST_ANY_VARGS);
|
||||
}
|
||||
|
||||
else{
|
||||
param->typespec = parse_expr();
|
||||
if(token_match(TK_Assign))
|
||||
param->expr = parse_expr();
|
||||
}
|
||||
|
||||
params.add(param);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ get_default_type_from_untyped(Ast_Type *type){
|
||||
case TYPE_UNTYPED_INT: return type_s64; break;
|
||||
case TYPE_UNTYPED_BOOL: return type_bool; break;
|
||||
case TYPE_UNTYPED_STRING: return type_string; break;
|
||||
case TYPE_UNTYPED_FLOAT: return type_f64; break;
|
||||
case TYPE_UNTYPED_FLOAT: return type_f32; break;
|
||||
default: invalid_codepath;
|
||||
}
|
||||
return 0;
|
||||
@@ -891,24 +891,12 @@ resolve_lambda_type(Ast_Lambda *lambda){
|
||||
}
|
||||
|
||||
For(lambda->args){
|
||||
if(is_flag_set(it->flags, AST_ANY_VARGS)){
|
||||
if(it->expr)
|
||||
compiler_error(it->pos, "Internal compiler error: Default value for .. multiple arguments should be null");
|
||||
if(it->typespec)
|
||||
compiler_error(it->pos, "Internal compiler error: Typespec for .. multiple arguments should be null");
|
||||
|
||||
it->type = type_slice(type_any, it);
|
||||
}
|
||||
|
||||
|
||||
else {
|
||||
Ast_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL);
|
||||
Operand default_value = resolve_expr(it->expr, AST_CAN_BE_NULL, type, 0);
|
||||
make_sure_value_is_compatible_with_type(it->pos, &default_value, type, EXPR_CAN_BE_NULL);
|
||||
|
||||
it->type = type;
|
||||
try_propagating_resolved_type_to_untyped_literals(it->expr, it->type);
|
||||
}
|
||||
|
||||
args.add(it->type);
|
||||
}
|
||||
@@ -1290,16 +1278,27 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str
|
||||
|
||||
// Try finding a operator overload
|
||||
if(!is_const){
|
||||
U64 hash = calculate_hash_for_arguments(left.type, right.type);
|
||||
Ast_Decl *operator_overload = resolve_operator_overload(node->parent_scope, left.type, right.type, node->pos, node->op, hash);
|
||||
Value left_copy = left.value;
|
||||
Value right_copy = right.value;
|
||||
try_converting_untyped_to_default_type(&left_copy);
|
||||
try_converting_untyped_to_default_type(&right_copy);
|
||||
U64 hash = calculate_hash_for_arguments(left_copy.type, right_copy.type);
|
||||
Ast_Decl *operator_overload = resolve_operator_overload(node->parent_scope, left_copy.type, right_copy.type, node->pos, node->op, hash);
|
||||
if(operator_overload){
|
||||
proceed_to_default_operator_handler = false;
|
||||
if(operator_overload->lambda->ret.len != 1){
|
||||
compiler_error(operator_overload->pos, "Operator overload is required to have exactly 1 return value");
|
||||
}
|
||||
|
||||
left.value = left_copy;
|
||||
right.value = right_copy;
|
||||
|
||||
node->resolved_type = operator_overload->type->func.ret;
|
||||
node->resolved_operator_overload = operator_overload;
|
||||
|
||||
// We opt out early because we convert all literals to default type
|
||||
// We don't need to propagate resolved type
|
||||
return operand_rvalue(node->resolved_type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1529,15 +1528,9 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str
|
||||
if(item){
|
||||
set_flag(item->call_flags, CALL_INCLUDED);
|
||||
Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type, field_access_scope);
|
||||
if(is_flag_set(lambda_arg->flags, AST_ANY_VARGS)){
|
||||
make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type->base, TYPE_AND_EXPR_REQUIRED);
|
||||
item->resolved_type = expr.type;
|
||||
}
|
||||
|
||||
else{
|
||||
make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED);
|
||||
item->resolved_type = lambda_arg->type;
|
||||
}
|
||||
|
||||
try_propagating_resolved_type_to_untyped_literals(item->item, item->resolved_type);
|
||||
item->resolved_index = lambda->args.get_index(&lambda_arg);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
VariadicArguments :: (string: *char, args: ..): Any
|
||||
VariadicArguments :: (string: *char, args: []Any): Any
|
||||
return args[0]
|
||||
|
||||
AnyArguments :: (values: []Any)
|
||||
@@ -39,8 +39,6 @@ IntegerToString :: (value: S64, result: *U8, base: S64): *U8
|
||||
*ptr1++ = tmp_char
|
||||
return result
|
||||
|
||||
|
||||
|
||||
StringToDouble :: (s: String): F64
|
||||
sign: F64 = 1.0
|
||||
i := 0
|
||||
@@ -56,7 +54,7 @@ StringToDouble :: (s: String): F64
|
||||
|
||||
return 0
|
||||
|
||||
FormatString :: (buffer: *U8, buffer_len: U64, string: String, args: ..)
|
||||
FormatString :: (buffer: *U8, buffer_len: U64, string: String, args: []Any)
|
||||
// @todo(krzosa): Add consideration of buffer SIZE! Add some function to handle this OutStr or something
|
||||
arg_counter := 0
|
||||
out_buffer_len := 0
|
||||
|
||||
@@ -8,9 +8,29 @@ len : S64
|
||||
*(result.data->*S64) = *(a.data->*S64) + *(b.data->*S64)
|
||||
return result
|
||||
|
||||
"+" :: (a: Any, b: S64): Any
|
||||
result: Any = storage[len++]
|
||||
if a.type == S64
|
||||
*(result.data->*S64) = *(a.data->*S64) + b
|
||||
return result
|
||||
|
||||
"==" :: (a: Any, b: S64): Bool
|
||||
result := false
|
||||
if a.type == S64
|
||||
result = *(a.data->*S64) == b
|
||||
return result
|
||||
|
||||
"==" :: (a: Any, b: Any): Bool
|
||||
result := false
|
||||
if a.type == S64 && b.type == S64
|
||||
result = *(a.data->*S64) == *(b.data->*S64)
|
||||
return result
|
||||
|
||||
main :: (): int
|
||||
a: Any = 10
|
||||
b: Any = 20
|
||||
c := a + b
|
||||
Assert(c.type == S64 && *(c.data->*S64) == 30)
|
||||
Assert(c.type == S64 && c == 30)
|
||||
Assert(a+b+a==c+(5+5))
|
||||
|
||||
return 0
|
||||
@@ -29,13 +29,13 @@ main :: (): int
|
||||
|
||||
// We can also tell the compiler to infer the type
|
||||
this_is_s64_by_default := 10
|
||||
this_is_f64_by_default := 10.1251
|
||||
this_is_f32_by_default := 10.1251
|
||||
this_is_string_by_default := "Thing"
|
||||
|
||||
// Reassigning values is exactly like in other languages
|
||||
this_is_s64_by_default = 20
|
||||
this_is_string_by_default = "Other_Thing"
|
||||
this_is_f64_by_default = 15.1255
|
||||
this_is_f32_by_default = 15.1255
|
||||
|
||||
// @todo: Add type_of operator!!!
|
||||
// Assert(type_of(this_is_string_by_default) == String)
|
||||
@@ -51,7 +51,7 @@ main :: (): int
|
||||
|
||||
// When it comes to runtime variables it's a bit different
|
||||
// To do this we need a cast
|
||||
combining_types := this_is_s64_by_default->F64 + this_is_f64_by_default
|
||||
combining_types := this_is_s64_by_default->F32 + this_is_f32_by_default
|
||||
|
||||
Assert(s64val == 0 && s32val == 0 && s16val == 0 && s8val == 0 && intval == 0 && u64val == 0 && u32val == 0 && u16val == 0 && u8val == 0 && f64val == 0 && f32val == 0)
|
||||
Assert(string_val[0] == 'S')
|
||||
@@ -59,7 +59,7 @@ main :: (): int
|
||||
Assert(signed_variable == 10 && unsigned_variable == 10)
|
||||
Assert(INT_VALUE == 10)
|
||||
Assert(FLOAT_VALUE == 124.125)
|
||||
Assert(this_is_f64_by_default == 15.1255)
|
||||
Assert(this_is_f32_by_default == 15.1255)
|
||||
Assert(combining_types == 15.1255 + 20)
|
||||
|
||||
// Compound statements
|
||||
|
||||
@@ -141,7 +141,7 @@ WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nS
|
||||
window_dc := GetDC(window)
|
||||
bitmap := CreateBitmap(screen_size)
|
||||
|
||||
requested_time_per_frame := 1.0 / 60.0
|
||||
requested_time_per_frame: F64 = 1.0 / 60.0
|
||||
frame_start_time := Time()
|
||||
frame_number: S64
|
||||
for AppIsRunning
|
||||
|
||||
Reference in New Issue
Block a user