All the unimplementeds are gone!
This commit is contained in:
@@ -90,14 +90,15 @@ pub struct FunctionArg {
|
|||||||
pub struct ValueDef {
|
pub struct ValueDef {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
|
pub mtype: Option<Type>,
|
||||||
pub value: Expression,
|
pub value: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OperatorDef {
|
pub struct OperatorDef {
|
||||||
pub operator_name: Name,
|
pub operator_name: Name,
|
||||||
|
pub location: Location,
|
||||||
pub function_name: Name,
|
pub function_name: Name,
|
||||||
location: Location,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ pub enum Associativity {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of operators we use. This is only narrowly useful inside
|
||||||
|
/// this particular crate.
|
||||||
|
enum OperatorType {
|
||||||
|
Prefix,
|
||||||
|
Infix,
|
||||||
|
Postfix,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'lexer> Parser<'lexer> {
|
impl<'lexer> Parser<'lexer> {
|
||||||
/// Create a new parser from the given file index and lexer.
|
/// Create a new parser from the given file index and lexer.
|
||||||
///
|
///
|
||||||
@@ -614,12 +622,86 @@ impl<'lexer> Parser<'lexer> {
|
|||||||
/// to; that variable can be declared further on in the file or even in another module,
|
/// to; that variable can be declared further on in the file or even in another module,
|
||||||
/// as we won't try to resolve it until later.
|
/// as we won't try to resolve it until later.
|
||||||
///
|
///
|
||||||
/// Like most definitions, we'll abort cleanly if the first token isn't the "operator"
|
/// Like most definitions, we'll abort cleanly if the first token isn't "operator",
|
||||||
/// keyword, but all bets are off after that.
|
/// "infix", "postfix", or "prefix" keywords, but all bets are off after that.
|
||||||
pub fn parse_operator(&mut self) -> Result<OperatorDef, ParserError> {
|
pub fn parse_operator(&mut self) -> Result<OperatorDef, ParserError> {
|
||||||
let _operator = self.require_keyword("operator")?;
|
let (start, operator_type, associativity) = {
|
||||||
|
let mut optype = OperatorType::Infix;
|
||||||
|
let mut start = None;
|
||||||
|
let mut assoc = Associativity::None;
|
||||||
|
|
||||||
unimplemented!()
|
if let Ok(loc) = self.require_keyword("prefix") {
|
||||||
|
optype = OperatorType::Prefix;
|
||||||
|
start = Some(loc);
|
||||||
|
} else if let Ok(loc) = self.require_keyword("postfix") {
|
||||||
|
optype = OperatorType::Postfix;
|
||||||
|
start = Some(loc);
|
||||||
|
} else if let Ok(loc) = self.require_keyword("infix") {
|
||||||
|
start = Some(loc);
|
||||||
|
|
||||||
|
if self.require_keyword("right").is_ok() {
|
||||||
|
assoc = Associativity::Right;
|
||||||
|
} else if self.require_keyword("left").is_ok() {
|
||||||
|
assoc = Associativity::Left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let oploc = self.require_keyword("operator")?;
|
||||||
|
(start.unwrap_or(oploc), optype, assoc)
|
||||||
|
};
|
||||||
|
let operator_name = self.parse_operator_name("operator definition")?;
|
||||||
|
|
||||||
|
let level = if self.require_keyword("at").is_ok() {
|
||||||
|
let next = self
|
||||||
|
.next()?
|
||||||
|
.ok_or_else(|| self.bad_eof("precedence value in operator definition"))?;
|
||||||
|
|
||||||
|
match next.token {
|
||||||
|
Token::Integer(int_with_base) if int_with_base.value < 10 => {
|
||||||
|
int_with_base.value as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
Token::Integer(ref int_with_base) => {
|
||||||
|
return Err(ParserError::UnexpectedToken {
|
||||||
|
file: self.file.clone(),
|
||||||
|
span: next.span,
|
||||||
|
token: next.token.clone(),
|
||||||
|
expected: format!(
|
||||||
|
"number defining operator precedence ({} is too large",
|
||||||
|
int_with_base.value
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
return Err(ParserError::UnexpectedToken {
|
||||||
|
file: self.file.clone(),
|
||||||
|
span: next.span,
|
||||||
|
token: next.token,
|
||||||
|
expected: "number defining operator precedence".into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
5
|
||||||
|
};
|
||||||
|
|
||||||
|
let function_name = self.parse_name("operator function definition")?;
|
||||||
|
let end = self.require_token(Token::Semi, "end of operator definition")?;
|
||||||
|
|
||||||
|
match operator_type {
|
||||||
|
OperatorType::Infix => {
|
||||||
|
self.add_infix_precedence(operator_name.as_printed(), associativity, level)
|
||||||
|
}
|
||||||
|
OperatorType::Prefix => self.add_prefix_precedence(operator_name.as_printed(), level),
|
||||||
|
OperatorType::Postfix => self.add_postfix_precedence(operator_name.as_printed(), level),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(OperatorDef {
|
||||||
|
location: start.extend_to(&end),
|
||||||
|
operator_name,
|
||||||
|
function_name,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a function or a value.
|
/// Parse a function or a value.
|
||||||
@@ -648,33 +730,63 @@ impl<'lexer> Parser<'lexer> {
|
|||||||
//
|
//
|
||||||
// Or any of many variations of that.
|
// Or any of many variations of that.
|
||||||
Token::OpenParen => {
|
Token::OpenParen => {
|
||||||
unimplemented!()
|
self.save(next);
|
||||||
|
let arguments = self.parse_function_def_arguments()?;
|
||||||
|
let mut return_type = None;
|
||||||
|
|
||||||
|
if self.require_token(Token::Colon, "return type").is_ok() {
|
||||||
|
return_type = Some(self.parse_type()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Expression::Block(end, body) = self.parse_block()? else {
|
||||||
|
panic!("parse_block returned something that wasn't a block.");
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Def::Function(FunctionDef {
|
||||||
|
name,
|
||||||
|
location: start.extend_to(&end),
|
||||||
|
arguments,
|
||||||
|
return_type,
|
||||||
|
body,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we see a colon, then someone's giving us a type for what is probably
|
// If we see a colon, then someone's giving us a type for what is probably
|
||||||
// some form of simple constant, such as:
|
// some form of simple constant, such as:
|
||||||
//
|
//
|
||||||
// foo : Int = 4
|
// foo : Int = 4;
|
||||||
//
|
//
|
||||||
// But honestly, there's a lot of odd possibilities of complicated things
|
// But honestly, there's a lot of odd possibilities of complicated things
|
||||||
// they could write there.
|
// they could write there.
|
||||||
Token::Colon => {
|
Token::Colon => {
|
||||||
unimplemented!()
|
let value_type = self.parse_type()?;
|
||||||
|
let _ = self.require_operator("=")?;
|
||||||
|
let value = self.parse_expression()?;
|
||||||
|
let end = self.require_token(Token::Semi, "at end of definition")?;
|
||||||
|
|
||||||
|
Ok(Def::Value(ValueDef {
|
||||||
|
name,
|
||||||
|
location: start.extend_to(&end),
|
||||||
|
mtype: Some(value_type),
|
||||||
|
value,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we see an equal sign, we're jumping right to the value part of the
|
// If we see an equal sign, we're jumping right to the value part of the
|
||||||
// definition, and we're doing something like this:
|
// definition, and we're doing something like this:
|
||||||
//
|
//
|
||||||
// foo = 4
|
// foo = 4;
|
||||||
//
|
//
|
||||||
// Again, though, you could write all sorts of interesting things after
|
// Again, though, you could write all sorts of interesting things after
|
||||||
// that.
|
// that.
|
||||||
Token::OperatorName(eq) if eq == "=" => {
|
Token::OperatorName(eq) if eq == "=" => {
|
||||||
let value = self.parse_expression()?;
|
let value = self.parse_expression()?;
|
||||||
|
let end = self.require_token(Token::Semi, "at end of definition")?;
|
||||||
|
|
||||||
Ok(Def::Value(ValueDef {
|
Ok(Def::Value(ValueDef {
|
||||||
name,
|
name,
|
||||||
location: start.extend_to(&value.location()),
|
location: start.extend_to(&end),
|
||||||
|
mtype: None,
|
||||||
value,
|
value,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -690,6 +802,38 @@ impl<'lexer> Parser<'lexer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the arguments to a function declaration.
|
||||||
|
///
|
||||||
|
/// Function arguments should have types, but don't have to. This function assumes
|
||||||
|
/// that it's starting at the opening parenthesis, and will error (cleanly) if it
|
||||||
|
/// isn't.
|
||||||
|
fn parse_function_def_arguments(&mut self) -> Result<Vec<FunctionArg>, ParserError> {
|
||||||
|
let _ = self.require_token(Token::OpenParen, "start of function argument definition")?;
|
||||||
|
let mut result = vec![];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let next = self
|
||||||
|
.next()?
|
||||||
|
.ok_or_else(|| self.bad_eof("parsing function arguments"))?;
|
||||||
|
|
||||||
|
if matches!(next.token, Token::CloseParen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.save(next);
|
||||||
|
let name = self.parse_name("function argument name")?;
|
||||||
|
let mut arg_type = None;
|
||||||
|
|
||||||
|
if self.require_token(Token::Colon, "").is_ok() {
|
||||||
|
arg_type = Some(self.parse_type()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(FunctionArg { name, arg_type });
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a single expression out of the input stream.
|
/// Parse a single expression out of the input stream.
|
||||||
///
|
///
|
||||||
/// Because expressions can start with so many possible tokens, it's very
|
/// Because expressions can start with so many possible tokens, it's very
|
||||||
@@ -1580,4 +1724,26 @@ impl<'lexer> Parser<'lexer> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to parse an operator from the input stream.
|
||||||
|
///
|
||||||
|
/// If we don't find a name, the stream should be returned in the same state
|
||||||
|
/// at which it entered this function.
|
||||||
|
fn parse_operator_name(&mut self, place: &'static str) -> Result<Name, ParserError> {
|
||||||
|
let maybe_name = self
|
||||||
|
.next()?
|
||||||
|
.ok_or_else(|| self.bad_eof(format!("looking for a type name in {place}")))?;
|
||||||
|
|
||||||
|
if let Token::OperatorName(x) = maybe_name.token {
|
||||||
|
Ok(Name::new(self.to_location(maybe_name.span), x))
|
||||||
|
} else {
|
||||||
|
self.save(maybe_name.clone());
|
||||||
|
Err(ParserError::UnexpectedToken {
|
||||||
|
file: self.file.clone(),
|
||||||
|
span: maybe_name.span,
|
||||||
|
token: maybe_name.token,
|
||||||
|
expected: format!("looking for an operator name in {place}"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user