deimos-lang/src/ast/mod.rs

267 lines
7.9 KiB
Rust

pub mod node {
include!(concat!(env!("OUT_DIR"), "/src/ast/node.rs"));
impl OperatorInner {
pub fn name(&self) -> &'static str {
match self {
OperatorInner::Or => "op_or",
OperatorInner::And => "op_and",
OperatorInner::EqualTo => "op_eq",
OperatorInner::NotEqualTo => "op_neq",
OperatorInner::Greater => "op_gt",
OperatorInner::Less => "op_lt",
OperatorInner::GreaterEqual => "op_ge",
OperatorInner::LessEqual => "op_le",
OperatorInner::Add => "op_add",
OperatorInner::Subtract => "op_sub",
OperatorInner::Multiply => "op_mul",
OperatorInner::Divide => "op_div",
OperatorInner::Modulo => "op_mod",
OperatorInner::LeftShift => "op_ls",
OperatorInner::RightShift => "op_rs",
OperatorInner::Spread => "op_spread",
OperatorInner::Star => "op_star",
OperatorInner::Not => "op_not",
OperatorInner::Negative => "op_neg",
OperatorInner::PlusPlus => "op_pp",
OperatorInner::MinusMinus => "op_mm",
OperatorInner::CallOp => "op_call",
OperatorInner::Index => "op_index",
}
}
}
impl Default for Parameters {
fn default() -> Self {
Self::new(vec![])
}
}
impl Default for GenericParameters {
fn default() -> Self {
Self::new(Box::new(IdentifierList::new(vec![])))
}
}
impl Default for GenericArguments {
fn default() -> Self {
Self::new(Box::new(TypeUseList::new(vec![])))
}
}
impl Default for ImplementsList {
fn default() -> Self {
Self::new(vec![])
}
}
impl ReturnType {
pub fn void() -> Self {
Self::new(Box::new(TypeUse::PrimitiveType(PrimitiveType::Void)))
}
}
impl Default for ClassConstructor {
fn default() -> Self {
Self::new(vec![])
}
}
impl Default for ClosureParameters {
fn default() -> Self {
Self::new(vec![])
}
}
}
pub mod build {
use pest::iterators::Pairs;
include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs"));
pub fn build_ast(file_id: usize, parsed_pairs: &mut Pairs<Rule>) -> CompilationUnit {
let compilation_unit_pair = parsed_pairs.next().unwrap();
build_compilation_unit(file_id, compilation_unit_pair)
}
#[cfg(test)]
mod build_tests {
use super::*;
use crate::ast::ast_node::AstNodeRef;
use crate::ast::pretty_print::PrettyPrint;
use crate::ast::walk::walk_depth_first;
use crate::parser::DeimosParser;
use crate::util::indent_writer::IndentWriter;
use pest::Parser;
fn parse(rule: Rule, input: &str) -> Pair<Rule> {
let parse_result = DeimosParser::parse(rule, input);
parse_result.expect("parsing failed").next().unwrap()
}
fn fmt_ast(node: &dyn PrettyPrint) -> String {
let mut acc = String::new();
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
node.pretty_print(&mut indent_writer)
.expect("Pretty print failed");
acc
}
#[test]
fn boolean_literal_true() {
let pair = parse(
Rule::BooleanLiteral,
include_str!("build_tests/boolean_literal/true"),
);
assert_eq!(true, build_boolean_literal(0, pair));
}
#[test]
fn boolean_literal_false() {
let pair = parse(
Rule::BooleanLiteral,
include_str!("build_tests/boolean_literal/false"),
);
assert_eq!(false, build_boolean_literal(0, pair));
}
#[test]
fn backtick_inner_greeting() {
let pair = parse(
Rule::BacktickInner,
include_str!("build_tests/backtick_inner/greeting"),
);
assert_eq!("Hello, World!", build_backtick_inner(0, pair));
}
#[test]
fn backtick_string_mixed() {
let pair = parse(
Rule::BacktickString,
include_str!("build_tests/backtick_string/mixed"),
);
let backtick_string = build_backtick_string(0, pair);
assert_eq!(backtick_string.inners().count(), 2);
assert_eq!(backtick_string.expressions().count(), 1);
}
#[test]
fn d_string_expression_simple() {
let pair = parse(Rule::DStringExpression, "${thing}");
let d_string_expression = build_d_string_expression(0, pair);
}
#[test]
fn d_string_inner() {
let pair = parse(Rule::DStringInner, "Hello!");
let d_string_inner = build_d_string_inner(0, pair);
assert_eq!("Hello!", d_string_inner);
}
#[test]
fn d_string_mixed() {
let pair = parse(Rule::DString, "\"Hello, ${world}!\"");
let d_string = build_d_string(0, pair);
assert_eq!(d_string.inners().count(), 2);
assert_eq!(d_string.expressions().count(), 1);
}
#[test]
fn expression_simple_call() {
let pair = parse(Rule::Expression, "hello(42)");
let expression = build_expression(0, pair);
}
#[test]
fn multiple_expression_statements() {
let pair = parse(
Rule::Function,
"
fn test()
println(42)
println(43)
end
",
);
let function = build_function(0, pair);
let mut number_of_statements = 0;
walk_depth_first(&function, &mut |node| match node {
AstNodeRef::Statement(_) => {
number_of_statements += 1;
}
_ => {}
});
assert_eq!(2, number_of_statements, "Ast: {}", fmt_ast(&function));
}
#[test]
fn array_return_after_statement() {
let pair = parse(
Rule::Function,
"
fn test()
println(42)
[0, 1, 2]
end
",
);
let function = build_function(0, pair);
let mut number_of_statements = 0;
walk_depth_first(&function, &mut |node| {
if let AstNodeRef::Statement(stmt) = node {
number_of_statements += 1;
}
});
assert_eq!(2, number_of_statements);
}
#[test]
fn array_return_after_bare_identifier() {
// The following should parse as two expression statements
let pair = parse(
Rule::Function,
"
fn test()
x
[0, 1, 2]
end
",
);
let function = build_function(0, pair);
let mut number_of_statements = 0;
walk_depth_first(&function, &mut |node| {
if let AstNodeRef::Statement(stmt) = node {
number_of_statements += 1;
}
});
assert_eq!(2, number_of_statements);
}
}
}
pub mod pretty_print {
use crate::util::indent_writer::IndentWriter;
pub trait PrettyPrint {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result;
}
include!(concat!(env!("OUT_DIR"), "/src/ast/pretty_print.rs"));
}
pub mod ast_node {
include!(concat!(env!("OUT_DIR"), "/src/ast/ast_node.rs"));
}
pub mod walk {
include!(concat!(env!("OUT_DIR"), "/src/ast/walk.rs"));
}