feat: 支持 class 私有字段与品牌检查
This commit is contained in:
@@ -144,6 +144,8 @@ pub(crate) struct CompileCtx {
|
||||
pub(crate) in_instance_method: bool,
|
||||
pub(crate) in_static_method: bool,
|
||||
pub(crate) static_block_this_reg: Option<u8>,
|
||||
pub(crate) private_name_map: Vec<(String, u32)>,
|
||||
pub(crate) next_private_name_id: u32,
|
||||
pub(crate) after_super_insert: Option<Vec<opcode::Instr>>,
|
||||
pub(crate) after_super_inserted: bool,
|
||||
/// Set when alloc_reg() overflows into the reserved this/new.target range (≥254).
|
||||
@@ -208,6 +210,8 @@ impl CompileCtx {
|
||||
in_instance_method: false,
|
||||
in_static_method: false,
|
||||
static_block_this_reg: None,
|
||||
private_name_map: Vec::new(),
|
||||
next_private_name_id: 1,
|
||||
after_super_insert: None,
|
||||
after_super_inserted: false,
|
||||
reg_overflow: false,
|
||||
@@ -497,6 +501,8 @@ impl Compiler {
|
||||
// Inherit parent's builtin_reg_map so builtin identifiers (Math, Object, etc.)
|
||||
// resolve to the correct pre-allocated registers in the sub-module's register file.
|
||||
ctx.builtin_reg_map = parent_ctx.builtin_reg_map.clone();
|
||||
ctx.private_name_map = parent_ctx.private_name_map.clone();
|
||||
ctx.next_private_name_id = parent_ctx.next_private_name_id;
|
||||
|
||||
// Propagate enclosing_this_reg so nested arrow functions capture the correct `this`.
|
||||
ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg;
|
||||
|
||||
@@ -132,6 +132,14 @@ impl Compiler {
|
||||
if matches!(method.kind, MethodDefinitionKind::Constructor) {
|
||||
continue;
|
||||
}
|
||||
if matches!(method.key, oxide_parser::PropertyKey::PrivateIdentifier(_)) {
|
||||
if method.r#static {
|
||||
ctx.alloc_reg();
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 3;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
ctx.alloc_reg(); // key_reg
|
||||
ctx.projected_pc += 1;
|
||||
ctx.alloc_reg(); // method_reg
|
||||
@@ -479,6 +487,12 @@ impl Compiler {
|
||||
ctx.restore_reg_checkpoint(checkpoint.saturating_add(1));
|
||||
}
|
||||
}
|
||||
Expression::PrivateInExpression(pin) => {
|
||||
self.count_expression(&pin.right, ctx);
|
||||
ctx.alloc_reg();
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 2;
|
||||
}
|
||||
Expression::UnaryExpression(un) => {
|
||||
match un.operator {
|
||||
UnaryOperator::Delete => {
|
||||
@@ -516,6 +530,12 @@ impl Compiler {
|
||||
return;
|
||||
}
|
||||
match &call.callee {
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
self.count_expression(&member.object, ctx);
|
||||
ctx.alloc_reg();
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 2;
|
||||
}
|
||||
Expression::StaticMemberExpression(member) => {
|
||||
if matches!(&member.object, Expression::Super(_)) {
|
||||
ctx.alloc_reg(); // this register
|
||||
@@ -566,6 +586,11 @@ impl Compiler {
|
||||
self.count_expression(&assign.right, ctx);
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 1; // SET_PROP_DYNAMIC
|
||||
} else if let oxide_parser::AssignmentTarget::PrivateFieldExpression(member) = &assign.left {
|
||||
self.count_expression(&member.object, ctx);
|
||||
self.count_expression(&assign.right, ctx);
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 2; // LOAD_CONST private id + SET_PRIVATE
|
||||
} else if let oxide_parser::AssignmentTarget::ArrayAssignmentTarget(ap) = &assign.left {
|
||||
self.count_expression(&assign.right, ctx);
|
||||
self.count_array_assignment(ap, ctx);
|
||||
@@ -773,6 +798,12 @@ impl Compiler {
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 1; // GET_PROP_DYNAMIC
|
||||
}
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
self.count_expression(&member.object, ctx);
|
||||
ctx.alloc_reg();
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 2;
|
||||
}
|
||||
Expression::ParenthesizedExpression(p) => {
|
||||
self.count_expression(&p.expression, ctx);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,21 @@ use crate::compiler::{
|
||||
use crate::module::Constant;
|
||||
|
||||
impl Compiler {
|
||||
fn private_name_id(&self, name: &str, ctx: &CompileCtx) -> Result<u32, String> {
|
||||
ctx.private_name_map
|
||||
.iter()
|
||||
.find_map(|(n, id)| (n == name).then_some(*id))
|
||||
.ok_or_else(|| format!("private name #{name} is not defined"))
|
||||
}
|
||||
|
||||
fn emit_private_id_reg(&self, name: &str, ctx: &mut CompileCtx) -> Result<u8, String> {
|
||||
let id = self.private_name_id(name, ctx)?;
|
||||
let idx = ctx.add_constant(Constant::Int(id as i32));
|
||||
let reg = ctx.alloc_reg();
|
||||
ctx.emit_load_const(reg, idx);
|
||||
Ok(reg)
|
||||
}
|
||||
|
||||
fn emit_class_key_reg(&self, key: &PropertyKey, computed: bool, ctx: &mut CompileCtx) -> Result<u8, String> {
|
||||
if !computed {
|
||||
let name = self.class_property_name(key)?;
|
||||
@@ -54,6 +69,32 @@ impl Compiler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_private_field_init(
|
||||
&self, target_reg: u8, name: &str, value: Option<&Expression>, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
let key_reg = self.emit_private_id_reg(name, ctx)?;
|
||||
let value_reg = if let Some(expr) = value {
|
||||
self.emit_expression(expr, ctx)?
|
||||
} else {
|
||||
self.emit_undefined(ctx)
|
||||
};
|
||||
ctx.emit(opcode::encode(OpCode::INIT_PRIVATE, target_reg, value_reg, key_reg));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_private_method_init(
|
||||
&self, target_reg: u8, method: &oxide_parser::MethodDefinition, home_reg: u8, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
let PropertyKey::PrivateIdentifier(private) = &method.key else {
|
||||
return Err("expected private method key".into());
|
||||
};
|
||||
let name = private.name.as_str();
|
||||
let key_reg = self.emit_private_id_reg(name, ctx)?;
|
||||
let method_reg = self.emit_class_method_function(method, name, home_reg, ctx, &[])?;
|
||||
ctx.emit(opcode::encode(OpCode::INIT_PRIVATE, target_reg, method_reg, key_reg));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn count_public_field_init(
|
||||
&self, key: &PropertyKey, computed: bool, value: Option<&Expression>, ctx: &mut CompileCtx,
|
||||
) {
|
||||
@@ -67,6 +108,18 @@ impl Compiler {
|
||||
ctx.projected_pc += 1;
|
||||
}
|
||||
|
||||
fn count_private_field_init(&self, value: Option<&Expression>, ctx: &mut CompileCtx) {
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 1;
|
||||
if let Some(expr) = value {
|
||||
self.count_expression(expr, ctx);
|
||||
} else {
|
||||
ctx.alloc_reg();
|
||||
ctx.projected_pc += 1;
|
||||
}
|
||||
ctx.projected_pc += 1;
|
||||
}
|
||||
|
||||
fn static_property_name(&self, key: &PropertyKey) -> Result<String, String> {
|
||||
match key {
|
||||
PropertyKey::StaticIdentifier(ident) => Ok(ident.name.as_str().to_string()),
|
||||
@@ -368,14 +421,21 @@ impl Compiler {
|
||||
fn emit_class(&self, class: &Class, ctx: &mut CompileCtx) -> Result<u8, String> {
|
||||
let mut constructor_method = None;
|
||||
let mut instance_fields = Vec::new();
|
||||
let mut private_names = Vec::<(String, u32)>::new();
|
||||
let is_derived = class.super_class.is_some();
|
||||
|
||||
for element in &class.body.body {
|
||||
match element {
|
||||
ClassElement::MethodDefinition(method) => {
|
||||
let method = method.as_ref();
|
||||
if matches!(method.key, PropertyKey::PrivateIdentifier(_)) {
|
||||
return Err("private class elements not yet supported".into());
|
||||
if let PropertyKey::PrivateIdentifier(private) = &method.key {
|
||||
let name = private.name.as_str().to_string();
|
||||
if private_names.iter().any(|(existing, _)| existing == &name) {
|
||||
return Err(format!("duplicate private name #{name}"));
|
||||
}
|
||||
let id = ctx.next_private_name_id;
|
||||
ctx.next_private_name_id = ctx.next_private_name_id.saturating_add(1);
|
||||
private_names.push((name, id));
|
||||
}
|
||||
if method.kind == MethodDefinitionKind::Constructor {
|
||||
if constructor_method.is_some() {
|
||||
@@ -386,8 +446,14 @@ impl Compiler {
|
||||
}
|
||||
ClassElement::PropertyDefinition(prop) => {
|
||||
let prop = prop.as_ref();
|
||||
if matches!(prop.key, PropertyKey::PrivateIdentifier(_)) {
|
||||
return Err("private class elements not yet supported".into());
|
||||
if let PropertyKey::PrivateIdentifier(private) = &prop.key {
|
||||
let name = private.name.as_str().to_string();
|
||||
if private_names.iter().any(|(existing, _)| existing == &name) {
|
||||
return Err(format!("duplicate private name #{name}"));
|
||||
}
|
||||
let id = ctx.next_private_name_id;
|
||||
ctx.next_private_name_id = ctx.next_private_name_id.saturating_add(1);
|
||||
private_names.push((name, id));
|
||||
}
|
||||
if !prop.r#static {
|
||||
instance_fields.push(prop);
|
||||
@@ -409,7 +475,9 @@ impl Compiler {
|
||||
};
|
||||
|
||||
let saved_derived = ctx.in_derived_constructor;
|
||||
let saved_private_names = ctx.private_name_map.clone();
|
||||
ctx.in_derived_constructor = is_derived;
|
||||
ctx.private_name_map = private_names.clone();
|
||||
|
||||
let mut ctor_module = if let Some(method) = constructor_method {
|
||||
let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?;
|
||||
@@ -422,18 +490,36 @@ impl Compiler {
|
||||
FunctionBodyContext::ClassElement,
|
||||
Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| {
|
||||
for field in &instance_fields {
|
||||
compiler.count_public_field_init(&field.key, field.computed, field.value.as_ref(), field_ctx);
|
||||
if matches!(field.key, PropertyKey::PrivateIdentifier(_)) {
|
||||
compiler.count_private_field_init(field.value.as_ref(), field_ctx);
|
||||
} else {
|
||||
compiler.count_public_field_init(
|
||||
&field.key,
|
||||
field.computed,
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}),
|
||||
Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> {
|
||||
for field in &instance_fields {
|
||||
compiler.emit_public_field_init(
|
||||
254,
|
||||
&field.key,
|
||||
field.computed,
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
)?;
|
||||
if let PropertyKey::PrivateIdentifier(private) = &field.key {
|
||||
compiler.emit_private_field_init(
|
||||
254,
|
||||
private.name.as_str(),
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
)?;
|
||||
} else {
|
||||
compiler.emit_public_field_init(
|
||||
254,
|
||||
&field.key,
|
||||
field.computed,
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}),
|
||||
@@ -449,18 +535,36 @@ impl Compiler {
|
||||
FunctionBodyContext::ClassElement,
|
||||
Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| {
|
||||
for field in &instance_fields {
|
||||
compiler.count_public_field_init(&field.key, field.computed, field.value.as_ref(), field_ctx);
|
||||
if matches!(field.key, PropertyKey::PrivateIdentifier(_)) {
|
||||
compiler.count_private_field_init(field.value.as_ref(), field_ctx);
|
||||
} else {
|
||||
compiler.count_public_field_init(
|
||||
&field.key,
|
||||
field.computed,
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}),
|
||||
Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> {
|
||||
for field in &instance_fields {
|
||||
compiler.emit_public_field_init(
|
||||
254,
|
||||
&field.key,
|
||||
field.computed,
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
)?;
|
||||
if let PropertyKey::PrivateIdentifier(private) = &field.key {
|
||||
compiler.emit_private_field_init(
|
||||
254,
|
||||
private.name.as_str(),
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
)?;
|
||||
} else {
|
||||
compiler.emit_public_field_init(
|
||||
254,
|
||||
&field.key,
|
||||
field.computed,
|
||||
field.value.as_ref(),
|
||||
field_ctx,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}),
|
||||
@@ -473,8 +577,19 @@ impl Compiler {
|
||||
module.bytecode.push(opcode::encode(OpCode::SUPER_CALL, 0, 0, 0));
|
||||
module.bytecode.push(0);
|
||||
let mut field_ctx = CompileCtx::new();
|
||||
field_ctx.private_name_map = private_names.clone();
|
||||
for field in &instance_fields {
|
||||
self.emit_public_field_init(254, &field.key, field.computed, field.value.as_ref(), &mut field_ctx)?;
|
||||
if let PropertyKey::PrivateIdentifier(private) = &field.key {
|
||||
self.emit_private_field_init(254, private.name.as_str(), field.value.as_ref(), &mut field_ctx)?;
|
||||
} else {
|
||||
self.emit_public_field_init(
|
||||
254,
|
||||
&field.key,
|
||||
field.computed,
|
||||
field.value.as_ref(),
|
||||
&mut field_ctx,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
module.bytecode.extend(field_ctx.bytecode);
|
||||
module.constants = field_ctx.constants;
|
||||
@@ -524,6 +639,11 @@ impl Compiler {
|
||||
if method.kind == MethodDefinitionKind::Constructor {
|
||||
continue;
|
||||
}
|
||||
if matches!(method.key, PropertyKey::PrivateIdentifier(_)) {
|
||||
let home_reg = if method.r#static { ctor_reg } else { proto_reg };
|
||||
self.emit_private_method_init(home_reg, method, home_reg, ctx)?;
|
||||
continue;
|
||||
}
|
||||
let home_reg = if method.r#static { ctor_reg } else { proto_reg };
|
||||
let key_reg = self.emit_class_key_reg(&method.key, method.computed, ctx)?;
|
||||
let method_name = if method.computed {
|
||||
@@ -564,7 +684,11 @@ impl Compiler {
|
||||
if prop.r#static {
|
||||
let saved_static_this = ctx.static_block_this_reg;
|
||||
ctx.static_block_this_reg = Some(ctor_reg);
|
||||
self.emit_public_field_init(ctor_reg, &prop.key, prop.computed, prop.value.as_ref(), ctx)?;
|
||||
if let PropertyKey::PrivateIdentifier(private) = &prop.key {
|
||||
self.emit_private_field_init(ctor_reg, private.name.as_str(), prop.value.as_ref(), ctx)?;
|
||||
} else {
|
||||
self.emit_public_field_init(ctor_reg, &prop.key, prop.computed, prop.value.as_ref(), ctx)?;
|
||||
}
|
||||
ctx.static_block_this_reg = saved_static_this;
|
||||
}
|
||||
}
|
||||
@@ -582,6 +706,7 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.private_name_map = saved_private_names;
|
||||
Ok(ctor_reg)
|
||||
}
|
||||
|
||||
@@ -1168,6 +1293,13 @@ impl Compiler {
|
||||
ctx.emit_load_const(r, idx);
|
||||
Ok(r)
|
||||
}
|
||||
Expression::PrivateInExpression(pin) => {
|
||||
let obj_reg = self.emit_expression(&pin.right, ctx)?;
|
||||
let key_reg = self.emit_private_id_reg(pin.left.name.as_str(), ctx)?;
|
||||
let result_reg = ctx.alloc_reg();
|
||||
ctx.emit(opcode::encode(OpCode::PRIVATE_BRAND_IN, result_reg, obj_reg, key_reg));
|
||||
Ok(result_reg)
|
||||
}
|
||||
Expression::BinaryExpression(bin) => {
|
||||
let checkpoint = ctx.reg_checkpoint();
|
||||
let left = self.emit_expression(&bin.left, ctx)?;
|
||||
@@ -1362,6 +1494,13 @@ impl Compiler {
|
||||
ctx.emit(opcode::encode(OpCode::GET_PROP_DYNAMIC, obj_reg, key_reg, r));
|
||||
Ok(r)
|
||||
}
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
|
||||
let r = ctx.alloc_reg();
|
||||
ctx.emit(opcode::encode(OpCode::GET_PRIVATE, r, obj_reg, key_reg));
|
||||
Ok(r)
|
||||
}
|
||||
Expression::ObjectExpression(obj) => {
|
||||
let obj_reg = ctx.alloc_reg();
|
||||
ctx.emit(opcode::encode(OpCode::NEW_OBJECT, obj_reg, 0, 0));
|
||||
@@ -1464,6 +1603,15 @@ impl Compiler {
|
||||
let val_reg = self.emit_expression(&assign.right, ctx)?;
|
||||
ctx.emit(opcode::encode(OpCode::SET_PROP_DYNAMIC, obj_reg, key_reg, val_reg));
|
||||
Ok(val_reg)
|
||||
} else if let oxide_parser::AssignmentTarget::PrivateFieldExpression(member) = &assign.left {
|
||||
if assign.operator != AssignmentOperator::Assign {
|
||||
return Err("compound assignment to private fields not supported".into());
|
||||
}
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
let val_reg = self.emit_expression(&assign.right, ctx)?;
|
||||
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
|
||||
ctx.emit(opcode::encode(OpCode::SET_PRIVATE, obj_reg, val_reg, key_reg));
|
||||
Ok(val_reg)
|
||||
} else if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(id_ref) = &assign.left {
|
||||
if assign.operator != AssignmentOperator::Assign {
|
||||
if assign.operator == AssignmentOperator::Addition
|
||||
@@ -1820,6 +1968,13 @@ impl Compiler {
|
||||
return Ok(result_reg);
|
||||
}
|
||||
let (callee_reg, this_reg) = match &call.callee {
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.emit(opcode::encode(OpCode::GET_PRIVATE, callee_reg, obj_reg, key_reg));
|
||||
(callee_reg, obj_reg)
|
||||
}
|
||||
Expression::StaticMemberExpression(member) => {
|
||||
let is_super_member = matches!(&member.object, Expression::Super(_));
|
||||
let obj_reg = if is_super_member {
|
||||
|
||||
@@ -250,6 +250,10 @@ fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) {
|
||||
hash_expression(&cond.consequent, h);
|
||||
hash_expression(&cond.alternate, h);
|
||||
}
|
||||
Expression::PrivateInExpression(pin) => {
|
||||
pin.left.name.as_str().hash(h);
|
||||
hash_expression(&pin.right, h);
|
||||
}
|
||||
Expression::Identifier(_) => {}
|
||||
Expression::NumericLiteral(num) => {
|
||||
num.value.to_bits().hash(h);
|
||||
@@ -262,6 +266,9 @@ fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) {
|
||||
}
|
||||
Expression::AssignmentExpression(assign) => {
|
||||
std::mem::discriminant(&assign.operator).hash(h);
|
||||
if let Some(target) = assign.left.as_simple_assignment_target() {
|
||||
hash_simple_assignment_target(target, h);
|
||||
}
|
||||
hash_expression(&assign.right, h);
|
||||
}
|
||||
Expression::UpdateExpression(update) => {
|
||||
@@ -323,6 +330,10 @@ fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
hash_expression(&member.object, h);
|
||||
member.field.name.as_str().hash(h);
|
||||
}
|
||||
Expression::Super(_) => {}
|
||||
Expression::RegExpLiteral(lit) => {
|
||||
if let Some(raw) = &lit.raw {
|
||||
@@ -356,6 +367,10 @@ fn hash_simple_assignment_target(target: &SimpleAssignmentTarget, h: &mut rustc_
|
||||
hash_expression(&member.object, h);
|
||||
hash_expression(&member.expression, h);
|
||||
}
|
||||
SimpleAssignmentTarget::PrivateFieldExpression(member) => {
|
||||
hash_expression(&member.object, h);
|
||||
member.field.name.as_str().hash(h);
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -123,6 +123,10 @@ pub enum OpCode {
|
||||
// ── Parallel — placeholders (0x70-0x7F) ──
|
||||
FORK = 0x70,
|
||||
JOIN = 0x71,
|
||||
GET_PRIVATE = 0x72,
|
||||
SET_PRIVATE = 0x73,
|
||||
INIT_PRIVATE = 0x74,
|
||||
PRIVATE_BRAND_IN = 0x75,
|
||||
|
||||
// -- Bitwise (0x80-0x8F) --
|
||||
BIT_AND = 0x80,
|
||||
@@ -269,6 +273,10 @@ impl TryFrom<u8> for OpCode {
|
||||
0x66 => Ok(OpCode::PROFILE_CALL),
|
||||
0x70 => Ok(OpCode::FORK),
|
||||
0x71 => Ok(OpCode::JOIN),
|
||||
0x72 => Ok(OpCode::GET_PRIVATE),
|
||||
0x73 => Ok(OpCode::SET_PRIVATE),
|
||||
0x74 => Ok(OpCode::INIT_PRIVATE),
|
||||
0x75 => Ok(OpCode::PRIVATE_BRAND_IN),
|
||||
0x80 => Ok(OpCode::BIT_AND),
|
||||
0x81 => Ok(OpCode::BIT_OR),
|
||||
0x82 => Ok(OpCode::BIT_XOR),
|
||||
@@ -382,6 +390,10 @@ impl fmt::Display for OpCode {
|
||||
OpCode::PROFILE_CALL => "PROFILE_CALL",
|
||||
OpCode::FORK => "FORK",
|
||||
OpCode::JOIN => "JOIN",
|
||||
OpCode::GET_PRIVATE => "GET_PRIVATE",
|
||||
OpCode::SET_PRIVATE => "SET_PRIVATE",
|
||||
OpCode::INIT_PRIVATE => "INIT_PRIVATE",
|
||||
OpCode::PRIVATE_BRAND_IN => "PRIVATE_BRAND_IN",
|
||||
OpCode::BIT_AND => "BIT_AND",
|
||||
OpCode::BIT_OR => "BIT_OR",
|
||||
OpCode::BIT_XOR => "BIT_XOR",
|
||||
|
||||
Reference in New Issue
Block a user