Add huiac
binary that just prints out the AST.
This commit is contained in:
parent
2072134c80
commit
e1a0472ed8
9 changed files with 157 additions and 16 deletions
|
@ -1,5 +1,6 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"compiler",
|
"compiler",
|
||||||
|
"huiac",
|
||||||
"parser"
|
"parser"
|
||||||
]
|
]
|
||||||
|
|
8
huiac/Cargo.toml
Normal file
8
huiac/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "huiac"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["James Harton <james@automat.nz>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
huia-parser = { path = "../parser" }
|
||||||
|
clap = "2.32.0"
|
27
huiac/src/main.rs
Normal file
27
huiac/src/main.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
extern crate clap;
|
||||||
|
extern crate huia_parser;
|
||||||
|
|
||||||
|
use clap::{App, Arg};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
const VERSION: &'static 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.")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("INPUT")
|
||||||
|
.help("The source file to compile")
|
||||||
|
.required(true)
|
||||||
|
.index(1),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
let source_path = matches.value_of("INPUT").unwrap();
|
||||||
|
let source_file = fs::read_to_string(source_path).expect("Unable to read input file");
|
||||||
|
let result = huia_parser::parse_file(&source_file);
|
||||||
|
|
||||||
|
println!("{:?}", result);
|
||||||
|
}
|
24
parser/src/ast/file.rs
Normal file
24
parser/src/ast/file.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use ast::{consume, node::Node};
|
||||||
|
use grammar::Rule;
|
||||||
|
use pest::iterators::Pair;
|
||||||
|
use pest::Span;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct File<'a> {
|
||||||
|
span: Span<'a>,
|
||||||
|
children: Vec<Node<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Pair<'a, Rule>> for File<'a> {
|
||||||
|
fn from(pair: Pair<'a, Rule>) -> Self {
|
||||||
|
assert_eq!(pair.as_rule(), Rule::file);
|
||||||
|
|
||||||
|
let span = pair.clone().into_span();
|
||||||
|
let children = pair.into_inner().map(|p| consume(p)).collect();
|
||||||
|
|
||||||
|
File {
|
||||||
|
span: span,
|
||||||
|
children: children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ mod boolean;
|
||||||
mod braced;
|
mod braced;
|
||||||
mod call;
|
mod call;
|
||||||
mod constructor;
|
mod constructor;
|
||||||
|
mod file;
|
||||||
mod float;
|
mod float;
|
||||||
mod infix;
|
mod infix;
|
||||||
mod integer;
|
mod integer;
|
||||||
|
@ -25,6 +26,7 @@ pub use self::{
|
||||||
braced::Braced,
|
braced::Braced,
|
||||||
call::{Call, Message, Receiver},
|
call::{Call, Message, Receiver},
|
||||||
constructor::Constructor,
|
constructor::Constructor,
|
||||||
|
file::File,
|
||||||
float::Float,
|
float::Float,
|
||||||
infix::Infix,
|
infix::Infix,
|
||||||
integer::Integer,
|
integer::Integer,
|
||||||
|
@ -34,25 +36,34 @@ pub use self::{
|
||||||
unary::Unary,
|
unary::Unary,
|
||||||
variable::Variable,
|
variable::Variable,
|
||||||
};
|
};
|
||||||
|
use error::ParseError;
|
||||||
use grammar::Rule;
|
use grammar::Rule;
|
||||||
use pest::iterators::Pair;
|
use pest::iterators::Pair;
|
||||||
|
|
||||||
pub fn consume<'a>(pair: Pair<'a, Rule>) -> Node<'a> {
|
pub fn consume<'a>(pair: Pair<'a, Rule>) -> Node<'a> {
|
||||||
|
match build(pair) {
|
||||||
|
Ok(node) => node,
|
||||||
|
Err(e) => panic!("{}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build<'a>(pair: Pair<'a, Rule>) -> Result<Node<'a>, ParseError<'a>> {
|
||||||
match pair.as_rule() {
|
match pair.as_rule() {
|
||||||
Rule::array => Node::from(Array::from(pair)),
|
Rule::array => Ok(Node::from(Array::from(pair))),
|
||||||
Rule::atom => Node::from(Atom::from(pair)),
|
Rule::atom => Ok(Node::from(Atom::from(pair))),
|
||||||
Rule::boolean_true => Node::from(True::from(pair)),
|
Rule::boolean_true => Ok(Node::from(True::from(pair))),
|
||||||
Rule::boolean_false => Node::from(False::from(pair)),
|
Rule::boolean_false => Ok(Node::from(False::from(pair))),
|
||||||
Rule::braced => Node::from(Braced::from(pair)),
|
Rule::braced => Ok(Node::from(Braced::from(pair))),
|
||||||
Rule::call => Node::from(Call::from(pair)),
|
Rule::call => Ok(Node::from(Call::from(pair))),
|
||||||
Rule::constructor => Node::from(Constructor::from(pair)),
|
Rule::constructor => Ok(Node::from(Constructor::from(pair))),
|
||||||
Rule::expression_infix => precedence::climb(pair),
|
Rule::expression_infix => Ok(precedence::climb(pair)),
|
||||||
Rule::float => Node::from(Float::from(pair)),
|
Rule::file => Ok(Node::from(File::from(pair))),
|
||||||
Rule::integer => Node::from(Integer::from(pair)),
|
Rule::float => Ok(Node::from(Float::from(pair))),
|
||||||
Rule::property => Node::from(Property::from(pair)),
|
Rule::integer => Ok(Node::from(Integer::from(pair))),
|
||||||
Rule::string => Node::from(StringLiteral::from(pair)),
|
Rule::property => Ok(Node::from(Property::from(pair))),
|
||||||
Rule::unary => Node::from(Unary::from(pair)),
|
Rule::string => Ok(Node::from(StringLiteral::from(pair))),
|
||||||
Rule::variable => Node::from(Variable::from(pair)),
|
Rule::unary => Ok(Node::from(Unary::from(pair))),
|
||||||
_ => panic!("Node {:?} is not a consumable", pair),
|
Rule::variable => Ok(Node::from(Variable::from(pair))),
|
||||||
|
_ => Err(ParseError::from(pair)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use ast::{
|
||||||
braced::Braced,
|
braced::Braced,
|
||||||
call::Call,
|
call::Call,
|
||||||
constructor::Constructor,
|
constructor::Constructor,
|
||||||
|
file::File,
|
||||||
float::Float,
|
float::Float,
|
||||||
infix::Infix,
|
infix::Infix,
|
||||||
integer::Integer,
|
integer::Integer,
|
||||||
|
@ -22,6 +23,7 @@ pub enum Node<'a> {
|
||||||
Call(Call<'a>),
|
Call(Call<'a>),
|
||||||
Constructor(Constructor<'a>),
|
Constructor(Constructor<'a>),
|
||||||
False(False<'a>),
|
False(False<'a>),
|
||||||
|
File(File<'a>),
|
||||||
Float(Float<'a>),
|
Float(Float<'a>),
|
||||||
Infix(Infix<'a>),
|
Infix(Infix<'a>),
|
||||||
Integer(Integer<'a>),
|
Integer(Integer<'a>),
|
||||||
|
@ -68,6 +70,12 @@ impl<'a> From<False<'a>> for Node<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<File<'a>> for Node<'a> {
|
||||||
|
fn from(inner: File<'a>) -> Self {
|
||||||
|
Node::File(inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<Float<'a>> for Node<'a> {
|
impl<'a> From<Float<'a>> for Node<'a> {
|
||||||
fn from(inner: Float<'a>) -> Self {
|
fn from(inner: Float<'a>) -> Self {
|
||||||
Node::Float(inner)
|
Node::Float(inner)
|
||||||
|
|
40
parser/src/error.rs
Normal file
40
parser/src/error.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use grammar::Rule;
|
||||||
|
use pest;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParseError<'a> {
|
||||||
|
PestError(pest::Error<'a, Rule>),
|
||||||
|
AstGeneration(pest::iterators::Pair<'a, Rule>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<pest::Error<'a, Rule>> for ParseError<'a> {
|
||||||
|
fn from(pest: pest::Error<'a, Rule>) -> Self {
|
||||||
|
ParseError::PestError(pest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<pest::iterators::Pair<'a, Rule>> for ParseError<'a> {
|
||||||
|
fn from(pest: pest::iterators::Pair<'a, Rule>) -> Self {
|
||||||
|
ParseError::AstGeneration(pest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for ParseError<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ParseError::PestError(ref e) => write!(f, "{}", e),
|
||||||
|
ParseError::AstGeneration(_) => write!(f, "Internal error during AST generation"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Error for ParseError<'a> {
|
||||||
|
fn cause(&self) -> Option<&Error> {
|
||||||
|
match self {
|
||||||
|
ParseError::PestError(ref e) => Some(e),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,4 +10,10 @@ extern crate lazy_static;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
|
mod error;
|
||||||
mod grammar;
|
mod grammar;
|
||||||
|
mod parse;
|
||||||
|
|
||||||
|
pub use ast::*;
|
||||||
|
pub use error::ParseError;
|
||||||
|
pub use parse::parse_file;
|
||||||
|
|
16
parser/src/parse.rs
Normal file
16
parser/src/parse.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use ast::{build, Node};
|
||||||
|
use error::ParseError;
|
||||||
|
use grammar::{Grammar, Rule};
|
||||||
|
use pest::{iterators::Pair, Parser};
|
||||||
|
|
||||||
|
pub fn parse_file<'a>(source: &'a str) -> Result<Node<'a>, ParseError<'a>> {
|
||||||
|
run_parser(source, Rule::file).and_then(build)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_parser<'a>(source: &'a str, rule: Rule) -> Result<Pair<'a, Rule>, ParseError<'a>> {
|
||||||
|
let result = Grammar::parse(rule, source);
|
||||||
|
match result {
|
||||||
|
Ok(mut pairs) => Ok(pairs.next().unwrap()),
|
||||||
|
Err(pest_error) => Err(ParseError::from(pest_error)),
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue