use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::intern::Symbol;
pub(crate) mod symbol_serde {
use crate::intern::Symbol;
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S: Serializer>(s: &Symbol, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_u32(s.index() as u32)
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<Symbol, D::Error> {
Ok(Symbol::from_index(u32::deserialize(de)? as usize))
}
}
pub(crate) mod f64_bits {
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S: Serializer>(v: &f64, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_u64(v.to_bits())
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<f64, D::Error> {
Ok(f64::from_bits(u64::deserialize(de)?))
}
}
pub type Reg = u16;
pub type ConstIdx = u32;
pub type FuncIdx = u16;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Constant {
Int(i64),
Float(#[serde(with = "f64_bits")] f64),
Bool(bool),
Text(String),
Char(char),
Nothing,
Duration(i64),
Date(i32),
Moment(i64),
Span { months: i32, days: i32 },
Time(i64),
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum ChanElem {
Unknown,
Int,
Float,
Bool,
Text,
}
impl ChanElem {
pub fn from_type_name(name: &str) -> ChanElem {
match name {
"Int" | "Nat" => ChanElem::Int,
"Float" => ChanElem::Float,
"Bool" => ChanElem::Bool,
"Text" => ChanElem::Text,
_ => ChanElem::Unknown,
}
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum Op {
LoadConst { dst: Reg, idx: ConstIdx },
Move { dst: Reg, src: Reg },
EnsureOwned { reg: Reg },
Add { dst: Reg, lhs: Reg, rhs: Reg },
AddAssign { dst: Reg, src: Reg },
Sub { dst: Reg, lhs: Reg, rhs: Reg },
Mul { dst: Reg, lhs: Reg, rhs: Reg },
Div { dst: Reg, lhs: Reg, rhs: Reg },
ExactDiv { dst: Reg, lhs: Reg, rhs: Reg },
FloorDiv { dst: Reg, lhs: Reg, rhs: Reg },
Mod { dst: Reg, lhs: Reg, rhs: Reg },
DivPow2 { dst: Reg, lhs: Reg, k: u8 },
MagicDivU { dst: Reg, lhs: Reg, magic: u64, more: u8, mul_back: i64 },
Lt { dst: Reg, lhs: Reg, rhs: Reg },
Gt { dst: Reg, lhs: Reg, rhs: Reg },
LtEq { dst: Reg, lhs: Reg, rhs: Reg },
GtEq { dst: Reg, lhs: Reg, rhs: Reg },
Eq { dst: Reg, lhs: Reg, rhs: Reg },
ApproxEq { dst: Reg, lhs: Reg, rhs: Reg },
NotEq { dst: Reg, lhs: Reg, rhs: Reg },
Not { dst: Reg, src: Reg },
Concat { dst: Reg, lhs: Reg, rhs: Reg },
SeqConcat { dst: Reg, lhs: Reg, rhs: Reg },
Pow { dst: Reg, lhs: Reg, rhs: Reg },
BitXor { dst: Reg, lhs: Reg, rhs: Reg },
BitAnd { dst: Reg, lhs: Reg, rhs: Reg },
BitOr { dst: Reg, lhs: Reg, rhs: Reg },
Shl { dst: Reg, lhs: Reg, rhs: Reg },
Shr { dst: Reg, lhs: Reg, rhs: Reg },
Jump { target: usize },
JumpIfFalse { cond: Reg, target: usize },
JumpIfTrue { cond: Reg, target: usize },
Call { dst: Reg, func: FuncIdx, args_start: Reg, arg_count: u16 },
CallBuiltin {
dst: Reg,
builtin: crate::semantics::builtins::BuiltinId,
args_start: Reg,
arg_count: u16,
},
CallValue { dst: Reg, callee: Reg, args_start: Reg, arg_count: u16, name_for_err: ConstIdx },
MakeClosure { dst: Reg, func: FuncIdx, locals_start: Reg },
CheckPolicy {
subject: Reg,
#[serde(with = "symbol_serde")]
predicate: Symbol,
is_capability: bool,
object: Reg,
source_text: ConstIdx,
},
ListPushField { obj: Reg, field: ConstIdx, src: Reg },
GlobalGet { dst: Reg, idx: u16 },
GlobalSet { idx: u16, src: Reg },
Return { src: Reg },
ReturnNothing,
NewList { dst: Reg, start: Reg, count: u16 },
NewEmptyList { dst: Reg },
NewEmptyListI32 { dst: Reg },
NewEmptySet { dst: Reg },
NewEmptyMap { dst: Reg },
NewRange { dst: Reg, start: Reg, end: Reg },
ListPush { list: Reg, value: Reg },
SetAdd { set: Reg, value: Reg },
RemoveFrom { collection: Reg, value: Reg },
SetIndex { collection: Reg, index: Reg, value: Reg },
SetIndexUnchecked { collection: Reg, index: Reg, value: Reg },
Index { dst: Reg, collection: Reg, index: Reg },
IndexUnchecked { dst: Reg, collection: Reg, index: Reg },
RegionBoundsGuard { array: Reg, bound: Reg, iv: Reg, add_max: i32, add_min: i32 },
Length { dst: Reg, collection: Reg },
Contains { dst: Reg, collection: Reg, value: Reg },
FormatValue { dst: Reg, src: Reg, spec: ConstIdx, debug_prefix: ConstIdx },
SliceOp { dst: Reg, collection: Reg, start: Reg, end: Reg },
DeepClone { dst: Reg, src: Reg },
NewTuple { dst: Reg, start: Reg, count: u16 },
UnionOp { dst: Reg, lhs: Reg, rhs: Reg },
IntersectOp { dst: Reg, lhs: Reg, rhs: Reg },
LoadToday { dst: Reg },
LoadNow { dst: Reg },
NewStruct { dst: Reg, type_name: ConstIdx },
StructInsert { obj: Reg, field: ConstIdx, value: Reg },
GetField { dst: Reg, obj: Reg, field: ConstIdx },
NewInductive { dst: Reg, type_name: ConstIdx, ctor: ConstIdx, args_start: Reg, count: u16 },
TestArm { dst: Reg, target: Reg, variant: ConstIdx },
BindArm { dst: Reg, target: Reg, field: ConstIdx, index: u16 },
CrdtBump { obj: Reg, field: ConstIdx, amount: Reg, negate: bool },
CrdtMerge { target: Reg, source: Reg },
NewCrdt { dst: Reg, kind: u8 },
CrdtAppend { seq: Reg, value: Reg },
CrdtResolve { obj: Reg, field: ConstIdx, value: Reg },
IterPrepare { iterable: Reg },
IterNext { dst: Reg, exit: usize },
IterPop,
ListPop { list: Reg, dst: Reg },
Sleep { duration: Reg },
DestructureTuple { src: Reg, start: Reg, count: u16 },
Show { src: Reg },
Args { dst: Reg },
ChanNew { dst: Reg, cap: i32, elem: ChanElem },
ChanSend { chan: Reg, val: Reg },
ChanRecv { dst: Reg, chan: Reg },
ChanTrySend { dst: Reg, chan: Reg, val: Reg },
ChanTryRecv { dst: Reg, chan: Reg },
ChanClose { chan: Reg },
Spawn { func: FuncIdx, args_start: Reg, arg_count: u16 },
SpawnHandle { dst: Reg, func: FuncIdx, args_start: Reg, arg_count: u16 },
TaskAwait { dst: Reg, handle: Reg },
TaskAbort { handle: Reg },
SelectArmRecv { chan: Reg, var: Reg },
SelectArmTimeout { ticks: Reg },
SelectWait { dst_arm: Reg },
NetConnect { url: Reg },
NetListen { topic: Reg },
NetSend { to: Reg, msg: Reg },
NetStream { to: Reg, values: Reg },
NetAwait { dst: Reg, from: Reg, stream: bool },
NetMakePeer { dst: Reg, addr: Reg },
NetSync { dst: Reg, topic: Reg },
FailWith { msg: ConstIdx },
Halt,
}
#[derive(Clone, Debug, PartialEq)]
pub enum BoundaryType {
Int,
Float,
Bool,
Text,
Date,
Moment,
Word32,
Word64,
Seq(Box<BoundaryType>),
Struct(String),
Enum(String),
Map(Box<BoundaryType>, Box<BoundaryType>),
Tuple(Vec<BoundaryType>),
Builtin(String),
}
#[derive(Clone, Debug)]
pub struct StructTypeDef {
pub name: String,
pub fields: Vec<(String, BoundaryType)>,
}
#[derive(Clone, Debug)]
pub struct EnumVariantDef {
pub name: String,
pub field_types: Vec<BoundaryType>,
}
#[derive(Clone, Debug)]
pub struct EnumTypeDef {
pub name: String,
pub variants: Vec<EnumVariantDef>,
}
#[derive(Clone, Debug)]
pub struct CompiledFunction {
pub name: Symbol,
pub entry_pc: usize,
pub param_count: u16,
pub register_count: usize,
pub captures: Vec<(Symbol, Option<u16>)>,
pub named_regs: Vec<bool>,
pub param_kinds: Vec<Option<super::native_tier::ParamKind>>,
pub ret_kind: Option<super::native_tier::SlotKind>,
pub param_types: Vec<Option<BoundaryType>>,
pub return_type: Option<BoundaryType>,
pub mutable_param_regs: Vec<Reg>,
}
#[derive(Clone, Debug, Default)]
pub struct CompiledProgram {
pub constants: Vec<Constant>,
pub code: Vec<Op>,
pub register_count: usize,
pub functions: Vec<CompiledFunction>,
pub fn_index: HashMap<Symbol, FuncIdx>,
pub globals: Vec<String>,
pub named_regs: Vec<bool>,
pub loop_locals: HashMap<usize, Vec<bool>>,
pub reg_names: Vec<(u16, String)>,
pub struct_types: Vec<StructTypeDef>,
pub enum_types: Vec<EnumTypeDef>,
pub global_types: Vec<Option<BoundaryType>>,
}
#[cfg(test)]
mod concurrency_op_tests {
use super::*;
#[test]
fn concurrency_ops_serde_roundtrip() {
let ops = [
Op::ChanNew { dst: 1, cap: -1, elem: ChanElem::Int },
Op::ChanNew { dst: 2, cap: 8, elem: ChanElem::Text },
Op::ChanSend { chan: 3, val: 4 },
Op::ChanRecv { dst: 5, chan: 6 },
Op::ChanTrySend { dst: 7, chan: 8, val: 9 },
Op::ChanTryRecv { dst: 10, chan: 11 },
Op::ChanClose { chan: 12 },
Op::Spawn { func: 1, args_start: 13, arg_count: 2 },
Op::SpawnHandle { dst: 14, func: 2, args_start: 15, arg_count: 0 },
Op::TaskAwait { dst: 16, handle: 17 },
Op::TaskAbort { handle: 18 },
Op::SelectArmRecv { chan: 19, var: 20 },
Op::SelectArmTimeout { ticks: 21 },
Op::SelectWait { dst_arm: 22 },
];
for op in ops {
let json = serde_json::to_string(&op).expect("serialize");
let back: Op = serde_json::from_str(&json).expect("deserialize");
assert_eq!(format!("{op:?}"), format!("{back:?}"), "roundtrip {op:?} via {json}");
}
}
}