use {
crate::{
error::{Error, SourceRange, listing, throw},
evaluator::is_value,
format::CodeStr,
term,
term::free_variables,
token::{self, TerminatorType, Token},
},
colored::Colorize,
num_bigint::BigInt,
scopeguard::defer,
std::{
cell::RefCell,
collections::{HashMap, HashSet},
path::Path,
rc::Rc,
},
};
pub const PLACEHOLDER_VARIABLE: &str = "_";
type ErrorFactory<'a> = Rc<dyn Fn(Option<&'a Path>, &'a str) -> Error + 'a>;
fn error_factory<'a>(
tokens: &'a [Token<'a>],
position: usize,
expectation: &str,
) -> ErrorFactory<'a> {
let source_range = token_source_range(tokens, position);
let expectation = expectation.to_owned();
Rc::new(move |source_path, source_contents| {
if tokens.is_empty() {
throw::<Error>(
&format!("Expected {expectation}, but the file is empty."),
source_path,
Some(&listing(source_contents, source_range)),
None,
)
} else if position == tokens.len() {
throw::<Error>(
&format!("Expected {expectation} at the end of the file."),
source_path,
Some(&listing(source_contents, source_range)),
None,
)
} else {
throw::<Error>(
&if let token::Variant::Terminator(TerminatorType::LineBreak) =
tokens[position].variant
{
format!("Expected {expectation} at the end of this line:")
} else {
format!(
"Expected {}, but encountered {}.",
expectation,
tokens[position].to_string().code_str(),
)
},
source_path,
Some(&listing(source_contents, source_range)),
None,
)
}
})
}
fn span(x: SourceRange, y: SourceRange) -> SourceRange {
SourceRange {
start: x.start,
end: y.end,
}
}
fn token_source_range<'a>(tokens: &'a [Token<'a>], position: usize) -> SourceRange {
if position == tokens.len() {
tokens
.last()
.map_or(SourceRange { start: 0, end: 0 }, |token| SourceRange {
start: token.source_range.end,
end: token.source_range.end,
})
} else {
tokens[position].source_range
}
}
fn empty_source_range<'a>(tokens: &'a [Token<'a>], position: usize) -> SourceRange {
let source_range = token_source_range(tokens, position);
SourceRange {
start: source_range.start,
end: source_range.start,
}
}
#[derive(Clone, Copy, Debug)]
struct SourceVariable<'a> {
source_range: SourceRange,
name: &'a str,
}
#[derive(Clone)]
struct Term<'a> {
source_range: SourceRange,
group: bool, variant: Variant<'a>,
errors: Vec<ErrorFactory<'a>>,
}
#[derive(Clone)]
enum Variant<'a> {
ParseError,
Type,
Variable(&'a str),
Lambda(SourceVariable<'a>, bool, Option<Rc<Term<'a>>>, Rc<Term<'a>>),
Pi(SourceVariable<'a>, bool, Rc<Term<'a>>, Rc<Term<'a>>),
Application(Rc<Term<'a>>, Rc<Term<'a>>),
Let(
SourceVariable<'a>,
Option<Rc<Term<'a>>>,
Rc<Term<'a>>,
Rc<Term<'a>>,
),
Integer,
IntegerLiteral(BigInt),
Negation(Rc<Term<'a>>),
Sum(Rc<Term<'a>>, Rc<Term<'a>>),
Difference(Rc<Term<'a>>, Rc<Term<'a>>),
Product(Rc<Term<'a>>, Rc<Term<'a>>),
Quotient(Rc<Term<'a>>, Rc<Term<'a>>),
LessThan(Rc<Term<'a>>, Rc<Term<'a>>),
LessThanOrEqualTo(Rc<Term<'a>>, Rc<Term<'a>>),
EqualTo(Rc<Term<'a>>, Rc<Term<'a>>),
GreaterThan(Rc<Term<'a>>, Rc<Term<'a>>),
GreaterThanOrEqualTo(Rc<Term<'a>>, Rc<Term<'a>>),
Boolean,
True,
False,
If(Rc<Term<'a>>, Rc<Term<'a>>, Rc<Term<'a>>),
}
fn error_term<'a>(tokens: &'a [Token<'a>], position: usize, expectation: &str) -> Term<'a> {
Term {
source_range: empty_source_range(tokens, position),
group: false,
variant: Variant::ParseError,
errors: vec![error_factory(tokens, position, expectation)],
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum Nonterminal {
Term,
Type,
Variable,
Lambda,
LambdaImplicit,
AnnotatedLambda,
AnnotatedLambdaImplicit,
Pi,
PiImplicit,
NonDependentPi,
Application,
Let,
Integer,
IntegerLiteral,
Negation,
Sum,
Difference,
Product,
Quotient,
LessThan,
LessThanOrEqualTo,
EqualTo,
GreaterThan,
GreaterThanOrEqualTo,
Boolean,
True,
False,
If,
Group,
Atom,
SmallTerm,
MediumTerm,
LargeTerm,
HugeTerm,
GiantTerm,
JumboTerm,
}
type Cache<'a> = HashMap<(Nonterminal, usize), (Term<'a>, usize, bool)>;
macro_rules! cache_check {
($cache:ident, $nonterminal:ident, $start:expr $(,)?) => {{
let start = $start;
let cache_key = (Nonterminal::$nonterminal, start);
if let Some(result) = $cache.get(&cache_key) {
return result.clone();
}
cache_key
}};
}
macro_rules! cache_return {
($cache:ident, $cache_key:expr, $value:expr $(,)?) => {{
let cache_key = $cache_key;
let value = $value;
$cache.insert(cache_key, value.clone());
return value;
}};
}
macro_rules! try_return {
($cache:ident, $cache_key:expr, $value:expr $(,)?) => {{
let cache_key = $cache_key;
let value = $value;
if let Variant::ParseError = value.0.variant {
} else {
cache_return!($cache, cache_key, value)
}
}};
}
macro_rules! try_eval {
($cache:ident, $cache_key:expr, $value:expr $(,)?) => {{
let cache_key = $cache_key;
let value = $value;
if let Variant::ParseError = value.0.variant {
cache_return!($cache, cache_key, value)
}
value
}};
}
macro_rules! consume_token_0 {
(
$cache:ident,
$cache_key:expr,
$tokens:expr,
$next:expr,
$variant:ident,
$expectation:expr $(,)?
) => {{
let cache_key = $cache_key;
let tokens = $tokens;
let next = $next;
let expectation = $expectation;
if next == tokens.len() {
cache_return!(
$cache,
cache_key,
(error_term(tokens, next, expectation), next, false),
)
}
if let token::Variant::$variant = tokens[next].variant {
next + 1
} else {
cache_return!(
$cache,
cache_key,
(error_term(tokens, next, expectation), next, false),
)
}
}};
}
macro_rules! consume_token_1 {
(
$cache:ident,
$cache_key:expr,
$tokens:expr,
$next:expr,
$variant:ident,
$expectation:expr $(,)?
) => {{
let cache_key = $cache_key;
let tokens = $tokens;
let next = $next;
let expectation = $expectation;
if next == tokens.len() {
cache_return!(
$cache,
cache_key,
(error_term(tokens, next, expectation), next, false),
)
}
if let token::Variant::$variant(argument) = &tokens[next].variant {
(argument.clone(), next + 1)
} else {
cache_return!(
$cache,
cache_key,
(error_term(tokens, next, expectation), next, false),
)
}
}};
}
macro_rules! expect_token_0 {
(
$tokens:expr,
$next:expr,
$errors:ident,
$variant:ident,
$expectation:expr,
$report_error:expr $(,)?
) => {{
let tokens = $tokens;
let next = $next;
let expectation = $expectation;
let report_error = $report_error;
if report_error {
if next == tokens.len() {
$errors.push(error_factory(tokens, next, expectation));
} else if let token::Variant::$variant = tokens[next].variant {
} else {
$errors.push(error_factory(tokens, next, expectation));
}
}
let mut next = next;
let mut found = false;
let mut depth = 0_usize;
while next < tokens.len() {
match tokens[next].variant {
token::Variant::$variant if depth == 0 => {
next += 1;
found = true;
break;
}
token::Variant::LeftParen => {
depth += 1;
}
token::Variant::RightParen => {
if depth > 0 {
depth -= 1;
} else {
break;
}
}
token::Variant::Terminator(_) if depth == 0 => {
break;
}
_ => {}
}
next += 1;
}
(found, next)
}};
}
macro_rules! expect_token_1 {
(
$tokens:expr,
$next:expr,
$errors:ident,
$variant:ident,
$expectation:expr,
$report_error:expr $(,)?
) => {{
let tokens = $tokens;
let next = $next;
let expectation = $expectation;
let report_error = $report_error;
if report_error {
if next == tokens.len() {
$errors.push(error_factory(tokens, next, expectation));
} else if let token::Variant::$variant(_) = tokens[next].variant {
} else {
$errors.push(error_factory(tokens, next, expectation));
}
}
let mut next = next;
let mut argument_option = None;
let mut depth = 0_usize;
while next < tokens.len() {
match &tokens[next].variant {
token::Variant::$variant(argument) if depth == 0 => {
next += 1;
argument_option = Some(argument.clone());
break;
}
token::Variant::LeftParen => {
depth += 1;
}
token::Variant::RightParen => {
if depth > 0 {
depth -= 1;
} else {
break;
}
}
token::Variant::Terminator(_) if depth == 0 => {
break;
}
_ => {}
}
next += 1;
}
(argument_option, next)
}};
}
fn collect_error_factories<'a>(error_factories: &mut Vec<ErrorFactory<'a>>, term: &Term<'a>) {
match &term.variant {
Variant::ParseError
| Variant::Type
| Variant::Variable(_)
| Variant::Integer
| Variant::IntegerLiteral(_)
| Variant::Boolean
| Variant::True
| Variant::False => {}
Variant::Lambda(_, _, domain, body) => {
if let Some(domain) = domain {
collect_error_factories(error_factories, domain);
}
collect_error_factories(error_factories, body);
}
Variant::Pi(_, _, domain, codomain) => {
collect_error_factories(error_factories, domain);
collect_error_factories(error_factories, codomain);
}
Variant::Application(applicand, argument) => {
collect_error_factories(error_factories, applicand);
collect_error_factories(error_factories, argument);
}
Variant::Let(_, annotation, definition, body) => {
if let Some(annotation) = annotation {
collect_error_factories(error_factories, annotation);
}
collect_error_factories(error_factories, definition);
collect_error_factories(error_factories, body);
}
Variant::Negation(subterm) => {
collect_error_factories(error_factories, subterm);
}
Variant::Sum(term1, term2)
| Variant::Difference(term1, term2)
| Variant::Product(term1, term2)
| Variant::Quotient(term1, term2)
| Variant::LessThan(term1, term2)
| Variant::LessThanOrEqualTo(term1, term2)
| Variant::EqualTo(term1, term2)
| Variant::GreaterThan(term1, term2)
| Variant::GreaterThanOrEqualTo(term1, term2) => {
collect_error_factories(error_factories, term1);
collect_error_factories(error_factories, term2);
}
Variant::If(condition, then_branch, else_branch) => {
collect_error_factories(error_factories, condition);
collect_error_factories(error_factories, then_branch);
collect_error_factories(error_factories, else_branch);
}
}
for error_factory in &term.errors {
error_factories.push(error_factory.clone());
}
}
#[allow(clippy::too_many_lines)]
fn reassociate_applications<'a>(acc: Option<Term<'a>>, term: &Term<'a>) -> Term<'a> {
let reduced = match &term.variant {
Variant::ParseError => {
panic!(
"{} called on a {}.",
"reassociate_applications".code_str(),
"ParseError".code_str(),
)
}
Variant::Type
| Variant::Variable(_)
| Variant::Integer
| Variant::IntegerLiteral(_)
| Variant::Boolean
| Variant::True
| Variant::False => term.clone(),
Variant::Lambda(variable, implicit, domain, body) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Lambda(
*variable,
*implicit,
domain
.as_ref()
.map(|domain| Rc::new(reassociate_applications(None, domain))),
Rc::new(reassociate_applications(None, body)),
),
errors: vec![],
},
Variant::Pi(variable, implicit, domain, codomain) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Pi(
*variable,
*implicit,
Rc::new(reassociate_applications(None, domain)),
Rc::new(reassociate_applications(None, codomain)),
),
errors: vec![],
},
Variant::Application(applicand, argument) => {
return if argument.group {
if let Some(acc) = acc {
Term {
source_range: span(acc.source_range, argument.source_range),
group: true,
variant: Variant::Application(
Rc::new(reassociate_applications(Some(acc), applicand)),
Rc::new(reassociate_applications(None, argument)),
),
errors: vec![],
}
} else {
Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Application(
Rc::new(reassociate_applications(None, applicand)),
Rc::new(reassociate_applications(None, argument)),
),
errors: vec![],
}
}
} else {
reassociate_applications(
Some(if let Some(acc) = acc {
Term {
source_range: span(acc.source_range, applicand.source_range),
group: true,
variant: Variant::Application(
Rc::new(acc),
Rc::new(reassociate_applications(None, applicand)),
),
errors: vec![],
}
} else {
reassociate_applications(None, applicand)
}),
argument,
)
};
}
Variant::Let(variable, annotation, definition, body) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Let(
*variable,
annotation
.as_ref()
.map(|annotation| Rc::new(reassociate_applications(None, annotation))),
Rc::new(reassociate_applications(None, definition)),
Rc::new(reassociate_applications(None, body)),
),
errors: vec![],
},
Variant::Negation(subterm) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Negation(Rc::new(reassociate_applications(None, subterm))),
errors: vec![],
},
Variant::Sum(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Sum(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::Difference(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Difference(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::Product(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Product(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::Quotient(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Quotient(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::LessThan(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::LessThan(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::LessThanOrEqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::LessThanOrEqualTo(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::EqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::EqualTo(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::GreaterThan(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::GreaterThan(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::GreaterThanOrEqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::GreaterThanOrEqualTo(
Rc::new(reassociate_applications(None, term1)),
Rc::new(reassociate_applications(None, term2)),
),
errors: vec![],
},
Variant::If(condition, then_branch, else_branch) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::If(
Rc::new(reassociate_applications(None, condition)),
Rc::new(reassociate_applications(None, then_branch)),
Rc::new(reassociate_applications(None, else_branch)),
),
errors: vec![],
},
};
if let Some(acc) = acc {
Term {
source_range: span(acc.source_range, reduced.source_range),
group: true,
variant: Variant::Application(Rc::new(acc), Rc::new(reduced)),
errors: vec![],
}
} else {
reduced
}
}
#[derive(Eq, Ord, PartialEq, PartialOrd)]
enum ProductOrQuotient {
Product,
Quotient,
}
#[allow(clippy::too_many_lines)]
fn reassociate_products_and_quotients<'a>(
acc: Option<(Term<'a>, ProductOrQuotient)>,
term: &Term<'a>,
) -> Term<'a> {
let reduced = match &term.variant {
Variant::ParseError => {
panic!(
"{} called on a {}.",
"reassociate_products_and_quotients".code_str(),
"ParseError".code_str(),
)
}
Variant::Type
| Variant::Variable(_)
| Variant::Integer
| Variant::IntegerLiteral(_)
| Variant::Boolean
| Variant::True
| Variant::False => term.clone(),
Variant::Lambda(variable, implicit, domain, body) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Lambda(
*variable,
*implicit,
domain
.as_ref()
.map(|domain| Rc::new(reassociate_products_and_quotients(None, domain))),
Rc::new(reassociate_products_and_quotients(None, body)),
),
errors: vec![],
},
Variant::Pi(variable, implicit, domain, codomain) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Pi(
*variable,
*implicit,
Rc::new(reassociate_products_and_quotients(None, domain)),
Rc::new(reassociate_products_and_quotients(None, codomain)),
),
errors: vec![],
},
Variant::Application(applicand, argument) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Application(
Rc::new(reassociate_products_and_quotients(None, applicand)),
Rc::new(reassociate_products_and_quotients(None, argument)),
),
errors: vec![],
},
Variant::Let(variable, annotation, definition, body) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Let(
*variable,
annotation.as_ref().map(|annotation| {
Rc::new(reassociate_products_and_quotients(None, annotation))
}),
Rc::new(reassociate_products_and_quotients(None, definition)),
Rc::new(reassociate_products_and_quotients(None, body)),
),
errors: vec![],
},
Variant::Negation(subterm) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Negation(Rc::new(reassociate_products_and_quotients(None, subterm))),
errors: vec![],
},
Variant::Sum(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Sum(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
},
Variant::Difference(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Difference(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
},
Variant::Product(term1, term2) => {
return if term2.group {
if let Some(acc) = acc {
Term {
source_range: span(acc.0.source_range, term2.source_range),
group: true,
variant: Variant::Product(
Rc::new(reassociate_products_and_quotients(Some(acc), term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
}
} else {
Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Product(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
}
}
} else {
reassociate_products_and_quotients(
Some((
if let Some((acc, operator)) = acc {
Term {
source_range: span(acc.source_range, term1.source_range),
group: true,
variant: match operator {
ProductOrQuotient::Product => Variant::Product(
Rc::new(acc),
Rc::new(reassociate_products_and_quotients(None, term1)),
),
ProductOrQuotient::Quotient => Variant::Quotient(
Rc::new(acc),
Rc::new(reassociate_products_and_quotients(None, term1)),
),
},
errors: vec![],
}
} else {
reassociate_products_and_quotients(None, term1)
},
ProductOrQuotient::Product,
)),
term2,
)
};
}
Variant::Quotient(term1, term2) => {
return if term2.group {
if let Some(acc) = acc {
Term {
source_range: span(acc.0.source_range, term2.source_range),
group: true,
variant: Variant::Quotient(
Rc::new(reassociate_products_and_quotients(Some(acc), term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
}
} else {
Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Quotient(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
}
}
} else {
reassociate_products_and_quotients(
Some((
if let Some((acc, operator)) = acc {
Term {
source_range: span(acc.source_range, term1.source_range),
group: true,
variant: match operator {
ProductOrQuotient::Product => Variant::Product(
Rc::new(acc),
Rc::new(reassociate_products_and_quotients(None, term1)),
),
ProductOrQuotient::Quotient => Variant::Quotient(
Rc::new(acc),
Rc::new(reassociate_products_and_quotients(None, term1)),
),
},
errors: vec![],
}
} else {
reassociate_products_and_quotients(None, term1)
},
ProductOrQuotient::Quotient,
)),
term2,
)
};
}
Variant::LessThan(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::LessThan(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
},
Variant::LessThanOrEqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::LessThanOrEqualTo(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
},
Variant::EqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::EqualTo(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
},
Variant::GreaterThan(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::GreaterThan(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
},
Variant::GreaterThanOrEqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::GreaterThanOrEqualTo(
Rc::new(reassociate_products_and_quotients(None, term1)),
Rc::new(reassociate_products_and_quotients(None, term2)),
),
errors: vec![],
},
Variant::If(condition, then_branch, else_branch) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::If(
Rc::new(reassociate_products_and_quotients(None, condition)),
Rc::new(reassociate_products_and_quotients(None, then_branch)),
Rc::new(reassociate_products_and_quotients(None, else_branch)),
),
errors: vec![],
},
};
if let Some((acc, operator)) = acc {
Term {
source_range: span(acc.source_range, reduced.source_range),
group: true,
variant: match operator {
ProductOrQuotient::Product => Variant::Product(Rc::new(acc), Rc::new(reduced)),
ProductOrQuotient::Quotient => Variant::Quotient(Rc::new(acc), Rc::new(reduced)),
},
errors: vec![],
}
} else {
reduced
}
}
#[derive(Eq, Ord, PartialEq, PartialOrd)]
enum SumOrDifference {
Sum,
Difference,
}
#[allow(clippy::too_many_lines)]
fn reassociate_sums_and_differences<'a>(
acc: Option<(Term<'a>, SumOrDifference)>,
term: &Term<'a>,
) -> Term<'a> {
let reduced = match &term.variant {
Variant::ParseError => {
panic!(
"{} called on a {}.",
"reassociate_sums_and_differences".code_str(),
"ParseError".code_str(),
)
}
Variant::Type
| Variant::Variable(_)
| Variant::Integer
| Variant::IntegerLiteral(_)
| Variant::Boolean
| Variant::True
| Variant::False => term.clone(),
Variant::Lambda(variable, implicit, domain, body) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Lambda(
*variable,
*implicit,
domain
.as_ref()
.map(|domain| Rc::new(reassociate_sums_and_differences(None, domain))),
Rc::new(reassociate_sums_and_differences(None, body)),
),
errors: vec![],
},
Variant::Pi(variable, implicit, domain, codomain) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Pi(
*variable,
*implicit,
Rc::new(reassociate_sums_and_differences(None, domain)),
Rc::new(reassociate_sums_and_differences(None, codomain)),
),
errors: vec![],
},
Variant::Application(applicand, argument) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Application(
Rc::new(reassociate_sums_and_differences(None, applicand)),
Rc::new(reassociate_sums_and_differences(None, argument)),
),
errors: vec![],
},
Variant::Let(variable, annotation, definition, body) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Let(
*variable,
annotation
.as_ref()
.map(|annotation| Rc::new(reassociate_sums_and_differences(None, annotation))),
Rc::new(reassociate_sums_and_differences(None, definition)),
Rc::new(reassociate_sums_and_differences(None, body)),
),
errors: vec![],
},
Variant::Negation(subterm) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Negation(Rc::new(reassociate_sums_and_differences(None, subterm))),
errors: vec![],
},
Variant::Sum(term1, term2) => {
return if term2.group {
if let Some(acc) = acc {
Term {
source_range: span(acc.0.source_range, term2.source_range),
group: true,
variant: Variant::Sum(
Rc::new(reassociate_sums_and_differences(Some(acc), term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
}
} else {
Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Sum(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
}
}
} else {
reassociate_sums_and_differences(
Some((
if let Some((acc, operator)) = acc {
Term {
source_range: span(acc.source_range, term1.source_range),
group: true,
variant: match operator {
SumOrDifference::Sum => Variant::Sum(
Rc::new(acc),
Rc::new(reassociate_sums_and_differences(None, term1)),
),
SumOrDifference::Difference => Variant::Difference(
Rc::new(acc),
Rc::new(reassociate_sums_and_differences(None, term1)),
),
},
errors: vec![],
}
} else {
reassociate_sums_and_differences(None, term1)
},
SumOrDifference::Sum,
)),
term2,
)
};
}
Variant::Difference(term1, term2) => {
return if term2.group {
if let Some(acc) = acc {
Term {
source_range: span(acc.0.source_range, term2.source_range),
group: true,
variant: Variant::Difference(
Rc::new(reassociate_sums_and_differences(Some(acc), term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
}
} else {
Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Difference(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
}
}
} else {
reassociate_sums_and_differences(
Some((
if let Some((acc, operator)) = acc {
Term {
source_range: span(acc.source_range, term1.source_range),
group: true,
variant: match operator {
SumOrDifference::Sum => Variant::Sum(
Rc::new(acc),
Rc::new(reassociate_sums_and_differences(None, term1)),
),
SumOrDifference::Difference => Variant::Difference(
Rc::new(acc),
Rc::new(reassociate_sums_and_differences(None, term1)),
),
},
errors: vec![],
}
} else {
reassociate_sums_and_differences(None, term1)
},
SumOrDifference::Difference,
)),
term2,
)
};
}
Variant::Product(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Product(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
},
Variant::Quotient(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::Quotient(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
},
Variant::LessThan(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::LessThan(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
},
Variant::LessThanOrEqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::LessThanOrEqualTo(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
},
Variant::EqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::EqualTo(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
},
Variant::GreaterThan(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::GreaterThan(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
},
Variant::GreaterThanOrEqualTo(term1, term2) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::GreaterThanOrEqualTo(
Rc::new(reassociate_sums_and_differences(None, term1)),
Rc::new(reassociate_sums_and_differences(None, term2)),
),
errors: vec![],
},
Variant::If(condition, then_branch, else_branch) => Term {
source_range: term.source_range,
group: term.group,
variant: Variant::If(
Rc::new(reassociate_sums_and_differences(None, condition)),
Rc::new(reassociate_sums_and_differences(None, then_branch)),
Rc::new(reassociate_sums_and_differences(None, else_branch)),
),
errors: vec![],
},
};
if let Some((acc, operator)) = acc {
Term {
source_range: span(acc.source_range, reduced.source_range),
group: true,
variant: match operator {
SumOrDifference::Sum => Variant::Sum(Rc::new(acc), Rc::new(reduced)),
SumOrDifference::Difference => Variant::Difference(Rc::new(acc), Rc::new(reduced)),
},
errors: vec![],
}
} else {
reduced
}
}
#[allow(clippy::too_many_lines)]
fn resolve_variables<'a>(
source_path: Option<&'a Path>,
source_contents: &'a str,
term: &Term<'a>,
depth: usize,
context: &mut HashMap<&'a str, usize>,
errors: &mut Vec<Error>,
) -> term::Term<'a> {
match &term.variant {
Variant::ParseError => {
panic!(
"{} called on a {}.",
"resolve_variables".code_str(),
"ParseError".code_str(),
)
}
Variant::Type => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Type,
}
}
Variant::Variable(variable) => {
if let Some(variable_depth) = context.get(variable) {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Variable(variable, depth - 1 - variable_depth),
}
} else {
if *variable != PLACEHOLDER_VARIABLE {
errors.push(throw::<Error>(
&format!("Variable {} not in scope.", variable.code_str()),
source_path,
Some(&listing(source_contents, term.source_range)),
None,
));
}
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Unifier(Rc::new(RefCell::new(None)), 0),
}
}
}
Variant::Lambda(variable, implicit, domain, body) => {
let resolved_domain = domain.as_ref().map(|domain| {
resolve_variables(source_path, source_contents, domain, depth, context, errors)
});
if variable.name != PLACEHOLDER_VARIABLE {
if context.contains_key(variable.name) {
errors.push(throw::<Error>(
&format!("Variable {} already exists.", variable.name.code_str()),
source_path,
Some(&listing(source_contents, variable.source_range)),
None,
));
}
context.insert(variable.name, depth);
}
let context_cell = RefCell::new(context);
defer! {{ context_cell.borrow_mut().remove(variable.name); }};
let mut guard = context_cell.borrow_mut();
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Lambda(
variable.name,
*implicit,
resolved_domain.map_or_else(
|| {
Rc::new(term::Term {
source_range: None,
variant: term::Variant::Unifier(Rc::new(RefCell::new(None)), 0),
})
},
Rc::new,
),
Rc::new(resolve_variables(
source_path,
source_contents,
body,
depth + 1,
&mut guard,
errors,
)),
),
}
}
Variant::Pi(variable, implicit, domain, codomain) => {
let resolved_domain =
resolve_variables(source_path, source_contents, domain, depth, context, errors);
if variable.name != PLACEHOLDER_VARIABLE {
if context.contains_key(variable.name) {
errors.push(throw::<Error>(
&format!("Variable {} already exists.", variable.name.code_str()),
source_path,
Some(&listing(source_contents, variable.source_range)),
None,
));
}
context.insert(variable.name, depth);
}
let context_cell = RefCell::new(context);
defer! {{ context_cell.borrow_mut().remove(variable.name); }};
let mut guard = context_cell.borrow_mut();
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Pi(
variable.name,
*implicit,
Rc::new(resolved_domain),
Rc::new(resolve_variables(
source_path,
source_contents,
codomain,
depth + 1,
&mut guard,
errors,
)),
),
}
}
Variant::Application(applicand, argument) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Application(
Rc::new(resolve_variables(
source_path,
source_contents,
applicand,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
argument,
depth,
context,
errors,
)),
),
}
}
Variant::Let(_, _, _, _) => {
let mut definitions = vec![];
let innermost_body = collect_definitions(&mut definitions, Rc::new(term.clone()));
let context_cell = RefCell::new((context, vec![]));
defer! {{
let mut guard = context_cell.borrow_mut();
let (borrowed_context, borrowed_variables_added) = &mut (*guard);
for variable_added in borrowed_variables_added {
borrowed_context.remove(*variable_added);
}
}};
for (i, (inner_variable, _, _)) in definitions.iter().enumerate() {
if inner_variable.name != PLACEHOLDER_VARIABLE {
let mut guard = context_cell.borrow_mut();
let (borrowed_context, borrowed_variables_added) = &mut (*guard);
if borrowed_context.contains_key(inner_variable.name) {
errors.push(throw::<Error>(
&format!(
"Variable {} already exists.",
inner_variable.name.code_str(),
),
source_path,
Some(&listing(source_contents, inner_variable.source_range)),
None,
));
}
borrowed_context.insert(inner_variable.name, depth + i);
borrowed_variables_added.push(inner_variable.name);
}
}
let new_depth = depth + definitions.len();
let mut resolved_definitions = vec![];
for (i, (inner_variable, inner_annotation, inner_definition)) in
definitions.iter().enumerate()
{
let mut guard = context_cell.borrow_mut();
let (borrowed_context, _) = &mut (*guard);
let resolved_annotation = match inner_annotation {
Some(annotation) => Rc::new(resolve_variables(
source_path,
source_contents,
annotation,
new_depth,
borrowed_context,
errors,
)),
None => Rc::new(term::Term {
source_range: None,
variant: term::Variant::Unifier(
Rc::new(RefCell::new(None)),
definitions.len() - i,
),
}),
};
let resolved_definition = resolve_variables(
source_path,
source_contents,
inner_definition,
new_depth,
borrowed_context,
errors,
);
resolved_definitions.push((
inner_variable.name,
resolved_annotation,
Rc::new(resolved_definition),
));
}
let mut guard = context_cell.borrow_mut();
let (borrowed_context, _) = &mut (*guard);
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Let(
resolved_definitions,
Rc::new(resolve_variables(
source_path,
source_contents,
&innermost_body,
new_depth,
borrowed_context,
errors,
)),
),
}
}
Variant::Integer => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Integer,
}
}
Variant::IntegerLiteral(integer) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::IntegerLiteral(integer.clone()),
}
}
Variant::Negation(subterm) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Negation(Rc::new(resolve_variables(
source_path,
source_contents,
subterm,
depth,
context,
errors,
))),
}
}
Variant::Sum(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Sum(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::Difference(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Difference(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::Product(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Product(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::Quotient(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Quotient(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::LessThan(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::LessThan(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::LessThanOrEqualTo(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::LessThanOrEqualTo(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::EqualTo(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::EqualTo(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::GreaterThan(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::GreaterThan(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::GreaterThanOrEqualTo(term1, term2) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::GreaterThanOrEqualTo(
Rc::new(resolve_variables(
source_path,
source_contents,
term1,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
term2,
depth,
context,
errors,
)),
),
}
}
Variant::Boolean => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::Boolean,
}
}
Variant::True => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::True,
}
}
Variant::False => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::False,
}
}
Variant::If(condition, then_branch, else_branch) => {
term::Term {
source_range: Some(term.source_range),
variant: term::Variant::If(
Rc::new(resolve_variables(
source_path,
source_contents,
condition,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
then_branch,
depth,
context,
errors,
)),
Rc::new(resolve_variables(
source_path,
source_contents,
else_branch,
depth,
context,
errors,
)),
),
}
}
}
}
#[allow(clippy::type_complexity)]
fn collect_definitions<'a>(
definitions: &mut Vec<(SourceVariable<'a>, Option<Rc<Term<'a>>>, Rc<Term<'a>>)>,
term: Rc<Term<'a>>,
) -> Rc<Term<'a>> {
match &term.variant {
Variant::Let(variable, annotation, definition, body) => {
definitions.push((*variable, annotation.clone(), definition.clone()));
collect_definitions(definitions, body.clone())
}
_ => term,
}
}
#[allow(clippy::too_many_lines)]
fn check_definitions<'a>(
source_path: Option<&'a Path>,
source_contents: &'a str,
term: &term::Term<'a>,
depth: usize,
errors: &mut Vec<Error>,
) {
match &term.variant {
term::Variant::Type
| term::Variant::Variable(_, _)
| term::Variant::Integer
| term::Variant::IntegerLiteral(_)
| term::Variant::Boolean
| term::Variant::True
| term::Variant::False => {}
term::Variant::Unifier(subterm, subterm_shift) => {
assert_eq!(*subterm_shift, 0);
if let Some(subterm) = { subterm.borrow().clone() } {
check_definitions(source_path, source_contents, &subterm, depth, errors);
}
}
term::Variant::Lambda(_, _, domain, body) => {
check_definitions(source_path, source_contents, domain, depth, errors);
check_definitions(source_path, source_contents, body, depth + 1, errors);
}
term::Variant::Pi(_, _, domain, codomain) => {
check_definitions(source_path, source_contents, domain, depth, errors);
check_definitions(source_path, source_contents, codomain, depth + 1, errors);
}
term::Variant::Application(applicand, argument) => {
check_definitions(source_path, source_contents, applicand, depth, errors);
check_definitions(source_path, source_contents, argument, depth, errors);
}
term::Variant::Let(definitions, body) => {
let new_depth = depth + definitions.len();
for i in 0..definitions.len() {
if !is_value(&definitions[i].2) {
let mut visited = HashSet::new();
check_definition(
source_path,
source_contents,
definitions,
i,
i,
&mut visited,
errors,
);
}
}
check_definitions(source_path, source_contents, body, new_depth, errors);
}
term::Variant::Negation(subterm) => {
check_definitions(source_path, source_contents, subterm, depth, errors);
}
term::Variant::Sum(term1, term2)
| term::Variant::Difference(term1, term2)
| term::Variant::Product(term1, term2)
| term::Variant::Quotient(term1, term2)
| term::Variant::LessThan(term1, term2)
| term::Variant::LessThanOrEqualTo(term1, term2)
| term::Variant::EqualTo(term1, term2)
| term::Variant::GreaterThan(term1, term2)
| term::Variant::GreaterThanOrEqualTo(term1, term2) => {
check_definitions(source_path, source_contents, term1, depth, errors);
check_definitions(source_path, source_contents, term2, depth, errors);
}
term::Variant::If(condition, then_branch, else_branch) => {
check_definitions(source_path, source_contents, condition, depth, errors);
check_definitions(source_path, source_contents, then_branch, depth, errors);
check_definitions(source_path, source_contents, else_branch, depth, errors);
}
}
}
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
fn check_definition<'a>(
source_path: Option<&'a Path>,
source_contents: &'a str,
definitions: &[(&'a str, Rc<term::Term<'a>>, Rc<term::Term<'a>>)],
start_index: usize, current_index: usize, visited: &mut HashSet<usize>,
errors: &mut Vec<Error>,
) {
let mut variables = HashSet::new();
free_variables(&definitions[current_index].2, 0, &mut variables);
for variable in variables {
if variable < definitions.len() {
let definition_index = definitions.len() - 1 - variable;
if visited.insert(definition_index) {
if is_value(&definitions[definition_index].2) {
check_definition(
source_path,
source_contents,
definitions,
start_index,
definition_index,
visited,
errors,
);
} else if definition_index >= start_index {
errors.push(throw::<Error>(
&format!(
"The definition of {} references {} (directly or indirectly), \
which will not be available in time during evaluation.",
definitions[start_index].0.code_str(),
definitions[definition_index].0.code_str(),
),
source_path,
definitions[start_index]
.2
.source_range
.map(|source_range| listing(source_contents, source_range))
.as_deref(),
None,
));
}
}
}
}
}
pub fn parse<'a>(
source_path: Option<&'a Path>,
source_contents: &'a str,
tokens: &'a [Token<'a>],
context: &[&'a str],
) -> Result<term::Term<'a>, Vec<Error>> {
let mut cache = Cache::new();
let (term, next, _) = parse_term(&mut cache, tokens, 0);
let mut error_factories = vec![];
collect_error_factories(&mut error_factories, &term);
if error_factories.is_empty() && next != tokens.len() {
error_factories.push(error_factory(tokens, next, "the end of the file"));
}
if !error_factories.is_empty() {
return Err(error_factories
.into_iter()
.map(|error_factory| error_factory(source_path, source_contents))
.collect());
}
let reassociated_term = reassociate_sums_and_differences(
None,
&reassociate_products_and_quotients(None, &reassociate_applications(None, &term)),
);
let mut context: HashMap<&'a str, usize> = context
.iter()
.enumerate()
.map(|(i, variable)| (*variable, i))
.collect();
let mut errors = vec![];
let resolved_term = resolve_variables(
source_path,
source_contents,
&reassociated_term,
context.len(),
&mut context,
&mut errors,
);
check_definitions(
source_path,
source_contents,
&resolved_term,
context.len(),
&mut errors,
);
if errors.is_empty() {
Ok(resolved_term)
} else {
Err(errors)
}
}
fn parse_term<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Term, start);
try_return!(cache, cache_key, parse_let(cache, tokens, start));
try_return!(cache, cache_key, parse_jumbo_term(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
fn parse_type<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Type, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
Type,
&format!("{}", token::Variant::Type.to_string().code_str()),
);
cache_return!(
cache,
cache_key,
(
Term {
source_range: token_source_range(tokens, start),
group: false,
variant: Variant::Type,
errors: vec![],
},
next,
true,
),
)
}
fn parse_variable<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Variable, start);
let variable_source_range = token_source_range(tokens, start);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, start, Identifier, "a variable");
cache_return!(
cache,
cache_key,
(
Term {
source_range: variable_source_range,
group: false,
variant: Variant::Variable(variable),
errors: vec![],
},
next,
true,
),
)
}
fn parse_lambda<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Lambda, start);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, start, Identifier, "a variable");
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
ThickArrow,
&format!("{}", token::Variant::ThickArrow.to_string().code_str()),
);
let (body, next, confident_next) = parse_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), body.source_range),
group: false,
variant: Variant::Lambda(
SourceVariable {
source_range: token_source_range(tokens, start),
name: variable,
},
false,
None,
Rc::new(body),
),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_lambda_implicit<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, LambdaImplicit, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
LeftCurly,
&format!("{}", token::Variant::LeftCurly.to_string().code_str()),
);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, next, Identifier, "a variable");
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
RightCurly,
&format!("{}", token::Variant::RightCurly.to_string().code_str()),
);
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
ThickArrow,
&format!("{}", token::Variant::ThickArrow.to_string().code_str()),
);
let (body, next, confident_next) = parse_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), body.source_range),
group: false,
variant: Variant::Lambda(
SourceVariable {
source_range: token_source_range(tokens, start),
name: variable,
},
true,
None,
Rc::new(body),
),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_annotated_lambda<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, AnnotatedLambda, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
LeftParen,
&format!("{}", token::Variant::LeftParen.to_string().code_str()),
);
let variable_source_range = token_source_range(tokens, next);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, next, Identifier, "a variable");
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Colon,
&format!("{}", token::Variant::Colon.to_string().code_str()),
);
let (domain, next, _) = try_eval!(cache, cache_key, parse_jumbo_term(cache, tokens, next));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
RightParen,
&format!("{}", token::Variant::RightParen.to_string().code_str()),
);
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
ThickArrow,
&format!("{}", token::Variant::ThickArrow.to_string().code_str()),
);
let (body, next, confident_next) = parse_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), body.source_range),
group: false,
variant: Variant::Lambda(
SourceVariable {
source_range: variable_source_range,
name: variable,
},
false,
Some(Rc::new(domain)),
Rc::new(body),
),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_annotated_lambda_implicit<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, AnnotatedLambdaImplicit, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
LeftCurly,
&format!("{}", token::Variant::LeftCurly.to_string().code_str()),
);
let variable_source_range = token_source_range(tokens, next);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, next, Identifier, "a variable");
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Colon,
&format!("{}", token::Variant::Colon.to_string().code_str()),
);
let (domain, next, _) = try_eval!(cache, cache_key, parse_jumbo_term(cache, tokens, next));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
RightCurly,
&format!("{}", token::Variant::RightCurly.to_string().code_str()),
);
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
ThickArrow,
&format!("{}", token::Variant::ThickArrow.to_string().code_str()),
);
let (body, next, confident_next) = parse_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), body.source_range),
group: false,
variant: Variant::Lambda(
SourceVariable {
source_range: variable_source_range,
name: variable,
},
true,
Some(Rc::new(domain)),
Rc::new(body),
),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_pi<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Pi, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
LeftParen,
&format!("{}", token::Variant::LeftParen.to_string().code_str()),
);
let variable_source_range = token_source_range(tokens, next);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, next, Identifier, "a variable");
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Colon,
&format!("{}", token::Variant::Colon.to_string().code_str()),
);
let (domain, next, _) = try_eval!(cache, cache_key, parse_jumbo_term(cache, tokens, next));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
RightParen,
&format!("{}", token::Variant::RightParen.to_string().code_str()),
);
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
ThinArrow,
&format!("{}", token::Variant::ThinArrow.to_string().code_str()),
);
let (codomain, next, confident_next) = parse_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), codomain.source_range),
group: false,
variant: Variant::Pi(
SourceVariable {
source_range: variable_source_range,
name: variable,
},
false,
Rc::new(domain),
Rc::new(codomain),
),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_pi_implicit<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, PiImplicit, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
LeftCurly,
&format!("{}", token::Variant::LeftCurly.to_string().code_str()),
);
let variable_source_range = token_source_range(tokens, next);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, next, Identifier, "a variable");
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Colon,
&format!("{}", token::Variant::Colon.to_string().code_str()),
);
let (domain, next, _) = try_eval!(cache, cache_key, parse_jumbo_term(cache, tokens, next));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
RightCurly,
&format!("{}", token::Variant::RightCurly.to_string().code_str()),
);
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
ThinArrow,
&format!("{}", token::Variant::ThinArrow.to_string().code_str()),
);
let (codomain, next, confident_next) = parse_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), codomain.source_range),
group: false,
variant: Variant::Pi(
SourceVariable {
source_range: variable_source_range,
name: variable,
},
true,
Rc::new(domain),
Rc::new(codomain),
),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_non_dependent_pi<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, NonDependentPi, start);
let (domain, next, _) = try_eval!(cache, cache_key, parse_small_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
ThinArrow,
&format!("{}", token::Variant::ThinArrow.to_string().code_str()),
);
let (codomain, next, confident_next) = parse_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(domain.source_range, codomain.source_range),
group: false,
variant: Variant::Pi(
SourceVariable {
source_range: empty_source_range(tokens, start),
name: PLACEHOLDER_VARIABLE,
},
false,
Rc::new(domain),
Rc::new(codomain),
),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_application<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Application, start);
let (applicand, next, _) = try_eval!(cache, cache_key, parse_atom(cache, tokens, start));
let (argument, next, confident_next) =
try_eval!(cache, cache_key, parse_small_term(cache, tokens, next));
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(applicand.source_range, argument.source_range),
group: false,
variant: Variant::Application(Rc::new(applicand), Rc::new(argument)),
errors: vec![],
},
next,
confident_next,
),
)
}
#[allow(clippy::cognitive_complexity)]
#[allow(clippy::too_many_lines)]
fn parse_let<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Let, start);
let variable_source_range = token_source_range(tokens, start);
let (variable, next) =
consume_token_1!(cache, cache_key, tokens, start, Identifier, "a variable");
let (annotation, next, annotation_confident_next) = if next < tokens.len() {
if let token::Variant::Colon = tokens[next].variant {
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Colon,
&format!("{}", token::Variant::Colon.to_string().code_str()),
);
let (annotation, next, confident_next) =
try_eval!(cache, cache_key, parse_small_term(cache, tokens, next));
(Some(Rc::new(annotation)), next, confident_next)
} else {
(None, next, true)
}
} else {
(None, next, true)
};
let mut errors = vec![];
let (equals_found, next) = if annotation.is_some() {
expect_token_0!(
tokens,
next,
errors,
Equals,
&format!("{}", token::Variant::Equals.to_string().code_str()),
annotation_confident_next,
)
} else {
(
true,
consume_token_0!(
cache,
cache_key,
tokens,
next,
Equals,
&format!("{}", token::Variant::Equals.to_string().code_str()),
),
)
};
let (definition, next, definition_confident_next) = if equals_found {
parse_term(cache, tokens, next)
} else {
(
Term {
source_range: empty_source_range(tokens, next),
group: false,
variant: Variant::ParseError,
errors: vec![],
},
next,
false,
)
};
let (terminator_type, next) = expect_token_1!(
tokens,
next,
errors,
Terminator,
&format!(
"{} or a line break followed by an expression",
token::Variant::Terminator(TerminatorType::Semicolon)
.to_string()
.code_str(),
),
definition_confident_next,
);
let (body, next, body_confident_next) = if terminator_type.is_some() {
parse_term(cache, tokens, next)
} else {
(
Term {
source_range: empty_source_range(tokens, next),
group: false,
variant: Variant::ParseError,
errors: vec![],
},
next,
false,
)
};
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(variable_source_range, body.source_range),
group: false,
variant: Variant::Let(
SourceVariable {
source_range: variable_source_range,
name: variable,
},
annotation,
Rc::new(definition),
Rc::new(body),
),
errors,
},
next,
body_confident_next,
),
)
}
fn parse_integer<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Integer, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
Integer,
&format!("{}", token::Variant::Integer.to_string().code_str()),
);
cache_return!(
cache,
cache_key,
(
Term {
source_range: token_source_range(tokens, start),
group: false,
variant: Variant::Integer,
errors: vec![],
},
next,
true,
),
)
}
fn parse_integer_literal<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, IntegerLiteral, start);
let (integer, next) = consume_token_1!(
cache,
cache_key,
tokens,
start,
IntegerLiteral,
"an integer literal",
);
cache_return!(
cache,
cache_key,
(
Term {
source_range: token_source_range(tokens, start),
group: false,
variant: Variant::IntegerLiteral(integer),
errors: vec![],
},
next,
true,
),
)
}
fn parse_negation<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Negation, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
Minus,
&format!("{}", token::Variant::Minus.to_string().code_str()),
);
let (subterm, next, confident_next) = parse_large_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), subterm.source_range),
group: false,
variant: Variant::Negation(Rc::new(subterm)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_sum<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Sum, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_large_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Plus,
&format!("{}", token::Variant::Plus.to_string().code_str()),
);
let (term2, next, confident_next) = parse_huge_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::Sum(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_difference<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Difference, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_large_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Minus,
&format!("{}", token::Variant::Minus.to_string().code_str()),
);
let (term2, next, confident_next) = parse_huge_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::Difference(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_product<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Product, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_small_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Asterisk,
&format!("{}", token::Variant::Asterisk.to_string().code_str()),
);
let (term2, next, confident_next) = parse_large_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::Product(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_quotient<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Quotient, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_small_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
Slash,
&format!("{}", token::Variant::Slash.to_string().code_str()),
);
let (term2, next, confident_next) = parse_large_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::Quotient(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_less_than<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, LessThan, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_huge_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
LessThan,
&format!("{}", token::Variant::LessThan.to_string().code_str()),
);
let (term2, next, confident_next) = parse_huge_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::LessThan(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_less_than_or_equal_to<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, LessThanOrEqualTo, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_huge_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
LessThanOrEqualTo,
&format!(
"{}",
token::Variant::LessThanOrEqualTo.to_string().code_str(),
),
);
let (term2, next, confident_next) = parse_huge_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::LessThanOrEqualTo(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_equal_to<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, EqualTo, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_huge_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
DoubleEquals,
&format!("{}", token::Variant::DoubleEquals.to_string().code_str()),
);
let (term2, next, confident_next) = parse_huge_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::EqualTo(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_greater_than<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, GreaterThan, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_huge_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
GreaterThan,
&format!("{}", token::Variant::GreaterThan.to_string().code_str()),
);
let (term2, next, confident_next) = parse_huge_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::GreaterThan(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_greater_than_or_equal_to<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, GreaterThanOrEqualTo, start);
let (term1, next, _) = try_eval!(cache, cache_key, parse_huge_term(cache, tokens, start));
let next = consume_token_0!(
cache,
cache_key,
tokens,
next,
GreaterThanOrEqualTo,
&format!(
"{}",
token::Variant::GreaterThanOrEqualTo.to_string().code_str(),
),
);
let (term2, next, confident_next) = parse_huge_term(cache, tokens, next);
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(term1.source_range, term2.source_range),
group: false,
variant: Variant::GreaterThanOrEqualTo(Rc::new(term1), Rc::new(term2)),
errors: vec![],
},
next,
confident_next,
),
)
}
fn parse_boolean<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Boolean, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
Boolean,
&format!("{}", token::Variant::Boolean.to_string().code_str()),
);
cache_return!(
cache,
cache_key,
(
Term {
source_range: token_source_range(tokens, start),
group: false,
variant: Variant::Boolean,
errors: vec![],
},
next,
true,
),
)
}
fn parse_true<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, True, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
True,
&format!("{}", token::Variant::True.to_string().code_str()),
);
cache_return!(
cache,
cache_key,
(
Term {
source_range: token_source_range(tokens, start),
group: false,
variant: Variant::True,
errors: vec![],
},
next,
true,
),
)
}
fn parse_false<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, False, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
False,
&format!("{}", token::Variant::False.to_string().code_str()),
);
cache_return!(
cache,
cache_key,
(
Term {
source_range: token_source_range(tokens, start),
group: false,
variant: Variant::False,
errors: vec![],
},
next,
true,
),
)
}
fn parse_if<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, If, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
If,
&format!("{}", token::Variant::If.to_string().code_str()),
);
let (condition, next, condition_confident_next) = parse_term(cache, tokens, next);
let mut errors = vec![];
let (found_then, next) = expect_token_0!(
tokens,
next,
errors,
Then,
&format!("{}", token::Variant::Then.to_string().code_str()),
condition_confident_next,
);
let (then_branch, next, then_branch_confident_next) = if found_then {
parse_term(cache, tokens, next)
} else {
(
Term {
source_range: empty_source_range(tokens, next),
group: false,
variant: Variant::ParseError,
errors: vec![],
},
next,
false,
)
};
let (found_else, next) = expect_token_0!(
tokens,
next,
errors,
Else,
&format!("{}", token::Variant::Else.to_string().code_str()),
then_branch_confident_next,
);
let (else_branch, next, else_branch_confident_next) = if found_else {
parse_term(cache, tokens, next)
} else {
(
Term {
source_range: empty_source_range(tokens, next),
group: false,
variant: Variant::ParseError,
errors: vec![],
},
next,
false,
)
};
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(token_source_range(tokens, start), else_branch.source_range),
group: false,
variant: Variant::If(
Rc::new(condition),
Rc::new(then_branch),
Rc::new(else_branch),
),
errors,
},
next,
else_branch_confident_next,
),
)
}
#[allow(clippy::too_many_lines)]
fn parse_group<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Group, start);
let next = consume_token_0!(
cache,
cache_key,
tokens,
start,
LeftParen,
&format!("{}", token::Variant::LeftParen.to_string().code_str()),
);
let (term, next, confident_next) = try_eval!(cache, cache_key, parse_term(cache, tokens, next));
let mut phony_errors = vec![];
let (found, next) = expect_token_0!(
tokens,
next,
phony_errors,
RightParen,
&format!("{}", token::Variant::RightParen.to_string().code_str()),
confident_next,
);
let mut errors = term.errors.clone();
if !found {
errors.push(Rc::new(move |source_path, source_contents| {
let left_parenthesis_source_range = token_source_range(tokens, start);
if next == tokens.len() {
throw::<Error>(
"This parenthesis was never closed:",
source_path,
Some(&listing(source_contents, left_parenthesis_source_range)),
None,
)
} else {
let left_parenthesis_listing =
listing(source_contents, left_parenthesis_source_range);
let unexpected_token_source_range = token_source_range(tokens, next);
let unexpected_token_listing =
listing(source_contents, unexpected_token_source_range);
Error {
message: if let token::Variant::Terminator(TerminatorType::LineBreak) =
tokens[next].variant
{
if let Some(path) = source_path {
format!(
"{} {} This parenthesis was never closed:\n\n{}\n\nIt was \
expected to be closed at the end of this line:\n\n{}",
"[Error]".red().bold(),
format!("[{}]", path.to_string_lossy().code_str()).magenta(),
left_parenthesis_listing,
unexpected_token_listing,
)
} else {
format!(
"{} This parenthesis was never closed:\n\n{}\n\nIt was \
expected to be closed at the end of this line:\n\n{}",
"[Error]".red().bold(),
left_parenthesis_listing,
unexpected_token_listing,
)
}
} else if let Some(path) = source_path {
format!(
"{} {} This parenthesis was never closed:\n\n{}\n\nIt was \
expected to be closed before {}:\n\n{}",
"[Error]".red().bold(),
format!("[{}]", path.to_string_lossy().code_str()).magenta(),
left_parenthesis_listing,
tokens[next].to_string().code_str(),
unexpected_token_listing,
)
} else {
format!(
"{} This parenthesis was never closed:\n\n{}\n\nIt was \
expected to be closed before {}:\n\n{}",
"[Error]".red().bold(),
left_parenthesis_listing,
tokens[next].to_string().code_str(),
unexpected_token_listing,
)
},
reason: None,
}
}
}));
}
cache_return!(
cache,
cache_key,
(
Term {
source_range: span(
token_source_range(tokens, start),
token_source_range(tokens, next - 1),
),
group: true,
variant: term.variant,
errors,
},
next,
found,
),
)
}
fn parse_atom<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, Atom, start);
try_return!(cache, cache_key, parse_type(cache, tokens, start));
try_return!(cache, cache_key, parse_variable(cache, tokens, start));
try_return!(cache, cache_key, parse_integer(cache, tokens, start));
try_return!(
cache,
cache_key,
parse_integer_literal(cache, tokens, start),
);
try_return!(cache, cache_key, parse_boolean(cache, tokens, start));
try_return!(cache, cache_key, parse_true(cache, tokens, start));
try_return!(cache, cache_key, parse_false(cache, tokens, start));
try_return!(cache, cache_key, parse_group(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
fn parse_small_term<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, SmallTerm, start);
try_return!(cache, cache_key, parse_application(cache, tokens, start));
try_return!(cache, cache_key, parse_atom(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
fn parse_medium_term<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, MediumTerm, start);
try_return!(cache, cache_key, parse_product(cache, tokens, start));
try_return!(cache, cache_key, parse_quotient(cache, tokens, start));
try_return!(cache, cache_key, parse_small_term(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
fn parse_large_term<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, LargeTerm, start);
try_return!(cache, cache_key, parse_negation(cache, tokens, start));
try_return!(cache, cache_key, parse_medium_term(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
fn parse_huge_term<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, HugeTerm, start);
try_return!(cache, cache_key, parse_sum(cache, tokens, start));
try_return!(cache, cache_key, parse_difference(cache, tokens, start));
try_return!(cache, cache_key, parse_large_term(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
fn parse_giant_term<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, GiantTerm, start);
try_return!(cache, cache_key, parse_less_than(cache, tokens, start));
try_return!(
cache,
cache_key,
parse_less_than_or_equal_to(cache, tokens, start),
);
try_return!(cache, cache_key, parse_equal_to(cache, tokens, start));
try_return!(cache, cache_key, parse_greater_than(cache, tokens, start));
try_return!(
cache,
cache_key,
parse_greater_than_or_equal_to(cache, tokens, start),
);
try_return!(cache, cache_key, parse_huge_term(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
fn parse_jumbo_term<'a>(
cache: &mut Cache<'a>,
tokens: &'a [Token<'a>],
start: usize,
) -> (Term<'a>, usize, bool) {
let cache_key = cache_check!(cache, JumboTerm, start);
try_return!(cache, cache_key, parse_lambda(cache, tokens, start));
try_return!(
cache,
cache_key,
parse_lambda_implicit(cache, tokens, start),
);
try_return!(
cache,
cache_key,
parse_annotated_lambda(cache, tokens, start),
);
try_return!(
cache,
cache_key,
parse_annotated_lambda_implicit(cache, tokens, start),
);
try_return!(cache, cache_key, parse_pi(cache, tokens, start));
try_return!(cache, cache_key, parse_pi_implicit(cache, tokens, start));
try_return!(
cache,
cache_key,
parse_non_dependent_pi(cache, tokens, start),
);
try_return!(cache, cache_key, parse_if(cache, tokens, start));
try_return!(cache, cache_key, parse_giant_term(cache, tokens, start));
cache_return!(
cache,
cache_key,
(error_term(tokens, start, "an expression"), start, false),
)
}
#[cfg(test)]
mod tests {
use {
crate::{
assert_fails, assert_same,
error::SourceRange,
parser::parse,
term::{
Term,
Variant::{
Application, Boolean, Difference, EqualTo, False, GreaterThan,
GreaterThanOrEqualTo, If, Integer, IntegerLiteral, Lambda, LessThan,
LessThanOrEqualTo, Let, Negation, Pi, Product, Quotient, Sum, True, Type,
Unifier, Variable,
},
},
tokenizer::tokenize,
},
num_bigint::ToBigInt,
std::{cell::RefCell, fmt::Write, rc::Rc},
};
#[test]
fn parse_empty() {
let source = "";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_fails!(
parse(None, source, &tokens[..], &context[..]),
"file is empty",
);
}
#[test]
fn parse_type() {
let source = "type";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 4 }),
variant: Type,
},
);
}
#[test]
fn parse_variable() {
let source = "x";
let tokens = tokenize(None, source).unwrap();
let context = ["x"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: Variable("x", 0),
},
);
}
#[test]
fn parse_variable_unifier() {
let source = "_";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: Unifier(Rc::new(RefCell::new(None)), 0),
},
);
}
#[test]
fn parse_variable_missing() {
let source = "x";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_fails!(
parse(None, source, &tokens[..], &context[..]),
"not in scope",
);
}
#[test]
fn parse_lambda() {
let source = "x => x";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 6 }),
variant: Lambda(
"x",
false,
Rc::new(Term {
source_range: None,
variant: Unifier(Rc::new(RefCell::new(None)), 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("x", 0),
}),
),
},
);
}
#[test]
fn parse_lambda_implicit() {
let source = "{x} => x";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 8 }),
variant: Lambda(
"x",
true,
Rc::new(Term {
source_range: None,
variant: Unifier(Rc::new(RefCell::new(None)), 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 7, end: 8 }),
variant: Variable("x", 0),
}),
),
},
);
}
#[test]
fn parse_annotated_lambda() {
let source = "(x : a) => x";
let tokens = tokenize(None, source).unwrap();
let context = ["a"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 12 }),
variant: Lambda(
"x",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("a", 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 11, end: 12 }),
variant: Variable("x", 0),
}),
),
},
);
}
#[test]
fn parse_annotated_lambda_implicit() {
let source = "{x : a} => x";
let tokens = tokenize(None, source).unwrap();
let context = ["a"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 12 }),
variant: Lambda(
"x",
true,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("a", 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 11, end: 12 }),
variant: Variable("x", 0),
}),
),
},
);
}
#[test]
fn parse_lambda_shadowing() {
let source = "(x : a) => x";
let tokens = tokenize(None, source).unwrap();
let context = ["a", "x"];
assert_fails!(
parse(None, source, &tokens[..], &context[..]),
"already exists",
);
}
#[test]
fn parse_lambda_placeholder_variable() {
let source = "(_ : a) => (_ : a) => a";
let tokens = tokenize(None, source).unwrap();
let context = ["a"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 23 }),
variant: Lambda(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("a", 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 11, end: 23 }),
variant: Lambda(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 16, end: 17 }),
variant: Variable("a", 1),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 22, end: 23 }),
variant: Variable("a", 2),
}),
),
}),
),
},
);
}
#[test]
fn parse_pi() {
let source = "(x : a) -> x";
let tokens = tokenize(None, source).unwrap();
let context = ["a"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 12 }),
variant: Pi(
"x",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("a", 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 11, end: 12 }),
variant: Variable("x", 0),
}),
),
},
);
}
#[test]
fn parse_pi_implicit() {
let source = "{x : a} -> x";
let tokens = tokenize(None, source).unwrap();
let context = ["a"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 12 }),
variant: Pi(
"x",
true,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("a", 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 11, end: 12 }),
variant: Variable("x", 0),
}),
),
},
);
}
#[test]
fn parse_pi_shadowing() {
let source = "(x : a) -> x";
let tokens = tokenize(None, source).unwrap();
let context = ["a", "x"];
assert_fails!(
parse(None, source, &tokens[..], &context[..]),
"already exists",
);
}
#[test]
fn parse_pi_placeholder_variable() {
let source = "(_ : a) -> (_ : a) -> a";
let tokens = tokenize(None, source).unwrap();
let context = ["a"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 23 }),
variant: Pi(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("a", 0),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 11, end: 23 }),
variant: Pi(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 16, end: 17 }),
variant: Variable("a", 1),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 22, end: 23 }),
variant: Variable("a", 2),
}),
),
}),
),
},
);
}
#[test]
fn parse_non_dependent_pi() {
let source = "a -> b";
let tokens = tokenize(None, source).unwrap();
let context = ["a", "b"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 6 }),
variant: Pi(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: Variable("a", 1),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("b", 1),
}),
),
},
);
}
#[test]
fn parse_non_dependent_pi_associativity() {
let source = "a -> b -> c";
let tokens = tokenize(None, source).unwrap();
let context = ["a", "b", "c"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 11 }),
variant: Pi(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: Variable("a", 2),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 11 }),
variant: Pi(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("b", 2),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 10, end: 11 }),
variant: Variable("c", 2),
}),
),
}),
),
},
);
}
#[test]
fn parse_application() {
let source = "f x";
let tokens = tokenize(None, source).unwrap();
let context = ["f", "x"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 3 }),
variant: Application(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: Variable("f", 1),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 2, end: 3 }),
variant: Variable("x", 0),
}),
),
},
);
}
#[test]
fn parse_application_associativity() {
let source = "f x y";
let tokens = tokenize(None, source).unwrap();
let context = ["f", "x", "y"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: Application(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 3 }),
variant: Application(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: Variable("f", 2),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 2, end: 3 }),
variant: Variable("x", 1),
}),
),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: Variable("y", 0),
}),
),
},
);
}
#[test]
fn parse_application_grouped_argument() {
let source = "f (x y)";
let tokens = tokenize(None, source).unwrap();
let context = ["f", "x", "y"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 7 }),
variant: Application(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: Variable("f", 2),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 3, end: 6 }),
variant: Application(
Rc::new(Term {
source_range: Some(SourceRange { start: 3, end: 4 }),
variant: Variable("x", 1),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: Variable("y", 0),
}),
),
}),
),
},
);
}
#[test]
fn parse_let() {
let source = "x = ((_ : type) => y) type; y : type = type; x";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 46 }),
variant: Let(
vec![
(
"x",
Rc::new(Term {
source_range: None,
variant: Unifier(Rc::new(RefCell::new(None)), 2),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 26 }),
variant: Application(
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 21 }),
variant: Lambda(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange {
start: 10,
end: 14,
}),
variant: Type,
}),
Rc::new(Term {
source_range: Some(SourceRange {
start: 19,
end: 20,
}),
variant: Variable("y", 1),
}),
),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 22, end: 26 }),
variant: Type,
}),
),
}),
),
(
"y",
Rc::new(Term {
source_range: Some(SourceRange { start: 32, end: 36 }),
variant: Type,
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 39, end: 43 }),
variant: Type,
}),
),
],
Rc::new(Term {
source_range: Some(SourceRange { start: 45, end: 46 }),
variant: Variable("x", 1),
}),
),
},
);
}
#[test]
fn parse_integer() {
let source = "int";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 3 }),
variant: Integer,
},
);
}
#[test]
fn parse_integer_literal() {
let source = "42";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 2 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&42_i32).unwrap()),
},
);
}
#[test]
fn parse_negation() {
let source = "-2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 2 }),
variant: Negation(Rc::new(Term {
source_range: Some(SourceRange { start: 1, end: 2 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
})),
},
);
}
#[test]
fn parse_sum() {
let source = "1 + 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: Sum(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_difference() {
let source = "1 - 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: Difference(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_product() {
let source = "2 * 3";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: Product(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&3_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_quotient() {
let source = "7 / 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: Quotient(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&7_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_arithmetic() {
let source = "1 + 2 * (3 - 4 / 5)";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 19 }),
variant: Sum(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 19 }),
variant: Product(
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 8, end: 19 }),
variant: Difference(
Rc::new(Term {
source_range: Some(SourceRange { start: 9, end: 10 }),
variant: IntegerLiteral(
ToBigInt::to_bigint(&3_i32).unwrap(),
),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 13, end: 18 }),
variant: Quotient(
Rc::new(Term {
source_range: Some(SourceRange {
start: 13,
end: 14,
}),
variant: IntegerLiteral(
ToBigInt::to_bigint(&4_i32).unwrap(),
),
}),
Rc::new(Term {
source_range: Some(SourceRange {
start: 17,
end: 18,
}),
variant: IntegerLiteral(
ToBigInt::to_bigint(&5_i32).unwrap(),
),
}),
),
}),
),
}),
),
}),
),
},
);
}
#[test]
fn parse_less_than() {
let source = "1 < 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: LessThan(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_less_than_or_equal_to() {
let source = "1 <= 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 6 }),
variant: LessThanOrEqualTo(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_equal_to() {
let source = "1 == 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 6 }),
variant: EqualTo(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_greater_than() {
let source = "1 > 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: GreaterThan(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 4, end: 5 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_greater_than_or_equal_to() {
let source = "1 >= 2";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 6 }),
variant: GreaterThanOrEqualTo(
Rc::new(Term {
source_range: Some(SourceRange { start: 0, end: 1 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 6 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&2_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_boolean() {
let source = "bool";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 4 }),
variant: Boolean,
},
);
}
#[test]
fn parse_true() {
let source = "true";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 4 }),
variant: True,
},
);
}
#[test]
fn parse_false() {
let source = "false";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 5 }),
variant: False,
},
);
}
#[test]
fn parse_if() {
let source = "if true then 0 else 1";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 21 }),
variant: If(
Rc::new(Term {
source_range: Some(SourceRange { start: 3, end: 7 }),
variant: True,
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 13, end: 14 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&0_i32).unwrap()),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 20, end: 21 }),
variant: IntegerLiteral(ToBigInt::to_bigint(&1_i32).unwrap()),
}),
),
},
);
}
#[test]
fn parse_group() {
let source = "(x)";
let tokens = tokenize(None, source).unwrap();
let context = ["x"];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 3 }),
variant: Variable("x", 0),
},
);
}
#[test]
fn parse_identity_function() {
let source = "(a : type) => (b : type) => (f : a -> b) => (x : a) => f x";
let tokens = tokenize(None, source).unwrap();
let context = [];
assert_same!(
parse(None, source, &tokens[..], &context[..]).unwrap(),
Term {
source_range: Some(SourceRange { start: 0, end: 58 }),
variant: Lambda(
"a",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 5, end: 9 }),
variant: Type,
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 14, end: 58 }),
variant: Lambda(
"b",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 19, end: 23 }),
variant: Type,
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 28, end: 58 }),
variant: Lambda(
"f",
false,
Rc::new(Term {
source_range: Some(SourceRange { start: 33, end: 39 }),
variant: Pi(
"_",
false,
Rc::new(Term {
source_range: Some(SourceRange {
start: 33,
end: 34,
}),
variant: Variable("a", 1),
}),
Rc::new(Term {
source_range: Some(SourceRange {
start: 38,
end: 39,
}),
variant: Variable("b", 1),
}),
),
}),
Rc::new(Term {
source_range: Some(SourceRange { start: 44, end: 58 }),
variant: Lambda(
"x",
false,
Rc::new(Term {
source_range: Some(SourceRange {
start: 49,
end: 50,
}),
variant: Variable("a", 2),
}),
Rc::new(Term {
source_range: Some(SourceRange {
start: 55,
end: 58,
}),
variant: Application(
Rc::new(Term {
source_range: Some(SourceRange {
start: 55,
end: 56,
}),
variant: Variable("f", 1),
}),
Rc::new(Term {
source_range: Some(SourceRange {
start: 57,
end: 58,
}),
variant: Variable("x", 0),
}),
),
}),
),
}),
),
}),
),
}),
),
},
);
}
}