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