Skip to content

Commit

Permalink
Merge branch 'next' into vlopes11-node-source-location
Browse files Browse the repository at this point in the history
  • Loading branch information
vlopes11 committed May 19, 2023
2 parents ac9d385 + 4565d20 commit 58ded25
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 155 deletions.
5 changes: 5 additions & 0 deletions assembly/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ mod parsers;
pub use parsers::{ModuleAst, ProcedureAst, ProgramAst};
use parsers::{NAMESPACE_LABEL_PARSER, PROCEDURE_LABEL_PARSER};

pub mod ast {
pub use crate::parsers::{Instruction, ModuleAst, Node, ProcedureAst, ProgramAst};
pub use crate::procedures::ProcedureName;
}

pub use vm_core::utils::{
ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader,
};
Expand Down
18 changes: 17 additions & 1 deletion assembly/src/parsers/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ impl PartialEq for CodeBody {
}
}

impl FromIterator<Node> for CodeBody {
fn from_iter<T: IntoIterator<Item = Node>>(nodes: T) -> Self {
Self {
nodes: nodes.into_iter().collect(),
locations: Vec::new(),
}
}
}

impl FromIterator<(Node, SourceLocation)> for CodeBody {
fn from_iter<T: IntoIterator<Item = (Node, SourceLocation)>>(nodes: T) -> Self {
let (nodes, locations) = nodes.into_iter().unzip();
Self { nodes, locations }
}
}

