dyon/
lib.rs

1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3extern crate piston_meta;
4extern crate range;
5extern crate read_color;
6extern crate read_token;
7#[cfg(all(not(target_family = "wasm"), feature = "http"))]
8extern crate reqwest;
9#[macro_use]
10extern crate lazy_static;
11extern crate tree_mem_sort;
12extern crate vecmath;
13
14use piston_meta::{parse_errstr, syntax_errstr, MetaData, Syntax};
15use range::Range;
16use std::any::Any;
17use std::collections::HashMap;
18use std::fmt;
19use std::sync::{Arc, Mutex};
20#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
21use threading::JoinHandle;
22
23pub mod ast;
24pub mod embed;
25mod lifetime;
26mod link;
27pub mod macros;
28mod mat4;
29mod module;
30mod prelude;
31pub mod runtime;
32#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
33pub mod threading;
34mod ty;
35mod vec4;
36mod write;
37
38mod dyon_std;
39mod grab;
40
41pub use ast::Lazy;
42pub use link::Link;
43pub use mat4::Mat4;
44pub use module::Module;
45pub use prelude::{Dfn, Lt, Prelude};
46pub use runtime::Runtime;
47pub use ty::Type;
48pub use vec4::Vec4;
49
50/// A common error message when there is no value on the stack.
51pub const TINVOTS: &str = "There is no value on the stack";
52/// A common error message when the call stack is empty.
53pub const CSIE: &str = "Call stack is empty";
54
55lazy_static! {
56    pub(crate) static ref LESS: Arc<String> = Arc::new("less".into());
57    pub(crate) static ref LESS_OR_EQUAL: Arc<String> = Arc::new("less_or_equal".into());
58    pub(crate) static ref GREATER: Arc<String> = Arc::new("greater".into());
59    pub(crate) static ref GREATER_OR_EQUAL: Arc<String> = Arc::new("greater_or_equal".into());
60    pub(crate) static ref EQUAL: Arc<String> = Arc::new("equal".into());
61    pub(crate) static ref NOT_EQUAL: Arc<String> = Arc::new("not_equal".into());
62    pub(crate) static ref AND_ALSO: Arc<String> = Arc::new("and_also".into());
63    pub(crate) static ref OR_ELSE: Arc<String> = Arc::new("or_else".into());
64    pub(crate) static ref ADD: Arc<String> = Arc::new("add".into());
65    pub(crate) static ref SUB: Arc<String> = Arc::new("sub".into());
66    pub(crate) static ref MUL: Arc<String> = Arc::new("mul".into());
67    pub(crate) static ref DIV: Arc<String> = Arc::new("div".into());
68    pub(crate) static ref REM: Arc<String> = Arc::new("rem".into());
69    pub(crate) static ref POW: Arc<String> = Arc::new("pow".into());
70    pub(crate) static ref DOT: Arc<String> = Arc::new("dot".into());
71    pub(crate) static ref CROSS: Arc<String> = Arc::new("cross".into());
72    pub(crate) static ref NOT: Arc<String> = Arc::new("not".into());
73    pub(crate) static ref NEG: Arc<String> = Arc::new("neg".into());
74    pub(crate) static ref NORM: Arc<String> = Arc::new("norm".into());
75    pub(crate) static ref T: Arc<String> = Arc::new("T".into());
76}
77
78/// Type alias for lazy invariants of external functions.
79pub type LazyInvariant = &'static [&'static [Lazy]];
80
81/// Lazy invariant to unwrap first argument.
82pub static LAZY_UNWRAP_OR: LazyInvariant = &[&[Lazy::UnwrapOk, Lazy::UnwrapSome]];
83/// Lazy invariant for `&&`.
84pub static LAZY_AND: LazyInvariant = &[&[Lazy::Variable(Variable::Bool(false, None))]];
85/// Lazy invariant for `||`.
86pub static LAZY_OR: LazyInvariant = &[&[Lazy::Variable(Variable::Bool(true, None))]];
87/// Lazy invariant that no arguments have lazy invariants.
88pub static LAZY_NO: LazyInvariant = &[];
89
90/// Type alias for Dyon arrays.
91pub type Array = Arc<Vec<Variable>>;
92/// Type alias for Dyon objects.
93pub type Object = Arc<HashMap<Arc<String>, Variable>>;
94/// Type alias for Rust objects.
95pub type RustObject = Arc<Mutex<dyn Any>>;
96
97/// Stores Dyon errors.
98#[derive(Debug, Clone)]
99pub struct Error {
100    /// The error message.
101    pub message: Variable,
102    /// Extra information to help debug error.
103    /// Stores error messages for all `?` operators.
104    pub trace: Vec<String>,
105}
106
107/// Stores a thread handle.
108#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
109#[derive(Clone)]
110pub struct Thread {
111    /// The handle of the thread.
112    pub handle: Option<Arc<Mutex<JoinHandle<Result<Variable, String>>>>>,
113}
114
115#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
116impl Thread {
117    /// Creates a new thread handle.
118    pub fn new(handle: JoinHandle<Result<Variable, String>>) -> Thread {
119        Thread {
120            handle: Some(Arc::new(Mutex::new(handle))),
121        }
122    }
123
124    /// Removes the thread handle from the stack.
125    /// This is to prevent an extra reference when resolving the variable.
126    pub fn invalidate_handle(
127        rt: &mut Runtime,
128        var: Variable,
129    ) -> Result<JoinHandle<Result<Variable, String>>, String> {
130        let thread = match var {
131            Variable::Ref(ind) => {
132                use std::mem::replace;
133
134                match replace(
135                    &mut rt.stack[ind],
136                    Variable::Thread(Thread { handle: None }),
137                ) {
138                    Variable::Thread(th) => th,
139                    x => return Err(rt.expected(&x, "Thread")),
140                }
141            }
142            Variable::Thread(thread) => thread,
143            x => return Err(rt.expected(&x, "Thread")),
144        };
145        let handle = match thread.handle {
146            None => return Err("The Thread has already been invalidated".into()),
147            Some(thread) => thread,
148        };
149        let mutex = Arc::try_unwrap(handle).map_err(|_| {
150            format!(
151                "{}\nCan not access Thread because there is \
152            more than one reference to it",
153                rt.stack_trace()
154            )
155        })?;
156        mutex.into_inner().map_err(|err| {
157            format!(
158                "{}\nCan not lock Thread mutex:\n{}",
159                rt.stack_trace(),
160                err.to_string()
161            )
162        })
163    }
164}
165
166#[cfg(all(not(target_family = "wasm"), feature = "threading"))]
167impl fmt::Debug for Thread {
168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169        write!(f, "thread")
170    }
171}
172
173/// Prevents unsafe references from being accessed outside library.
174#[derive(Debug, Clone)]
175pub struct UnsafeRef(*mut Variable);
176
177/// Stores closure environment.
178#[derive(Clone)]
179pub struct ClosureEnvironment {
180    /// The module that the closure was created.
181    pub module: Arc<Module>,
182    /// Relative index, used to look up function indices.
183    pub relative: usize,
184}
185
186impl fmt::Debug for ClosureEnvironment {
187    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188        write!(f, "ClosureEnvironment")
189    }
190}
191
192/// Dyon variable.
193#[derive(Debug, Clone)]
194pub enum Variable {
195    /// Reference.
196    Ref(usize),
197    /// Return handle.
198    Return,
199    /// Boolean.
200    Bool(bool, Option<Box<Vec<Variable>>>),
201    /// F64.
202    F64(f64, Option<Box<Vec<Variable>>>),
203    /// 4D vector.
204    Vec4([f32; 4]),
205    /// 4D matrix.
206    Mat4(Box<[[f32; 4]; 4]>),
207    /// Text.
208    Str(Arc<String>),
209    /// Array.
210    Array(Array),
211    /// Object.
212    Object(Object),
213    /// Link.
214    Link(Box<Link>),
215    /// Unsafe reference.
216    UnsafeRef(UnsafeRef),
217    /// Rust object.
218    RustObject(RustObject),
219    /// Option.
220    Option(Option<Box<Variable>>),
221    /// Result.
222    Result(Result<Box<Variable>, Box<Error>>),
223    /// Thread handle.
224    #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
225    Thread(Thread),
226    /// Stores closure together with a closure environment,
227    /// which makes sure that the closure can be called correctly
228    /// no matter where it goes.
229    Closure(Arc<ast::Closure>, Box<ClosureEnvironment>),
230    /// In-type.
231    #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
232    In(Arc<Mutex<::std::sync::mpsc::Receiver<Variable>>>),
233}
234
235/// This is requires because `UnsafeRef(*mut Variable)` can not be sent across threads.
236/// The lack of `UnsafeRef` variant when sending across threads is guaranteed at language level.
237/// The interior of `UnsafeRef` can not be accessed outside this library.
238unsafe impl Send for Variable {}
239
240impl Variable {
241    /// Creates a variable of type `f64`.
242    pub fn f64(val: f64) -> Variable {
243        Variable::F64(val, None)
244    }
245
246    /// Creates a variable of type `bool`.
247    pub fn bool(val: bool) -> Variable {
248        Variable::Bool(val, None)
249    }
250
251    /// Returns type of variable.
252    pub fn typeof_var(&self) -> Arc<String> {
253        use self::runtime::*;
254        use Variable::*;
255
256        match *self {
257            Str(_) => TEXT_TYPE.clone(),
258            F64(_, _) => F64_TYPE.clone(),
259            Vec4(_) => VEC4_TYPE.clone(),
260            Mat4(_) => MAT4_TYPE.clone(),
261            Return => RETURN_TYPE.clone(),
262            Bool(_, _) => BOOL_TYPE.clone(),
263            Object(_) => OBJECT_TYPE.clone(),
264            Array(_) => ARRAY_TYPE.clone(),
265            Link(_) => LINK_TYPE.clone(),
266            Ref(_) => REF_TYPE.clone(),
267            UnsafeRef(_) => UNSAFE_REF_TYPE.clone(),
268            RustObject(_) => RUST_OBJECT_TYPE.clone(),
269            Option(_) => OPTION_TYPE.clone(),
270            Result(_) => RESULT_TYPE.clone(),
271            #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
272            Thread(_) => THREAD_TYPE.clone(),
273            Closure(_, _) => CLOSURE_TYPE.clone(),
274            #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
275            In(_) => IN_TYPE.clone(),
276        }
277    }
278
279    fn deep_clone(&self, stack: &[Variable]) -> Variable {
280        use Variable::*;
281
282        match *self {
283            F64(_, _) => self.clone(),
284            Vec4(_) => self.clone(),
285            Mat4(_) => self.clone(),
286            Return => self.clone(),
287            Bool(_, _) => self.clone(),
288            Str(_) => self.clone(),
289            Object(ref obj) => {
290                let mut res = obj.clone();
291                for val in Arc::make_mut(&mut res).values_mut() {
292                    *val = val.deep_clone(stack);
293                }
294                Object(res)
295            }
296            Array(ref arr) => {
297                let mut res = arr.clone();
298                for it in Arc::make_mut(&mut res) {
299                    *it = it.deep_clone(stack);
300                }
301                Array(res)
302            }
303            Link(_) => self.clone(),
304            Ref(ind) => stack[ind].deep_clone(stack),
305            UnsafeRef(_) => panic!("Unsafe reference can not be cloned"),
306            RustObject(_) => self.clone(),
307            Option(None) => Variable::Option(None),
308            // `some(x)` always uses deep clone, so it does not contain references.
309            Option(Some(ref v)) => Option(Some(v.clone())),
310            // `ok(x)` always uses deep clone, so it does not contain references.
311            Result(Ok(ref ok)) => Result(Ok(ok.clone())),
312            // `err(x)` always uses deep clone, so it does not contain references.
313            Result(Err(ref err)) => Result(Err(err.clone())),
314            #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
315            Thread(_) => self.clone(),
316            Closure(_, _) => self.clone(),
317            #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
318            In(_) => self.clone(),
319        }
320    }
321}
322
323impl PartialEq for Variable {
324    fn eq(&self, other: &Variable) -> bool {
325        match (self, other) {
326            (&Variable::Return, _) => false,
327            (&Variable::Bool(a, _), &Variable::Bool(b, _)) => a == b,
328            (&Variable::F64(a, _), &Variable::F64(b, _)) => a == b,
329            (&Variable::Str(ref a), &Variable::Str(ref b)) => a == b,
330            (&Variable::Object(ref a), &Variable::Object(ref b)) => a == b,
331            (&Variable::Array(ref a), &Variable::Array(ref b)) => a == b,
332            (&Variable::Ref(_), _) => false,
333            (&Variable::UnsafeRef(_), _) => false,
334            (&Variable::RustObject(_), _) => false,
335            _ => false,
336        }
337    }
338}
339
340/// Refers to a function.
341#[derive(Clone, Copy, Debug)]
342pub enum FnIndex {
343    /// No function.
344    None,
345    /// Relative to function you call from.
346    Loaded(isize),
347    /// External function with no return value.
348    Void(FnVoidRef),
349    /// Extern function with return value.
350    Return(FnReturnRef),
351    /// Extern function with return value and lazy invariant.
352    Lazy(FnReturnRef, LazyInvariant),
353    /// Extern binary operator.
354    BinOp(FnBinOpRef),
355    /// Extern unary operator.
356    UnOp(FnUnOpRef),
357}
358
359/// Refers to an external function.
360#[derive(Clone, Copy)]
361pub enum FnExt {
362    /// External function with no return value.
363    Void(fn(&mut Runtime) -> Result<(), String>),
364    /// External function with return value.
365    Return(fn(&mut Runtime) -> Result<Variable, String>),
366    /// External binary operator.
367    BinOp(fn(&Variable, &Variable) -> Result<Variable, String>),
368    /// External unary operator.
369    UnOp(fn(&Variable) -> Result<Variable, String>),
370}
371
372impl From<fn(&mut Runtime) -> Result<(), String>> for FnExt {
373    fn from(val: fn(&mut Runtime) -> Result<(), String>) -> Self {
374        FnExt::Void(val)
375    }
376}
377
378impl From<fn(&mut Runtime) -> Result<Variable, String>> for FnExt {
379    fn from(val: fn(&mut Runtime) -> Result<Variable, String>) -> Self {
380        FnExt::Return(val)
381    }
382}
383
384impl From<fn(&Variable, &Variable) -> Result<Variable, String>> for FnExt {
385    fn from(val: fn(&Variable, &Variable) -> Result<Variable, String>) -> Self {
386        FnExt::BinOp(val)
387    }
388}
389
390impl From<fn(&Variable) -> Result<Variable, String>> for FnExt {
391    fn from(val: fn(&Variable) -> Result<Variable, String>) -> Self {
392        FnExt::UnOp(val)
393    }
394}
395
396impl fmt::Debug for FnExt {
397    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
398        write!(f, "FnExt")
399    }
400}
401
402/// Used to store direct reference to external function.
403#[derive(Copy)]
404pub struct FnUnOpRef(pub fn(&Variable) -> Result<Variable, String>);
405
406impl Clone for FnUnOpRef {
407    fn clone(&self) -> FnUnOpRef {
408        *self
409    }
410}
411
412impl fmt::Debug for FnUnOpRef {
413    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
414        write!(f, "FnUnOpRef")
415    }
416}
417
418/// Used to store direct reference to external function.
419#[derive(Copy)]
420pub struct FnBinOpRef(pub fn(&Variable, &Variable) -> Result<Variable, String>);
421
422impl Clone for FnBinOpRef {
423    fn clone(&self) -> FnBinOpRef {
424        *self
425    }
426}
427
428impl fmt::Debug for FnBinOpRef {
429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430        write!(f, "FnBinOpRef")
431    }
432}
433
434/// Used to store direct reference to external function.
435#[derive(Copy)]
436pub struct FnReturnRef(pub fn(&mut Runtime) -> Result<Variable, String>);
437
438impl Clone for FnReturnRef {
439    fn clone(&self) -> FnReturnRef {
440        *self
441    }
442}
443
444impl fmt::Debug for FnReturnRef {
445    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
446        write!(f, "FnExternalRef")
447    }
448}
449
450/// Used to store direct reference to external function that does not return anything.
451#[derive(Copy)]
452pub struct FnVoidRef(pub fn(&mut Runtime) -> Result<(), String>);
453
454impl Clone for FnVoidRef {
455    fn clone(&self) -> FnVoidRef {
456        *self
457    }
458}
459
460impl fmt::Debug for FnVoidRef {
461    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
462        write!(f, "FnExternalRef")
463    }
464}
465
466struct FnExternal {
467    namespace: Arc<Vec<Arc<String>>>,
468    name: Arc<String>,
469    f: FnExt,
470    p: Dfn,
471}
472
473impl Clone for FnExternal {
474    fn clone(&self) -> FnExternal {
475        FnExternal {
476            namespace: self.namespace.clone(),
477            name: self.name.clone(),
478            f: self.f,
479            p: self.p.clone(),
480        }
481    }
482}
483
484/// Runs a program using a source file.
485pub fn run(source: &str) -> Result<(), String> {
486    let mut module = Module::new();
487    load(source, &mut module)?;
488    let mut runtime = runtime::Runtime::new();
489    runtime.run(&Arc::new(module))?;
490    Ok(())
491}
492
493/// Runs a program from a string.
494pub fn run_str(source: &str, d: Arc<String>) -> Result<(), String> {
495    let mut module = Module::new();
496    load_str(source, d, &mut module)?;
497    let mut runtime = runtime::Runtime::new();
498    runtime.run(&Arc::new(module))?;
499    Ok(())
500}
501
502/// Used to call specific functions with arguments.
503pub struct Call {
504    args: Vec<Variable>,
505    name: Arc<String>,
506}
507
508impl Call {
509    /// Creates a new call.
510    pub fn new(name: &str) -> Call {
511        Call {
512            args: vec![],
513            name: Arc::new(name.into()),
514        }
515    }
516
517    /// Push value to argument list.
518    pub fn arg<T: embed::PushVariable>(mut self, val: T) -> Self {
519        self.args.push(val.push_var());
520        self
521    }
522
523    /// Push Vec4 to argument list.
524    pub fn vec4<T: embed::ConvertVec4>(mut self, val: T) -> Self {
525        self.args.push(Variable::Vec4(val.to()));
526        self
527    }
528
529    /// Push Rust object to argument list.
530    pub fn rust<T: 'static>(mut self, val: T) -> Self {
531        self.args
532            .push(Variable::RustObject(Arc::new(Mutex::new(val)) as RustObject));
533        self
534    }
535
536    /// Run call without any return value.
537    pub fn run(&self, runtime: &mut Runtime, module: &Arc<Module>) -> Result<(), String> {
538        runtime.call_str(&self.name, &self.args, module)
539    }
540
541    /// Run call with return value.
542    pub fn run_ret<T: embed::PopVariable>(
543        &self,
544        runtime: &mut Runtime,
545        module: &Arc<Module>,
546    ) -> Result<T, String> {
547        let val = runtime.call_str_ret(&self.name, &self.args, module)?;
548        T::pop_var(runtime, runtime.get(&val))
549    }
550
551    /// Convert return value to a Vec4 convertible type.
552    pub fn run_vec4<T: embed::ConvertVec4>(
553        &self,
554        runtime: &mut Runtime,
555        module: &Arc<Module>,
556    ) -> Result<T, String> {
557        let val = runtime.call_str_ret(&self.name, &self.args, module)?;
558        match runtime.get(&val) {
559            &Variable::Vec4(val) => Ok(T::from(val)),
560            x => Err(runtime.expected(x, "vec4")),
561        }
562    }
563}
564
565/// Loads source from file.
566pub fn load(source: &str, module: &mut Module) -> Result<(), String> {
567    use std::fs::File;
568    use std::io::Read;
569
570    let mut data_file =
571        File::open(source).map_err(|err| format!("Could not open `{}`, {}", source, err))?;
572    let mut data = Arc::new(String::new());
573    data_file.read_to_string(Arc::make_mut(&mut data))
574        .map_err(|err| format!("Could not open `{}`, {}", source, err))?;
575    load_str(source, data, module)
576}
577
578lazy_static! {
579    static ref SYNTAX_RULES: Result<Syntax, String> = {
580        let syntax = include_str!("../assets/syntax.txt");
581        syntax_errstr(syntax)
582    };
583}
584
585/// Generates graph of nodes after lifetime and type check.
586///
587/// Ignores errors generated during lifetime or type check.
588/// Returns an error if the source does not satisfy the syntax.
589///
590/// This data is what the lifetime/type-checker knows about the source.
591pub(crate) fn check_str(
592    source: &str,
593    d: Arc<String>,
594    module: &Module,
595) -> Result<Vec<lifetime::Node>, String> {
596    let syntax_rules = SYNTAX_RULES.as_ref().map_err(|err| err.clone())?;
597
598    let mut data = vec![];
599    parse_errstr(syntax_rules, &d, &mut data)
600        .map_err(|err| format!("In `{}:`\n{}", source, err))?;
601
602    let check_data = data.clone();
603    let prelude = Arc::new(Prelude::from_module(module));
604
605    let mut nodes = vec![];
606    let _ = lifetime::check_core(&mut nodes, &check_data, &prelude);
607    Ok(nodes)
608}
609
610/// Loads a source from string.
611///
612/// - source - The name of source file
613/// - d - The data of source file
614/// - module - The module to load the source
615pub fn load_str(source: &str, d: Arc<String>, module: &mut Module) -> Result<(), String> {
616    #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
617    struct MaybeThread<T>(std::thread::JoinHandle<T>);
618
619    #[cfg(all(not(target_family = "wasm"), feature = "threading"))]
620    impl<T> MaybeThread<T>
621    where
622        T: Send + 'static,
623    {
624        fn spawn<F>(func: F) -> Self
625        where
626            F: FnOnce() -> T + Send + 'static,
627        {
628            Self(std::thread::spawn(func))
629        }
630        fn join(self) -> T {
631            self.0.join().unwrap()
632        }
633    }
634
635    #[cfg(any(target_family = "wasm", not(feature = "threading")))]
636    struct MaybeThread<T>(T);
637
638    #[cfg(any(target_family = "wasm", not(feature = "threading")))]
639    impl<T> MaybeThread<T> {
640        fn spawn<F>(func: F) -> Self where F: FnOnce() -> T {
641            Self(func())
642        }
643        fn join(self) -> T {
644            self.0
645        }
646    }
647
648    let syntax_rules = SYNTAX_RULES.as_ref().map_err(|err| err.clone())?;
649
650    let mut data = vec![];
651    parse_errstr(syntax_rules, &d, &mut data)
652        .map_err(|err| format!("In `{}:`\n{}", source, err))?;
653
654    let check_data = data.clone();
655    let prelude = Arc::new(Prelude::from_module(module));
656
657    // Do lifetime checking in parallel directly on meta data if possible.
658    let handle = MaybeThread::spawn(move || {
659        let check_data = check_data;
660        lifetime::check(&check_data, &prelude)
661    });
662
663    // Convert to AST.
664    let mut ignored = vec![];
665    let conv_res = ast::convert(
666        Arc::new(source.into()),
667        d.clone(),
668        &data,
669        &mut ignored,
670        module,
671    );
672
673    // Check that lifetime checking succeeded.
674    match handle.join() {
675        Ok(refined_rets) => {
676            for (name, ty) in &refined_rets {
677                if let FnIndex::Loaded(f_index) = module.find_function(name, 0) {
678                    let f = &mut module.functions[f_index as usize];
679                    f.ret = ty.clone();
680                }
681            }
682        }
683        Err(err_msg) => {
684            use piston_meta::ParseErrorHandler;
685            use std::io::Write;
686
687            let (range, msg) = err_msg.decouple();
688
689            let mut buf: Vec<u8> = vec![];
690            writeln!(&mut buf, "In `{}`:\n", source).unwrap();
691            ParseErrorHandler::new(&d)
692                .write_msg(&mut buf, range, &msg)
693                .unwrap();
694            return Err(String::from_utf8(buf).unwrap());
695        }
696    }
697
698    check_ignored_meta_data(conv_res, source, &d, &data, &ignored)
699}
700
701/// Loads a source from meta data.
702/// Assumes the source passes the lifetime checker.
703pub fn load_meta(
704    source: &str,
705    d: Arc<String>,
706    data: &[Range<MetaData>],
707    module: &mut Module,
708) -> Result<(), String> {
709    // Convert to AST.
710    let mut ignored = vec![];
711    let conv_res = ast::convert(
712        Arc::new(source.into()),
713        d.clone(),
714        data,
715        &mut ignored,
716        module,
717    );
718
719    check_ignored_meta_data(conv_res, source, &d, data, &ignored)
720}
721
722fn check_ignored_meta_data(
723    conv_res: Result<(), ()>,
724    source: &str,
725    d: &Arc<String>,
726    data: &[Range<MetaData>],
727    ignored: &[Range],
728) -> Result<(), String> {
729    use piston_meta::json;
730
731    if !ignored.is_empty() || conv_res.is_err() {
732        use piston_meta::ParseErrorHandler;
733        use std::io::Write;
734
735        let mut buf: Vec<u8> = vec![];
736        if !ignored.is_empty() {
737            writeln!(&mut buf, "Some meta data was ignored in the syntax").unwrap();
738            writeln!(&mut buf, "START IGNORED").unwrap();
739            json::write(&mut buf, &data[ignored[0].iter()]).unwrap();
740            writeln!(&mut buf, "END IGNORED").unwrap();
741
742            writeln!(&mut buf, "In `{}`:\n", source).unwrap();
743            ParseErrorHandler::new(d)
744                .write_msg(
745                    &mut buf,
746                    data[ignored[0].iter()][0].range(),
747                    "Could not understand this",
748                )
749                .unwrap();
750        }
751        if let Err(()) = conv_res {
752            writeln!(&mut buf, "Conversion error").unwrap();
753        }
754        return Err(String::from_utf8(buf).unwrap());
755    }
756
757    Ok(())
758}
759
760/// Reports and error to standard output.
761pub fn error(res: Result<(), String>) -> bool {
762    match res {
763        Err(err) => {
764            println!();
765            println!(" --- ERROR --- ");
766            println!("{}", err);
767            true
768        }
769        Ok(()) => false,
770    }
771}