From cb1d36c6d8bc84f3422c71ab3eb29606e80f7837 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 26 Aug 2025 14:58:51 -0400 Subject: Formatting for reductions --- src/ast.c | 48 ++++++++++++++++++++++++++------------------- src/compile/comparisons.c | 14 ++++++++++++- src/compile/reductions.c | 7 ++++--- src/formatter/formatter.c | 50 +++++++++++++++++++++++++++++++++++++++++------ src/formatter/utils.c | 38 ----------------------------------- src/formatter/utils.h | 1 - src/parse/expressions.c | 4 +++- 7 files changed, 92 insertions(+), 70 deletions(-) diff --git a/src/ast.c b/src/ast.c index 3b58b919..03843438 100644 --- a/src/ast.c +++ b/src/ast.c @@ -76,32 +76,40 @@ CONSTFUNC const char *binop_method_name(ast_e tag) { CONSTFUNC const char *binop_operator(ast_e tag) { switch (tag) { - case Multiply: - case MultiplyUpdate: return "*"; - case Divide: - case DivideUpdate: return "/"; - case Mod: - case ModUpdate: return "%"; - case Plus: - case PlusUpdate: return "+"; - case Minus: - case MinusUpdate: return "-"; - case LeftShift: - case LeftShiftUpdate: return "<<"; - case RightShift: - case RightShiftUpdate: return ">>"; - case And: - case AndUpdate: return "&"; - case Or: - case OrUpdate: return "|"; - case Xor: - case XorUpdate: return "^"; + case Power: return "^"; + case PowerUpdate: return "^="; + case Concat: return "++"; + case ConcatUpdate: return "++="; + case Multiply: return "*"; + case MultiplyUpdate: return "*="; + case Divide: return "/"; + case DivideUpdate: return "/="; + case Mod: return "mod"; + case ModUpdate: return "mod="; + case Mod1: return "mod1"; + case Mod1Update: return "mod1="; + case Plus: return "+"; + case PlusUpdate: return "+="; + case Minus: return "-"; + case MinusUpdate: return "-="; + case LeftShift: return "<<"; + case LeftShiftUpdate: return "<<="; + case RightShift: return ">>"; + case RightShiftUpdate: return ">>="; + case And: return "and"; + case AndUpdate: return "and="; + case Or: return "or"; + case OrUpdate: return "or="; + case Xor: return "xor"; + case XorUpdate: return "xor="; case Equals: return "=="; case NotEquals: return "!="; case LessThan: return "<"; case LessThanOrEquals: return "<="; case GreaterThan: return ">"; case GreaterThanOrEquals: return ">="; + case Min: return "_min_"; + case Max: return "_max_"; default: return NULL; } } diff --git a/src/compile/comparisons.c b/src/compile/comparisons.c index d73664de..d7531261 100644 --- a/src/compile/comparisons.c +++ b/src/compile/comparisons.c @@ -7,6 +7,18 @@ #include "../typecheck.h" #include "compilation.h" +static CONSTFUNC const char *comparison_operator(ast_e tag) { + switch (tag) { + case Equals: return "=="; + case NotEquals: return "!="; + case LessThan: return "<"; + case LessThanOrEquals: return "<="; + case GreaterThan: return ">"; + case GreaterThanOrEquals: return ">="; + default: return NULL; + } +} + Text_t compile_comparison(env_t *env, ast_t *ast) { switch (ast->tag) { @@ -75,7 +87,7 @@ Text_t compile_comparison(env_t *env, ast_t *ast) { if (ast->tag == Compare) return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")"); - const char *op = binop_operator(ast->tag); + const char *op = comparison_operator(ast->tag); switch (operand_t->tag) { case BigIntType: return Texts("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)"); case BoolType: diff --git a/src/compile/reductions.c b/src/compile/reductions.c index e0477a9c..1652384c 100644 --- a/src/compile/reductions.c +++ b/src/compile/reductions.c @@ -12,6 +12,7 @@ public Text_t compile_reduction(env_t *env, ast_t *ast) { DeclareMatch(reduction, ast, Reduction); ast_e op = reduction->op; + const char *op_str = binop_operator(op); type_t *iter_t = get_type(env, reduction->iter); type_t *item_t = get_iterated_type(iter_t); @@ -29,7 +30,7 @@ Text_t compile_reduction(env_t *env, ast_t *ast) { type_t *item_value_type = item_t; ast_t *item_value = item; if (reduction->key) { - set_binding(body_scope, "$", item_t, compile(body_scope, item)); + set_binding(body_scope, op_str, item_t, compile(body_scope, item)); item_value = reduction->key; item_value_type = get_type(body_scope, reduction->key); } @@ -67,7 +68,7 @@ Text_t compile_reduction(env_t *env, ast_t *ast) { ast_e cmp_op = op == Min ? LessThan : GreaterThan; if (reduction->key) { env_t *key_scope = fresh_scope(env); - set_binding(key_scope, "$", item_t, item_code); + set_binding(key_scope, op_str, item_t, item_code); type_t *key_type = get_type(key_scope, reduction->key); Text_t superlative_key = op == Min ? Text("min_key") : Text("max_key"); code = Texts(code, compile_declaration(key_type, superlative_key), ";\n"); @@ -111,7 +112,7 @@ Text_t compile_reduction(env_t *env, ast_t *ast) { type_t *reduction_type = Match(get_type(env, ast), OptionalType)->type; ast_t *item_value = item; if (reduction->key) { - set_binding(body_scope, "$", item_t, compile(body_scope, item)); + set_binding(body_scope, op_str, item_t, compile(body_scope, item)); item_value = reduction->key; } diff --git a/src/formatter/formatter.c b/src/formatter/formatter.c index a48a1f33..5dd65d04 100644 --- a/src/formatter/formatter.c +++ b/src/formatter/formatter.c @@ -44,6 +44,7 @@ OptionalText_t format_inline_code(ast_t *ast, Table_t comments) { /*inline*/ case LangDef: /*inline*/ case Extend: /*inline*/ case FunctionDef: + /*inline*/ case ConvertDef: /*inline*/ case DocTest: return NONE_TEXT; /*inline*/ case Lambda: { @@ -232,6 +233,14 @@ OptionalText_t format_inline_code(ast_t *ast, Table_t comments) { ast_t *key = ast->tag == Min ? Match(ast, Min)->key : Match(ast, Max)->key; return Texts(lhs, key ? fmt_inline(key, comments) : (ast->tag == Min ? Text(" _min_ ") : Text(" _max_ ")), rhs); } + /*inline*/ case Reduction: { + DeclareMatch(reduction, ast, Reduction); + if (reduction->key) { + return Texts("(", fmt_inline(reduction->key, comments), ": ", fmt_inline(reduction->iter, comments)); + } else { + return Texts("(", binop_operator(reduction->op), ": ", fmt_inline(reduction->iter, comments)); + } + } /*inline*/ case None: return Text("none"); /*inline*/ case Bool: @@ -259,7 +268,7 @@ OptionalText_t format_inline_code(ast_t *ast, Table_t comments) { } /*inline*/ case BINOP_CASES: { binary_operands_t operands = BINARY_OPERANDS(ast); - const char *op = binop_tomo_operator(ast->tag); + const char *op = binop_operator(ast->tag); Text_t lhs = fmt_inline(operands.lhs, comments); Text_t rhs = fmt_inline(operands.rhs, comments); @@ -274,7 +283,7 @@ OptionalText_t format_inline_code(ast_t *ast, Table_t comments) { rhs = parenthesize(rhs, EMPTY_TEXT); Text_t space = op_tightness[ast->tag] >= op_tightness[Multiply] ? EMPTY_TEXT : Text(" "); - return Texts(lhs, space, Text$from_str(binop_tomo_operator(ast->tag)), space, rhs); + return Texts(lhs, space, Text$from_str(binop_operator(ast->tag)), space, rhs); } default: { fail("Formatting not implemented for: ", ast_to_sexp(ast)); @@ -412,6 +421,16 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { code = Texts(code, ")\n", indent, single_indent, fmt(lambda->body, comments, Texts(indent, single_indent))); return Texts(code); } + /*multiline*/ case ConvertDef: { + DeclareMatch(convert, ast, ConvertDef); + Text_t code = Texts("convert (", format_args(convert->args, comments, indent)); + if (convert->ret_type) + code = Texts(code, convert->args ? Text(" -> ") : Text("-> "), format_type(convert->ret_type)); + if (convert->cache) code = Texts(code, "; cache=", fmt(convert->cache, comments, indent)); + if (convert->is_inline) code = Texts(code, "; inline"); + code = Texts(code, ")\n", indent, single_indent, fmt(convert->body, comments, Texts(indent, single_indent))); + return Texts(code); + } /*multiline*/ case StructDef: { DeclareMatch(def, ast, StructDef); Text_t code = Texts("struct ", Text$from_str(def->name), "(", format_args(def->fields, comments, indent)); @@ -484,6 +503,7 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { return Texts(fmt(entry->key, comments, indent), "=", fmt(entry->value, comments, indent)); } /*multiline*/ case Declare: { + if (inlined_fits) return inlined; DeclareMatch(decl, ast, Declare); Text_t code = fmt(decl->var, comments, indent); if (decl->type) code = Texts(code, " : ", format_type(decl->type)); @@ -492,6 +512,7 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { return code; } /*multiline*/ case Assign: { + if (inlined_fits) return inlined; DeclareMatch(assign, ast, Assign); Text_t code = EMPTY_TEXT; for (ast_list_t *target = assign->targets; target; target = target->next) { @@ -508,15 +529,18 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { /*multiline*/ case Pass: return Text("pass"); /*multiline*/ case Return: { + if (inlined_fits) return inlined; ast_t *value = Match(ast, Return)->value; return value ? Texts("return ", fmt(value, comments, indent)) : Text("return"); } /*inline*/ case Not: { + if (inlined_fits) return inlined; ast_t *val = Match(ast, Not)->value; if (is_binary_operation(val)) return Texts("not ", termify(val, comments, indent)); else return Texts("not ", fmt(val, comments, indent)); } /*inline*/ case Negative: { + if (inlined_fits) return inlined; ast_t *val = Match(ast, Negative)->value; if (is_binary_operation(val)) return Texts("-", termify(val, comments, indent)); else return Texts("-", fmt(val, comments, indent)); @@ -542,10 +566,12 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { return Texts(termify(val, comments, indent), "!"); } /*multiline*/ case FieldAccess: { + if (inlined_fits) return inlined; DeclareMatch(access, ast, FieldAccess); return Texts(termify(access->fielded, comments, indent), ".", Text$from_str(access->field)); } /*multiline*/ case Index: { + if (inlined_fits) return inlined; DeclareMatch(index, ast, Index); if (index->index) return Texts(termify(index->indexed, comments, indent), "[", fmt(index->index, comments, indent), "]"); @@ -583,14 +609,26 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { assert(inlined.length > 0); return inlined; } - /*inline*/ case Min: - /*inline*/ case Max: { + /*multiline*/ case Min: + /*multiline*/ case Max: { + if (inlined_fits) return inlined; Text_t lhs = termify(ast->tag == Min ? Match(ast, Min)->lhs : Match(ast, Max)->lhs, comments, indent); Text_t rhs = termify(ast->tag == Min ? Match(ast, Min)->rhs : Match(ast, Max)->rhs, comments, indent); ast_t *key = ast->tag == Min ? Match(ast, Min)->key : Match(ast, Max)->key; Text_t op = key ? fmt(key, comments, indent) : (ast->tag == Min ? Text("_min_") : Text("_max_")); return Texts(lhs, " ", op, " ", rhs); } + /*multiline*/ case Reduction: { + if (inlined_fits) return inlined; + DeclareMatch(reduction, ast, Reduction); + if (reduction->key) { + return Texts("(", fmt(reduction->key, comments, Texts(indent, single_indent)), ": ", + fmt(reduction->iter, comments, Texts(indent, single_indent))); + } else { + return Texts("(", binop_operator(reduction->op), ": ", + fmt(reduction->iter, comments, Texts(indent, single_indent))); + } + } /*multiline*/ case Stop: /*multiline*/ case Skip: /*multiline*/ case None: @@ -627,7 +665,7 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { /*multiline*/ case BINOP_CASES: { if (inlined_fits) return inlined; binary_operands_t operands = BINARY_OPERANDS(ast); - const char *op = binop_tomo_operator(ast->tag); + const char *op = binop_operator(ast->tag); Text_t lhs = fmt(operands.lhs, comments, indent); Text_t rhs = fmt(operands.rhs, comments, indent); @@ -641,7 +679,7 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { rhs = parenthesize(rhs, indent); Text_t space = op_tightness[ast->tag] >= op_tightness[Multiply] ? EMPTY_TEXT : Text(" "); - return Texts(lhs, space, Text$from_str(binop_tomo_operator(ast->tag)), space, rhs); + return Texts(lhs, space, Text$from_str(binop_operator(ast->tag)), space, rhs); } default: { if (inlined_fits) return inlined; diff --git a/src/formatter/utils.c b/src/formatter/utils.c index a032ec2f..fa4ec806 100644 --- a/src/formatter/utils.c +++ b/src/formatter/utils.c @@ -74,44 +74,6 @@ CONSTFUNC ast_t *unwrap_block(ast_t *ast) { return ast; } -CONSTFUNC const char *binop_tomo_operator(ast_e tag) { - switch (tag) { - case Power: return "^"; - case PowerUpdate: return "^="; - case Concat: return "++"; - case ConcatUpdate: return "++="; - case Multiply: return "*"; - case MultiplyUpdate: return "*="; - case Divide: return "/"; - case DivideUpdate: return "/="; - case Mod: return "mod"; - case ModUpdate: return "mod="; - case Mod1: return "mod1"; - case Mod1Update: return "mod1="; - case Plus: return "+"; - case PlusUpdate: return "+="; - case Minus: return "-"; - case MinusUpdate: return "-="; - case LeftShift: return "<<"; - case LeftShiftUpdate: return "<<="; - case RightShift: return ">>"; - case RightShiftUpdate: return ">>="; - case And: return "and"; - case AndUpdate: return "and="; - case Or: return "or"; - case OrUpdate: return "or="; - case Xor: return "xor"; - case XorUpdate: return "xor="; - case Equals: return "=="; - case NotEquals: return "!="; - case LessThan: return "<"; - case LessThanOrEquals: return "<="; - case GreaterThan: return ">"; - case GreaterThanOrEquals: return ">="; - default: return NULL; - } -} - OptionalText_t termify_inline(ast_t *ast, Table_t comments) { if (range_has_comment(ast->start, ast->end, comments)) return NONE_TEXT; switch (ast->tag) { diff --git a/src/formatter/utils.h b/src/formatter/utils.h index 9dc230e4..d847c2fb 100644 --- a/src/formatter/utils.h +++ b/src/formatter/utils.h @@ -26,6 +26,5 @@ CONSTFUNC bool should_have_blank_line(ast_t *ast); Text_t indent_code(Text_t code); Text_t parenthesize(Text_t code, Text_t indent); CONSTFUNC ast_t *unwrap_block(ast_t *ast); -CONSTFUNC const char *binop_tomo_operator(ast_e tag); OptionalText_t termify_inline(ast_t *ast, Table_t comments); Text_t termify(ast_t *ast, Table_t comments, Text_t indent); diff --git a/src/parse/expressions.c b/src/parse/expressions.c index 6104b2d2..32133fe9 100644 --- a/src/parse/expressions.c +++ b/src/parse/expressions.c @@ -49,7 +49,9 @@ ast_t *parse_reduction(parse_ctx_t *ctx, const char *pos) { ast_e op = match_binary_operator(&pos); if (op == Unknown) return NULL; - ast_t *key = NewAST(ctx->file, pos, pos, Var, .name = "$"); + const char *op_str = binop_operator(op); + assert(op_str); + ast_t *key = NewAST(ctx->file, pos, pos, Var, .name = op_str); for (bool progress = true; progress;) { ast_t *new_term; progress = -- cgit v1.2.3