Skip to content

Commit

Permalink
Add some codespan errors to analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
sbillig committed May 9, 2021
1 parent 0e31d9e commit a9a5ba2
Show file tree
Hide file tree
Showing 229 changed files with 4,045 additions and 2,688 deletions.
71 changes: 65 additions & 6 deletions analyzer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ use crate::errors::SemanticError;
use crate::namespace::events::EventDef;
use crate::namespace::scopes::{ContractFunctionDef, ContractScope, ModuleScope, Shared};
use crate::namespace::types::{Array, Contract, FixedSize, Struct, Tuple, Type};
pub use fe_common::diagnostics::Label;
use fe_common::diagnostics::{Diagnostic, Severity};
use fe_common::files::SourceFileId;
use fe_common::Span;
use fe_parser::ast as fe;
use fe_parser::node::{Node, NodeId};

use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Debug;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::rc::Rc;

Expand Down Expand Up @@ -285,7 +289,7 @@ impl From<Shared<ModuleScope>> for ModuleAttributes {

/// Contains contextual information about a Fe module and can be queried using
/// `Spanned` AST nodes.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct Context {
/// Node ids in the order they were visited.
pub node_ids: Vec<NodeId>,
Expand All @@ -300,16 +304,30 @@ pub struct Context {
pub events: BTreeMap<NodeId, EventDef>,
pub type_descs: BTreeMap<NodeId, Type>,
pub module: Option<ModuleAttributes>,
pub file_id: SourceFileId,
pub diagnostics: Vec<Diagnostic>,
}

impl Context {
pub fn new_shared() -> Shared<Self> {
Rc::new(RefCell::new(Self::new()))
pub fn new_shared(file_id: SourceFileId) -> Shared<Self> {
Rc::new(RefCell::new(Self::new(file_id)))
}

pub fn new() -> Self {
pub fn new(file_id: SourceFileId) -> Self {
Context {
..Default::default()
node_ids: Vec::new(),
spans: BTreeMap::new(),
expressions: BTreeMap::new(),
emits: BTreeMap::new(),
functions: BTreeMap::new(),
declarations: BTreeMap::new(),
contracts: BTreeMap::new(),
calls: BTreeMap::new(),
events: BTreeMap::new(),
type_descs: BTreeMap::new(),
module: None,
file_id,
diagnostics: Vec::new(),
}
}

Expand Down Expand Up @@ -503,4 +521,45 @@ impl Context {
})
.collect::<Vec<_>>()
}

pub fn error(
&mut self,
message: impl Into<String>,
label_span: Span,
label: impl Into<String>,
) {
self.fancy_error(message, vec![Label::primary(label_span, label)], vec![]);
}

pub fn type_error(
&mut self,
message: impl Into<String>,
span: Span,
expected: impl Display,
actual: impl Display,
) {
self.error(
message,
span,
format!("this has type `{}`; expected type `{}`", actual, expected),
)
}

pub fn fancy_error(
&mut self,
message: impl Into<String>,
labels: Vec<Label>,
notes: Vec<String>,
) {
self.diagnostics.push(Diagnostic {
severity: Severity::Error,
code: None,
message: message.into(),
labels: labels
.into_iter()
.map(|lbl| lbl.into_cs_label(self.file_id))
.collect(),
notes,
});
}
}
22 changes: 22 additions & 0 deletions analyzer/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
//! Semantic errors.
use ansi_term::Color::Red;
use fe_common::diagnostics::Diagnostic;
use fe_parser::node::Span;

#[derive(Debug)]
pub struct AnalyzerError {
pub diagnostics: Vec<Diagnostic>,
pub classic: Option<SemanticError>,
}

/// Errors for things that may arise in a valid Fe AST.
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
Expand All @@ -26,6 +33,7 @@ pub enum ErrorKind {
UndefinedValue,
UnexpectedReturn,
WrongNumberOfParams,
Fatal,
}

#[derive(Debug, PartialEq)]
Expand All @@ -37,6 +45,20 @@ pub struct SemanticError {
}

impl SemanticError {
pub fn fatal() -> Self {
SemanticError {
kind: ErrorKind::Fatal,
context: vec![],
}
}

pub fn with_kind(kind: ErrorKind) -> Self {
SemanticError {
kind,
context: vec![],
}
}

/// Create a new error with kind `BreakWithoutLoop`
pub fn break_without_loop() -> Self {
SemanticError {
Expand Down
37 changes: 30 additions & 7 deletions analyzer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,44 @@ pub mod namespace;
mod operations;
mod traversal;

use crate::errors::SemanticError;
use crate::errors::{AnalyzerError, ErrorKind};
use context::Context;
use fe_common::files::SourceFileId;
use fe_parser::ast as fe;
use std::rc::Rc;

/// Performs semantic analysis of the source program and returns a `Context`
/// instance.
pub fn analyze(module: &fe::Module) -> Result<Context, SemanticError> {
let context = Context::new_shared();
traversal::module::module(Rc::clone(&context), module)?;
Ok(Rc::try_unwrap(context)
pub fn analyze(module: &fe::Module, file_id: SourceFileId) -> Result<Context, AnalyzerError> {
let context = Context::new_shared(file_id);
let result = traversal::module::module(Rc::clone(&context), module);

// This should never panic.
let context = Rc::try_unwrap(context)
.map_err(|_| "more than one strong reference pointing to context")
// This should never panic.
.expect("failed to unwrap reference counter")
.into_inner())
.into_inner();

match result {
Ok(()) => {
if context.diagnostics.is_empty() {
Ok(context)
} else {
Err(AnalyzerError {
diagnostics: context.diagnostics,
classic: None,
})
}
}
Err(err) => Err(AnalyzerError {
diagnostics: context.diagnostics,
classic: if err.kind == ErrorKind::Fatal {
None
} else {
Some(err)
},
}),
}
}

#[cfg(feature = "fix-context-harness")]
Expand Down
19 changes: 13 additions & 6 deletions analyzer/src/namespace/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,15 @@ impl EventDef {
}

/// The event's field types.
pub fn all_field_types(&self) -> Vec<FixedSize> {
self.fields.iter().map(|(_, typ)| typ.to_owned()).collect()
pub fn iter_field_types(&self) -> impl Iterator<Item = &FixedSize> + '_ {
self.fields.iter().map(|(_, typ)| typ)
}

pub fn has_field(&self, field_name: &str) -> bool {
self.fields
.iter()
.find(|(name, _)| name == field_name)
.is_some()
}
}

Expand All @@ -86,11 +93,11 @@ mod tests {
);

assert_eq!(
event.all_field_types(),
event.iter_field_types().collect::<Vec<_>>(),
vec![
FixedSize::Base(Base::Address),
FixedSize::Base(Base::Address),
FixedSize::bool(),
&FixedSize::Base(Base::Address),
&FixedSize::Base(Base::Address),
&FixedSize::bool(),
],
);

Expand Down
Loading

0 comments on commit a9a5ba2

Please sign in to comment.