I don't remember what I was doing.
This commit is contained in:
parent
6785e01df7
commit
8b464e68bd
33 changed files with 501 additions and 148 deletions
|
@ -6,3 +6,4 @@ authors = ["James Harton <james@automat.nz>"]
|
|||
[dependencies]
|
||||
huia-parser = { path = "../parser" }
|
||||
huia-linter = { path = "../linter" }
|
||||
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
use huia_linter::Violation;
|
||||
use huia_parser::{File, ParseError};
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CompileError {
|
||||
ParseError(ParseError),
|
||||
LintError(Vec<Violation>),
|
||||
}
|
||||
use huia_parser::File;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Compiler {
|
||||
|
@ -16,8 +9,6 @@ pub struct Compiler {
|
|||
violations: Vec<Violation>,
|
||||
}
|
||||
|
||||
pub type CompilerResult = Result<Compiler, CompileError>;
|
||||
|
||||
impl Compiler {
|
||||
pub fn new(source_code: String, source_name: String, node: File) -> Compiler {
|
||||
let violations = vec![];
|
||||
|
@ -45,11 +36,3 @@ impl Compiler {
|
|||
&self.violations
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for CompileError {}
|
||||
|
||||
impl fmt::Display for CompileError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
113
compiler/src/compiler/error.rs
Normal file
113
compiler/src/compiler/error.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use huia_linter;
|
||||
use huia_linter::Violation;
|
||||
use huia_parser;
|
||||
use huia_parser::IntoSpan;
|
||||
use span::Span;
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CompileError {
|
||||
messages: Vec<Message>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Message {
|
||||
span: Span,
|
||||
message: String,
|
||||
description: Option<String>,
|
||||
suggestions: Option<String>,
|
||||
severity: Severity,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Severity {
|
||||
Error = 0,
|
||||
Info,
|
||||
Warn,
|
||||
}
|
||||
|
||||
impl From<huia_linter::Severity> for Severity {
|
||||
fn from(sev: huia_linter::Severity) -> Severity {
|
||||
if sev.is_info() {
|
||||
Severity::Info
|
||||
} else if sev.is_warn() {
|
||||
Severity::Warn
|
||||
} else if sev.is_error() {
|
||||
Severity::Error
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Violation>> for CompileError {
|
||||
fn from(violations: Vec<Violation>) -> Self {
|
||||
let mut messages: Vec<Message> = vec![];
|
||||
|
||||
for violation in violations {
|
||||
messages.push(Message {
|
||||
span: Span::from(violation.into_span().clone()),
|
||||
message: violation.message().to_string(),
|
||||
description: match violation.description() {
|
||||
Some(value) => Some(value.to_string()),
|
||||
None => None,
|
||||
},
|
||||
suggestions: match violation.suggestion() {
|
||||
Some(value) => Some(value.to_string()),
|
||||
None => None,
|
||||
},
|
||||
severity: Severity::from(violation.severity()),
|
||||
})
|
||||
}
|
||||
|
||||
CompileError { messages: messages }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<huia_parser::ParseError> for CompileError {
|
||||
fn from(parse_error: huia_parser::ParseError) -> Self {
|
||||
let positives = fmt_rule_list(parse_error.positives());
|
||||
let negatives = fmt_rule_list(parse_error.negatives());
|
||||
let suggestions = match (negatives.is_empty(), positives.is_empty()) {
|
||||
(false, false) => Some(format!("unexpected {}; expected {}", positives, negatives)),
|
||||
(false, true) => Some(format!("unexpected {}", negatives)),
|
||||
(true, false) => Some(format!("expected {}", positives)),
|
||||
(true, true) => None,
|
||||
};
|
||||
|
||||
let message = Message {
|
||||
span: Span::from(parse_error.span()),
|
||||
message: "Unable to parse input".to_string(),
|
||||
description: None,
|
||||
suggestions: suggestions,
|
||||
severity: Severity::Error,
|
||||
};
|
||||
CompileError {
|
||||
messages: vec![message],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_rule_list(rules: Vec<huia_parser::grammar::Rule>) -> String {
|
||||
let mut value = String::new();
|
||||
let mut count = 1;
|
||||
let len = rules.len();
|
||||
for rule in rules {
|
||||
value.push_str(&format!("{}", rule));
|
||||
count = count + 1;
|
||||
if count < len {
|
||||
value.push_str(", ");
|
||||
} else if count == len {
|
||||
value.push_str(" or ");
|
||||
}
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
impl Error for CompileError {}
|
||||
|
||||
impl fmt::Display for CompileError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
7
compiler/src/compiler/mod.rs
Normal file
7
compiler/src/compiler/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
mod compiler;
|
||||
mod error;
|
||||
mod result;
|
||||
|
||||
pub use self::compiler::Compiler;
|
||||
pub use self::error::CompileError;
|
||||
pub use self::result::CompilerResult;
|
3
compiler/src/compiler/result.rs
Normal file
3
compiler/src/compiler/result.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
use super::{CompileError, Compiler};
|
||||
|
||||
pub type CompilerResult = Result<Compiler, CompileError>;
|
|
@ -4,14 +4,21 @@ extern crate huia_linter;
|
|||
extern crate huia_parser;
|
||||
|
||||
mod compiler;
|
||||
mod position;
|
||||
mod source;
|
||||
mod source_buffer;
|
||||
mod source_file;
|
||||
mod span;
|
||||
mod stages;
|
||||
|
||||
use source_buffer::SourceBuffer;
|
||||
use source_file::SourceFile;
|
||||
|
||||
/// Version number of the huia-compiler crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
pub use compiler::{CompileError, Compiler, CompilerResult};
|
||||
|
||||
pub fn compile_file(path: &str) -> compiler::CompilerResult {
|
||||
let input = SourceFile::new(path);
|
||||
stages::compile(input)
|
||||
|
|
18
compiler/src/position.rs
Normal file
18
compiler/src/position.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use huia_parser;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Position {
|
||||
byte: usize,
|
||||
line: usize,
|
||||
column: usize,
|
||||
}
|
||||
|
||||
impl From<huia_parser::Position> for Position {
|
||||
fn from(pos: huia_parser::Position) -> Position {
|
||||
Position {
|
||||
byte: pos.byte(),
|
||||
line: pos.line(),
|
||||
column: pos.column(),
|
||||
}
|
||||
}
|
||||
}
|
18
compiler/src/span.rs
Normal file
18
compiler/src/span.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use huia_parser;
|
||||
use position::Position;
|
||||
|
||||
/// A range within the input source.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Span {
|
||||
start: Position,
|
||||
end: Position,
|
||||
}
|
||||
|
||||
impl From<huia_parser::Span> for Span {
|
||||
fn from(span: huia_parser::Span) -> Span {
|
||||
Span {
|
||||
start: Position::from(span.start().clone()),
|
||||
end: Position::from(span.end().clone()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ pub fn lint_ast<'a>(mut compiler: Compiler) -> CompilerResult {
|
|||
compiler.push_violations(&mut violations);
|
||||
Ok(compiler)
|
||||
} else {
|
||||
Err(CompileError::LintError(errors))
|
||||
Err(CompileError::from(errors))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ pub fn parse(input: impl Source) -> CompilerResult {
|
|||
let result = File::parse(&source_code);
|
||||
match result {
|
||||
Ok(node) => Ok(Compiler::new(source_code, source_name, node)),
|
||||
Err(err) => Err(CompileError::ParseError(err)),
|
||||
Err(err) => Err(CompileError::from(err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,3 +6,5 @@ authors = ["James Harton <james@automat.nz>"]
|
|||
[dependencies]
|
||||
clap = "2.32.0"
|
||||
huia-compiler = { path = "../compiler" }
|
||||
ansi_term = "0.11"
|
||||
term_size = "0.3.1"
|
||||
|
|
18
huiac/src/error.rs
Normal file
18
huiac/src/error.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use ansi_term::{Color::White, Style};
|
||||
use huia_compiler::CompileError;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error(CompileError);
|
||||
|
||||
impl From<CompileError> for Error {
|
||||
fn from(e: CompileError) -> Error {
|
||||
Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
|
@ -1,18 +1,25 @@
|
|||
#![forbid(unsafe_code)]
|
||||
|
||||
extern crate ansi_term;
|
||||
extern crate clap;
|
||||
extern crate huia_compiler;
|
||||
extern crate term_size;
|
||||
|
||||
mod error;
|
||||
mod terminal;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use error::Error;
|
||||
use std::process;
|
||||
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
/// Version number of the huiac crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("huiac")
|
||||
.version(VERSION)
|
||||
.author("James Harton <james@automat.nz>")
|
||||
.about("The compiler for the Huia programming language.")
|
||||
.about("The CLI for the Huia programming language compiler.")
|
||||
.arg(
|
||||
Arg::with_name("INPUT")
|
||||
.help("The source file to compile")
|
||||
|
@ -27,7 +34,7 @@ fn main() {
|
|||
println!("{:#?}", result.unwrap());
|
||||
process::exit(0);
|
||||
} else {
|
||||
println!("{}", result.err().unwrap());
|
||||
println!("{}", Error::from(result.err().unwrap()));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use huia_parser::*;
|
||||
use lint::Lint;
|
||||
use rule::*;
|
||||
use rules::*;
|
||||
use violation::Violation;
|
||||
|
||||
impl Lint for ArgumentName {
|
||||
fn lint(&self) -> Vec<Result<(), Violation>> {
|
||||
|
|
|
@ -3,11 +3,15 @@
|
|||
extern crate heck;
|
||||
extern crate huia_parser;
|
||||
mod ast;
|
||||
mod lint;
|
||||
mod rule;
|
||||
mod rules;
|
||||
mod severity;
|
||||
mod violation;
|
||||
|
||||
pub use rule::{Lint, Violation};
|
||||
pub use lint::Lint;
|
||||
pub use severity::Severity;
|
||||
pub use violation::Violation;
|
||||
|
||||
/// Version number of the huia-liter crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
|
45
linter/src/lint.rs
Normal file
45
linter/src/lint.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use rule::RuleResult;
|
||||
use violation::Violation;
|
||||
|
||||
/// The ability to lint oneself
|
||||
///
|
||||
/// This trait is implemented by all the ast nodes so that we know which rules
|
||||
/// to apply to any given node. See `huia_linter::ast` for details.
|
||||
pub trait Lint {
|
||||
/// Return the result of running all rules applicable to `Self`.
|
||||
fn lint(&self) -> Vec<RuleResult> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
/// Return all violations.
|
||||
fn all_violations(&self) -> Vec<Violation> {
|
||||
self.lint().iter().filter_map(|r| r.clone().err()).collect()
|
||||
}
|
||||
|
||||
/// Return only error violations.
|
||||
fn error_violations(&self) -> Vec<Violation> {
|
||||
self.lint()
|
||||
.iter()
|
||||
.filter_map(|r| r.clone().err())
|
||||
.filter(|r| r.is_error())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return only info violations.
|
||||
fn info_violations(&self) -> Vec<Violation> {
|
||||
self.lint()
|
||||
.iter()
|
||||
.filter_map(|r| r.clone().err())
|
||||
.filter(|r| r.is_info())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return only warn violations
|
||||
fn warn_violations(&self) -> Vec<Violation> {
|
||||
self.lint()
|
||||
.iter()
|
||||
.filter_map(|r| r.clone().err())
|
||||
.filter(|r| r.is_warn())
|
||||
.collect()
|
||||
}
|
||||
}
|
|
@ -1,62 +1,16 @@
|
|||
use huia_parser::IntoSpan;
|
||||
use severity::Severity;
|
||||
|
||||
/// A rule violation
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Violation {
|
||||
message: String,
|
||||
description: Option<String>,
|
||||
suggestion: Option<String>,
|
||||
severity: Severity,
|
||||
}
|
||||
|
||||
impl Violation {
|
||||
/// Is the severity `Info`?
|
||||
pub fn is_info(&self) -> bool {
|
||||
match self.severity {
|
||||
Severity::Info => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the severity `Warn`?
|
||||
pub fn is_warn(&self) -> bool {
|
||||
match self.severity {
|
||||
Severity::Warn => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the severity `Error`?
|
||||
pub fn is_error(&self) -> bool {
|
||||
match self.severity {
|
||||
Severity::Error => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// The description of this violation
|
||||
pub fn description(&self) -> Option<&str> {
|
||||
match self.description {
|
||||
Some(ref s) => Some(s),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A suggested fix for this violation
|
||||
pub fn suggestion(&self) -> Option<&str> {
|
||||
match self.suggestion {
|
||||
Some(ref s) => Some(s),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
use violation::Violation;
|
||||
|
||||
pub type RuleResult = Result<(), Violation>;
|
||||
|
||||
/// A linting rule
|
||||
///
|
||||
/// Your rule must implement this trait to be used by the linter.
|
||||
pub trait Rule {
|
||||
pub trait Rule
|
||||
where
|
||||
Self: IntoSpan,
|
||||
{
|
||||
/// Is the node valid?
|
||||
fn is_valid(&self) -> bool;
|
||||
|
||||
|
@ -83,6 +37,7 @@ pub trait Rule {
|
|||
Ok(())
|
||||
} else {
|
||||
Err(Violation {
|
||||
span: self.into_span().clone(),
|
||||
message: self.message(),
|
||||
description: self.description(),
|
||||
suggestion: self.suggestion(),
|
||||
|
@ -91,46 +46,3 @@ pub trait Rule {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The ability to lint oneself
|
||||
///
|
||||
/// This trait is implemented by all the ast nodes so that we know which rules
|
||||
/// to apply to any given node. See `huia_linter::ast` for details.
|
||||
pub trait Lint {
|
||||
/// Return the result of running all rules applicable to `Self`.
|
||||
fn lint(&self) -> Vec<RuleResult> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
/// Return all violations.
|
||||
fn all_violations(&self) -> Vec<Violation> {
|
||||
self.lint().iter().filter_map(|r| r.clone().err()).collect()
|
||||
}
|
||||
|
||||
/// Return only error violations.
|
||||
fn error_violations(&self) -> Vec<Violation> {
|
||||
self.lint()
|
||||
.iter()
|
||||
.filter_map(|r| r.clone().err())
|
||||
.filter(|r| r.is_error())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return only info violations.
|
||||
fn info_violations(&self) -> Vec<Violation> {
|
||||
self.lint()
|
||||
.iter()
|
||||
.filter_map(|r| r.clone().err())
|
||||
.filter(|r| r.is_info())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return only warn violations
|
||||
fn warn_violations(&self) -> Vec<Violation> {
|
||||
self.lint()
|
||||
.iter()
|
||||
.filter_map(|r| r.clone().err())
|
||||
.filter(|r| r.is_warn())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use heck::SnakeCase;
|
||||
use huia_parser::ArgumentName;
|
||||
use huia_parser::{ArgumentName, IntoSpan, Span};
|
||||
use rule::Rule;
|
||||
use severity::Severity;
|
||||
|
||||
|
@ -38,6 +38,12 @@ impl<'a> From<&'a ArgumentName> for ArgumentNameShouldBeSnakeCase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoSpan for ArgumentNameShouldBeSnakeCase<'a> {
|
||||
fn into_span(&self) -> &Span {
|
||||
self.0.into_span()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use heck::SnakeCase;
|
||||
use huia_parser::Atom;
|
||||
use huia_parser::{Atom, IntoSpan, Span};
|
||||
use rule::Rule;
|
||||
use severity::Severity;
|
||||
|
||||
|
@ -38,6 +38,12 @@ impl<'a> From<&'a Atom> for AtomShouldBeSnakeCase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoSpan for AtomShouldBeSnakeCase<'a> {
|
||||
fn into_span(&self) -> &Span {
|
||||
self.0.into_span()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use heck::SnakeCase;
|
||||
use huia_parser::DefineFunction;
|
||||
use huia_parser::{DefineFunction, IntoSpan, Span};
|
||||
use rule::Rule;
|
||||
use severity::Severity;
|
||||
|
||||
|
@ -38,6 +38,12 @@ impl<'a> From<&'a DefineFunction> for FunctionNameShouldBeSnakeCase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoSpan for FunctionNameShouldBeSnakeCase<'a> {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.0.into_span()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use heck::SnakeCase;
|
||||
use huia_parser::Property;
|
||||
use huia_parser::{IntoSpan, Property, Span};
|
||||
use rule::Rule;
|
||||
use severity::Severity;
|
||||
|
||||
|
@ -38,6 +38,12 @@ impl<'a> From<&'a Property> for PropertyNameShouldBeSnakeCase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoSpan for PropertyNameShouldBeSnakeCase<'a> {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.0.into_span()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use heck::CamelCase;
|
||||
use huia_parser::TypeName;
|
||||
use huia_parser::{IntoSpan, Span, TypeName};
|
||||
use rule::Rule;
|
||||
use severity::Severity;
|
||||
|
||||
|
@ -37,6 +37,12 @@ impl<'a> From<&'a TypeName> for TypeNameShouldBeCamelCase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoSpan for TypeNameShouldBeCamelCase<'a> {
|
||||
fn into_span(&self) -> &Span {
|
||||
self.0.into_span()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use heck::SnakeCase;
|
||||
use huia_parser::Variable;
|
||||
use huia_parser::{IntoSpan, Span, Variable};
|
||||
use rule::Rule;
|
||||
use severity::Severity;
|
||||
|
||||
|
@ -38,6 +38,12 @@ impl<'a> From<&'a Variable> for VariableNameShouldBeSnakeCase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoSpan for VariableNameShouldBeSnakeCase<'a> {
|
||||
fn into_span(&self) -> &Span {
|
||||
self.0.into_span()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
68
linter/src/violation.rs
Normal file
68
linter/src/violation.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use huia_parser::{IntoSpan, Span};
|
||||
use severity::Severity;
|
||||
|
||||
/// A rule violation
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Violation {
|
||||
pub span: Span,
|
||||
pub message: String,
|
||||
pub description: Option<String>,
|
||||
pub suggestion: Option<String>,
|
||||
pub severity: Severity,
|
||||
}
|
||||
|
||||
impl Violation {
|
||||
/// Is the severity `Info`?
|
||||
pub fn is_info(&self) -> bool {
|
||||
match self.severity {
|
||||
Severity::Info => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the severity `Warn`?
|
||||
pub fn is_warn(&self) -> bool {
|
||||
match self.severity {
|
||||
Severity::Warn => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the severity `Error`?
|
||||
pub fn is_error(&self) -> bool {
|
||||
match self.severity {
|
||||
Severity::Error => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn message(&self) -> &str {
|
||||
&self.message
|
||||
}
|
||||
|
||||
/// The description of this violation
|
||||
pub fn description(&self) -> Option<&str> {
|
||||
match self.description {
|
||||
Some(ref s) => Some(s),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A suggested fix for this violation
|
||||
pub fn suggestion(&self) -> Option<&str> {
|
||||
match self.suggestion {
|
||||
Some(ref s) => Some(s),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn severity(&self) -> Severity {
|
||||
self.severity.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoSpan for Violation {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use ast::span::Span;
|
||||
use ast::{into_span::IntoSpan, span::Span};
|
||||
use grammar::Rule;
|
||||
use parse::Parse;
|
||||
use pest::iterators::Pair;
|
||||
|
@ -35,6 +35,12 @@ impl ArgumentName {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoSpan for ArgumentName {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use ast::{argument_name::ArgumentName, expression::Expression, span::Span, type_name::TypeName};
|
||||
use ast::{
|
||||
argument_name::ArgumentName, expression::Expression, into_span::IntoSpan, span::Span,
|
||||
type_name::TypeName,
|
||||
};
|
||||
use grammar::Rule;
|
||||
use parse::Parse;
|
||||
use pest::iterators::{Pair, Pairs};
|
||||
|
@ -156,6 +159,12 @@ impl<'a> From<Pair<'a, Rule>> for FunctionType {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoSpan for DefineFunction {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -46,7 +46,7 @@ pub use self::{
|
|||
map::{Map, MapPair},
|
||||
operator::Operator,
|
||||
property::Property,
|
||||
span::Span,
|
||||
span::{Position, Span},
|
||||
string::StringLiteral,
|
||||
type_name::TypeName,
|
||||
unary::Unary,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ast::span::Span;
|
||||
use ast::{into_span::IntoSpan, span::Span};
|
||||
use grammar::Rule;
|
||||
use parse::Parse;
|
||||
use pest::iterators::Pair;
|
||||
|
@ -41,6 +41,12 @@ impl Property {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoSpan for Property {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,29 +1,70 @@
|
|||
use pest;
|
||||
|
||||
/// A location within the input source.
|
||||
/// A range within the input source.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Span {
|
||||
start: usize,
|
||||
end: usize,
|
||||
start: Position,
|
||||
end: Position,
|
||||
}
|
||||
|
||||
impl Span {
|
||||
/// The start position of the current node.
|
||||
pub fn start(&self) -> usize {
|
||||
self.start
|
||||
pub fn start(&self) -> &Position {
|
||||
&self.start
|
||||
}
|
||||
|
||||
/// The end position of the current node.
|
||||
pub fn end(&self) -> usize {
|
||||
self.end
|
||||
pub fn end(&self) -> &Position {
|
||||
&self.end
|
||||
}
|
||||
|
||||
/// Make a new span where the start and end positions are the same.
|
||||
pub fn point(point: Position) -> Span {
|
||||
Span {
|
||||
start: point.clone(),
|
||||
end: point,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<pest::Span<'a>> for Span {
|
||||
fn from(pest: pest::Span<'a>) -> Span {
|
||||
Span {
|
||||
start: pest.start(),
|
||||
end: pest.end(),
|
||||
start: Position::from(pest.start_pos()),
|
||||
end: Position::from(pest.end_pos()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A location within the input source.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Position {
|
||||
byte: usize,
|
||||
line: usize,
|
||||
column: usize,
|
||||
}
|
||||
|
||||
impl<'a> From<pest::Position<'a>> for Position {
|
||||
fn from(pest: pest::Position<'a>) -> Position {
|
||||
let byte = pest.pos();
|
||||
let (line, column) = pest.line_col();
|
||||
Position { byte, line, column }
|
||||
}
|
||||
}
|
||||
|
||||
impl Position {
|
||||
/// A byte offset of the position in the input
|
||||
pub fn byte(&self) -> usize {
|
||||
self.byte
|
||||
}
|
||||
|
||||
/// The line number of this position in the input
|
||||
pub fn line(&self) -> usize {
|
||||
self.line
|
||||
}
|
||||
|
||||
/// The column number of this position in the input
|
||||
pub fn column(&self) -> usize {
|
||||
self.column
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ast::span::Span;
|
||||
use ast::{into_span::IntoSpan, span::Span};
|
||||
use grammar::Rule;
|
||||
use parse::Parse;
|
||||
use pest::iterators::Pair;
|
||||
|
@ -34,6 +34,12 @@ impl TypeName {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoSpan for TypeName {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ast::span::Span;
|
||||
use ast::{into_span::IntoSpan, span::Span};
|
||||
use grammar::Rule;
|
||||
use parse::Parse;
|
||||
use pest::iterators::Pair;
|
||||
|
@ -36,6 +36,12 @@ impl Variable {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoSpan for Variable {
|
||||
fn into_span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ast::Span;
|
||||
use ast::{Position, Span};
|
||||
use grammar::Rule;
|
||||
use pest;
|
||||
use std::error::Error;
|
||||
|
@ -18,24 +18,51 @@ pub enum ParseError {
|
|||
PestError {
|
||||
positives: Vec<Rule>,
|
||||
negatives: Vec<Rule>,
|
||||
position: usize,
|
||||
position: Position,
|
||||
},
|
||||
|
||||
/// There was an error converting the parse tree into AST.
|
||||
AstGeneration { rule: Rule, span: Span },
|
||||
}
|
||||
|
||||
impl ParseError {
|
||||
/// Returns a Span where the error took place.
|
||||
///
|
||||
/// In the case of a parse error it returns a span where the start and end
|
||||
/// positions are the same.
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
ParseError::PestError { position, .. } => Span::point(position.clone()),
|
||||
ParseError::AstGeneration { span, .. } => span.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn positives(&self) -> Vec<Rule> {
|
||||
match self {
|
||||
ParseError::PestError { positives, .. } => positives.clone(),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn negatives(&self) -> Vec<Rule> {
|
||||
match self {
|
||||
ParseError::PestError { negatives, .. } => negatives.clone(),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<pest::Error<'a, Rule>> for ParseError {
|
||||
fn from(pest: pest::Error<'a, Rule>) -> Self {
|
||||
match pest {
|
||||
pest::Error::ParsingError {
|
||||
ref positives,
|
||||
ref negatives,
|
||||
ref pos,
|
||||
positives,
|
||||
negatives,
|
||||
pos,
|
||||
} => ParseError::PestError {
|
||||
positives: positives.clone(),
|
||||
negatives: negatives.clone(),
|
||||
position: pos.pos(),
|
||||
positives: positives,
|
||||
negatives: negatives,
|
||||
position: Position::from(pos),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::fmt;
|
||||
|
||||
const _GRAMMAR: &'static str = include_str!("../grammar.pest");
|
||||
|
||||
/// The Grammar derived from `grammar.pest`.
|
||||
|
@ -5,5 +7,11 @@ const _GRAMMAR: &'static str = include_str!("../grammar.pest");
|
|||
#[grammar = "grammar.pest"]
|
||||
pub struct Grammar;
|
||||
|
||||
impl fmt::Display for Rule {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
|
Reference in a new issue