1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::convert::TryInto;
use crate::{
diag,
expansion::ast::{Address, AttributeName_, ModuleIdent, ModuleIdent_},
naming::ast as N,
parser::ast::FunctionName,
shared::{
known_attributes::{KnownAttribute, NativeAttribute},
CompilationEnv, Identifier,
},
};
use move_ir_types::ast as IR;
pub const FAKE_NATIVE_ATTR: AttributeName_ =
AttributeName_::Known(KnownAttribute::Native(NativeAttribute::BytecodeInstruction));
pub fn function(
env: &mut CompilationEnv,
module_opt: Option<ModuleIdent>,
function_name: FunctionName,
function: &N::Function,
) {
let loc = match function.attributes.get_loc_(&FAKE_NATIVE_ATTR) {
None => return,
Some(loc) => *loc,
};
let module = match module_opt {
Some(module) => module,
None => {
let msg = format!(
"Invalid usage of '{}' attribute to map function to bytecode instruction.",
NativeAttribute::BYTECODE_INSTRUCTION
);
let smsg = "Script functions are never mapped to bytecode instructions";
let diag = diag!(
Attributes::InvalidBytecodeInst,
(loc, msg),
(function_name.loc(), smsg),
);
env.add_diag(diag);
return;
}
};
if resolve_builtin(&module, &function_name).is_none() {
let attr_msg = format!(
"Invalid usage of '{}' attribute to map function to bytecode instruction.",
NativeAttribute::BYTECODE_INSTRUCTION
);
let name_msg = format!(
"No known mapping of '{}::{}' to bytecode instruction",
module, function_name
);
let diag = diag!(
Attributes::InvalidBytecodeInst,
(loc, attr_msg),
(function_name.loc(), name_msg),
);
env.add_diag(diag);
}
match &function.body.value {
N::FunctionBody_::Native => (),
N::FunctionBody_::Defined(_) => {
let attr_msg = format!(
"Invalid usage of '{}' attribute on non-native function",
NativeAttribute::BYTECODE_INSTRUCTION
);
let diag = diag!(Attributes::InvalidBytecodeInst, (loc, attr_msg));
env.add_diag(diag);
}
}
}
pub fn resolve_builtin(
module: &ModuleIdent,
function: &FunctionName,
) -> Option<fn(Vec<IR::Type>) -> IR::Bytecode_> {
let sp!(_, ModuleIdent_ { address, module }) = module;
let addr_name = match address {
Address::Numerical(Some(sp!(_, n_)), _) | Address::NamedUnassigned(sp!(_, n_)) => n_,
_ => return None,
};
Some(
match (
addr_name.as_str(),
module.value().as_str(),
function.value().as_str(),
) {
("std", "vector", "empty") => |tys| IR::Bytecode_::VecPack(expect_one_ty_arg(tys), 0),
("std", "vector", "length") => |tys| IR::Bytecode_::VecLen(expect_one_ty_arg(tys)),
("std", "vector", "borrow") => {
|tys| IR::Bytecode_::VecImmBorrow(expect_one_ty_arg(tys))
}
("std", "vector", "push_back") => {
|tys| IR::Bytecode_::VecPushBack(expect_one_ty_arg(tys))
}
("std", "vector", "borrow_mut") => {
|tys| IR::Bytecode_::VecMutBorrow(expect_one_ty_arg(tys))
}
("std", "vector", "pop_back") => {
|tys| IR::Bytecode_::VecPopBack(expect_one_ty_arg(tys))
}
("std", "vector", "destroy_empty") => {
|tys| IR::Bytecode_::VecUnpack(expect_one_ty_arg(tys), 0)
}
("std", "vector", "swap") => |tys| IR::Bytecode_::VecSwap(expect_one_ty_arg(tys)),
_ => return None,
},
)
}
fn expect_one_ty_arg(ty_args: Vec<IR::Type>) -> IR::Type {
let [ty]: [IR::Type; 1] = ty_args
.try_into()
.expect("ICE native bytecode function expected a single type argument");
ty
}