Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement stdlib structure #121

Merged
merged 4 commits into from
Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
#"examples",
#"miden",
"processor",
"stdlib",
#"verifier"
]

Expand Down
1 change: 1 addition & 0 deletions assembly/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ std = ["vm-core/std", "winter-utils/std"]

[dependencies]
vm-core = { package = "miden-core", path = "../core", version = "0.2", default-features = false }
vm-stdlib = { package = "miden-stdlib", path = "../stdlib", version = "0.1", default-features = false }
winter-utils = { package = "winter-utils", version = "0.3", default-features = false }
94 changes: 94 additions & 0 deletions assembly/src/context/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use super::{CodeBlock, ProcMap, Procedure, MODULE_PATH_DELIM};
use winter_utils::collections::BTreeMap;

// ASSEMBLY CONTEXT
// ================================================================================================

/// Context for a compilation of a given script or module.
///
/// An assembly context contains a set of procedures which can be called from the parsed code.
/// The procedures are divided into local and imported procedures. Local procedures are procedures
/// parsed from the body or a script or a module, while imported procedures are imported from
/// other modules.
///
/// Local procedures are owned by the context, while imported procedures are stored by reference.
pub struct AssemblyContext<'a> {
local_procs: ProcMap,
imported_procs: BTreeMap<String, &'a Procedure>,
}

impl<'a> AssemblyContext<'a> {
// CONSTRUCTOR
// --------------------------------------------------------------------------------------------
/// Returns a new empty [AssemblyContext].
pub fn new() -> Self {
Self {
local_procs: BTreeMap::new(),
imported_procs: BTreeMap::new(),
}
}

// STATE ACCESSORS
// --------------------------------------------------------------------------------------------

/// Returns true if a procedure with the specified label exists in this context.
pub fn contains_proc(&self, label: &str) -> bool {
self.local_procs.contains_key(label) || self.imported_procs.contains_key(label)
}

/// Returns a code root of a procedure for the specified label from this context.
pub fn get_proc_code(&self, label: &str) -> Option<&CodeBlock> {
// `expect()`'s are OK here because we first check if a given map contains the key
if self.imported_procs.contains_key(label) {
let proc = *self
.imported_procs
.get(label)
.expect("no procedure after contains");
Some(proc.code_root())
} else if self.local_procs.contains_key(label) {
let proc = self
.local_procs
.get(label)
.expect("no procedure after contains");
Some(proc.code_root())
} else {
None
}
}

// STATE MUTATORS
// --------------------------------------------------------------------------------------------

/// Adds a local procedure to this context.
///
/// A label for a local procedure is set simply `proc.label`.
///
/// # Panics
/// Panics if a procedure with the specified label already exists in this context.
pub fn add_local_proc(&mut self, proc: Procedure) {
let label = proc.label();
assert!(!self.contains_proc(label), "duplicate procedure: {}", label);
self.local_procs.insert(label.to_string(), proc);
}

/// Adds an imported procedure to this context.
///
/// A label for an imported procedure is set to `prefix::proc.label`.
///
/// # Panics
/// Panics if a procedure with the specified label already exists in this context.
pub fn add_imported_proc(&mut self, prefix: &str, proc: &'a Procedure) {
let label = format!("{}{}{}", prefix, MODULE_PATH_DELIM, proc.label());
assert!(
!self.contains_proc(&label),
"duplicate procedure: {}",
label
);
self.imported_procs.insert(label, proc);
}

/// Extracts local procedures from this context.
pub fn into_local_procs(self) -> ProcMap {
self.local_procs
}
}
46 changes: 46 additions & 0 deletions assembly/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,52 @@ impl AssemblyError {
}
}

pub fn prc_export_not_allowed(token: &Token, label: &str) -> Self {
AssemblyError {
message: format!("exported procedures not allowed in this context: {}", label),
step: token.pos(),
op: token.to_string(),
}
}

// IMPORTS AND MODULES
// --------------------------------------------------------------------------------------------

pub fn missing_import_source(token: &Token, module_path: &str) -> Self {
AssemblyError {
message: format!("module source not found: {}", module_path),
step: token.pos(),
op: token.to_string(),
}
}

pub fn dangling_ops_after_module(token: &Token, module_path: &str) -> Self {
AssemblyError {
message: format!("dangling instructions after module end at {}", module_path),
step: token.pos(),
op: token.to_string(),
}
}

pub fn circular_module_dependency(token: &Token, module_chain: &[String]) -> Self {
AssemblyError {
message: format!(
"circular module dependency in the following chain: {:?}",
module_chain
),
step: token.pos(),
op: token.to_string(),
}
}

pub fn invalid_module_path(token: &Token, module_path: &str) -> Self {
AssemblyError {
message: format!("invalid module import path: {}", module_path),
step: token.pos(),
op: token.to_string(),
}
}

// PUBLIC ACCESSORS
// --------------------------------------------------------------------------------------------
pub fn message(&self) -> &String {
Expand Down