diff --git a/releasenotes.md b/releasenotes.md index 25c7baeff..f9ff2a437 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -16,6 +16,8 @@ - Improve error messages on expressions like `var $type = int;` #1553. - Disallow casting a `void*` to `any` or an interface, unless it is `null`. - Defer resolution of declarations when looked up in `def` aliased #1559. +- Adding constants to the Json AST #1540 +- Adding info to the globals inside Json AST #1541 ### Fixes - `Unsupported int[*] $x = { 1, 2, 3, 4 }` #1489. diff --git a/src/compiler/json_output.c b/src/compiler/json_output.c index 82be183a4..30e3301d4 100644 --- a/src/compiler/json_output.c +++ b/src/compiler/json_output.c @@ -160,6 +160,638 @@ void print_type(FILE *file, TypeInfo *type) } } +void print_var_expr(FILE *file, Expr *expr); + +void print_var_expr_unary(FILE *file, ExprUnary *expr, bool is_post) +{ + if (is_post) print_var_expr(file, expr->expr); + switch (expr->operator) + { + case UNARYOP_ERROR: + UNREACHABLE + case UNARYOP_DEREF: + fputs("*", file); + break; + case UNARYOP_ADDR: + fputs("&", file); + break; + case UNARYOP_NEG: + fputs("-", file); + break; + case UNARYOP_PLUS: + fputs("+", file); + break; + case UNARYOP_BITNEG: + fputs("~", file); + break; + case UNARYOP_NOT: + fputs("!", file); + break; + case UNARYOP_INC: + fputs("++", file); + break; + case UNARYOP_DEC: + fputs("--", file); + break; + case UNARYOP_TADDR: + fputs("&&", file); + break; + } + if (!is_post) print_var_expr(file, expr->expr); +} + +void print_var_expr_range(FILE *file, Range *r) +{ + if (r->is_len) + { + if (r->start_from_end) fputs("^", file); + PRINTF("%d", r->start_index); + fputs(" : ", file); + if (r->end_from_end) fputs("^", file); + PRINTF("%d", r->len_index); + } + else + { + switch (r->range_type) + { + case RANGE_DYNAMIC: + if (r->start_from_end) fputs("^", file); + print_var_expr(file, exprptr(r->start)); + fputs("..", file); + if (r->end) print_var_expr(file, exprptr(r->end)); + break; + case RANGE_CONST_END: + fputs("TODO: RANGE_CONST_END", file); + break; + case RANGE_CONST_LEN: + fputs("TODO: RANGE_CONST_LEN", file); + break; + case RANGE_CONST_RANGE: + fputs("TODO: RANGE_CONST_RANGE", file); + break; + } + } +} + +void print_var_expr(FILE *file, Expr *expr) +{ + if (!expr) + { + fputs("NULL EXPR", file); + return; + } + + switch (expr->expr_kind) + { + case EXPR_BITASSIGN: + case EXPR_BITACCESS: + case EXPR_ACCESS: + print_var_expr(file, expr->access_expr.parent); + fputs(".", file); + print_var_expr(file, expr->access_expr.child); + break; + case EXPR_BINARY: + print_var_expr(file, exprptr(expr->binary_expr.left)); + switch (expr->binary_expr.operator) + { + case BINARYOP_ERROR: + UNREACHABLE + case BINARYOP_MULT: + fputs(" * ", file); + break; + case BINARYOP_SUB: + fputs(" - ", file); + break; + case BINARYOP_ADD: + fputs(" + ", file); + break; + case BINARYOP_DIV: + fputs(" / ", file); + break; + case BINARYOP_MOD: + fputs(" % ", file); + break; + case BINARYOP_SHR: + fputs(" >> ", file); + break; + case BINARYOP_SHL: + fputs(" << ", file); + break; + case BINARYOP_BIT_OR: + fputs(" | ", file); + break; + case BINARYOP_BIT_XOR: + fputs(" ^ ", file); + break; + case BINARYOP_BIT_AND: + fputs(" & ", file); + break; + case BINARYOP_AND: + case BINARYOP_CT_AND: + fputs(" && ", file); + break; + case BINARYOP_OR: + case BINARYOP_CT_OR: + fputs(" || ", file); + break; + case BINARYOP_ELSE: + fputs(" ?? ", file); + break; + case BINARYOP_CT_CONCAT: + fputs(" +++ ", file); + break; + case BINARYOP_GT: + fputs(" > ", file); + break; + case BINARYOP_GE: + fputs(" >= ", file); + break; + case BINARYOP_LT: + fputs(" < ", file); + break; + case BINARYOP_LE: + fputs(" <= ", file); + break; + case BINARYOP_NE: + fputs(" != ", file); + break; + case BINARYOP_EQ: + fputs(" == ", file); + break; + case BINARYOP_ASSIGN: + fputs(" = ", file); + break; + case BINARYOP_ADD_ASSIGN: + fputs(" += ", file); + break; + case BINARYOP_BIT_AND_ASSIGN: + fputs(" &= ", file); + break; + case BINARYOP_BIT_OR_ASSIGN: + fputs(" |= ", file); + break; + case BINARYOP_BIT_XOR_ASSIGN: + fputs(" ^= ", file); + break; + case BINARYOP_DIV_ASSIGN: + fputs(" /= ", file); + break; + case BINARYOP_MOD_ASSIGN: + fputs(" %= ", file); + break; + case BINARYOP_MULT_ASSIGN: + fputs(" *= ", file); + break; + case BINARYOP_SHR_ASSIGN: + fputs(" >>= ", file); + break; + case BINARYOP_SHL_ASSIGN: + fputs(" <<= ", file); + break; + case BINARYOP_SUB_ASSIGN: + fputs(" -= ", file); + break; + } + print_var_expr(file, exprptr(expr->binary_expr.right)); + break; + case EXPR_TYPECALL: + case EXPR_CALL: + { + if (!expr->call_expr.is_pointer_call) print_var_expr(file, exprptr(expr->call_expr.function)); + fputs("(", file); + FOREACH_IDX(i, Expr *, e, expr->call_expr.arguments) + { + print_var_expr(file, e); + if (i != vec_size(expr->call_expr.arguments) - 1) fputs(", ", file); + } + fputs(")", file); + } + break; + case EXPR_CAST: + fputs("(", file); + print_type(file, type_infoptr(expr->cast_expr.type_info)); + fputs(")", file); + print_var_expr(file, exprptr(expr->cast_expr.expr)); + break; + case EXPR_BUILTIN: + case EXPR_COMPILER_CONST: + PRINTF("$$%s", expr->builtin_expr.ident); + break; + case EXPR_COMPOUND_LITERAL: + print_type(file, expr->expr_compound_literal.type_info); + print_var_expr(file, expr->expr_compound_literal.initializer); + break; + case EXPR_CONST: + switch (expr->const_expr.const_kind) + { + case CONST_FLOAT: + PRINTF("%f", expr->const_expr.fxx.f); + break; + case CONST_INTEGER: + fputs(i128_to_string(expr->const_expr.ixx.i, 10, true, false), file); + break; + case CONST_BOOL: + fputs(expr->const_expr.b ? "true" : "false", file); + break; + case CONST_ENUM: + PRINTF("%u", expr->const_expr.enum_err_val->enum_constant.ordinal); + break; + case CONST_ERR: + fputs("TODO: CONST_ERR", file); + break; + case CONST_BYTES: + case CONST_STRING: + PRINTF("\\\"%.*s\\\"", expr->const_expr.bytes.len, expr->const_expr.bytes.ptr); + break; + case CONST_POINTER: +#if PLATFORM_WINDOWS || __APPLE__ + PRINTF("%llu", expr->const_expr.ptr); +#else + PRINTF("%lu", expr->const_expr.ptr); +#endif + break; + case CONST_TYPEID: + fputs(expr->const_expr.typeid->name, file); + break; + case CONST_SLICE: + fputs("TODO: CONST_SLICE", file); + break; + case CONST_INITIALIZER: + fputs("TODO: CONST_INITIALIZER", file); + break; + case CONST_UNTYPED_LIST: + fputs("{", file); + { + FOREACH_IDX(i, Expr *, e, expr->const_expr.untyped_list) + { + print_var_expr(file, e); + if (i != vec_size(expr->const_expr.untyped_list) - 1) fputs(", ", file); + } + } + fputs("}", file); + break; + case CONST_REF: + fputs("TODO: CONST_REF", file); + break; + case CONST_MEMBER: + fputs("TODO: CONST_MEMBER", file); + break; + } + break; + case EXPR_CT_AND_OR: + { + if (expr->ct_and_or_expr.is_and) + { + fputs("$and(", file); + } + else + { + fputs("$or(", file); + } + FOREACH_IDX(i, Expr *, e, expr->ct_and_or_expr.args) + { + print_var_expr(file, e); + if (i != vec_size(expr->ct_and_or_expr.args) - 1) fputs(", ", file); + } + fputs(")", file); + } + break; + case EXPR_CT_ARG: + fputs("$", file); + print_var_expr(file, exprptr(expr->ct_arg_expr.arg)); + break; + case EXPR_CT_CALL: + switch (expr->ct_call_expr.token_type) + { + case TOKEN_CT_ALIGNOF: // $alignof + fputs("$alignof(", file); + break; + case TOKEN_CT_APPEND: // $append + fputs("$append(", file); + break; + case TOKEN_CT_ASSERT: // $assert + fputs("$assert(", file); + break; + case TOKEN_CT_ECHO: // $echo + fputs("$echo(", file); + break; + case TOKEN_CT_EMBED: // $embed + fputs("$embed(", file); + break; + case TOKEN_CT_EVALTYPE: // $evaltype + fputs("$evaltype(", file); + break; + case TOKEN_CT_ERROR: // $error + fputs("$error(", file); + break; + case TOKEN_CT_EXEC: // $exec + fputs("$exec(", file); + break; + case TOKEN_CT_EXTNAMEOF: // $extnameof + fputs("$extnameof(", file); + break; + case TOKEN_CT_FEATURE: // $feature + fputs("$feature(", file); + break; + case TOKEN_CT_NAMEOF: // $nameof + fputs("$nameof(", file); + break; + case TOKEN_CT_OFFSETOF: // $offsetof + fputs("$offsetof(", file); + break; + case TOKEN_CT_QNAMEOF: // $qnameof + fputs("$qnameof(", file); + break; + case TOKEN_CT_SIZEOF: // $sizeof + fputs("$sizeof(", file); + break; + case TOKEN_CT_STRINGIFY: // $stringify + fputs("$stringify(", file); + break; + case TOKEN_CT_TYPEFROM: // $typefrom + fputs("$typefrom(", file); + break; + case TOKEN_CT_TYPEOF: // $typeof + fputs("$typeof(", file); + break; + case TOKEN_CT_VACOUNT: // $vacount + fputs("$vacount(", file); + break; + case TOKEN_CT_VATYPE: // $vatype + fputs("$vatype(", file); + break; + case TOKEN_CT_VACONST: // $vaconst, + fputs("$vaconst(", file); + break; + case TOKEN_CT_VAREF: // $varef, + fputs("$varef(", file); + break; + case TOKEN_CT_VAARG: // $vaarg, + fputs("$vaarg(", file); + break; + case TOKEN_CT_VAEXPR: // $vaexpr, + fputs("$vaexpr(", file); + break; + default: + UNREACHABLE + } + print_var_expr(file, expr->ct_call_expr.main_var); + fputs(")", file); + break; + case EXPR_CT_CASTABLE: + fputs("$assignable(", file); + print_var_expr(file, exprptr(expr->castable_expr.expr)); + fputs(", ", file); + print_type(file, type_infoptr(expr->castable_expr.type)); + fputs(")", file); + break; + case EXPR_CT_APPEND: + case EXPR_CT_CONCAT: + { + FOREACH_IDX(i, Expr *, e, expr->ct_concat) + { + print_var_expr(file, e); + if (i != vec_size(expr->ct_concat) - 1) fputs(" +++ ", file); + } + } + break; + case EXPR_CT_DEFINED: + fputs("$defined(", file); + { + FOREACH_IDX(i, Expr *, e, expr->expression_list) + { + print_var_expr(file, e); + if (i != vec_size(expr->ct_concat) - 1) fputs(", ", file); + } + } + fputs(")", file); + break; + case EXPR_CT_EVAL: + fputs("$eval(", file); + print_var_expr(file, expr->inner_expr); + fputs(")", file); + break; + case EXPR_CT_IDENT: + fputs(expr->ct_ident_expr.identifier, file); + break; + case EXPR_CT_IS_CONST: + fputs("$is_const(", file); + print_var_expr(file, expr->inner_expr); + fputs(")", file); + break; + case EXPR_DECL: + fputs("TODO: EXPR_DECL", file); + break; + case EXPR_DESIGNATOR: + { + FOREACH(DesignatorElement *, d, expr->designator_expr.path) + { + switch (d->kind) + { + case DESIGNATOR_FIELD: + fputs(".", file); + print_var_expr(file, d->field_expr); + break; + case DESIGNATOR_ARRAY: + case DESIGNATOR_RANGE: + fputs("[", file); + if (d->index_expr) print_var_expr(file, d->index_expr); + if (d->index_end_expr) + { + fputs("..", file); + print_var_expr(file, d->index_end_expr); + } + fputs("]", file); + break; + } + } + fputs(" = ", file); + print_var_expr(file, expr->designator_expr.value); + } + break; + case EXPR_EMBED: + fputs("$embed(", file); + print_var_expr(file, expr->embed_expr.filename); + if (expr->embed_expr.len) + { + fputs(", ", file); + print_var_expr(file, expr->embed_expr.len); + } + break; + case EXPR_EXPRESSION_LIST: + { + FOREACH_IDX(i, Expr *, e, expr->expression_list) + { + print_var_expr(file, e); + if (i != vec_size(expr->ct_concat) - 1) fputs(", ", file); + } + } + break; + case EXPR_EXPR_BLOCK: + fputs("TODO: EXPR_EXPR_BLOCK", file); + break; + case EXPR_FORCE_UNWRAP: + print_var_expr(file, expr->inner_expr); + fputs("!!", file); + break; + case EXPR_GENERIC_IDENT: + print_var_expr(file, exprptr(expr->generic_ident_expr.parent)); + fputs("(<", file); + { + FOREACH_IDX(i, Expr *, e, expr->generic_ident_expr.parmeters) + { + print_var_expr(file, e); + if (i != vec_size(expr->call_expr.arguments) - 1) fputs(", ", file); + } + } + fputs(">)", file); + break; + case EXPR_HASH_IDENT: + PRINTF("#%s", expr->hash_ident_expr.identifier); + break; + case EXPR_IDENTIFIER: + if (expr->identifier_expr.path) + { + if (expr->identifier_expr.path->module) + { + PRINTF("%s::", expr->identifier_expr.path->module); + } + } + if (expr->identifier_expr.ident) + { + fputs(expr->identifier_expr.ident, file); + } + break; + case EXPR_DESIGNATED_INITIALIZER_LIST: + case EXPR_INITIALIZER_LIST: + { + fputs("{ ", file); + FOREACH_IDX(i, Expr *, e, expr->initializer_list) + { + print_var_expr(file, e); + if (i != vec_size(expr->initializer_list) - 1) fputs(", ", file); + } + fputs(" }", file); + } + break; + case EXPR_LAMBDA: + fputs("TODO: EXPR_LAMBDA", file); + break; + case EXPR_MACRO_BLOCK: + fputs("TODO: EXPR_MACRO_BLOCK", file); + break; + case EXPR_MACRO_BODY_EXPANSION: + fputs("TODO: EXPR_MACRO_BODY_EXPANSION", file); + break; + case EXPR_MEMBER_GET: + fputs("TODO: EXPR_MEMBER_GET", file); + break; + case EXPR_NAMED_ARGUMENT: + PRINTF("%s: ", expr->named_argument_expr.name); + print_var_expr(file, expr->named_argument_expr.value); + break; + case EXPR_OPERATOR_CHARS: + fputs("TODO: EXPR_OPERATOR_CHARS", file); + break; + case EXPR_OPTIONAL: + print_var_expr(file, expr->inner_expr); + fputs("?", file); + break; + case EXPR_OTHER_CONTEXT: + fputs("TODO: EXPR_OTHER_CONTEXT", file); + break; + case EXPR_POINTER_OFFSET: + fputs("TODO: EXPR_POINTER_OFFSET", file); + break; + case EXPR_POST_UNARY: + print_var_expr_unary(file, &expr->unary_expr, true); + break; + case EXPR_RETHROW: + print_var_expr(file, expr->rethrow_expr.inner); + fputs("!", file); + break; + case EXPR_SLICE: + { + print_var_expr(file, exprptr(expr->slice_expr.expr)); + fputs("[", file); + print_var_expr_range(file, &expr->slice_expr.range); + fputs("]", file); + } + break; + case EXPR_SLICE_ASSIGN: + fputs("TODO: EXPR_SLICE_ASSIGN", file); + break; + case EXPR_SLICE_COPY: + fputs("TODO: EXPR_SLICE_COPY", file); + break; + case EXPR_SPLAT: + fputs("TODO: EXPR_SPLAT", file); + break; + case EXPR_STRINGIFY: + fputs("$stringify(", file); + print_var_expr(file, expr->inner_expr); + fputs(")", file); + break; + case EXPR_SUBSCRIPT: + fputs("TODO: EXPR_SUBSCRIPT", file); + break; + case EXPR_SUBSCRIPT_ADDR: + fputs("TODO: EXPR_SUBSCRIPT_ADDR", file); + break; + case EXPR_SUBSCRIPT_ASSIGN: + fputs("TODO: EXPR_SUBSCRIPT_ASSIGN", file); + break; + case EXPR_SWIZZLE: + fputs("TODO: EXPR_SWIZZLE", file); + break; + case EXPR_TERNARY: + { + print_var_expr(file, exprptr(expr->ternary_expr.cond)); + fputs(" ? ", file); + Expr *then = exprptr(expr->ternary_expr.then_expr); + if (then) print_var_expr(file, then); + fputs(" : ", file); + print_var_expr(file, exprptr(expr->ternary_expr.else_expr)); + } + break; + case EXPR_TYPEID: + print_type(file, expr->typeid_expr); + break; + case EXPR_TYPEID_INFO: + print_var_expr(file, exprptr(expr->typeid_info_expr.parent)); + break; + case EXPR_TYPEINFO: + print_type(file, expr->type_expr); + break; + case EXPR_UNARY: + print_var_expr_unary(file, &expr->unary_expr, false); + break; + case EXPR_VASPLAT: + fputs("$vasplat[", file); + print_var_expr_range(file, &expr->vasplat_expr); + fputs("]", file); + break; + case EXPR_NOP: + case EXPR_ASM: + case EXPR_COND: + case EXPR_RETVAL: + // if not in doc lexing "mode", this is unreachable + case EXPR_POISONED: + case EXPR_TEST_HOOK: + case EXPR_ANYSWITCH: + case EXPR_TRY_UNWRAP: + case EXPR_LAST_FAULT: + case EXPR_MACRO_BODY: + // nested inside EXPR_CALL, avoid macro substitution + case EXPR_DEFAULT_ARG: + case EXPR_CATCH_UNWRAP: + case EXPR_BENCHMARK_HOOK: + case EXPR_BUILTIN_ACCESS: + case EXPR_TRY_UNWRAP_CHAIN: + UNREACHABLE + } +} + static inline void emit_type_data(FILE *file, Module *module, Decl *type) { PRINTF("\t\t\"%s::%s\": {\n", module->name->module, type->name); @@ -253,6 +885,7 @@ static inline void emit_types(FILE *file) } fputs("\n\t},\n", file); } + static inline void emit_globals(FILE *file) { fputs("\t\"globals\": [\n", file); @@ -262,11 +895,53 @@ static inline void emit_globals(FILE *file) if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_GLOBAL) continue; if (decl_is_hidden(decl)) continue; INSERT_COMMA; - PRINTF("\t\t\"%s::%s\"", module->name->module, decl->name); + PRINTF("\t\t\"%s::%s\": {\n", module->name->module, decl->name); + fputs("\t\t\t\"type\": \"", file); + if (decl->var.type_info) + { + print_type(file, type_infoptr(decl->var.type_info)); + } + else + { + fputs("", file); + } + fputs("\",\n", file); + fputs("\t\t\t\"value\": \"", file); + if (decl->var.init_expr) print_var_expr(file, decl->var.init_expr); + fputs("\"\n\t\t}", file); + FOREACH_DECL_END; + } + fputs("\n\t],\n", file); +} + +static inline void emit_constants(FILE *file) +{ + fputs("\t\"constants\": [\n", file); + { + bool first = true; + FOREACH_DECL(Decl *decl, compiler.context.module_list) + if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_CONST) continue; + if (decl_is_hidden(decl)) continue; + INSERT_COMMA; + PRINTF("\t\t\"%s::%s\": {\n", module->name->module, decl->name); + fputs("\t\t\t\"type\": \"", file); + if (decl->var.type_info) + { + print_type(file, type_infoptr(decl->var.type_info)); + } + else + { + fputs("", file); + } + fputs("\",\n", file); + fputs("\t\t\t\"value\": \"", file); + print_var_expr(file, decl->var.init_expr); + fputs("\"\n\t\t}", file); FOREACH_DECL_END; } - PRINTF("\n\t]"); + fputs("\n\t]", file); } + static inline void emit_functions(FILE *file) { fputs("\t\"functions\": {\n", file); @@ -293,6 +968,7 @@ static inline void emit_functions(FILE *file) } fputs("\n\t},\n", file); } + static inline void emit_json_to_file(FILE *file) { fputs("{\n", file); @@ -300,10 +976,10 @@ static inline void emit_json_to_file(FILE *file) emit_types(file); emit_functions(file); emit_globals(file); + emit_constants(file); fputs("\n}", file); } - void emit_json(void) { emit_json_to_file(stdout);