use std::sync::Arc;
use super::{
BinKind, CapSource, Const, DefaultIr, EnumVariant, FmtSpec, MacroKind, Member, MethodName,
NO_TYPE, PatInfo, PathRef, Reg, StructLit, UnKind,
};
use crate::interpreter::numeric::IntWidth;
use crate::interpreter::typeir::{CastIr, TypeIr};
#[derive(Clone)]
pub enum Op {
LoadConst {
dst: Reg,
k: u16,
},
LoadInt {
dst: Reg,
v: i64,
},
LoadIntW {
dst: Reg,
v: i64,
w: IntWidth,
},
LoadBool {
dst: Reg,
v: bool,
},
LoadUnit {
dst: Reg,
},
LoadUpvalue {
dst: Reg,
idx: u16,
},
LoadCell {
dst: Reg,
cell: Reg,
},
StoreCell {
cell: Reg,
src: Reg,
},
DropCell {
cell: Reg,
},
StoreUpvalue {
idx: u16,
src: Reg,
},
LoadGlobal {
dst: Reg,
idx: u32,
},
Move {
dst: Reg,
src: Reg,
},
Bin {
dst: Reg,
a: Reg,
b: Reg,
op: BinKind,
},
BinImm {
dst: Reg,
a: Reg,
imm: i64,
op: BinKind,
},
Un {
dst: Reg,
a: Reg,
op: UnKind,
},
BinInt {
dst: Reg,
a: Reg,
b: Reg,
op: BinKind,
w: IntWidth,
},
BinIntImm {
dst: Reg,
a: Reg,
imm: i64,
op: BinKind,
w: IntWidth,
},
BinFloat {
dst: Reg,
a: Reg,
b: Reg,
op: BinKind,
f32: bool,
},
Jump {
to: u32,
},
JumpIfFalse {
cond: Reg,
to: u32,
},
JumpIfTrue {
cond: Reg,
to: u32,
},
CmpJump {
a: Reg,
b: Reg,
op: BinKind,
to: u32,
},
CmpJumpImm {
a: Reg,
imm: i64,
op: BinKind,
to: u32,
},
CmpJumpInt {
a: Reg,
b: Reg,
op: BinKind,
w: IntWidth,
to: u32,
},
CmpJumpIntImm {
a: Reg,
imm: i64,
op: BinKind,
w: IntWidth,
to: u32,
},
CallFn {
dst: Reg,
func: u32,
base: Reg,
argc: u16,
targ: u32,
},
CallValue {
dst: Reg,
callee: Reg,
base: Reg,
argc: u16,
},
CallPath {
dst: Reg,
path: u16,
base: Reg,
argc: u16,
},
PathValue {
dst: Reg,
path: u16,
},
Method {
dst: Reg,
recv: Reg,
name: u16,
base: Reg,
argc: u16,
},
GetOrDefault {
dst: Reg,
recv: Reg,
key: Reg,
default: Reg,
},
Ret {
src: Reg,
},
MakeVec {
dst: Reg,
base: Reg,
count: u16,
},
MakeMap {
dst: Reg,
set: bool,
},
MakeTuple {
dst: Reg,
base: Reg,
count: u16,
},
MakeArrayRepeat {
dst: Reg,
val: Reg,
count: Reg,
},
MakeRange {
dst: Reg,
start: Reg,
end: Reg,
inclusive: bool,
},
IterInit {
dst: Reg,
src: Reg,
owned: bool,
},
ForNext {
iter: Reg,
idx: Reg,
val: Reg,
to: u32,
},
MakeStruct {
dst: Reg,
info: u16,
base: Reg,
},
MakeEnum {
dst: Reg,
info: u16,
base: Reg,
count: u16,
},
LoadEnum {
dst: Reg,
info: u16,
},
MakeClosure {
dst: Reg,
child: u16,
},
Index {
dst: Reg,
base: Reg,
key: Reg,
},
SetIndex {
base: Reg,
key: Reg,
val: Reg,
},
Deref {
dst: Reg,
src: Reg,
},
SetDeref {
target: Reg,
val: Reg,
},
DerefBinAssign {
target: Reg,
val: Reg,
op: BinKind,
},
SetDerefParam {
target: Reg,
val: Reg,
},
GetField {
dst: Reg,
base: Reg,
member: u16,
},
SetField {
base: Reg,
member: u16,
val: Reg,
},
TakeField {
dst: Reg,
base: Reg,
member: u16,
},
Own {
dst: Reg,
src: Reg,
root: Reg,
},
Take {
dst: Reg,
src: Reg,
},
Copy {
dst: Reg,
src: Reg,
},
RefIndex {
dst: Reg,
base: Reg,
key: Reg,
},
RefField {
dst: Reg,
base: Reg,
member: u16,
},
MakeBorrow {
dst: Reg,
src: Reg,
},
DefaultOf {
dst: Reg,
src: Reg,
},
BuildDefault {
dst: Reg,
ir: u16,
},
DropScope {
list: u16,
},
DropParams {
list: u16,
},
Try {
dst: Reg,
src: Reg,
conv: u16,
},
TryJump {
dst: Reg,
src: Reg,
to: u32,
conv: u16,
},
Cast {
dst: Reg,
src: Reg,
ty: u16,
},
Coerce {
dst: Reg,
src: Reg,
ty: u16,
},
TestBind {
val: Reg,
pat: u16,
dst: Reg,
},
Fmt {
dst: Reg,
spec: u16,
},
MacroCall {
kind: MacroKind,
dst: Reg,
spec: u16,
},
Dbg {
dst: Reg,
base: Reg,
argc: u16,
},
Spawn {
dst: Reg,
child: u16,
},
Await {
dst: Reg,
src: Reg,
},
}
pub struct Chunk {
pub code: Vec<Op>,
pub lines: Vec<u32>,
pub cols: Vec<u32>,
pub file: Arc<str>,
pub num_regs: usize,
pub num_params: usize,
pub param_types: Vec<Option<String>>,
pub name: String,
pub module: u16,
pub moves: bool,
pub consts: Vec<Const>,
pub members: Vec<Member>,
pub pats: Vec<PatInfo>,
pub fmts: Vec<FmtSpec>,
pub struct_lits: Vec<StructLit>,
pub enum_variants: Vec<EnumVariant>,
pub casts: Vec<CastIr>,
pub defaults: Vec<DefaultIr>,
pub try_targets: Vec<Arc<str>>,
pub coerces: Vec<TypeIr>,
pub paths: Vec<PathRef>,
pub names: Vec<MethodName>,
pub children: Vec<Arc<Chunk>>,
pub child_caps: Vec<Vec<CapSource>>,
pub child_moves: Vec<Arc<[bool]>>,
pub generics: Vec<Arc<str>>,
pub drop_lists: Vec<Arc<[Reg]>>,
pub droppable: Arc<[Reg]>,
pub lent_params: Arc<[Reg]>,
pub call_type_args: Vec<Arc<[TypeIr]>>,
pub path_forwarder: bool,
pub clears_frame: bool,
}
impl Chunk {
pub fn empty(name: impl Into<String>) -> Chunk {
Chunk {
code: Vec::new(),
lines: Vec::new(),
cols: Vec::new(),
file: Arc::from(""),
num_regs: 0,
num_params: 0,
param_types: Vec::new(),
name: name.into(),
module: 0,
moves: false,
consts: Vec::new(),
members: Vec::new(),
pats: Vec::new(),
fmts: Vec::new(),
struct_lits: Vec::new(),
enum_variants: Vec::new(),
casts: Vec::new(),
defaults: Vec::new(),
try_targets: Vec::new(),
coerces: Vec::new(),
paths: Vec::new(),
names: Vec::new(),
children: Vec::new(),
child_caps: Vec::new(),
child_moves: Vec::new(),
generics: Vec::new(),
drop_lists: Vec::new(),
droppable: Arc::from(Vec::new()),
lent_params: Arc::from(Vec::new()),
call_type_args: Vec::new(),
path_forwarder: false,
clears_frame: false,
}
}
}
pub struct StructShape {
pub name: Arc<str>,
pub type_id: u16,
pub fields: Vec<Arc<str>>,
pub renames: Vec<Option<Arc<str>>>,
pub skip_none: Vec<bool>,
}
impl StructShape {
pub fn new(name: impl Into<Arc<str>>, fields: Vec<Arc<str>>) -> Arc<StructShape> {
Arc::new(StructShape {
name: name.into(),
type_id: NO_TYPE,
fields,
renames: Vec::new(),
skip_none: Vec::new(),
})
}
pub fn typed(
name: impl Into<Arc<str>>,
type_id: u16,
fields: Vec<Arc<str>>,
renames: Vec<Option<Arc<str>>>,
skip_none: Vec<bool>,
) -> Arc<StructShape> {
Arc::new(StructShape {
name: name.into(),
type_id,
fields,
renames,
skip_none,
})
}
pub fn slot(&self, field: &str) -> Option<usize> {
self.fields.iter().position(|f| &**f == field)
}
}
pub fn path_call_chunk(path: PathRef, num_params: usize) -> Arc<Chunk> {
let count = u16::try_from(num_params).expect("parameter count fits u16");
let dst = count * 2;
let mut chunk = Chunk::empty("<pathfn>");
chunk.path_forwarder = true;
chunk.num_params = num_params;
chunk.num_regs = num_params * 2 + 1;
chunk.paths.push(path);
for i in 0..count {
chunk.code.push(Op::Move {
dst: count + i,
src: i,
});
}
chunk.code.push(Op::CallPath {
dst,
path: 0,
base: count,
argc: count,
});
chunk.code.push(Op::Ret { src: dst });
Arc::new(chunk)
}