Reorganize parser
This commit is contained in:
parent
e429693364
commit
1593080b8d
File diff suppressed because it is too large
Load Diff
749
dust-lang/src/parser/mod.rs
Normal file
749
dust-lang/src/parser/mod.rs
Normal file
@ -0,0 +1,749 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
|
||||
use chumsky::{input::SpannedInput, pratt::*, prelude::*};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::*,
|
||||
error::DustError,
|
||||
identifier::Identifier,
|
||||
lexer::{Control, Keyword, Operator, Token},
|
||||
};
|
||||
|
||||
use self::{enum_declaration::EnumVariant, type_constructor::TypeInvokationConstructor};
|
||||
|
||||
pub type ParserInput<'src> =
|
||||
SpannedInput<Token<'src>, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>;
|
||||
|
||||
pub type ParserExtra<'src> = extra::Err<Rich<'src, Token<'src>, SimpleSpan>>;
|
||||
|
||||
pub fn parse<'src>(
|
||||
tokens: &'src [(Token<'src>, SimpleSpan)],
|
||||
) -> Result<AbstractTree, Vec<DustError>> {
|
||||
let statements = parser(false)
|
||||
.parse(tokens.spanned((tokens.len()..tokens.len()).into()))
|
||||
.into_result()
|
||||
.map_err(|errors| {
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|error| DustError::from(error))
|
||||
.collect::<Vec<DustError>>()
|
||||
})?;
|
||||
|
||||
Ok(AbstractTree::new(statements))
|
||||
}
|
||||
|
||||
pub fn parser<'src>(
|
||||
allow_built_ins: bool,
|
||||
) -> impl Parser<'src, ParserInput<'src>, Vec<Statement>, ParserExtra<'src>> {
|
||||
let comment = select_ref! {
|
||||
Token::Comment(_) => {}
|
||||
};
|
||||
let identifiers: RefCell<HashMap<&str, Identifier>> = RefCell::new(HashMap::new());
|
||||
let identifier = select! {
|
||||
Token::Identifier(text) => {
|
||||
let mut identifiers = identifiers.borrow_mut();
|
||||
|
||||
if let Some(identifier) = identifiers.get(&text) {
|
||||
identifier.clone()
|
||||
} else {
|
||||
let new = Identifier::new(text);
|
||||
|
||||
identifiers.insert(text, new.clone());
|
||||
|
||||
new
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let positioned_identifier = identifier
|
||||
.clone()
|
||||
.map_with(|identifier, state| identifier.with_position(state.span()));
|
||||
|
||||
let basic_value = select! {
|
||||
Token::Boolean(boolean) => ValueNode::Boolean(boolean),
|
||||
Token::Float(float) => ValueNode::Float(float),
|
||||
Token::Integer(integer) => ValueNode::Integer(integer),
|
||||
Token::String(text) => ValueNode::String(text.to_string()),
|
||||
}
|
||||
.map_with(|value, state| Expression::Value(value.with_position(state.span())));
|
||||
|
||||
let raw_integer = select! {
|
||||
Token::Integer(integer) => integer
|
||||
};
|
||||
|
||||
let type_constructor = recursive(|type_constructor| {
|
||||
let primitive_type = choice((
|
||||
just(Token::Keyword(Keyword::Any)).to(Type::Any),
|
||||
just(Token::Keyword(Keyword::Bool)).to(Type::Boolean),
|
||||
just(Token::Keyword(Keyword::Float)).to(Type::Float),
|
||||
just(Token::Keyword(Keyword::Int)).to(Type::Integer),
|
||||
just(Token::Keyword(Keyword::None)).to(Type::None),
|
||||
just(Token::Keyword(Keyword::Range)).to(Type::Range),
|
||||
just(Token::Keyword(Keyword::Str)).to(Type::String),
|
||||
))
|
||||
.map_with(|r#type, state| TypeConstructor::Raw(r#type.with_position(state.span())));
|
||||
|
||||
let function_type = just(Token::Keyword(Keyword::Fn))
|
||||
.ignore_then(
|
||||
positioned_identifier
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.at_least(1)
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::Pipe)),
|
||||
just(Token::Control(Control::Pipe)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.then(
|
||||
type_constructor
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
),
|
||||
)
|
||||
.then_ignore(just(Token::Control(Control::SkinnyArrow)))
|
||||
.then(type_constructor.clone())
|
||||
.map_with(
|
||||
|((type_parameters, value_parameters), return_type), state| {
|
||||
TypeConstructor::Function(
|
||||
FunctionTypeConstructor {
|
||||
type_parameters,
|
||||
value_parameters,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
.with_position(state.span()),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let list_type = type_constructor
|
||||
.clone()
|
||||
.then_ignore(just(Token::Control(Control::Semicolon)))
|
||||
.then(raw_integer.clone())
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::SquareOpen)),
|
||||
just(Token::Control(Control::SquareClose)),
|
||||
)
|
||||
.map_with(|(item_type, length), state| {
|
||||
TypeConstructor::List(
|
||||
ListTypeConstructor {
|
||||
length: length as usize,
|
||||
item_type: Box::new(item_type),
|
||||
}
|
||||
.with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
let list_of_type = type_constructor
|
||||
.clone()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::SquareOpen)),
|
||||
just(Token::Control(Control::SquareClose)),
|
||||
)
|
||||
.map_with(|item_type, state| {
|
||||
TypeConstructor::ListOf(Box::new(item_type).with_position(state.span()))
|
||||
});
|
||||
|
||||
let type_invokation = positioned_identifier
|
||||
.clone()
|
||||
.then(
|
||||
type_constructor
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.at_least(1)
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.map(|(identifier, type_arguments)| {
|
||||
TypeConstructor::Invokation(TypeInvokationConstructor {
|
||||
identifier,
|
||||
type_arguments,
|
||||
})
|
||||
});
|
||||
|
||||
choice((
|
||||
type_invokation,
|
||||
function_type,
|
||||
list_type,
|
||||
list_of_type,
|
||||
primitive_type,
|
||||
))
|
||||
});
|
||||
|
||||
let type_specification =
|
||||
just(Token::Control(Control::Colon)).ignore_then(type_constructor.clone());
|
||||
|
||||
let statement = recursive(|statement| {
|
||||
let allow_built_ins = allow_built_ins.clone();
|
||||
|
||||
let block = statement
|
||||
.clone()
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::CurlyOpen)),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
)
|
||||
.map_with(|statements, state| Block::new(statements).with_position(state.span()));
|
||||
|
||||
let expression = recursive(|expression| {
|
||||
let allow_built_ins = allow_built_ins.clone();
|
||||
|
||||
let identifier_expression = identifier.clone().map_with(|identifier, state| {
|
||||
Expression::Identifier(identifier.with_position(state.span()))
|
||||
});
|
||||
|
||||
let range = raw_integer
|
||||
.clone()
|
||||
.then_ignore(just(Token::Control(Control::DoubleDot)))
|
||||
.then(raw_integer)
|
||||
.map_with(|(start, end), state| {
|
||||
Expression::Value(ValueNode::Range(start..end).with_position(state.span()))
|
||||
});
|
||||
|
||||
let list = expression
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::SquareOpen)),
|
||||
just(Token::Control(Control::SquareClose)),
|
||||
)
|
||||
.map_with(|list, state| {
|
||||
Expression::Value(ValueNode::List(list).with_position(state.span()))
|
||||
});
|
||||
|
||||
let map_fields = identifier
|
||||
.clone()
|
||||
.then(type_specification.clone().or_not())
|
||||
.then_ignore(just(Token::Operator(Operator::Assign)))
|
||||
.then(expression.clone())
|
||||
.map(|((identifier, r#type), expression)| (identifier, r#type, expression));
|
||||
|
||||
let map = map_fields
|
||||
.separated_by(just(Token::Control(Control::Comma)).or_not())
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::CurlyOpen)),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
)
|
||||
.map_with(|map_assigment_list, state| {
|
||||
Expression::Value(
|
||||
ValueNode::Map(map_assigment_list).with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
let function = just(Token::Keyword(Keyword::Fn))
|
||||
.ignore_then(
|
||||
identifier
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.at_least(1)
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::Pipe)),
|
||||
just(Token::Control(Control::Pipe)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.then(
|
||||
identifier
|
||||
.clone()
|
||||
.then_ignore(just(Token::Control(Control::Colon)))
|
||||
.then(type_constructor.clone())
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
),
|
||||
)
|
||||
.then_ignore(just(Token::Control(Control::SkinnyArrow)))
|
||||
.then(type_constructor.clone())
|
||||
.then(block.clone())
|
||||
.map_with(
|
||||
|(((type_parameters, value_parameters), return_type), body), state| {
|
||||
Expression::Value(
|
||||
ValueNode::Function {
|
||||
type_parameters,
|
||||
value_parameters,
|
||||
return_type,
|
||||
body,
|
||||
}
|
||||
.with_position(state.span()),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let enum_instance = positioned_identifier
|
||||
.clone()
|
||||
.then_ignore(just(Token::Control(Control::DoubleColon)))
|
||||
.then(positioned_identifier.clone())
|
||||
.then(
|
||||
expression
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.map_with(|((type_name, variant), content), state| {
|
||||
Expression::Value(
|
||||
ValueNode::EnumInstance {
|
||||
type_name,
|
||||
variant,
|
||||
content,
|
||||
}
|
||||
.with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
let built_in_function_call = choice((
|
||||
just(Token::Keyword(Keyword::Length))
|
||||
.ignore_then(expression.clone())
|
||||
.map_with(|argument, state| {
|
||||
Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::Length(argument))
|
||||
.with_position(state.span()),
|
||||
)
|
||||
}),
|
||||
just(Token::Keyword(Keyword::ReadFile))
|
||||
.ignore_then(expression.clone())
|
||||
.map_with(|argument, state| {
|
||||
Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::ReadFile(argument))
|
||||
.with_position(state.span()),
|
||||
)
|
||||
}),
|
||||
just(Token::Keyword(Keyword::ReadLine)).map_with(|_, state| {
|
||||
Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::ReadLine).with_position(state.span()),
|
||||
)
|
||||
}),
|
||||
just(Token::Keyword(Keyword::Sleep))
|
||||
.ignore_then(expression.clone())
|
||||
.map_with(|argument, state| {
|
||||
Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::Sleep(argument))
|
||||
.with_position(state.span()),
|
||||
)
|
||||
}),
|
||||
just(Token::Keyword(Keyword::WriteLine))
|
||||
.ignore_then(expression.clone())
|
||||
.map_with(|argument, state| {
|
||||
Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::WriteLine(argument))
|
||||
.with_position(state.span()),
|
||||
)
|
||||
}),
|
||||
just(Token::Keyword(Keyword::JsonParse))
|
||||
.ignore_then(type_constructor.clone())
|
||||
.then(expression.clone())
|
||||
.map_with(|(constructor, argument), state| {
|
||||
Expression::BuiltInFunctionCall(
|
||||
Box::new(BuiltInFunctionCall::JsonParse(constructor, argument))
|
||||
.with_position(state.span()),
|
||||
)
|
||||
}),
|
||||
))
|
||||
.try_map_with(move |expression, state| {
|
||||
if allow_built_ins {
|
||||
Ok(expression)
|
||||
} else {
|
||||
Err(Rich::custom(
|
||||
state.span(),
|
||||
"Built-in function calls can only be used by the standard library.",
|
||||
))
|
||||
}
|
||||
});
|
||||
|
||||
let turbofish = type_constructor
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.at_least(1)
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
)
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::DoubleColon)),
|
||||
just(Token::Control(Control::DoubleColon)),
|
||||
);
|
||||
|
||||
let atom = choice((
|
||||
enum_instance.clone(),
|
||||
range.clone(),
|
||||
function.clone(),
|
||||
list.clone(),
|
||||
map.clone(),
|
||||
basic_value.clone(),
|
||||
identifier_expression.clone(),
|
||||
expression.clone().delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
),
|
||||
));
|
||||
|
||||
let logic_math_indexes_as_and_function_calls = atom.pratt((
|
||||
// Logic
|
||||
prefix(
|
||||
2,
|
||||
just(Token::Operator(Operator::Not)),
|
||||
|_, expression, span| {
|
||||
Expression::Logic(Box::new(Logic::Not(expression)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Equal)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(Box::new(Logic::Equal(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::NotEqual)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(
|
||||
Box::new(Logic::NotEqual(left, right)).with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Greater)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(Box::new(Logic::Greater(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Less)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(Box::new(Logic::Less(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::GreaterOrEqual)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(
|
||||
Box::new(Logic::GreaterOrEqual(left, right)).with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::LessOrEqual)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(
|
||||
Box::new(Logic::LessOrEqual(left, right)).with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::And)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(Box::new(Logic::And(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Or)),
|
||||
|left, _, right, span| {
|
||||
Expression::Logic(Box::new(Logic::Or(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
// Math
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Add)),
|
||||
|left, _, right, span| {
|
||||
Expression::Math(Box::new(Math::Add(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Subtract)),
|
||||
|left, _, right, span| {
|
||||
Expression::Math(Box::new(Math::Subtract(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(2),
|
||||
just(Token::Operator(Operator::Multiply)),
|
||||
|left, _, right, span| {
|
||||
Expression::Math(Box::new(Math::Multiply(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(2),
|
||||
just(Token::Operator(Operator::Divide)),
|
||||
|left, _, right, span| {
|
||||
Expression::Math(Box::new(Math::Divide(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Modulo)),
|
||||
|left, _, right, span| {
|
||||
Expression::Math(Box::new(Math::Modulo(left, right)).with_position(span))
|
||||
},
|
||||
),
|
||||
// Indexes
|
||||
infix(
|
||||
left(4),
|
||||
just(Token::Control(Control::Dot)),
|
||||
|left, _, right, span| {
|
||||
Expression::MapIndex(
|
||||
Box::new(MapIndex::new(left, right)).with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
postfix(
|
||||
3,
|
||||
expression.clone().delimited_by(
|
||||
just(Token::Control(Control::SquareOpen)),
|
||||
just(Token::Control(Control::SquareClose)),
|
||||
),
|
||||
|left, right, span| {
|
||||
Expression::ListIndex(
|
||||
Box::new(ListIndex::new(left, right)).with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
// Function call
|
||||
postfix(
|
||||
3,
|
||||
turbofish.clone().or_not().then(
|
||||
expression
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
),
|
||||
),
|
||||
|function_expression, (type_parameters, value_parameters), span| {
|
||||
Expression::FunctionCall(
|
||||
FunctionCall::new(
|
||||
function_expression,
|
||||
type_parameters,
|
||||
value_parameters,
|
||||
)
|
||||
.with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
// As
|
||||
postfix(
|
||||
2,
|
||||
just(Token::Keyword(Keyword::As)).ignore_then(type_constructor.clone()),
|
||||
|expression, constructor, span| {
|
||||
Expression::As(
|
||||
Box::new(As::new(expression, constructor)).with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
));
|
||||
|
||||
choice((
|
||||
logic_math_indexes_as_and_function_calls,
|
||||
enum_instance,
|
||||
built_in_function_call,
|
||||
range,
|
||||
function,
|
||||
list,
|
||||
map,
|
||||
basic_value,
|
||||
identifier_expression,
|
||||
))
|
||||
});
|
||||
|
||||
let expression_statement = expression
|
||||
.clone()
|
||||
.map(|expression| Statement::Expression(expression));
|
||||
|
||||
let async_block = just(Token::Keyword(Keyword::Async))
|
||||
.ignore_then(statement.clone().repeated().collect().delimited_by(
|
||||
just(Token::Control(Control::CurlyOpen)),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
))
|
||||
.map_with(|statements, state| {
|
||||
Statement::AsyncBlock(AsyncBlock::new(statements).with_position(state.span()))
|
||||
});
|
||||
|
||||
let r#break = just(Token::Keyword(Keyword::Break))
|
||||
.map_with(|_, state| Statement::Break(().with_position(state.span())));
|
||||
|
||||
let assignment = positioned_identifier
|
||||
.clone()
|
||||
.then(type_specification.clone().or_not())
|
||||
.then(choice((
|
||||
just(Token::Operator(Operator::Assign)).to(AssignmentOperator::Assign),
|
||||
just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign),
|
||||
just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign),
|
||||
)))
|
||||
.then(statement.clone())
|
||||
.map_with(|(((identifier, r#type), operator), statement), state| {
|
||||
Statement::Assignment(
|
||||
Assignment::new(identifier, r#type, operator, statement)
|
||||
.with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
let block_statement = block.clone().map(|block| Statement::Block(block));
|
||||
|
||||
let r#loop = statement
|
||||
.clone()
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Keyword(Keyword::Loop)).then(just(Token::Control(Control::CurlyOpen))),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
)
|
||||
.map_with(|statements, state| {
|
||||
Statement::Loop(Loop::new(statements).with_position(state.span()))
|
||||
});
|
||||
|
||||
let r#while = just(Token::Keyword(Keyword::While))
|
||||
.ignore_then(expression.clone())
|
||||
.then(statement.clone().repeated().collect().delimited_by(
|
||||
just(Token::Control(Control::CurlyOpen)),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
))
|
||||
.map_with(|(expression, statements), state| {
|
||||
Statement::While(While::new(expression, statements).with_position(state.span()))
|
||||
});
|
||||
|
||||
let if_else = just(Token::Keyword(Keyword::If))
|
||||
.ignore_then(expression.clone())
|
||||
.then(block.clone())
|
||||
.then(
|
||||
just(Token::Keyword(Keyword::Else))
|
||||
.ignore_then(just(Token::Keyword(Keyword::If)))
|
||||
.ignore_then(expression.clone())
|
||||
.then(block.clone())
|
||||
.repeated()
|
||||
.collect(),
|
||||
)
|
||||
.then(
|
||||
just(Token::Keyword(Keyword::Else))
|
||||
.ignore_then(block.clone())
|
||||
.or_not(),
|
||||
)
|
||||
.map_with(
|
||||
|(((if_expression, if_block), else_ifs), else_block), state| {
|
||||
Statement::IfElse(
|
||||
IfElse::new(if_expression, if_block, else_ifs, else_block)
|
||||
.with_position(state.span()),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let type_alias = just(Token::Keyword(Keyword::Type))
|
||||
.ignore_then(positioned_identifier.clone())
|
||||
.then_ignore(just(Token::Operator(Operator::Assign)))
|
||||
.then(type_constructor.clone())
|
||||
.map_with(|(identifier, constructor), state| {
|
||||
Statement::TypeAlias(
|
||||
TypeAlias::new(identifier, constructor).with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
let enum_variant = positioned_identifier
|
||||
.clone()
|
||||
.then(
|
||||
type_constructor
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.map(|(identifier, constructors)| EnumVariant {
|
||||
name: identifier,
|
||||
content: constructors,
|
||||
});
|
||||
|
||||
let enum_declaration = just(Token::Keyword(Keyword::Enum))
|
||||
.ignore_then(positioned_identifier.clone())
|
||||
.then(
|
||||
positioned_identifier
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Operator(Operator::Less)),
|
||||
just(Token::Operator(Operator::Greater)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.then(
|
||||
enum_variant
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::CurlyOpen)),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
),
|
||||
)
|
||||
.map_with(|((name, type_parameters), variants), state| {
|
||||
Statement::EnumDeclaration(
|
||||
EnumDeclaration {
|
||||
name,
|
||||
type_parameters,
|
||||
variants,
|
||||
}
|
||||
.with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
comment
|
||||
.repeated()
|
||||
.or_not()
|
||||
.ignore_then(choice((
|
||||
assignment,
|
||||
expression_statement,
|
||||
async_block,
|
||||
if_else,
|
||||
r#break,
|
||||
block_statement,
|
||||
r#loop,
|
||||
r#while,
|
||||
type_alias,
|
||||
enum_declaration,
|
||||
)))
|
||||
.then_ignore(just(Token::Control(Control::Semicolon)).or_not())
|
||||
});
|
||||
|
||||
statement.repeated().collect()
|
||||
}
|
1194
dust-lang/src/parser/tests.rs
Normal file
1194
dust-lang/src/parser/tests.rs
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user