Skip to content

Commit

Permalink
Merge pull request #45 from sezna/github-deps
Browse files Browse the repository at this point in the history
GitHub deps
  • Loading branch information
sezna authored Jun 24, 2024
2 parents 780fcc1 + 4f1d40e commit 937f597
Show file tree
Hide file tree
Showing 24 changed files with 786 additions and 234 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pete/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ petr-profiling = { path = "../petr-profiling" }
miette = { version = "7.2.0", features = ["fancy"] }
thiserror = "1.0"
toml = "0.8"
termcolor = "1.4.1"

[features]
debug = ["petr-utils/debug", "petr-resolve/debug"]
Expand Down
216 changes: 125 additions & 91 deletions pete/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
use std::{
fs,
path::{Path, PathBuf},
rc::Rc,
};

use clap::Parser as ClapParser;
use petr_ir::Lowerer;
use petr_parse::Parser;
use petr_pkg::BuildPlan;
use petr_utils::{IndexMap, SourceId, SpannedItem};
use petr_utils::{Identifier, IndexMap, SourceId, SpannedItem};
use petr_vm::Vm;
use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};

mod error {
use thiserror::Error;
#[derive(Error, Debug)]
pub enum PeteError {
#[error(transparent)]
IoError(#[from] std::io::Error),
Io(#[from] std::io::Error),
#[error(transparent)]
TomlSeriatlizeError(#[from] toml::ser::Error),
TomlSeriatlize(#[from] toml::ser::Error),
#[error(transparent)]
Pkg(#[from] petr_pkg::error::PkgError),
}
}

Expand Down Expand Up @@ -80,58 +84,12 @@ fn main() -> Result<(), error::PeteError> {
match cli.command {
Commands::Run { target, path, time } => {
let mut timings = petr_profiling::Timings::default();
timings.start("full compile");
timings.start("load project and dependencies");
let (lockfile, buf, _build_plan) = load_project_and_dependencies(&path);
let lockfile_toml = toml::to_string(&lockfile).expect("Failed to serialize lockfile to TOML");
let lockfile_path = path.join("petr.lock");
fs::write(lockfile_path, lockfile_toml).expect("Failed to write lockfile");

timings.end("load project and dependencies");

// convert pathbufs into strings for the parser
let buf = buf
.into_iter()
.map(|(pathbuf, s)| (pathbuf.to_string_lossy().to_string(), s))
.collect::<Vec<_>>();

timings.start("parse");
// parse
let parser = Parser::new(buf);
let (ast, parse_errs, interner, source_map) = parser.into_result();
timings.end("parse");

render_errors(parse_errs, &source_map);
// errs.append(&mut parse_errs);
// resolve symbols
timings.start("symbol resolution");
let (resolution_errs, resolved) = petr_resolve::resolve_symbols(ast, interner);
timings.end("symbol resolution");

// TODO impl diagnostic for resolution errors
if !resolution_errs.is_empty() {
dbg!(&resolution_errs);
}
// errs.append(&mut resolution_errs);

timings.start("type check");
// type check
let (type_errs, type_checker) = petr_typecheck::type_check(resolved);

timings.end("type check");

// TODO impl diagnostic for type errors
if !type_errs.is_empty() {
dbg!(&type_errs);
}
// errs.append(&mut type_errs);

timings.start("lowering");
let lowerer: Lowerer = Lowerer::new(type_checker);
timings.end("lowering");
let lowerer = compile(path, &mut timings)?;

let (data, instructions) = lowerer.finalize();

timings.end("full compile");

timings.start("execution");
match target.to_lowercase().as_str() {
"vm" => {
Expand All @@ -144,7 +102,6 @@ fn main() -> Result<(), error::PeteError> {
},
}
timings.end("execution");
timings.end("full compile");
if time {
println!("{}", timings.render());
}
Expand Down Expand Up @@ -173,55 +130,42 @@ fn main() -> Result<(), error::PeteError> {
}
},
Commands::Ir { path } => {
let (lockfile, buf, _build_plan) = load_project_and_dependencies(&path);
let lockfile_toml = toml::to_string(&lockfile)?;
let lockfile_path = path.join("petr.lock");
fs::write(lockfile_path, lockfile_toml)?;

// convert pathbufs into strings for the parser
let buf = buf
.into_iter()
.map(|(pathbuf, s)| (pathbuf.to_string_lossy().to_string(), s))
.collect::<Vec<_>>();

// parse
let parser = Parser::new(buf);
let (ast, parse_errs, interner, source_map) = parser.into_result();

render_errors(parse_errs, &source_map);
// errs.append(&mut parse_errs);
// resolve symbols
let (resolution_errs, resolved) = petr_resolve::resolve_symbols(ast, interner);

// TODO impl diagnostic for resolution errors
if !resolution_errs.is_empty() {
dbg!(&resolution_errs);
}
// errs.append(&mut resolution_errs);

// type check
let (type_errs, type_checker) = petr_typecheck::type_check(resolved);

// TODO impl diagnostic for type errors
if !type_errs.is_empty() {
dbg!(&type_errs);
}
// errs.append(&mut type_errs);
let lowerer: Lowerer = Lowerer::new(type_checker);
let lowerer = compile(path, &mut petr_profiling::Timings::default())?;

println!("{}", lowerer.pretty_print());
},
}
Ok(())
}

fn load_project_and_dependencies(path: &Path) -> (petr_pkg::Lockfile, Vec<(PathBuf, String)>, BuildPlan) {
#[allow(clippy::type_complexity)]
fn load_project_and_dependencies(path: &Path) -> Result<(petr_pkg::Lockfile, Vec<(PathBuf, String)>, BuildPlan), crate::error::PeteError> {
let manifest = petr_pkg::manifest::find_manifest(Some(path.to_path_buf())).expect("Failed to find manifest");
let dependencies = manifest.dependencies;
let (lockfile, build_plan) = petr_pkg::load_dependencies(dependencies);
let mut stdout = StandardStream::stdout(ColorChoice::Always);

if !dependencies.is_empty() {
stdout.set_color(ColorSpec::new().set_bold(true))?;
/*
todo!(
"instead of saying fetching, pay attention to if it already exists
and print if it does or doesn't. also, check if checksum agrees with lockfile
and use rev etc on github dep to determine thet key"
);
*/
println!(
"Fetching {} {} for package {}",
dependencies.len(),
if dependencies.len() == 1 { "dependency" } else { "dependencies" },
manifest.name
);

stdout.set_color(ColorSpec::new().set_bold(false))?;
}
let (lockfile, build_plan) = petr_pkg::load_dependencies(dependencies)?;

let files = load_files(path);
(lockfile, files, build_plan)
Ok((lockfile, files, build_plan))
}

fn load_files(path: &Path) -> Vec<(PathBuf, String)> {
Expand Down Expand Up @@ -259,3 +203,93 @@ fn render_errors<T>(
eprintln!("{:?}", rendered);
}
}

fn compile(
path: PathBuf,
timings: &mut petr_profiling::Timings,
) -> Result<Lowerer, crate::error::PeteError> {
timings.start("full compile");
timings.start("load project and dependencies");
let (lockfile, buf, build_plan) = load_project_and_dependencies(&path)?;
let lockfile_toml = toml::to_string(&lockfile).expect("Failed to serialize lockfile to TOML");
let lockfile_path = path.join("petr.lock");
fs::write(lockfile_path, lockfile_toml).expect("Failed to write lockfile");
timings.end("load project and dependencies");

// convert pathbufs into strings for the parser
let buf = buf
.into_iter()
.map(|(pathbuf, s)| (pathbuf.to_string_lossy().to_string(), s))
.collect::<Vec<_>>();

timings.start("parsing stage");
timings.start("parse user code");
// parse
// construct an interner for symbols, which will be used throughout the whole compilation.
let parser = Parser::new(buf);
let (ast, mut parse_errs, mut interner, mut source_map) = parser.into_result();

timings.end("parse user code");
timings.start("parse dependencies");

let mut dependencies = Vec::with_capacity(build_plan.items.len());

for item in build_plan.items {
let (lockfile, buf, _build_plan) = load_project_and_dependencies(&item.path_to_source)?;
// TODO(alex) -- transitive dependencies, get these build plans too
let lockfile_toml = toml::to_string(&lockfile)?;
let lockfile_path = path.join("petr.lock");
fs::write(lockfile_path, lockfile_toml)?;
// the idea here is that we re-use the interner and source map,
// so we don't have to worry about scoping symbol IDs and source IDs to packages
let parser = Parser::new_with_existing_interner_and_source_map(
buf.into_iter()
.map(|(pathbuf, s)| (pathbuf.to_string_lossy().to_string(), s))
.collect::<Vec<_>>(),
interner,
source_map,
);
let (ast, mut new_parse_errs, new_interner, new_source_map) = parser.into_result();
interner = new_interner;
parse_errs.append(&mut new_parse_errs);
source_map = new_source_map;
let name = Identifier {
id: interner.insert(Rc::from(item.manifest.name)),
};
dependencies.push((item.key, name, item.depends_on, ast));
}

timings.end("parse dependencies");
timings.end("parsing stage");

render_errors(parse_errs, &source_map);
// errs.append(&mut parse_errs);
// resolve symbols
timings.start("symbol resolution");
let (resolution_errs, resolved) = petr_resolve::resolve_symbols(ast, interner, dependencies);
timings.end("symbol resolution");

// TODO impl diagnostic for resolution errors
if !resolution_errs.is_empty() {
dbg!(&resolution_errs);
}
// errs.append(&mut resolution_errs);

timings.start("type check");
// type check
let (type_errs, type_checker) = petr_typecheck::type_check(resolved);

timings.end("type check");

// TODO impl diagnostic for type errors
if !type_errs.is_empty() {
dbg!(&type_errs);
}
// errs.append(&mut type_errs);

timings.start("lowering");
let lowerer: Lowerer = Lowerer::new(type_checker);
timings.end("lowering");

Ok(lowerer)
}
33 changes: 31 additions & 2 deletions petr-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@ pub struct Ast {
pub modules: Vec<Module>,
}

impl std::fmt::Debug for Ast {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
writeln!(f, "AST")?;
for module in self.modules.iter() {
let path = module.name.iter().map(|x| format!("{}", x.id)).collect::<Vec<_>>().join(".");
writeln!(f, "Module: {path}")?;
for node in module.nodes.iter() {
match node.item() {
AstNode::FunctionDeclaration(fun) => writeln!(f, " Function: {}", fun.item().name.id)?,
AstNode::TypeDeclaration(ty) => writeln!(f, " Type: {}", ty.item().name.id)?,
AstNode::ImportStatement(i) => writeln!(
f,
" Import: {}",
i.item().path.iter().map(|x| format!("{}", x.id)).collect::<Vec<_>>().join(".")
)?,
}
}
}
Ok(())
}
}

pub struct Module {
pub name: Path,
pub nodes: Vec<SpannedItem<AstNode>>,
Expand All @@ -27,7 +52,7 @@ pub enum AstNode {
}

pub struct ImportStatement {
pub path: Box<[Identifier]>,
pub path: Path,
pub alias: Option<Identifier>,
pub visibility: Visibility,
}
Expand All @@ -49,7 +74,7 @@ impl TypeDeclaration {
}
}

#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Visibility {
Local,
Exported,
Expand Down Expand Up @@ -91,8 +116,12 @@ pub enum Expression {
pub struct ExpressionWithBindings {
pub bindings: Vec<Binding>,
pub expression: Box<Expression>,
pub expr_id: ExprId,
}

#[derive(Clone, Debug, PartialOrd, Ord, Eq, PartialEq, Copy)]
pub struct ExprId(pub usize);

#[derive(Clone)]
pub struct Binding {
pub name: Identifier,
Expand Down
2 changes: 1 addition & 1 deletion petr-ast/src/pretty_print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl PrettyPrint for ImportStatement {
"{}{} {}",
" ".repeat(indentation),
if self.is_exported() { "export" } else { "import" },
self.path.iter().map(|id| interner.get(id.id)).collect::<Vec<_>>().join("."),
self.path.identifiers.iter().map(|id| interner.get(id.id)).collect::<Vec<_>>().join("."),
);
if let Some(alias) = self.alias {
buf.push_str(&format!(" as {}", interner.get(alias.id)));
Expand Down
Loading

0 comments on commit 937f597

Please sign in to comment.