tin_lang/
lib.rs

1//! Tin is a simple embeddable programming language.
2//!
3//! The aim is to have a very light-weight footprint and a simple API.
4//!
5//! # Examples
6//!
7//! ```
8//! # extern crate failure;
9//! # extern crate tin_lang;
10//! # fn main() -> Result<(), failure::Error> {
11//! let source = r#"
12//! Int = 0u32;
13//! pickFirst = |a: Int, b: Int| Int {
14//!   capture = |x: Int| Int { a };
15//!   capture(b)
16//! };
17//! main = || Int { pickFirst(42u32, 62u32) };
18//! "#;
19//!
20//! let mut tin = tin_lang::Tin::new();
21//! tin.load(source)?;
22//!
23//! /*
24//! let mut module = tin.compile()?;
25//! let main = module.function::<tin_lang::module::Function0<u32>>("main").unwrap();
26//!
27//! let result = main();
28//! assert_eq!(42, result);
29//! */
30//! # Ok(())
31//! # }
32//! ```
33#![deny(nonstandard_style, warnings, unused)]
34#![deny(
35    missing_docs,
36    missing_debug_implementations,
37    missing_copy_implementations,
38    trivial_casts,
39    trivial_numeric_casts,
40    unstable_features,
41    unused_import_braces,
42    unused_qualifications
43)]
44#![cfg_attr(feature = "cargo-clippy", deny(clippy::all, clippy::pedantic))]
45
46extern crate cranelift;
47extern crate cranelift_module;
48extern crate cranelift_simplejit;
49extern crate dot;
50#[macro_use]
51extern crate failure;
52#[macro_use]
53extern crate lalrpop_util;
54#[macro_use]
55extern crate log;
56extern crate specs;
57#[macro_use]
58extern crate specs_derive;
59extern crate specs_visitor;
60#[macro_use]
61extern crate specs_visitor_derive;
62#[cfg(test)]
63extern crate env_logger;
64
65use std::fmt;
66
67mod ast;
68mod codegen;
69mod ir;
70mod parser;
71#[cfg(test)]
72mod test_util;
73
74pub mod error;
75pub mod graph;
76pub mod module;
77
78pub use error::Error;
79pub use error::Result;
80
81/// An instance of the Tin runtime.
82pub struct Tin {
83    ir: ir::Ir,
84    parser: <ast::Module<parser::Context> as parser::Parse>::Parser,
85}
86
87impl Tin {
88    /// Creates a new instance of the Tin runtime.
89    pub fn new() -> Tin {
90        use parser::Parse;
91
92        let ir = ir::Ir::new();
93        let parser = ast::Module::new_parser();
94
95        Tin { ir, parser }
96    }
97
98    /// Loads the specified source code as a module.
99    ///
100    /// # Errors
101    ///
102    /// This function will return an error if the source code contains a syntax error or if the
103    /// resulting logical structure has semantic errors or type errors.
104    ///
105    /// Calling this function several times will load source code into the same module scope, but
106    /// references in code from earlier calls will not be able to refer to definitions from code
107    /// from later calls.  Any references will eagerly be resolved and fail early.
108    ///
109    /// # Examples
110    ///
111    /// Loading a very basic module:
112    ///
113    /// ```
114    /// # extern crate failure;
115    /// # extern crate tin_lang;
116    /// # fn main() -> Result<(), failure::Error> {
117    /// let mut tin = tin_lang::Tin::new();
118    /// tin.load("U32 = 0u32; main = || U32 { 42u32 };")?;
119    /// # Ok(())
120    /// # }
121    /// ```
122    ///
123    /// Unresolved references are not allowed:
124    ///
125    /// ```
126    /// # extern crate failure;
127    /// # extern crate tin_lang;
128    /// # fn main() -> Result<(), failure::Error> {
129    /// let mut tin = tin_lang::Tin::new();
130    /// let result = tin.load("U32 = 0u32; main = || U32 { a };");
131    /// assert!(result.is_err());
132    /// # Ok(())
133    /// # }
134    /// ```
135    pub fn load(&mut self, source: &str) -> Result<()> {
136        let module = parser::Parser::parse(&mut self.parser, source)?;
137        self.ir.load(&module)?;
138
139        Ok(())
140    }
141
142    /// Creates a graph representation of the current IR of this Tin instance.
143    ///
144    /// This can be used to for example visualize the code using GraphViz or other tools.
145    pub fn graph(&self) -> graph::Graph {
146        graph::Graph::new(&self.ir)
147    }
148
149    /// Compiles the code loaded so far into a stand-alone module.
150    ///
151    /// This module is detached from the runtime and can be used even after the runtime has been
152    /// dropped.  Once all required Tin code has been loaded, it is therefore recommended to drop
153    /// this instance and only keep the compiled module around.
154    ///
155    /// # Examples
156    ///
157    /// Compiling a very basic module:
158    ///
159    /// ```
160    /// # extern crate failure;
161    /// # extern crate tin_lang;
162    /// # fn main() -> Result<(), failure::Error> {
163    /// let mut tin = tin_lang::Tin::new();
164    /// tin.load("U32 = 0u32; main = || U32 { 42u32 };")?;
165    ///
166    /// let mut module = tin.compile()?;
167    /// let main = module.function::<tin_lang::module::Function0<u32>>("main").unwrap();
168    ///
169    /// let result = main();
170    /// assert_eq!(42, result);
171    /// # Ok(())
172    /// # }
173    /// ```
174    pub fn compile(&mut self) -> Result<module::Module> {
175        self.ir.check_types();
176        let module = codegen::Codegen::new(&self.ir).compile();
177        Ok(module)
178    }
179}
180
181impl Default for Tin {
182    fn default() -> Self {
183        Tin::new()
184    }
185}
186
187impl fmt::Debug for Tin {
188    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189        f.debug_struct("Tin").finish()
190    }
191}