diff --git a/project.4coder b/project.4coder index 4c4e9f4c..0dfc2fee 100644 --- a/project.4coder +++ b/project.4coder @@ -49,7 +49,7 @@ commands = // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg no_meta debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build ryan_scratch no_meta && pushd build && ryan_scratch && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/project.raddbg b/project.raddbg index bffd93b9..8c9b43d1 100644 --- a/project.raddbg +++ b/project.raddbg @@ -9,6 +9,13 @@ target: debug_subprocesses: 0 } target: +{ + executable: "build/raddbg.exe" + working_directory: "../raddebugger" + arguments: "--user:test123" + debug_subprocesses: 0 +} +target: { executable: "build/mule_main.exe" working_directory: build @@ -18,6 +25,7 @@ target: { executable: "build/torture.exe" working_directory: build + arguments: "raddbg/*" } target: { @@ -31,14 +39,32 @@ target: arguments: "--rdi raddbg" } target: +{ + executable: "build/release_version/raddbg.exe" + working_directory: "build/release_version" +} +target: +{ + executable: "build/radbin.exe" + working_directory: build + arguments: "--rdi fat.so --capture" +} +target: +{ + executable: "build/radbin.exe" + working_directory: build + arguments: "--rdi fat.debug --capture" +} +target: +{ + executable: "build/radbin.exe" + working_directory: build + arguments: "--rdi raddbg" +} +watch_pin: expression: tag_hash_slots +target: { executable: "build/ryan_scratch.exe" working_directory: build enabled: 1 } -target: -{ - executable: "build/raddbg.exe" - working_directory: "build/" - arguments: "--bin --dump test123.rdi" -} diff --git a/src/eval2/eval2.c b/src/eval2/eval2.c index 9ee5e7be..c44262d6 100644 --- a/src/eval2/eval2.c +++ b/src/eval2/eval2.c @@ -796,11 +796,16 @@ internal E2_Expr * e2_expr_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_Expr *lhs, E2_Expr *rhs) { E2_Expr *e = e2_expr(arena); + E2_TypeKey arith_type_key = type_key; + if(RDI_EvalOp_FirstLogical <= op && op <= RDI_EvalOp_LastLogical) + { + arith_type_key = lhs->type_key; + } e->type_key = type_key; e->op = op; e->mode = E2_Mode_Value; - e->val.u512.u8[0] = e2_type_group_from_kind(e2_type_kind_from_key(type_key)); - e->val.u512.u8[1] = 8*e2_byte_size_from_type_key(type_key); + e->val.u512.u8[0] = e2_type_group_from_kind(e2_type_kind_from_key(arith_type_key)); + e->val.u512.u8[1] = 8*e2_byte_size_from_type_key(arith_type_key); e2_expr_push_child(e, lhs); e2_expr_push_child(e, rhs); return e; @@ -900,6 +905,12 @@ e2_expr_convert_if_possible(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key e2_expr_push_child(result, expr); } + // rjf: no-op from src -> dst + if(conversion_kind == RDI_EvalConversionKind_Noop) + { + result->type_key = dst_type_key; + } + // rjf: if shrinking integer sizes, truncate if(dst_byte_size < src_byte_size && e2_type_kind_is_integer(dst_type_kind)) { @@ -909,10 +920,20 @@ e2_expr_convert_if_possible(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key return result; } +internal E2_Expr * +e2_expr_type(Arena *arena, E2_TypeKey type_key) +{ + E2_Expr *expr = e2_expr(arena); + expr->type_key = type_key; + expr->mode = E2_Mode_Type; + return expr; +} + internal void e2_expr_push_child(E2_Expr *parent, E2_Expr *expr) { SLLQueuePush_NZ(&e2_expr_nil, parent->first, parent->last, expr, next); + parent->child_count += 1; } //////////////////////////////// @@ -1148,10 +1169,11 @@ e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *of } internal E2_Parse -e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E2_Expr *access_result, String8 string) +e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E2_Expr *access_result, E2_Val compile_time_eval_result, String8 string) { U64 off = state->string_off; E2_Parse parse = {E2_ParseStatus_Error, .expr = &e2_expr_nil, .params_expr = &e2_expr_nil}; + E2_Expr *last_chained_expr = &e2_expr_nil; E2_Expr *next_access_result = access_result; //- rjf: parse & attach to top parsing task - if we don't have a top task @@ -1258,6 +1280,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E { expr = next_access_result; next_access_result = &e2_expr_nil; + state->caller_request_count = 0; } // rjf: if we don't, ask for it - reset the offset to before this token @@ -1272,12 +1295,34 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E } } - //- rjf: standalone identifiers (also could be operator keyword) + //- rjf: standalone identifiers (also could be definition or operator keyword) else if(need_new_expr && e2_try_token(string, E2_TokenKind_Identifier, s(""), &off, &token)) { String8 identifier = str8_substr(string, token.range); B32 identifier_mapped = 0; + // rjf: first try to resolve as a definition + if(!identifier_mapped && e2_try_token(string, E2_TokenKind_Symbol, s("="), &off, 0)) + { + identifier_mapped = 1; + E2_ParseTask *task = state->free_task; + if(task != 0) + { + SLLStackPop(state->free_task); + } + else + { + task = push_array_no_zero(arena, E2_ParseTask, 1); + } + MemoryZeroStruct(task); + task->src_range = token.range; + task->child_count_target = 1; + task->op_kind = E2_OpKind_Define; + task->max_precedence = e2_op_kind_info_table[E2_OpKind_Define].precedence; + task->identifier = identifier; + SLLStackPush(state->top_task, task); + } + // rjf: first try to resolve as an operator name if(!identifier_mapped) { @@ -1324,6 +1369,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E { expr = e2_expr_from_name(expr_map, identifier); identifier_mapped = (expr != &e2_expr_nil); + state->caller_request_count = 0; } // rjf: couldn't map -> ask caller to resolve it @@ -1331,7 +1377,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E { done = 1; parse.status = E2_ParseStatus_MissedIdentifierResolution; - parse.missed_identifier = identifier; + parse.identifier = identifier; off = start_off; } } @@ -1386,6 +1432,30 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E } } + //- rjf: leaf string literals + else if(need_new_expr && e2_try_token(string, E2_TokenKind_StringLiteral, s(""), &off, &token)) + { + String8 token_string = str8_substr(string, token.range); + String8 unquoted_string = str8_skip(str8_chop(token_string, 1), 1); + String8 raw_string = raw_from_escaped_str8(arena, unquoted_string); + expr = e2_expr(arena); + expr->op = RDI_EvalOp_ConstString; + expr->mode = E2_Mode_Value; + expr->string = raw_string; + expr->val.u64 = raw_string.size; + expr->type_key = e2_type_key_cons_array(e2_type_key_basic(E2_TypeKind_UChar8), raw_string.size); + } + + //- rjf: leaf character literals + else if(need_new_expr && e2_try_token(string, E2_TokenKind_CharLiteral, s(""), &off, &token)) + { + String8 token_string = str8_substr(string, token.range); + String8 unquoted_string = str8_skip(str8_chop(token_string, 1), 1); + String8 raw_string = raw_from_escaped_str8(arena, unquoted_string); + UnicodeDecode decode = utf8_decode(raw_string.str, raw_string.size); + expr = e2_expr_const_u64_or_smaller(arena, decode.codepoint); + } + //- rjf: extend parsed expression tree with trailing operators if(!state->caller_info_completes_task && expr != &e2_expr_nil) { @@ -1452,7 +1522,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E if(state->caller_info_completes_task || expr != &e2_expr_nil) { //- rjf: pop finished expressions - for(;state->top_task != 0 && !done;) + for(B32 task_pushed = 0; state->top_task != 0 && !done && !task_pushed;) { //- rjf: gather finished expression to current task; increase task child count if(!state->caller_info_completes_task) @@ -1482,9 +1552,48 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E closer_found = e2_try_token(string, E2_TokenKind_Symbol, state->top_task->expected_closer, &off, 0); } + //- rjf: closer found, completed child count == 1 & completed child is a + // type evaluation - then this is cast. push a task to fill the operand + B32 is_cast = (closer_found && state->top_task->child_count == 1 && state->top_task->first_child->v->mode == E2_Mode_Type); + if(is_cast) + { + // rjf: pop the sub-task for the type expression + E2_Expr *type_expr = state->top_task->first_child->v; + { + E2_ParseTask *completed_task = state->top_task; + SLLStackPop(state->top_task); + SLLStackPush(state->free_task, completed_task); + } + + // rjf: push a new task for the castee operand + { + E2_ParseTask *task = state->free_task; + if(task != 0) + { + SLLStackPop(state->free_task); + } + else + { + task = push_array_no_zero(arena, E2_ParseTask, 1); + } + MemoryZeroStruct(task); + task->src_range = type_expr->src_range; + task->child_count = 1; + task->child_count_target = 2; + task->op_kind = E2_OpKind_CCast; + task->max_precedence = e2_op_kind_info_table[E2_OpKind_CCast].precedence; + SLLStackPush(state->top_task, task); + expr = &e2_expr_nil; + E2_ExprNode *child_n = push_array(arena, E2_ExprNode, 1); + SLLQueuePush(task->first_child, task->last_child, child_n); + child_n->v = type_expr; + task_pushed = 1; + } + } + //- rjf: caller-provided info completes a task, *or* closer found, // *or* task child count hits limit -> complete this subtree - if(state->caller_info_completes_task || closer_found || state->top_task->child_count >= state->top_task->child_count_target) + else if(state->caller_info_completes_task || closer_found || state->top_task->child_count >= state->top_task->child_count_target) { B32 completed_with_caller_info = state->caller_info_completes_task; state->caller_info_completes_task = 0; @@ -1494,7 +1603,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E E2_Expr *finished_root = &e2_expr_nil; E2_Expr *lhs = completed_task->first_child ? completed_task->first_child->v : &e2_expr_nil; E2_Expr *rhs = completed_task->last_child ? completed_task->last_child->v : &e2_expr_nil; - E2_Expr *mhs = completed_task->child_count == 3 ? lhs->next : &e2_expr_nil; + E2_Expr *mhs = completed_task->child_count == 3 ? completed_task->first_child->next->v : &e2_expr_nil; { RDI_EvalOp op = RDI_EvalOp_Stop; E2_TypeKey dst_type_key = {E2_TypeKeyKind_Null}; @@ -1558,6 +1667,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E { finished_root = next_access_result; next_access_result = &e2_expr_nil; + state->caller_request_count = 0; } else { @@ -1573,7 +1683,30 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E //- rjf: calls case E2_OpKind_Call: { - // TODO(rjf) + // rjf: calls of types redirect to casts + if(lhs->mode == E2_Mode_Type) + { + goto cast; + } + + // rjf: fallback => ask the caller to resolve the call + else + { + if(next_access_result != &e2_expr_nil) + { + finished_root = next_access_result; + next_access_result = &e2_expr_nil; + state->caller_request_count = 0; + } + else + { + done = 1; + parse.status = E2_ParseStatus_Call; + parse.expr = lhs; + parse.params_expr = rhs; + state->caller_info_completes_task = 1; + } + } }break; //- rjf: sizeof @@ -1585,6 +1718,32 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E finished_root->type_key = e2_type_key_basic(E2_TypeKind_U64); }break; + //- rjf: typeof + case E2_OpKind_TypeOf: + { + E2_TypeKey rhs_type_key = e2_type_key_unwrap(rhs->type_key, E2_TypeUnwrapFlag_AllDecorative & ~E2_TypeUnwrapFlag_Enums); + finished_root = e2_expr(arena); + finished_root->mode = E2_Mode_Type; + finished_root->type_key = rhs_type_key; + }break; + + //- rjf: casts + case E2_OpKind_CCast: + cast:; + { + E2_Expr *cast_type_expr = lhs; + E2_TypeKey cast_type_key = cast_type_expr->type_key; + if(e2_type_key_match(e2_type_key_zero(), cast_type_key)) + { + e2_msgf(arena, &parse.msgs, completed_task->src_range, "Cannot cast to this type."); + } + else + { + E2_Expr *castee_expr = rhs; + finished_root = e2_expr_convert_if_possible(arena, castee_expr, cast_type_key); + } + }break; + //- rjf: dereferences case E2_OpKind_Deref: case E2_OpKind_DerefAsm: @@ -1801,16 +1960,21 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E if(!malformed) { E2_TypeKey dst_type_key = lhs_type_key; + E2_Expr *lhs_converted = lhs_value; + E2_Expr *rhs_converted = rhs_value; if(RDI_EvalOp_FirstLogical <= op && op <= RDI_EvalOp_LastLogical) { dst_type_key = e2_type_key_basic(E2_TypeKind_Bool); + E2_TypeKey coerced_type_key = e2_coerced_type_key_from_operands(lhs_type_key, rhs_type_key); + lhs_converted = e2_expr_convert_if_possible(arena, lhs_value, coerced_type_key); + rhs_converted = e2_expr_convert_if_possible(arena, rhs_value, coerced_type_key); } else { dst_type_key = e2_coerced_type_key_from_operands(lhs_type_key, rhs_type_key); + lhs_converted = e2_expr_convert_if_possible(arena, lhs_value, dst_type_key); + rhs_converted = e2_expr_convert_if_possible(arena, rhs_value, dst_type_key); } - E2_Expr *lhs_converted = e2_expr_convert_if_possible(arena, lhs_value, dst_type_key); - E2_Expr *rhs_converted = e2_expr_convert_if_possible(arena, rhs_value, dst_type_key); finished_root = e2_expr_binary_op(arena, dst_type_key, op, lhs_converted, rhs_converted); } }break; @@ -1818,36 +1982,149 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E //- rjf: pointer-add arithmetic case ArithKind_PtrAdd: { - + // TODO(rjf) }break; //- rjf: pointer-sub arithmetic case ArithKind_PtrSub: { - + // TODO(rjf) }break; //- rjf: pointer-array comparisons case ArithKind_PtrArrayCompare: { - + // TODO(rjf) }break; //- rjf: type comparisons case ArithKind_TypeCompare: { - + // TODO(rjf) }break; } }break; - //- rjf: definitions (TODO(rjf): tricky with the 'user resolves expressions' model - let's figure it out once basics are in) - case E2_OpKind_Define:{}break; + //- rjf: definitions + case E2_OpKind_Define: + { + if(completed_with_caller_info) + { + finished_root = lhs; + } + else + { + done = 1; + parse.status = E2_ParseStatus_NewIdentifierDefinition; + parse.expr = lhs; + parse.identifier = completed_task->identifier; + state->caller_info_completes_task = 1; + } + }break; //- rjf: conditionals case E2_OpKind_Cond: { - // TODO(rjf) + // rjf: unpack operands + E2_Expr *condition_expr = lhs; + E2_Expr *pass_expr = mhs; + E2_Expr *fail_expr = rhs; + E2_TypeKey type_key = e2_coerced_type_key_from_operands(pass_expr->type_key, fail_expr->type_key); + + // rjf: determine if the mhs/rhs types force us to do compile-time evaluation of the condition + B32 compile_time_cond = 0; + { + RDI_EvalTypeGroup pass_type_group = e2_type_group_from_kind(e2_type_kind_from_key(pass_expr->type_key)); + RDI_EvalTypeGroup fail_type_group = e2_type_group_from_kind(e2_type_kind_from_key(fail_expr->type_key)); + RDI_EvalConversionKind conversion_kind = rdi_eval_conversion_kind_from_typegroups(fail_type_group, pass_type_group); + if(conversion_kind != RDI_EvalConversionKind_Legal && + conversion_kind != RDI_EvalConversionKind_Noop) + { + compile_time_cond = 1; + } + } + + // rjf: compile-time conditional -> ask caller to evaluate conditional + if(compile_time_cond) + { + if(!completed_with_caller_info) + { + done = 1; + parse.status = E2_ParseStatus_CompileTimeEval; + parse.expr = lhs; + state->caller_info_completes_task = 1; + } + else + { + if(compile_time_eval_result.u64 == 0) + { + finished_root = fail_expr; + } + else + { + finished_root = pass_expr; + } + } + } + + // rjf: runtime conditional -> build opcodes for evaluating condition, jumping, etc. + else + { + // rjf: convert pass/fail to coerced type + pass_expr = e2_expr_convert_if_possible(arena, pass_expr, type_key); + fail_expr = e2_expr_convert_if_possible(arena, fail_expr, type_key); + + // rjf: form conditional tree + E2_Expr *cond_root = e2_expr(arena); + E2_Expr *cjump_expr = e2_expr(arena); + E2_Expr *jump_expr = e2_expr(arena); + e2_expr_push_child(cond_root, condition_expr); + e2_expr_push_child(cond_root, cjump_expr); + e2_expr_push_child(cond_root, fail_expr); + e2_expr_push_child(cond_root, jump_expr); + e2_expr_push_child(cond_root, pass_expr); + + // rjf: compute # of bytes for pass + U64 pass_expr_byte_count = 0; + { + Temp scratch = scratch_begin(&arena, 1); + String8 pass_bytecode = e2_bytecode_from_expr(scratch.arena, pass_expr); + pass_expr_byte_count = pass_bytecode.size; + scratch_end(scratch); + } + + // rjf: configure unconditional jump (fail -> end) + jump_expr->op = RDI_EvalOp_Skip; + jump_expr->val.u64 = pass_expr_byte_count; + + // rjf: compute # of bytes for fail + U64 fail_expr_byte_count = 0; + { + Temp scratch = scratch_begin(&arena, 1); + String8 fail_bytecode = e2_bytecode_from_expr(scratch.arena, fail_expr); + fail_expr_byte_count = fail_bytecode.size; + scratch_end(scratch); + } + + // rjf: compute # of bytes for unconditional jump + U64 jump_expr_byte_count = 0; + { + Temp scratch = scratch_begin(&arena, 1); + String8 jump_bytecode = e2_bytecode_from_expr(scratch.arena, jump_expr); + jump_expr_byte_count = jump_bytecode.size; + scratch_end(scratch); + } + + // rjf: configure conditional jump + cjump_expr->op = RDI_EvalOp_Cond; + cjump_expr->val.u64 = fail_expr_byte_count + jump_expr_byte_count; + + // rjf: fill conditional root type + cond_root->type_key = type_key; + + // rjf: take result + finished_root = cond_root; + } }break; } } @@ -1858,15 +2135,15 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E e2_msgf(arena, &parse.msgs, r1u64(off, off), "Expected `%S`.", completed_task->expected_closer); } - //- rjf: work on the parent of the finished expression next - expr = finished_root; - //- rjf: release task if(!done) { SLLStackPop(state->top_task); SLLStackPush(state->free_task, completed_task); } + + //- rjf: work on the parent of the finished expression next + expr = finished_root; } //- rjf: if the top task is not done -> break & continue - reset expression, because we need to parse another. @@ -1876,25 +2153,24 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E break; } } - - //- rjf: for the last finished expression, if we do not have any further tasks, - // this is our result. - if(state->top_task == 0 && off >= string.size) + } + + //- rjf: we're always done if there's nothing left to parse, *or* if we made no progress. + if(off >= string.size || (off == start_off && !e2_parse_status_is_caller_request(parse.status))) + { + done = 1; + if(state->top_task == 0) { - parse.expr = expr; + if(parse.expr == &e2_expr_nil && expr != &e2_expr_nil) + { + parse.expr = expr; + } if(parse.status == E2_ParseStatus_Error) { parse.status = E2_ParseStatus_Good; } - break; } } - - //- rjf: we're always done if there's nothing left to parse - if(off >= string.size) - { - done = 1; - } } //- rjf: asking caller for info? -> if we already did this at this offset, @@ -1905,7 +2181,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E { if(parse.status == E2_ParseStatus_MissedIdentifierResolution) { - e2_msgf(arena, &parse.msgs, r1u64(state->string_off, state->string_off + parse.missed_identifier.size), "`%S` couldn't be resolved.", parse.missed_identifier); + e2_msgf(arena, &parse.msgs, r1u64(state->string_off, state->string_off + parse.identifier.size), "`%S` couldn't be resolved.", parse.identifier); } parse.status = E2_ParseStatus_Error; } @@ -1977,6 +2253,10 @@ e2_bytecode_from_expr(Arena *arena, E2_Expr *expr) //- rjf: unpack this op U16 ctrlbits = rdi_eval_op_ctrlbits_table[e->op]; U64 child_count = RDI_POPN_FROM_CTRLBITS(ctrlbits); + if(e->op == 0) + { + child_count = e->child_count; + } //- rjf: push the next child task if we can if(t->pushed_child_count < child_count) @@ -2003,17 +2283,24 @@ e2_bytecode_from_expr(Arena *arena, E2_Expr *expr) //- rjf: did push of all children -> push this expr's op, pop off stack else { - U16 ctrlbits = 0; - if(e->op < RDI_EvalOp_COUNT) + if(e->op != 0) { - ctrlbits = rdi_eval_op_ctrlbits_table[e->op]; + U16 ctrlbits = 0; + if(e->op < RDI_EvalOp_COUNT) + { + ctrlbits = rdi_eval_op_ctrlbits_table[e->op]; + } + U64 decode_byte_count = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); + U64 op_size = 1 + decode_byte_count; + U8 *op_buffer = push_array(scratch.arena, U8, op_size); + op_buffer[0] = e->op; + MemoryCopy(op_buffer+1, &e->val, decode_byte_count); + str8_list_push(scratch.arena, &strings, str8(op_buffer, op_size)); + if(e->string.size != 0) + { + str8_list_push(scratch.arena, &strings, e->string); + } } - U64 decode_byte_count = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); - U64 op_size = 1 + decode_byte_count; - U8 *op_buffer = push_array(scratch.arena, U8, op_size); - op_buffer[0] = e->op; - MemoryCopy(op_buffer+1, &e->val, decode_byte_count); - str8_list_push(scratch.arena, &strings, str8(op_buffer, op_size)); SLLStackPop(top_task); SLLStackPush(free_task, t); } diff --git a/src/eval2/eval2.h b/src/eval2/eval2.h index f920d69e..61ee043b 100644 --- a/src/eval2/eval2.h +++ b/src/eval2/eval2.h @@ -54,11 +54,13 @@ typedef enum E2_ParseStatus //- rjf: caller-provided info E2_ParseStatus_MissedIdentifierResolution, + E2_ParseStatus_NewIdentifierDefinition, E2_ParseStatus_MemberAccess, E2_ParseStatus_IndexAccess, E2_ParseStatus_Call, + E2_ParseStatus_CompileTimeEval, E2_ParseStatus_FirstCallerRequest = E2_ParseStatus_MissedIdentifierResolution, - E2_ParseStatus_LastCallerRequest = E2_ParseStatus_Call, + E2_ParseStatus_LastCallerRequest = E2_ParseStatus_CompileTimeEval, } E2_ParseStatus; @@ -315,6 +317,7 @@ struct E2_Expr E2_Expr *first; E2_Expr *last; E2_Expr *next; + U64 child_count; Rng1U64 src_range; String8 string; RDI_EvalOp op; @@ -356,6 +359,7 @@ struct E2_ParseTask U64 child_count_target; S64 max_precedence; E2_OpKind op_kind; + String8 identifier; String8 expected_closer; String8 expected_splitter; B32 splitter_is_required; @@ -393,7 +397,7 @@ typedef struct E2_Parse E2_Parse; struct E2_Parse { E2_ParseStatus status; - String8 missed_identifier; + String8 identifier; E2_Expr *expr; String8 member_name; E2_Expr *params_expr; @@ -566,6 +570,7 @@ internal E2_Expr *e2_expr_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalO internal E2_Expr *e2_expr_resolve_to_value(Arena *arena, E2_Expr *expr); internal E2_Expr *e2_expr_truncate(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key); internal E2_Expr *e2_expr_convert_if_possible(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key); +internal E2_Expr *e2_expr_type(Arena *arena, E2_TypeKey type_key); internal void e2_expr_push_child(E2_Expr *parent, E2_Expr *expr); //////////////////////////////// @@ -574,7 +579,7 @@ internal void e2_expr_push_child(E2_Expr *parent, E2_Expr *expr); internal E2_Token e2_token_from_string_off(String8 string, U64 start_off); internal U64 e2_read_token(String8 string, U64 off, E2_Token *token_out); internal B32 e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *off_out, E2_Token *token_out); -internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E2_Expr *access_result, String8 string); +internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E2_Expr *access_result, E2_Val compile_time_eval_result, String8 string); //////////////////////////////// //~ rjf: Expression -> Bytecode diff --git a/src/eval2/eval2.mdesk b/src/eval2/eval2.mdesk index 2f07c727..bfba77cd 100644 --- a/src/eval2/eval2.mdesk +++ b/src/eval2/eval2.mdesk @@ -9,6 +9,8 @@ E2_OpTable: {Call Call 1 "" "(" ")" ","} {DerefAsm UnaryPrefix 1 "[" "" "]" "" } {SizeOf UnaryPrefix 1 "sizeof " "" "" "" } + {TypeOf UnaryPrefix 1 "typeof " "" "" "" } + {CCast UnaryPrefix 1 "" "" "" "" } {Deref UnaryPrefix 2 "*" "" "" "" } {Address UnaryPrefix 2 "&" "" "" "" } {Pos UnaryPrefix 2 "+" "" "" "" } @@ -33,7 +35,7 @@ E2_OpTable: {BitOr Binary 10 "" "|" "" "" } {LogAnd Binary 11 "" "&&" "" "" } {LogOr Binary 12 "" "||" "" "" } - {Define Binary 13 "" "=" "" "" } + {Define Null 13 "" "=" "" "" } {Cond Ternary 14 "" "?" "" ":"} } diff --git a/src/eval2/generated/eval2.meta.c b/src/eval2/generated/eval2.meta.c index 0b8b63b1..7fd3f85b 100644 --- a/src/eval2/generated/eval2.meta.c +++ b/src/eval2/generated/eval2.meta.c @@ -4,7 +4,7 @@ //- GENERATED CODE C_LINKAGE_BEGIN -E2_OpInfo e2_op_kind_info_table[32] = +E2_OpInfo e2_op_kind_info_table[34] = { {0}, {E2_OpParseKind_Binary, 1, str8_lit_comp(""), str8_lit_comp("."), str8_lit_comp(""), str8_lit_comp("")}, @@ -12,6 +12,8 @@ E2_OpInfo e2_op_kind_info_table[32] = {E2_OpParseKind_Call, 1, str8_lit_comp(""), str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp(",")}, {E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp("["), str8_lit_comp(""), str8_lit_comp("]"), str8_lit_comp("")}, {E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp("sizeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, +{E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp("typeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, +{E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, {E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, {E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, {E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, diff --git a/src/eval2/generated/eval2.meta.h b/src/eval2/generated/eval2.meta.h index eedb460f..be6b0ca2 100644 --- a/src/eval2/generated/eval2.meta.h +++ b/src/eval2/generated/eval2.meta.h @@ -14,6 +14,8 @@ E2_OpKind_Index, E2_OpKind_Call, E2_OpKind_DerefAsm, E2_OpKind_SizeOf, +E2_OpKind_TypeOf, +E2_OpKind_CCast, E2_OpKind_Deref, E2_OpKind_Address, E2_OpKind_Pos, @@ -122,7 +124,7 @@ E2_TypeKind_LastMeta = E2_TypeKind_MetaDescription, } E2_TypeKind; C_LINKAGE_BEGIN -extern E2_OpInfo e2_op_kind_info_table[32]; +extern E2_OpInfo e2_op_kind_info_table[34]; extern U8 e2_type_kind_basic_byte_size_table[61]; extern String8 e2_type_kind_basic_string_table[61]; diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index 84f35ba9..f7294023 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -78,7 +78,7 @@ RDI_EVAL_CTRLBITS(8, 0, 1), RDI_EVAL_CTRLBITS(16, 0, 1), RDI_EVAL_CTRLBITS(32, 0, 1), RDI_EVAL_CTRLBITS(64, 0, 1), -RDI_EVAL_CTRLBITS(1, 0, 1), +RDI_EVAL_CTRLBITS(8, 0, 1), RDI_EVAL_CTRLBITS(2, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1), RDI_EVAL_CTRLBITS(2, 2, 1), @@ -92,15 +92,15 @@ RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 1, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 1, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), -RDI_EVAL_CTRLBITS(1, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 1, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), +RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1), diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 36509832..ff9bbd35 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -1213,7 +1213,7 @@ RDI_EvalOpTable: {ConstU128 15 16 0 1} {ConstU256 16 32 0 1} {ConstU512 17 64 0 1} - {ConstString 18 1 0 1} + {ConstString 18 8 0 1} {Abs 19 2 1 1} {Neg 20 2 1 1} {Add 21 2 2 1} @@ -1227,15 +1227,15 @@ RDI_EvalOpTable: {BitOr 29 2 2 1} {BitXor 30 2 2 1} {BitNot 31 2 1 1} - {LogAnd 32 1 2 1 FirstLogical} - {LogOr 33 1 2 1} - {LogNot 34 1 1 1} - {EqEq 35 1 2 1} - {NtEq 36 1 2 1} - {LsEq 37 1 2 1} - {GrEq 38 1 2 1} - {Less 39 1 2 1} - {Grtr 40 1 2 1 LastLogical} + {LogAnd 32 2 2 1 FirstLogical} + {LogOr 33 2 2 1} + {LogNot 34 2 1 1} + {EqEq 35 2 2 1} + {NtEq 36 2 2 1} + {LsEq 37 2 2 1} + {GrEq 38 2 2 1} + {Less 39 2 2 1} + {Grtr 40 2 2 1 LastLogical} {Trunc 41 1 1 1} {TruncSigned 42 1 1 1} {Convert 43 2 1 1} diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 8c19eaf3..0721d17a 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -36,6 +36,22 @@ entry_point(CmdLine *cmdline) { String8 strings[] = { + // (A)B + // (A) & B + // (A) + // int & B + // (1 + (int)&B) + s("foo = 123"), + s("1 > 2"), + s("1 ? \"Test\" : 888"), + s("'a'"), + s("'b'"), + s("float32(111)"), + s("float64(111)"), + s("222.f"), + s("222.0"), + s("(float32)222"), + s("(float64)222"), s("[123]"), s("foo"), s("foo.bar"), @@ -55,6 +71,7 @@ entry_point(CmdLine *cmdline) s("-123"), s("sizeof 123"), s("1 ? 123 : 456"), + s("0 ? 123 : 456"), s("123(1, 2, 3)"), }; for EachElement(idx, strings) @@ -68,9 +85,10 @@ entry_point(CmdLine *cmdline) E2_ParseState state = {0}; E2_ExprMap expr_map = {0}; E2_Expr *access_expr = &e2_expr_nil; + E2_Val compile_time_eval_result = {0}; for(;;) { - E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &expr_map, access_expr, strings[idx]); + E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &expr_map, access_expr, compile_time_eval_result, strings[idx]); expr = parse.expr; access_expr = &e2_expr_nil; for EachNode(n, E2_Msg, parse.msgs.first) @@ -79,15 +97,52 @@ entry_point(CmdLine *cmdline) } if(parse.status == E2_ParseStatus_MissedIdentifierResolution) { - e2_expr_map_push(scratch.arena, &expr_map, parse.missed_identifier, e2_expr_const_u64_or_smaller(scratch.arena, 123)); + E2_Expr *expr = &e2_expr_nil; + if(str8_match(parse.identifier, s("float32"), 0)) + { + expr = e2_expr_type(scratch.arena, e2_type_key_basic(E2_TypeKind_F32)); + } + else if(str8_match(parse.identifier, s("float64"), 0)) + { + expr = e2_expr_type(scratch.arena, e2_type_key_basic(E2_TypeKind_F64)); + } + else if(str8_match(parse.identifier, s("int32"), 0)) + { + expr = e2_expr_type(scratch.arena, e2_type_key_basic(E2_TypeKind_S32)); + } + else if(str8_match(parse.identifier, s("int64"), 0)) + { + expr = e2_expr_type(scratch.arena, e2_type_key_basic(E2_TypeKind_S64)); + } + else + { + expr = e2_expr_const_u64_or_smaller(scratch.arena, 123); + } + e2_expr_map_push(scratch.arena, &expr_map, parse.identifier, expr); + } + if(parse.status == E2_ParseStatus_NewIdentifierDefinition) + { + e2_expr_map_push(scratch.arena, &expr_map, parse.identifier, expr); + } + if(parse.status == E2_ParseStatus_MemberAccess) + { + access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 456); } if(parse.status == E2_ParseStatus_IndexAccess) { access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 111); } - if(parse.status == E2_ParseStatus_MemberAccess) + if(parse.status == E2_ParseStatus_Call) { - access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 456); + access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 123456); + } + if(parse.status == E2_ParseStatus_CompileTimeEval) + { + String8 bytecode = e2_bytecode_from_expr(scratch.arena, expr); + E2_InterpState interp_state = {0}; + E2_SpaceMap space_map = {0}; + E2_Interp interp = e2_interp_from_bytecode(scratch.arena, &interp_state, &space_map, bytecode); + compile_time_eval_result = interp.val; } if(e2_parse_status_is_terminal(parse.status)) { @@ -124,12 +179,17 @@ entry_point(CmdLine *cmdline) String8 msgs_string = str8_list_join(scratch.arena, &msgs, &join); // rjf: log - printf("%.*s -> %I64d *%s* %s%.*s\n", str8_varg(strings[idx]), - val.s64, - expr->mode == E2_Mode_Type ? "type" : - expr->mode == E2_Mode_Value ? "value" : - "address", - msgs_string.size != 0 ? " // " : "", str8_varg(msgs_string)); + String8 log = str8f(scratch.arena, "%S -> %I64d (f32: %f) (f64: %f) *%s* %s%S\n", + strings[idx], + val.s64, + val.f32, + val.f64, + expr->mode == E2_Mode_Type ? "type" : + expr->mode == E2_Mode_Value ? "value" : + "address", + msgs_string.size != 0 ? " // " : "", msgs_string); + raddbg_log("%S", log); + printf("%.*s", str8_varg(log)); fflush(stdout); scratch_end(scratch);