Skip to content

Commit

Permalink
Implicits std as a dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Oct 22, 2023
1 parent 02ef0ad commit 13f63c9
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 31 deletions.
11 changes: 9 additions & 2 deletions stage0/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,18 @@ fn main() -> ExitCode {
}
};

// Get std path.
let prefix = exe.parent().unwrap().parent().unwrap();
let mut std = prefix.join("share");

std.push("nitro");
std.push("nitro.npk");

// Execute the command.
let cx = Context {
prefix: exe.parent().unwrap().parent().unwrap(),
prefix,
targets: TargetResolver::new(),
deps: DependencyResolver::new(),
deps: DependencyResolver::new(std),
};

match args.subcommand().unwrap() {
Expand Down
27 changes: 25 additions & 2 deletions stage0/src/pkg/dep.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
use super::{PackageName, PackageVersion};
use super::{Package, PackageName, PackageVersion};
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use std::io::Write;
use std::path::PathBuf;
use std::rc::Rc;
use thiserror::Error;

/// An object for resolving package dependencies.
pub struct DependencyResolver {}

impl DependencyResolver {
pub fn new() -> Self {
pub fn new<S: Into<PathBuf>>(std: S) -> Self {
Self {}
}

pub fn resolve(&self, id: &Dependency) -> Result<Rc<Package>, DependencyResolveError> {
todo!()
}
}

/// A package dependency.
#[derive(Debug)]
pub struct Dependency {
name: PackageName,
version: PackageVersion,
}

impl Dependency {
pub fn new(name: PackageName, version: PackageVersion) -> Self {
Self { name, version }
}

pub fn serialize<W: Write>(&self, mut w: W) -> Result<(), std::io::Error> {
w.write_all(&self.name.to_bin())?;
w.write_all(&self.version.to_bin().to_be_bytes())
Expand All @@ -38,3 +51,13 @@ impl Hash for Dependency {
self.version.major().hash(state);
}
}

impl Display for Dependency {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} v{}", self.name, self.version)
}
}

/// Represents an error when [`DependencyResolver::resolve()`] is failed.
#[derive(Debug, Error)]
pub enum DependencyResolveError {}
24 changes: 22 additions & 2 deletions stage0/src/pkg/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl PackageMeta {
///
/// A package name must start with a lower case ASCII and followed by zero of more 0-9 and a-z (only
/// lower case). The maximum length is 32 characters.
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PackageName(String);

impl PackageName {
Expand All @@ -45,6 +45,12 @@ impl PackageName {
}
}

impl PartialEq<str> for PackageName {
fn eq(&self, other: &str) -> bool {
self.0 == other
}
}

impl<'a> Deserialize<'a> for PackageName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand Down Expand Up @@ -95,14 +101,22 @@ impl Display for PackageName {
/// A version of a Nitro package.
///
/// This is an implementation of https://semver.org.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct PackageVersion {
major: u16,
minor: u16,
patch: u16,
}

impl PackageVersion {
pub fn new(major: u16, minor: u16, patch: u16) -> Self {
Self {
major,
minor,
patch,
}
}

pub fn major(&self) -> u16 {
self.major
}
Expand All @@ -125,6 +139,12 @@ impl<'a> Deserialize<'a> for PackageVersion {
}
}

impl Display for PackageVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}

/// An implementation of [`Visitor`] for [`PackageName`].
struct PackageNameVisitor;

Expand Down
4 changes: 4 additions & 0 deletions stage0/src/pkg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ impl Package {
&self.meta
}

pub fn libs(&self) -> &HashMap<Target, Binary<Library>> {
&self.libs
}

pub fn pack<F: AsRef<Path>>(&self, file: F) -> Result<(), PackagePackError> {
// Create a package file.
let path = file.as_ref();
Expand Down
78 changes: 53 additions & 25 deletions stage0/src/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use crate::ast::{ParseError, SourceFile};
use crate::codegen::{BuildError, Codegen, TypeResolver};
use crate::lexer::SyntaxError;
use crate::pkg::{
Binary, DependencyResolver, Library, LibraryBinary, Package, PackageMeta, PackageName,
PackageVersion, PrimitiveTarget, Target, TargetArch, TargetEnv, TargetOs, TargetResolveError,
TargetResolver, TypeDeclaration,
Binary, Dependency, DependencyResolveError, DependencyResolver, Library, LibraryBinary,
Package, PackageMeta, PackageName, PackageVersion, PrimitiveTarget, Target, TargetArch,
TargetEnv, TargetOs, TargetResolveError, TargetResolver, TypeDeclaration,
};
use std::borrow::Cow;
use std::collections::{HashMap, HashSet, VecDeque};
Expand Down Expand Up @@ -104,6 +104,18 @@ impl<'a> Project<'a> {
let mut exes = HashMap::new();
let mut libs = HashMap::new();

// Resolve dependencies.
let mut deps = Vec::new();

if pkg.name() != "nitro" {
let id = Dependency::new("nitro".parse().unwrap(), PackageVersion::new(1, 0, 0));

match self.deps.resolve(&id) {
Ok(v) => deps.push(v),
Err(e) => return Err(ProjectBuildError::ResolveDependencyFailed(id, e)),
};
}

// Build library.
if !self.lib.is_empty() {
let root = self.meta.library().unwrap().sources();
Expand All @@ -114,6 +126,13 @@ impl<'a> Project<'a> {

resolver.populate_internal_types(&self.lib);

// Populate types from dependencies.
for dep in &deps {
if let Some(lib) = self.resolve_lib(target.clone(), dep.libs())? {
resolver.populate_external_types(dep.meta(), lib.bin().types());
}
}

// Build.
let br = self.build_for(root, false, &target, &self.lib, &resolver)?;
let out = self.link_lib(&br)?;
Expand Down Expand Up @@ -142,32 +161,18 @@ impl<'a> Project<'a> {

// Populate types from package library.
if !libs.is_empty() {
// Resolve library.
let mut target = target.clone();
let lib = loop {
if let Some(v) = libs.get(&target) {
break Some(v);
}

target = match self.targets.parent(&target) {
Ok(v) => match v {
Some(v) => v,
None => break None,
},
Err(e) => {
return Err(ProjectBuildError::ResolveParentTargetFailed(
target, e,
));
}
};
};

// Add types to resolver.
if let Some(lib) = lib {
if let Some(lib) = self.resolve_lib(target.clone(), &libs)? {
resolver.populate_external_types(&meta, lib.bin().types());
}
}

// Populate types from dependencies.
for dep in &deps {
if let Some(lib) = self.resolve_lib(target.clone(), dep.libs())? {
resolver.populate_external_types(dep.meta(), lib.bin().types());
}
}

// Build.
let br = self.build_for(root, true, &target, &self.exe, &resolver)?;
let out = self.link_exe(br)?;
Expand Down Expand Up @@ -278,6 +283,26 @@ impl<'a> Project<'a> {
Ok(())
}

fn resolve_lib<'b>(
&self,
mut target: Target,
libs: &'b HashMap<Target, Binary<Library>>,
) -> Result<Option<&'b Binary<Library>>, ProjectBuildError> {
loop {
if let Some(v) = libs.get(&target) {
break Ok(Some(v));
}

target = match self.targets.parent(&target) {
Ok(v) => match v {
Some(v) => v,
None => break Ok(None),
},
Err(e) => break Err(ProjectBuildError::ResolveParentTargetFailed(target, e)),
};
}
}

fn build_for<'b, R, S>(
&self,
root: R,
Expand Down Expand Up @@ -625,6 +650,9 @@ pub enum ProjectLoadError {
/// Represents an error when a [`Project`] is failed to build.
#[derive(Debug, Error)]
pub enum ProjectBuildError {
#[error("cannot resolve dependency {0}")]
ResolveDependencyFailed(Dependency, #[source] DependencyResolveError),

#[error("cannot resolve primitive target of {0}")]
ResolvePrimitiveTargetFailed(Target, #[source] TargetResolveError),

Expand Down

0 comments on commit 13f63c9

Please sign in to comment.