-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bin/Check+Analyser: Start laying out foundations of a static analyser
- Loading branch information
1 parent
3616c5d
commit a6ee6ad
Showing
19 changed files
with
456 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use pxp_ast::{ReturnStatement, Statement}; | ||
|
||
mod return_finder; | ||
|
||
pub(crate) fn find_returns_in_block<'a>(block: &'a [Statement]) -> Vec<&'a ReturnStatement> { | ||
return_finder::ReturnFinder::find(block) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use pxp_ast::{visitor::{Ancestors, NodeVisitor, NodeVisitorEscapeHatch, Visitor}, Node, ReturnStatement, Statement}; | ||
|
||
pub(super) struct ReturnFinder<'a> { | ||
returns: Vec<&'a ReturnStatement>, | ||
} | ||
|
||
impl<'a> ReturnFinder<'a> { | ||
fn new() -> Self { | ||
Self { | ||
returns: Vec::new(), | ||
} | ||
} | ||
|
||
pub(super) fn find(ast: &'a [Statement]) -> Vec<&'a ReturnStatement> { | ||
let mut finder = Self::new(); | ||
finder.traverse(ast); | ||
finder.returns | ||
} | ||
} | ||
|
||
impl<'a> NodeVisitor<'a> for ReturnFinder<'a> { | ||
fn enter(&mut self, node: Node<'a>, _: &mut Ancestors<'a>) -> NodeVisitorEscapeHatch { | ||
if !node.is_return_statement() { | ||
return NodeVisitorEscapeHatch::Continue; | ||
} | ||
|
||
self.returns.push(node.as_return_statement().unwrap()); | ||
|
||
NodeVisitorEscapeHatch::Continue | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use crate::rule::Rule; | ||
|
||
/// An API for collecting analysis rules into smaller groups. | ||
pub trait RuleCollection { | ||
/// Returns a collection of analysis rules. | ||
fn rules(&self) -> Vec<Box<dyn Rule>>; | ||
|
||
/// Returns the name of the collection. | ||
fn name(&self) -> &'static str; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
use pxp_ast::{Node, ResolvedName}; | ||
use pxp_diagnostics::Severity; | ||
use pxp_inference::TypeMap; | ||
use pxp_span::Span; | ||
use pxp_type::Type; | ||
|
||
use crate::{AnalyserDiagnostic, Reporter}; | ||
|
||
pub struct AnalyserContext<'a> { | ||
reporter: &'a mut Reporter, | ||
types: TypeMap, | ||
file: usize, | ||
} | ||
|
||
impl<'a> AnalyserContext<'a> { | ||
pub fn new(reporter: &'a mut Reporter, types: TypeMap, file: usize) -> Self { | ||
Self { reporter, types, file } | ||
} | ||
|
||
pub fn report(&mut self, diagnostic: AnalyserDiagnostic, severity: Severity, span: Span) { | ||
self.reporter.report(self.file, diagnostic, severity, span); | ||
} | ||
|
||
pub fn get_type(&self, node: &Node) -> &Type<ResolvedName> { | ||
self.types.resolve(node.id) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,13 @@ | ||
pub fn add(left: u64, right: u64) -> u64 { | ||
left + right | ||
} | ||
mod rule; | ||
mod collection; | ||
pub mod rules; | ||
mod runner; | ||
mod reporter; | ||
mod context; | ||
mod ast; | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn it_works() { | ||
let result = add(2, 2); | ||
assert_eq!(result, 4); | ||
} | ||
} | ||
pub use rule::Rule; | ||
pub use collection::RuleCollection; | ||
pub use runner::Runner; | ||
pub use reporter::{Reporter, AnalyserDiagnostic}; | ||
pub use context::AnalyserContext; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
use std::collections::HashMap; | ||
|
||
use pxp_diagnostics::{Diagnostic, DiagnosticKind, DiagnosticLabel, Severity}; | ||
use pxp_span::Span; | ||
|
||
#[derive(Debug)] | ||
pub struct Reporter { | ||
diagnostics: HashMap<usize, Vec<Diagnostic<AnalyserDiagnostic>>>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct AnalyserDiagnostic { | ||
code: String, | ||
identifier: String, | ||
message: String, | ||
help: Option<String>, | ||
labels: Vec<DiagnosticLabel>, | ||
} | ||
|
||
impl AnalyserDiagnostic { | ||
pub fn new() -> Self { | ||
Self { | ||
code: String::new(), | ||
identifier: String::new(), | ||
message: String::new(), | ||
help: None, | ||
labels: Vec::new(), | ||
} | ||
} | ||
|
||
pub fn code(mut self, code: &str) -> Self { | ||
self.code = code.to_string(); | ||
self | ||
} | ||
|
||
pub fn identifier(mut self, identifier: &str) -> Self { | ||
self.identifier = identifier.to_string(); | ||
self | ||
} | ||
|
||
pub fn message(mut self, message: &str) -> Self { | ||
self.message = message.to_string(); | ||
self | ||
} | ||
|
||
pub fn help(mut self, help: &str) -> Self { | ||
self.help = Some(help.to_string()); | ||
self | ||
} | ||
|
||
pub fn label(mut self, label: DiagnosticLabel) -> Self { | ||
self.labels.push(label); | ||
self | ||
} | ||
|
||
pub fn labels(mut self, labels: Vec<DiagnosticLabel>) -> Self { | ||
self.labels = labels; | ||
self | ||
} | ||
} | ||
|
||
impl DiagnosticKind for AnalyserDiagnostic { | ||
fn get_code(&self) -> String { | ||
self.code.clone() | ||
} | ||
|
||
fn get_identifier(&self) -> String { | ||
self.identifier.clone() | ||
} | ||
|
||
fn get_message(&self) -> String { | ||
self.message.clone() | ||
} | ||
|
||
fn get_help(&self) -> Option<String> { | ||
self.help.clone() | ||
} | ||
|
||
fn get_labels(&self) -> Vec<DiagnosticLabel> { | ||
self.labels.clone() | ||
} | ||
} | ||
|
||
impl Reporter { | ||
pub fn new() -> Self { | ||
Self { | ||
diagnostics: HashMap::new(), | ||
} | ||
} | ||
|
||
pub fn report(&mut self, file: usize, diagnostic: AnalyserDiagnostic, severity: Severity, span: Span) { | ||
let diagnostics = self.diagnostics.entry(file).or_default(); | ||
|
||
diagnostics.push(Diagnostic::new(diagnostic, severity, span)); | ||
} | ||
|
||
pub fn all(&self) -> &HashMap<usize, Vec<Diagnostic<AnalyserDiagnostic>>> { | ||
&self.diagnostics | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
use pxp_ast::{visitor::Ancestors, Node}; | ||
|
||
use crate::AnalyserContext; | ||
|
||
pub trait Rule { | ||
/// Determine if the rule should be execute for the given node and ancestor tree. | ||
fn should_run(&self, node: &Node, ancestors: &Ancestors) -> bool; | ||
|
||
/// Execute the rule for the given node and ancestor tree. | ||
fn run(&self, node: &Node, ancestors: &Ancestors, context: &mut AnalyserContext); | ||
|
||
/// Returns the name of the rule. | ||
fn name(&self) -> &'static str; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
mod return_type; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use pxp_ast::{visitor::Ancestors, Node}; | ||
|
||
use crate::Rule; | ||
|
||
pub struct ReturnTypeRule; | ||
|
||
impl Rule for ReturnTypeRule { | ||
fn should_run(&self, node: &Node, ancestors: &Ancestors) -> bool { | ||
|
||
} | ||
|
||
fn run(&self, node: &Node, ancestors: &Ancestors, context: &mut crate::AnalyserContext) { | ||
|
||
} | ||
|
||
fn name(&self) -> &'static str { | ||
"functions/return_type" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod functions; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use std::{path::Path, task::Context}; | ||
|
||
use pxp_ast::{visitor::{Ancestors, NodeVisitor, NodeVisitorEscapeHatch}, Node, Statement}; | ||
use pxp_inference::TypeEngine; | ||
|
||
use crate::{AnalyserContext, Reporter, Rule, RuleCollection}; | ||
|
||
pub struct Runner<'a> { | ||
rules: Vec<Box<dyn Rule>>, | ||
type_engine: &'a TypeEngine<'a>, | ||
} | ||
|
||
impl<'a> Runner<'a> { | ||
pub fn new(type_engine: &'a TypeEngine) -> Self { | ||
Self { | ||
rules: Vec::new(), | ||
type_engine, | ||
} | ||
} | ||
|
||
pub fn add_rule(&mut self, rule: impl Rule + 'static) { | ||
self.rules.push(Box::new(rule)); | ||
} | ||
|
||
pub fn add_collection(&mut self, collection: impl RuleCollection + 'static) { | ||
for rule in collection.rules() { | ||
self.rules.push(rule); | ||
} | ||
} | ||
|
||
pub fn run(&self, file: usize, reporter: &mut Reporter, ast: &[Statement]) { | ||
let types = self.type_engine.infer(ast); | ||
let mut context = AnalyserContext::new(reporter, types, file); | ||
let mut visitor = AnalyserVisitor::new(self, &mut context); | ||
|
||
visitor.traverse(ast); | ||
} | ||
} | ||
|
||
struct AnalyserVisitor<'a> { | ||
runner: &'a Runner<'a>, | ||
context: &'a mut AnalyserContext<'a>, | ||
} | ||
|
||
impl<'a> AnalyserVisitor<'a> { | ||
fn new(runner: &'a Runner, context: &'a mut AnalyserContext<'a>) -> Self { | ||
Self { runner, context } | ||
} | ||
} | ||
|
||
impl<'a> NodeVisitor<'a> for AnalyserVisitor<'a> { | ||
fn enter(&mut self, node: Node<'a>, ancestors: &mut Ancestors<'a>) -> NodeVisitorEscapeHatch { | ||
for rule in &self.runner.rules { | ||
if rule.should_run(&node, ancestors) { | ||
rule.run(&node, ancestors, self.context); | ||
} | ||
} | ||
|
||
NodeVisitorEscapeHatch::Continue | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.