impl CodeBody {
// CONSTRUCTOR
// --------------------------------------------------------------------------------------------
Expand All @@ -44,7 +60,7 @@ impl CodeBody {
/// Binds [SourceLocation] to their respective [Node].
///
/// It is expected to have the `locations` length equal to the `self.nodes` length.
pub fn with_locations<L>(mut self, locations: L) -> Self
pub fn with_source_locations<L>(mut self, locations: L) -> Self
where
L: IntoIterator<Item = SourceLocation>,
{
Expand Down
15 changes: 4 additions & 11 deletions assembly/src/parsers/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,16 +295,9 @@ impl ParserContext {
tokens.advance();

// build and return the procedure
let proc = ProcedureAst {
name,
docs,
num_locals,
is_export,
body,
start,
};

Ok(proc)
let (nodes, locations) = body.into_parts();
Ok(ProcedureAst::new(name, num_locals, nodes, is_export, docs)
.with_source_locations(locations, start))
}

// BODY PARSER
Expand Down Expand Up @@ -374,7 +367,7 @@ impl ParserContext {
return Err(ParsingError::body_too_long(token, nodes.len(), MAX_BODY_LEN));
}

Ok(CodeBody::new(nodes).with_locations(locations))
Ok(CodeBody::new(nodes).with_source_locations(locations))
}

// HELPER METHODS
Expand Down
129 changes: 99 additions & 30 deletions assembly/src/parsers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod body;
use body::CodeBody;
mod nodes;
use crate::utils::bound_into_included_u64;
pub(crate) use nodes::{Instruction, Node};
pub use nodes::{Instruction, Node};
mod context;
use context::ParserContext;
mod labels;
Expand Down Expand Up @@ -54,6 +54,36 @@ pub struct ProgramAst {
}

impl ProgramAst {
// CONSTRUCTORS
// --------------------------------------------------------------------------------------------
/// Constructs a [ProgramAst].
///
/// A program consist of a body and a set of internal (i.e., not exported) procedures.
pub fn new(local_procs: Vec<ProcedureAst>, body: Vec<Node>) -> Result<Self, ParsingError> {
if local_procs.len() > MAX_LOCL_PROCS {
return Err(ParsingError::too_many_module_procs(local_procs.len(), MAX_LOCL_PROCS));
}
let start = SourceLocation::default();
let body = CodeBody::new(body);
Ok(Self {
local_procs,
body,
start,
})
}

/// Binds the provided `locations` into the ast nodes.
///
/// The `start` location points to the first node of this block.
pub fn with_source_locations<L>(mut self, locations: L, start: SourceLocation) -> Self
where
L: IntoIterator<Item = SourceLocation>,
{
self.start = start;
self.body = self.body.with_source_locations(locations);
self
}

// PARSER
// --------------------------------------------------------------------------------------------
/// Parses the provided source into a [ProgramAst].
Expand Down Expand Up @@ -116,15 +146,8 @@ impl ProgramAst {
}

let local_procs = sort_procs_into_vec(context.local_procs);
if local_procs.len() > MAX_LOCL_PROCS {
return Err(ParsingError::too_many_module_procs(local_procs.len(), MAX_LOCL_PROCS));
}

Ok(Self {
body,
local_procs,
start,
})
let (nodes, locations) = body.into_parts();
Ok(Self::new(local_procs, nodes)?.with_source_locations(locations, start))
}

// SERIALIZATION / DESERIALIZATION
Expand Down Expand Up @@ -152,20 +175,15 @@ impl ProgramAst {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, DeserializationError> {
let mut source = SliceReader::new(bytes);

// TODO locations are currently not supported for serialization
let start = SourceLocation::default();

let num_local_procs = source.read_u16()?;
let local_procs = Deserializable::read_batch_from(&mut source, num_local_procs as usize)?;

let body_len = source.read_u16()? as usize;
let nodes = Deserializable::read_batch_from(&mut source, body_len)?;
let body = CodeBody::new(nodes);
Ok(ProgramAst {
local_procs,
body,
start,
})
match Self::new(local_procs, nodes) {
Err(err) => Err(DeserializationError::UnknownError(err.message().clone())),
Ok(res) => Ok(res),
}
}

// DESTRUCTURING
Expand All @@ -191,6 +209,23 @@ pub struct ModuleAst {
}

impl ModuleAst {
// AST
// --------------------------------------------------------------------------------------------
/// Constructs a [ModuleAst].
///
/// A module consists of internal and exported procedures but does not contain a body.
pub fn new(local_procs: Vec<ProcedureAst>, docs: Option<String>) -> Result<Self, ParsingError> {
if local_procs.len() > MAX_LOCL_PROCS {
return Err(ParsingError::too_many_module_procs(local_procs.len(), MAX_LOCL_PROCS));
}
if let Some(ref docs) = docs {
if docs.len() > MAX_DOCS_LEN {
return Err(ParsingError::module_docs_too_long(docs.len(), MAX_DOCS_LEN));
}
}
Ok(Self { docs, local_procs })
}

// PARSER
// --------------------------------------------------------------------------------------------
/// Parses the provided source into a [ModuleAst].
Expand Down Expand Up @@ -219,19 +254,11 @@ impl ModuleAst {

// get a list of local procs and make sure the number of procs is within the limit
let local_procs = sort_procs_into_vec(context.local_procs);
if local_procs.len() > MAX_LOCL_PROCS {
return Err(ParsingError::too_many_module_procs(local_procs.len(), MAX_LOCL_PROCS));
}

// get module docs and make sure the size is within the limit
let docs = tokens.take_module_comments();
if let Some(ref docs) = docs {
if docs.len() > MAX_DOCS_LEN {
return Err(ParsingError::module_docs_too_long(docs.len(), MAX_DOCS_LEN));
}
}

Ok(ModuleAst { docs, local_procs })
Self::new(local_procs, docs)
}

// PUBLIC ACCESSORS
Expand Down Expand Up @@ -300,7 +327,11 @@ impl Deserializable for ModuleAst {

let num_local_procs = source.read_u16()? as usize;
let local_procs = Deserializable::read_batch_from(source, num_local_procs)?;
Ok(Self { docs, local_procs })

match Self::new(local_procs, docs) {
Err(err) => Err(DeserializationError::UnknownError(err.message().clone())),
Ok(res) => Ok(res),
}
}
}

Expand All @@ -322,6 +353,44 @@ pub struct ProcedureAst {
pub is_export: bool,
}

impl ProcedureAst {
// CONSTRUCTORS
// --------------------------------------------------------------------------------------------
/// Constructs a [ProcedureAst].
///
/// A procedure consists of a name, a number of locals, a body, and a flag to signal whether the procedure is exported.
pub fn new(
name: ProcedureName,
num_locals: u16,
body: Vec<Node>,
is_export: bool,
docs: Option<String>,
) -> Self {
let start = SourceLocation::default();
let body = CodeBody::new(body);
Self {
name,
docs,
num_locals,
body,
is_export,
start,
}
}

/// Binds the provided `locations` into the ast nodes.
///
/// The `start` location points to the first node of this block.
pub fn with_source_locations<L>(mut self, locations: L, start: SourceLocation) -> Self
where
L: IntoIterator<Item = SourceLocation>,
{
self.start = start;
self.body = self.body.with_source_locations(locations);
self
}
}

impl Serializable for ProcedureAst {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
// asserts below are OK because we enforce limits on the procedure body size and length of
Expand Down Expand Up @@ -368,11 +437,11 @@ impl Deserializable for ProcedureAst {
let start = SourceLocation::default();
Ok(Self {
name,
docs,
num_locals,
body,
start,
is_export,
docs,
})
}
}
Expand Down
Loading

0 comments on commit 58ded25

Please sign in to comment.