Skip to content

Commit

Permalink
Merge pull request #310 from CohenArthur/load-libraries-from-path
Browse files Browse the repository at this point in the history
Load libraries from path
  • Loading branch information
CohenArthur authored Oct 21, 2021
2 parents 4766c78 + 100feb3 commit ddda3b6
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ impl Context {
});
entry_point.last().map(|l| l.resolve_type(&mut ctx));

self.included.clear();
match self.error_handler.has_errors() {
true => {
self.emit_errors();
Expand Down
95 changes: 58 additions & 37 deletions src/instruction/incl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,52 +72,31 @@ impl Incl {
&self,
base: &Path,
ctx: &mut Context,
) -> Option<(PathBuf, Vec<Box<dyn Instruction>>)> {
let formatted = match self.find_include_path(base) {
Ok(f) => f,
Err(e) => {
ctx.error(e);
return None;
}
};
) -> Result<(PathBuf, Vec<Box<dyn Instruction>>), Error> {
let formatted = self.find_include_path(base)?;

// If a source has already been included, skip it without returning
// an error
if ctx.is_included(&formatted) {
return Some((formatted, vec![]));
return Ok((formatted, vec![]));
}

ctx.debug("FINAL PATH", &format!("{:?}", formatted));

let input = match std::fs::read_to_string(&formatted) {
Ok(i) => i,
Err(e) => {
ctx.error(Error::from(e));
return None;
}
};
let input = std::fs::read_to_string(&formatted)?;

// We can't just parse the input, since it adds the instructions
// to an entry block in order to execute them. What we can do, is
// parse many instructions and add them to an empty ctx
let (remaining_input, instructions) = match Construct::many_instructions(input.as_str()) {
Ok(tuple) => tuple,
Err(e) => {
ctx.error(Error::from(e));
return None;
}
};
let (remaining_input, instructions) = Construct::many_instructions(input.as_str())?;

match remaining_input.len() {
// The remaining input is empty: We parsed the whole file properly
0 => Some((formatted, instructions)),
_ => {
ctx.error(Error::new(ErrKind::Parsing).with_msg(format!(
"error when parsing included file: {:?},\non the following input:\n{}",
formatted, remaining_input
)));
None
}
0 => Ok((formatted, instructions)),
_ => Err(Error::new(ErrKind::Parsing).with_msg(format!(
"error when parsing included file: {:?},\non the following input:\n{}",
formatted, remaining_input
))),
}
}

Expand All @@ -126,21 +105,41 @@ impl Incl {
&self,
base: &Path,
ctx: &mut Context,
) -> Option<(PathBuf, Vec<Box<dyn Instruction>>)> {
) -> Result<(PathBuf, Vec<Box<dyn Instruction>>), Error> {
self.inner_load(base, ctx)
}

/// Try to load code from jinko's installation path
fn _load_jinko_path(&self) -> Option<Vec<Box<dyn Instruction>>> {
todo!()
fn load_jinko_path(
&self,
ctx: &mut Context,
) -> Result<(PathBuf, Vec<Box<dyn Instruction>>), Error> {
let home = std::env::var("HOME")?;

let base = PathBuf::from(format!("{}/.jinko/libs/", home));
self.inner_load(&base, ctx)
}

/// Load the source code located at self.path
///
/// There are two ways to look for a source file: First in the includer's path, and
/// if not available in jinko's installation directory.
fn load(&self, base: &Path, ctx: &mut Context) -> Option<(PathBuf, Vec<Box<dyn Instruction>>)> {
self.load_relative(base, ctx)
// If we can load from the current path, we return early
let relative_err = match self.load_relative(base, ctx) {
Ok(tuple) => return Some(tuple),
Err(e) => e,
};

let jk_path_err = match self.load_jinko_path(ctx) {
Ok(tuple) => return Some(tuple),
Err(e) => e,
};

ctx.error(relative_err);
ctx.error(jk_path_err);

None
}

/// Format the correct prefix to include content as. This depends on the presence
Expand Down Expand Up @@ -202,6 +201,7 @@ impl Instruction for Incl {
}

fn execute(&self, ctx: &mut Context) -> Option<ObjectInstance> {
eprintln!("in exec {}", self.print());
ctx.debug("INCL ENTER", self.print().as_str());

let base = self.get_base(ctx);
Expand Down Expand Up @@ -237,6 +237,7 @@ impl TypeCheck for Incl {
fn resolve_type(&self, ctx: &mut TypeCtx) -> CheckedType {
// FIXME: This is a lot of code in common with execute()
let base = self.get_base(ctx.context);
eprintln!("in typechecker {}", self.print());

let old_path = ctx.context.path().cloned();

Expand All @@ -246,15 +247,14 @@ impl TypeCheck for Incl {
};

// Temporarily change the path of the context
ctx.context.set_path(Some(new_path.clone()));
ctx.context.set_path(Some(new_path));

content.iter_mut().for_each(|instr| {
instr.resolve_type(ctx);
});

// Reset the old path before leaving the instruction
ctx.context.set_path(old_path);
ctx.context.remove_included(&new_path);

CheckedType::Void
}
Expand All @@ -263,10 +263,31 @@ impl TypeCheck for Incl {
#[cfg(test)]
mod tests {
use super::*;
use crate::{jinko, jinko_fail};

#[test]
fn tc_typecheck_stdlib() {
let mut ctx = Context::new();
ctx.execute().unwrap();
}

#[test]
fn include_stdlib() {
jinko! {};
}

#[test]
fn include_non_existant() {
jinko_fail! {
incl does_not_exist_at_all;
};
}

#[test]
fn include_already_included() {
jinko! {
incl stdlib;
incl stdlib as std;
};
}
}

0 comments on commit ddda3b6

Please sign in to comment.