/* radare - LGPL - Copyright 2026 - pancake */

#include <r_asm.h>

static const char *pseudo_rules[] = {
	"stop_code/0/halt",
	"nop/0/nop",
	"pop_top/0/pop()",
	"dup_top/0/push(peek())",
	"dup_top_two/0/a = pop(); b = pop(); push(b); push(a); push(b); push(a)",
	"rot_two/0/a = pop(); b = pop(); push(a); push(b)",
	"rot_three/0/a = pop(); b = pop(); c = pop(); push(a); push(c); push(b)",
	"rot_four/0/a = pop(); b = pop(); c = pop(); d = pop(); push(a); push(d); push(c); push(b)",
	"return_value/0/return pop()",
	"yield_value/0/yield pop()",
	"yield_from/0/send = pop(); it = pop(); push(yield_from(it, send))",
	"get_iter/0/push(iter(pop()))",
	"get_yield_from_iter/0/push(yield_from_iter(pop()))",
	"load_build_class/0/push(__build_class__)",
	"break_loop/0/break",
	"import_star/0/import_star(pop())",
	"pop_block/0/pop_block()",
	"pop_except/0/pop_except()",
	"binary_subscr/0/index = pop(); obj = pop(); push(obj[index])",
	"store_subscr/0/index = pop(); obj = pop(); value = pop(); obj[index] = value",
	"delete_subscr/0/index = pop(); obj = pop(); delete obj[index]",
	"store_map/0/value = pop(); key = pop(); map = peek(); map[key] = value",
	"unary_positive/0/value = pop(); push(+value)",
	"unary_negative/0/value = pop(); push(-value)",
	"unary_not/0/value = pop(); push(!value)",
	"unary_invert/0/value = pop(); push(~value)",
	"binary_power/0/rhs = pop(); lhs = pop(); push(lhs ** rhs)",
	"binary_multiply/0/rhs = pop(); lhs = pop(); push(lhs * rhs)",
	"binary_matrix_multiply/0/rhs = pop(); lhs = pop(); push(lhs @ rhs)",
	"binary_modulo/0/rhs = pop(); lhs = pop(); push(lhs % rhs)",
	"binary_add/0/rhs = pop(); lhs = pop(); push(lhs + rhs)",
	"binary_subtract/0/rhs = pop(); lhs = pop(); push(lhs - rhs)",
	"binary_floor_divide/0/rhs = pop(); lhs = pop(); push(lhs // rhs)",
	"binary_true_divide/0/rhs = pop(); lhs = pop(); push(lhs / rhs)",
	"binary_lshift/0/rhs = pop(); lhs = pop(); push(lhs << rhs)",
	"binary_rshift/0/rhs = pop(); lhs = pop(); push(lhs >> rhs)",
	"binary_and/0/rhs = pop(); lhs = pop(); push(lhs & rhs)",
	"binary_xor/0/rhs = pop(); lhs = pop(); push(lhs ^ rhs)",
	"binary_or/0/rhs = pop(); lhs = pop(); push(lhs | rhs)",
	"inplace_power/0/rhs = pop(); lhs = pop(); push(lhs ** rhs)",
	"inplace_multiply/0/rhs = pop(); lhs = pop(); push(lhs * rhs)",
	"inplace_matrix_multiply/0/rhs = pop(); lhs = pop(); push(lhs @ rhs)",
	"inplace_modulo/0/rhs = pop(); lhs = pop(); push(lhs % rhs)",
	"inplace_add/0/rhs = pop(); lhs = pop(); push(lhs + rhs)",
	"inplace_subtract/0/rhs = pop(); lhs = pop(); push(lhs - rhs)",
	"inplace_floor_divide/0/rhs = pop(); lhs = pop(); push(lhs // rhs)",
	"inplace_true_divide/0/rhs = pop(); lhs = pop(); push(lhs / rhs)",
	"inplace_lshift/0/rhs = pop(); lhs = pop(); push(lhs << rhs)",
	"inplace_rshift/0/rhs = pop(); lhs = pop(); push(lhs >> rhs)",
	"inplace_and/0/rhs = pop(); lhs = pop(); push(lhs & rhs)",
	"inplace_xor/0/rhs = pop(); lhs = pop(); push(lhs ^ rhs)",
	"inplace_or/0/rhs = pop(); lhs = pop(); push(lhs | rhs)",
	"load_const/1/push($1)",
	"load_name/1/push($1)",
	"load_fast/1/push($1)",
	"load_global/1/push($1)",
	"load_deref/1/push($1)",
	"load_classderef/1/push($1)",
	"load_closure/1/push($1)",
	"load_attr/1/obj = pop(); push(obj.$1)",
	"load_method/1/obj = pop(); push(obj.$1)",
	"store_name/1/$1 = pop()",
	"store_fast/1/$1 = pop()",
	"store_global/1/$1 = pop()",
	"store_deref/1/$1 = pop()",
	"store_classderef/1/$1 = pop()",
	"store_annotation/1/$1 = pop()",
	"store_attr/1/value = pop(); obj = pop(); obj.$1 = value",
	"delete_name/1/delete $1",
	"delete_fast/1/delete $1",
	"delete_global/1/delete $1",
	"delete_deref/1/delete $1",
	"delete_classderef/1/delete $1",
	"delete_attr/1/obj = pop(); delete obj.$1",
	"compare_op/1/rhs = pop(); lhs = pop(); push(lhs $1 rhs)",
	"jump_forward/1/goto $1",
	"jump_absolute/1/goto $1",
	"continue_loop/1/goto $1",
	"jump_if_false_or_pop/1/if (!peek()) goto $1; pop()",
	"jump_if_true_or_pop/1/if (peek()) goto $1; pop()",
	"jump_if_false/1/if (!peek()) goto $1",
	"jump_if_true/1/if (peek()) goto $1",
	"pop_jump_if_false/1/if (!pop()) goto $1",
	"pop_jump_if_true/1/if (pop()) goto $1",
	"for_iter/1/it = peek(); if (!has_next(it)) goto $1; push(next(it))",
	"call_function/1/args = popn($1); fn = pop(); push(call(fn, args))",
	"call_method/1/args = popn($1); fn = pop(); push(call(fn, args))",
	"call_function_var/1/vargs = pop(); args = popn($1); fn = pop(); push(call_var(fn, args, vargs))",
	"call_function_var_kw/1/vargs = pop(); args = popn($1); fn = pop(); push(call_var(fn, args, vargs))",
	"call_function_kw/1/kw = pop(); args = popn($1); fn = pop(); push(call_kw(fn, args, kw))",
	"call_function_ex/1/args = pop(); fn = pop(); push(call(fn, args))",
	"make_function/1/meta = popn($1); name = pop(); code = pop(); push(make_function(code, name, meta))",
	"make_closure/1/meta = popn($1); name = pop(); code = pop(); push(make_function(code, name, meta))",
	"raise_varargs/1/raise(popn($1))",
	"build_tuple/1/push(tuple(popn($1)))",
	"build_list/1/push(list(popn($1)))",
	"build_set/1/push(set(popn($1)))",
	"build_string/1/push(join(popn($1)))",
	"build_map/1/push(new_map($1))",
	"build_const_key_map/1/keys = pop(); values = popn($1); push(dict(zip(keys, values)))",
	"build_slice/1/push(build_slice(popn($1)))",
	"unpack_sequence/1/pushn(unpack(pop(), $1))",
	"unpack_ex/1/pushn(unpack(pop(), $1))",
	"import_name/1/fromlist = pop(); level = pop(); push(import_module($1, level, fromlist))",
	"import_from/1/module = peek(); push(module.$1)",
	"list_append/1/peekn($1).append(pop())",
	"set_add/1/peekn($1).add(pop())",
	"map_add/1/value = pop(); key = pop(); peekn($1)[key] = value",
	"format_value/1/value = pop(); push(format(value, $1))",
	"extended_arg/1/extarg = $1",
	"setup_loop/1/setup_loop -> $1",
	"setup_except/1/setup_except -> $1",
	"setup_finally/1/setup_finally -> $1",
	"setup_with/1/setup_with -> $1",
	"setup_async_with/1/setup_async_with -> $1",
	NULL
};

static char *parse(RAsmPluginSession *aps, const char *data) {
	return r_str_pseudo_transform (pseudo_rules, data);
}

RAsmPlugin r_asm_plugin_pyc = {
	.meta = {
		.name = "pyc",
		.desc = "Python bytecode pseudo syntax",
		.author = "pancake",
		.license = "LGPL-3.0-only",
	},
	.parse = parse,
};

#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
	.type = R_LIB_TYPE_ASM,
	.data = &r_asm_plugin_pyc,
	.version = R2_VERSION
};
#endif
