use strict;
use warnings 'all';

do 'generate.pl';
our (@order, %ops);

sub generate_output {
    for my $opname (@order) {
	my ($op) = $ops{$opname};

	if (!$op->{OPTIMIZABLE} || $op->{UNIMPLEMENTED}) {
	    print "case $opname:\n";
	    print "  NOT_REACHED ();\n\n";
	    next;
	}

	my (@decls);
	my ($arg_idx) = 0;
	for my $arg (@{$op->{ARGS}}) {
	    my ($decl);
	    my ($name) = $arg->{NAME};
	    my ($type) = $arg->{TYPE};
	    my ($ctype) = c_type ($type);
	    my ($idx) = $arg->{IDX};
	    if (!defined ($idx)) {
		my ($func) = "get_$type->{ATOM}_arg";
		push (@decls, "${ctype}arg_$name = $func (node, $arg_idx)");
	    } else {
		my ($decl) = "size_t arg_$idx = node->arg_cnt";
		$decl .= " - $arg_idx" if $arg_idx;
		push (@decls, $decl);

		push (@decls, "${ctype}*arg_$name = "
		      . "get_$type->{ATOM}_args "
		      . " (node, $arg_idx, arg_$idx, e)");
	    }
	    $arg_idx++;
	}

	my ($sysmis_cond) = make_sysmis_decl ($op, "node->min_valid");
	push (@decls, $sysmis_cond) if defined $sysmis_cond;

	my (@args);
	for my $arg (@{$op->{ARGS}}) {
	    push (@args, "arg_$arg->{NAME}");
	    if (defined $arg->{IDX}) {
		my ($idx) = "arg_$arg->{IDX}";
		$idx .= " / $arg->{TIMES}" if $arg->{TIMES} != 1;
		push (@args, $idx);
	    }
	}
	for my $aux (@{$op->{AUX}}) {
	    my ($type) = $aux->{TYPE};
	    if ($type->{ROLE} eq 'leaf') {
		my ($func) = "get_$type->{ATOM}_arg";
		push (@args, "$func (node, $arg_idx)");
		$arg_idx++;
	    } elsif ($type->{ROLE} eq 'fixed') {
		push (@args, $type->{FIXED_VALUE});
	    } else {
		die;
	    }
	}

	my ($result) = "eval_$op->{OPNAME} (" . join (', ', @args) . ")";
	if (@decls && defined ($sysmis_cond)) {
	    my ($miss_ret) = $op->{RETURNS}{MISSING_VALUE};
	    push (@decls, c_type ($op->{RETURNS}) . "result = "
		  . "force_sysmis ? $miss_ret : $result");
	    $result = "result";
	}

	print "case $opname:\n";
	my ($alloc_func) = "expr_allocate_$op->{RETURNS}{NAME}";
	if (@decls) {
	    print "  {\n";
	    print "    $_;\n" foreach @decls;
	    print "    return $alloc_func (e, $result);\n";
	    print "  }\n";
	} else {
	    print "  return $alloc_func (e, $result);\n";
	}
	print "\n";
    }
}
