isla_lib/ir/
serialize.rs

1// BSD 2-Clause License
2//
3// Copyright (c) 2020 Alasdair Armstrong
4//
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
10//
11// 1. Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// 2. Redistributions in binary form must reproduce the above copyright
15// notice, this list of conditions and the following disclaimer in the
16// documentation and/or other materials provided with the distribution.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30//! This module provides serde-based serialization support for the
31//! IR. Note that the various `Primop*` instruction constructors
32//! cannot be serialized, as they are direct function pointers to the
33//! primop implementations. As such this module is intended to
34//! serialize and deserialize the AST _only before_ the primops have
35//! been inserted.
36
37use serde::{Deserialize, Serialize};
38
39use super::*;
40use crate::bitvector::BV;
41
42#[derive(Clone, Serialize, Deserialize)]
43enum SInstr<A> {
44    Decl(A, Ty<A>),
45    Init(A, Ty<A>, Exp<A>),
46    Jump(Exp<A>, usize, String),
47    Goto(usize),
48    Copy(Loc<A>, Exp<A>),
49    Monomorphize(A),
50    Call(Loc<A>, bool, A, Vec<Exp<A>>),
51    Failure,
52    Arbitrary,
53    End,
54}
55
56impl<A> SInstr<A> {
57    fn into_instr<B: BV>(self) -> Instr<A, B> {
58        use SInstr::*;
59        match self {
60            Decl(id, ty) => Instr::Decl(id, ty),
61            Init(id, ty, exp) => Instr::Init(id, ty, exp),
62            Jump(exp, target, info) => Instr::Jump(exp, target, info),
63            Goto(target) => Instr::Goto(target),
64            Copy(loc, exp) => Instr::Copy(loc, exp),
65            Monomorphize(id) => Instr::Monomorphize(id),
66            Call(loc, ext, id, args) => Instr::Call(loc, ext, id, args),
67            Failure => Instr::Failure,
68            Arbitrary => Instr::Arbitrary,
69            End => Instr::End,
70        }
71    }
72
73    fn from_instr<B: BV>(instr: Instr<A, B>) -> Option<Self> {
74        use Instr::*;
75        Some(match instr {
76            Decl(id, ty) => SInstr::Decl(id, ty),
77            Init(id, ty, exp) => SInstr::Init(id, ty, exp),
78            Jump(exp, target, info) => SInstr::Jump(exp, target, info),
79            Goto(target) => SInstr::Goto(target),
80            Copy(loc, exp) => SInstr::Copy(loc, exp),
81            Monomorphize(id) => SInstr::Monomorphize(id),
82            Call(loc, ext, id, args) => SInstr::Call(loc, ext, id, args),
83            Failure => SInstr::Failure,
84            Arbitrary => SInstr::Arbitrary,
85            End => SInstr::End,
86            _ => return None,
87        })
88    }
89}
90
91#[derive(Clone, Serialize, Deserialize)]
92enum SDef<A> {
93    Register(A, Ty<A>),
94    Let(Vec<(A, Ty<A>)>, Vec<SInstr<A>>),
95    Enum(A, Vec<A>),
96    Struct(A, Vec<(A, Ty<A>)>),
97    Union(A, Vec<(A, Ty<A>)>),
98    Val(A, Vec<Ty<A>>, Ty<A>),
99    Extern(A, String, Vec<Ty<A>>, Ty<A>),
100    Fn(A, Vec<A>, Vec<SInstr<A>>),
101}
102
103impl<A> SDef<A> {
104    fn into_def<B: BV>(self) -> Def<A, B> {
105        use SDef::*;
106        match self {
107            Register(id, ty) => Def::Register(id, ty),
108            Let(bindings, mut setup) => Def::Let(bindings, setup.drain(..).map(SInstr::into_instr).collect()),
109            Enum(id, elems) => Def::Enum(id, elems),
110            Struct(id, members) => Def::Struct(id, members),
111            Union(id, ctors) => Def::Union(id, ctors),
112            Val(id, arg_tys, ret_ty) => Def::Val(id, arg_tys, ret_ty),
113            Extern(id, ext, arg_tys, ret_ty) => Def::Extern(id, ext, arg_tys, ret_ty),
114            Fn(id, args, mut instrs) => Def::Fn(id, args, instrs.drain(..).map(SInstr::into_instr).collect()),
115        }
116    }
117
118    fn from_def<B: BV>(def: Def<A, B>) -> Option<SDef<A>> {
119        use Def::*;
120        Some(match def {
121            Register(id, ty) => SDef::Register(id, ty),
122            Let(bindings, mut setup) => {
123                SDef::Let(bindings, setup.drain(..).map(SInstr::from_instr).collect::<Option<_>>()?)
124            }
125            Enum(id, elems) => SDef::Enum(id, elems),
126            Struct(id, members) => SDef::Struct(id, members),
127            Union(id, ctors) => SDef::Union(id, ctors),
128            Val(id, arg_tys, ret_ty) => SDef::Val(id, arg_tys, ret_ty),
129            Extern(id, ext, arg_tys, ret_ty) => SDef::Extern(id, ext, arg_tys, ret_ty),
130            Fn(id, args, mut instrs) => {
131                SDef::Fn(id, args, instrs.drain(..).map(SInstr::from_instr).collect::<Option<_>>()?)
132            }
133        })
134    }
135}
136
137pub fn serialize<B: BV>(mut defs: Vec<Def<Name, B>>) -> Option<Vec<u8>> {
138    let sdefs: Vec<SDef<Name>> = defs.drain(..).map(SDef::from_def).collect::<Option<_>>()?;
139    bincode::serialize(&sdefs).ok()
140}
141
142pub fn deserialize<B: BV>(bytes: &[u8]) -> Option<Vec<Def<Name, B>>> {
143    let mut sdefs: Vec<SDef<Name>> = bincode::deserialize(bytes).ok()?;
144    Some(sdefs.drain(..).map(SDef::into_def).collect())
145}