strict_types/typelib/
compile.rs

1// Strict encoding schema library, implementing validation and parsing of strict encoded data
2// against a schema.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Designed in 2019-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
7// Written in 2024-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
8//
9// Copyright (C) 2022-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
10//                         Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
11// Copyright (C) 2022-2025 Dr Maxim Orlovsky.
12// All rights under the above copyrights are reserved.
13//
14// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
15// in compliance with the License. You may obtain a copy of the License at
16//
17//        http://www.apache.org/licenses/LICENSE-2.0
18//
19// Unless required by applicable law or agreed to in writing, software distributed under the License
20// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
21// or implied. See the License for the specific language governing permissions and limitations under
22// the License.
23
24use std::collections::BTreeMap;
25
26use encoding::LibName;
27use strict_encoding::TypeName;
28
29use crate::typelib::{Dependency, ExternTypes, InlineRef, InlineRef1, InlineRef2, LibRef};
30use crate::{SemId, Translate, TranspileError, TranspileRef, Ty};
31
32pub type TypeIndex = BTreeMap<TypeName, SemId>;
33
34#[deprecated(since = "1.3.0", note = "use CompileError")]
35pub type TranslateError = CompileError;
36
37#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
38#[display(doc_comments)]
39pub enum CompileError {
40    /// a different type with name `{0}` is already present
41    DuplicateName(TypeName),
42
43    /// type `{unknown}` referenced inside `{within}` is not known
44    UnknownType {
45        unknown: TypeName,
46        within: Ty<TranspileRef>,
47    },
48
49    /// return type indicating continue operation
50    Continue,
51
52    /// dependency {0} is already present in the library
53    DuplicatedDependency(Dependency),
54
55    /// too deep type nesting for type {2} inside {0}, path {1}
56    NestedInline(TypeName, String, String),
57
58    /// unknown library {0}
59    UnknownLib(LibName),
60
61    /// too many dependencies.
62    TooManyDependencies,
63
64    /// too many types
65    TooManyTypes,
66
67    /// library `{0}` contains too many types.
68    LibTooLarge(LibName),
69
70    /// library `{0}` used as a dependency doesn't provide type `{2}` with id {1}.
71    DependencyMissesType(LibName, SemId, TypeName),
72}
73
74impl From<TranspileError> for CompileError {
75    fn from(err: TranspileError) -> Self {
76        match err {
77            TranspileError::UnknownType { unknown, within } => {
78                Self::UnknownType { unknown, within }
79            }
80            TranspileError::UnknownLib(lib) => Self::UnknownLib(lib),
81            TranspileError::TooManyDependencies => Self::TooManyDependencies,
82            TranspileError::TooManyTypes => Self::TooManyTypes,
83            TranspileError::LibTooLarge(lib) => Self::LibTooLarge(lib),
84            TranspileError::DependencyMissesType(lib, sem_id, type_name) => {
85                Self::DependencyMissesType(lib, sem_id, type_name)
86            }
87        }
88    }
89}
90
91pub struct NestedContext {
92    pub top_name: TypeName,
93    pub index: TypeIndex,
94    pub extern_types: ExternTypes,
95    pub stack: Vec<String>,
96}
97
98impl Translate<LibRef> for TranspileRef {
99    type Context = ();
100    type Builder = NestedContext;
101    type Error = CompileError;
102
103    fn translate(
104        self,
105        builder: &mut Self::Builder,
106        ctx: &Self::Context,
107    ) -> Result<LibRef, Self::Error> {
108        match self {
109            TranspileRef::Embedded(ty) => {
110                builder.stack.push(ty.cls().to_string());
111                let res = ty.translate(builder, ctx).map(LibRef::Inline);
112                builder.stack.pop();
113                res
114            }
115            TranspileRef::Named(name) => {
116                let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
117                Ok(LibRef::Named(*id))
118            }
119            TranspileRef::Extern(ext) => Ok(LibRef::Extern(ext.into())),
120        }
121    }
122}
123
124impl Translate<InlineRef> for TranspileRef {
125    type Context = ();
126    type Builder = NestedContext;
127    type Error = CompileError;
128
129    fn translate(
130        self,
131        builder: &mut Self::Builder,
132        ctx: &Self::Context,
133    ) -> Result<InlineRef, Self::Error> {
134        match self {
135            TranspileRef::Embedded(ty) => {
136                builder.stack.push(ty.cls().to_string());
137                let res = ty.translate(builder, ctx).map(InlineRef::Inline);
138                builder.stack.pop();
139                res
140            }
141            TranspileRef::Named(name) => {
142                let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
143                Ok(InlineRef::Named(*id))
144            }
145            TranspileRef::Extern(ext) => Ok(InlineRef::Extern(ext.into())),
146        }
147    }
148}
149
150impl Translate<InlineRef1> for TranspileRef {
151    type Context = ();
152    type Builder = NestedContext;
153    type Error = CompileError;
154
155    fn translate(
156        self,
157        builder: &mut Self::Builder,
158        ctx: &Self::Context,
159    ) -> Result<InlineRef1, Self::Error> {
160        match self {
161            TranspileRef::Embedded(ty) => {
162                builder.stack.push(ty.cls().to_string());
163                let res = ty.translate(builder, ctx).map(InlineRef1::Inline);
164                builder.stack.pop();
165                res
166            }
167            TranspileRef::Named(name) => {
168                let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
169                Ok(InlineRef1::Named(*id))
170            }
171            TranspileRef::Extern(ext) => Ok(InlineRef1::Extern(ext.into())),
172        }
173    }
174}
175
176impl Translate<InlineRef2> for TranspileRef {
177    type Context = ();
178    type Builder = NestedContext;
179    type Error = CompileError;
180
181    fn translate(
182        self,
183        builder: &mut Self::Builder,
184        _ctx: &Self::Context,
185    ) -> Result<InlineRef2, Self::Error> {
186        match self {
187            TranspileRef::Embedded(_ty) => {
188                let mut path = builder.stack.clone();
189                let name = path.pop().unwrap_or_else(|| s!("<unnamed>"));
190                Err(CompileError::NestedInline(builder.top_name.clone(), path.join("."), name))
191            }
192            TranspileRef::Named(name) => {
193                let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
194                Ok(InlineRef2::Named(*id))
195            }
196            TranspileRef::Extern(ext) => Ok(InlineRef2::Extern(ext.into())),
197        }
198    }
199}