Interp - an Interpreted Programming Language Pt.13 - Importing

1 minute read

In Pt. 13 we implement importing code.

Dependencies

Include the dires and lazy_static crate.

Cargo.toml:

[dependencies]

...

dirs = "4.0.0"

Parsing

LineType

Add the Import LineType.

src/parser/line.rs:

pub enum LineType {
    ...
    Import(Expr),
}

Grammar

Add these tokens and grammar rules.

src/parser/grammar.lalrpop:

match {

    ...

    "imp",
}

...

pub Line: Line = {

    ...

    <l:@L> "imp" <a:string> => Line { type_: LineType::Import(a), loc: Loc { filename: filename.to_owned(), line_nr, index: l } },
}

exec_line

Implement the exec_line case. Importing from the include dirctory can be done by prefixing with `@`.

src/vm/mod.rs:


...

use std::fs;
use crate::parser;

...

pub fn exec_line(vm: &mut VM, parsed_line: &Line) {

    ...

    match &parsed_line.type_ {

        ...

        LineType::Import(expr) => {
            let filename = value_repr(expr_to_value(vm, expr));
            if filename.starts_with("@") {
                filename.remove(0);
                filename.insert_str(0,
                    dirs::data_dir().unwrap().join("interp/").to_str().unwrap());
            }
            match fs::read_to_string(&filename) {
                Ok(text) => {
                    let mut line_buffer = String::new();
                    for (line_nr, mut line_str) in text.lines().enumerate() {
                        if let Some(i) = line_str.find("#") {
                            line_str = &line_str[0..i];
                        }
                        if line_str.trim_end().ends_with("\\") {
                            line_buffer.push_str(&line_str[0..line_str.rfind("\\").unwrap()]);
                        } else  {
                            line_buffer.push_str(&line_str);
                            let parsed_line = parser::parse_line(
                                &line_buffer,
                                &filename,
                                line_nr
                            );
                            if let Ok(parsed_line) = parsed_line {
                                exec_line(vm, &parsed_line);
                            }
                            line_buffer.clear();
                        }
                    }
                }
                Err(err) => {
                    err::throw_loc(err::Err::FileError
                                   { file: filename, message: err.to_string() }, &expr.loc);
                }
            }
        }
    }
}

Source Code

Source code for this part can be found here.

Next Up

Click for Pt. 14 or click here for all parts.

Updated: