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}