Support NodeID in parser; note that NodeID::default() is a placeholder

This commit is contained in:
Pranav Gaddamadugu 2023-08-09 13:09:43 -04:00
parent 5a1b9efd80
commit a819488190
5 changed files with 124 additions and 50 deletions

View File

@ -19,6 +19,7 @@ use leo_span::Span;
/// A node ID.
// Development Note:
// A `NodeID` must implement: `Copy`, `Default`, among others.
// TODO (@d0cd): Replace use of `NodeID::default()` with unique IDs in the rest of the codebase.
pub type NodeID = usize;
/// A node in the AST.

View File

@ -131,7 +131,7 @@ impl<'a> ParserContext<'a> {
/// At the previous token, return and make an identifier with `name`.
fn mk_ident_prev(&self, name: Symbol) -> Identifier {
let span = self.prev_token.span;
Identifier { name, span }
Identifier { name, span, id: NodeID::default() }
}
/// Eats the next token if its an identifier and returns it.

View File

@ -73,6 +73,7 @@ impl ParserContext<'_> {
condition: Box::new(expr),
if_true: Box::new(if_true),
if_false: Box::new(if_false),
id: NodeID::default(),
});
}
Ok(expr)
@ -85,6 +86,7 @@ impl ParserContext<'_> {
op,
left: Box::new(left),
right: Box::new(right),
id: NodeID::default(),
})
}
@ -235,7 +237,7 @@ impl ParserContext<'_> {
if self.eat(&Token::As) {
let (type_, end_span) = self.parse_primitive_type()?;
let span = expr.span() + end_span;
expr = Expression::Cast(CastExpression { expression: Box::new(expr), type_, span });
expr = Expression::Cast(CastExpression { expression: Box::new(expr), type_, span, id: NodeID::default() });
}
Ok(expr)
@ -261,19 +263,20 @@ impl ParserContext<'_> {
// If the last operation is a negation and the inner expression is a literal, then construct a negative literal.
if let Some((UnaryOperation::Negate, _)) = ops.last() {
match inner {
Expression::Literal(Literal::Integer(integer_type, string, span)) => {
Expression::Literal(Literal::Integer(integer_type, string, span, id)) => {
// Remove the negation from the operations.
// Note that this unwrap is safe because there is at least one operation in `ops`.
let (_, op_span) = ops.pop().unwrap();
// Construct a negative integer literal.
inner = Expression::Literal(Literal::Integer(integer_type, format!("-{string}"), op_span + span));
inner =
Expression::Literal(Literal::Integer(integer_type, format!("-{string}"), op_span + span, id));
}
Expression::Literal(Literal::Field(string, span)) => {
Expression::Literal(Literal::Field(string, span, id)) => {
// Remove the negation from the operations.
// Note that
let (_, op_span) = ops.pop().unwrap();
// Construct a negative field literal.
inner = Expression::Literal(Literal::Field(format!("-{string}"), op_span + span));
inner = Expression::Literal(Literal::Field(format!("-{string}"), op_span + span, id));
}
Expression::Literal(Literal::Group(group_literal)) => {
// Remove the negation from the operations.
@ -281,17 +284,17 @@ impl ParserContext<'_> {
// Construct a negative group literal.
// Note that we only handle the case where the group literal is a single integral value.
inner = Expression::Literal(Literal::Group(Box::new(match *group_literal {
GroupLiteral::Single(string, span) => {
GroupLiteral::Single(format!("-{string}"), op_span + span)
GroupLiteral::Single(string, span, id) => {
GroupLiteral::Single(format!("-{string}"), op_span + span, id)
}
GroupLiteral::Tuple(tuple) => GroupLiteral::Tuple(tuple),
})));
}
Expression::Literal(Literal::Scalar(string, span)) => {
Expression::Literal(Literal::Scalar(string, span, id)) => {
// Remove the negation from the operations.
let (_, op_span) = ops.pop().unwrap();
// Construct a negative scalar literal.
inner = Expression::Literal(Literal::Scalar(format!("-{string}"), op_span + span));
inner = Expression::Literal(Literal::Scalar(format!("-{string}"), op_span + span, id));
}
_ => (), // Do nothing.
}
@ -299,7 +302,12 @@ impl ParserContext<'_> {
// Apply the operations in reverse order, constructing a unary expression.
for (op, op_span) in ops.into_iter().rev() {
inner = Expression::Unary(UnaryExpression { span: op_span + inner.span(), op, receiver: Box::new(inner) });
inner = Expression::Unary(UnaryExpression {
span: op_span + inner.span(),
op,
receiver: Box::new(inner),
id: NodeID::default(),
});
}
Ok(inner)
@ -315,7 +323,7 @@ impl ParserContext<'_> {
if let (true, Some(op)) = (args.is_empty(), UnaryOperation::from_symbol(method.name)) {
// Found an unary operator and the argument list is empty.
Ok(Expression::Unary(UnaryExpression { span, op, receiver: Box::new(receiver) }))
Ok(Expression::Unary(UnaryExpression { span, op, receiver: Box::new(receiver), id: NodeID::default() }))
} else if let (1, Some(op)) = (args.len(), BinaryOperation::from_symbol(method.name)) {
// Found a binary operator and the argument list contains a single argument.
Ok(Expression::Binary(BinaryExpression {
@ -323,6 +331,7 @@ impl ParserContext<'_> {
op,
left: Box::new(receiver),
right: Box::new(args.swap_remove(0)),
id: NodeID::default(),
}))
} else {
// Attempt to parse the method call as a mapping operation.
@ -342,12 +351,13 @@ impl ParserContext<'_> {
arguments
},
span,
id: NodeID::default(),
})))
}
_ => {
// Either an invalid unary/binary operator, or more arguments given.
self.emit_err(ParserError::invalid_method_call(receiver, method, args.len(), span));
Ok(Expression::Err(ErrExpression { span }))
Ok(Expression::Err(ErrExpression { span, id: NodeID::default() }))
}
}
}
@ -377,6 +387,7 @@ impl ParserContext<'_> {
ty: type_,
name: member_name,
arguments: args,
id: NodeID::default(),
})
} else {
// Return the struct constant.
@ -384,6 +395,7 @@ impl ParserContext<'_> {
span: module_name.span() + member_name.span(),
ty: type_,
name: member_name,
id: NodeID::default(),
})
}))
}
@ -407,8 +419,12 @@ impl ParserContext<'_> {
if self.check_int() {
// Eat a tuple member access.
let (index, span) = self.eat_integer()?;
expr =
Expression::Access(AccessExpression::Tuple(TupleAccess { tuple: Box::new(expr), index, span }))
expr = Expression::Access(AccessExpression::Tuple(TupleAccess {
tuple: Box::new(expr),
index,
span,
id: NodeID::default(),
}))
} else if self.eat(&Token::Leo) {
// Eat an external function call.
self.eat(&Token::Div); // todo: Make `/` a more general token.
@ -423,6 +439,7 @@ impl ParserContext<'_> {
function: Box::new(Expression::Identifier(name)),
external: Some(Box::new(expr)),
arguments,
id: NodeID::default(),
});
} else {
// Parse identifier name.
@ -437,6 +454,7 @@ impl ParserContext<'_> {
span: expr.span() + name.span(),
inner: Box::new(expr),
name,
id: NodeID::default(),
}))
}
}
@ -451,6 +469,7 @@ impl ParserContext<'_> {
function: Box::new(expr),
external: None,
arguments,
id: NodeID::default(),
});
}
// Check if next token is a dot to see if we are calling recursive method.
@ -472,7 +491,7 @@ impl ParserContext<'_> {
match elements.len() {
// If the tuple expression is empty, return a `UnitExpression`.
0 => Ok(Expression::Unit(UnitExpression { span })),
0 => Ok(Expression::Unit(UnitExpression { span, id: NodeID::default() })),
1 => match trailing {
// If there is one element in the tuple but no trailing comma, e.g `(foo)`, return the element.
false => Ok(elements.swap_remove(0)),
@ -481,7 +500,7 @@ impl ParserContext<'_> {
},
// Otherwise, return a tuple expression.
// Note: This is the only place where `TupleExpression` is constructed in the parser.
_ => Ok(Expression::Tuple(TupleExpression { elements, span })),
_ => Ok(Expression::Tuple(TupleExpression { elements, span, id: NodeID::default() })),
}
}
@ -529,7 +548,7 @@ impl ParserContext<'_> {
let end_span = check_ahead(dist, &Token::Group)?;
dist += 1; // Standing at `)` so advance one for 'group'.
let gt = GroupTuple { span: start_span + &end_span, x: first_gc, y: second_gc };
let gt = GroupTuple { span: start_span + &end_span, x: first_gc, y: second_gc, id: NodeID::default() };
// Eat everything so that this isn't just peeking.
for _ in 0..dist {
@ -559,7 +578,7 @@ impl ParserContext<'_> {
None
};
Ok(StructVariableInitializer { identifier, expression })
Ok(StructVariableInitializer { identifier, expression, id: NodeID::default() })
}
/// Returns an [`Expression`] AST node if the next tokens represent a
@ -569,7 +588,12 @@ impl ParserContext<'_> {
let (members, _, end) =
self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| p.parse_struct_member().map(Some))?;
Ok(Expression::Struct(StructExpression { span: identifier.span + end, name: identifier, members }))
Ok(Expression::Struct(StructExpression {
span: identifier.span + end,
name: identifier,
members,
id: NodeID::default(),
}))
}
/// Returns an [`Expression`] AST node if the next token is a primary expression:
@ -596,38 +620,42 @@ impl ParserContext<'_> {
// Literal followed by `field`, e.g., `42field`.
Some(Token::Field) => {
assert_no_whitespace("field")?;
Expression::Literal(Literal::Field(value, full_span))
Expression::Literal(Literal::Field(value, full_span, NodeID::default()))
}
// Literal followed by `group`, e.g., `42group`.
Some(Token::Group) => {
assert_no_whitespace("group")?;
Expression::Literal(Literal::Group(Box::new(GroupLiteral::Single(value, full_span))))
Expression::Literal(Literal::Group(Box::new(GroupLiteral::Single(
value,
full_span,
NodeID::default(),
))))
}
// Literal followed by `scalar` e.g., `42scalar`.
Some(Token::Scalar) => {
assert_no_whitespace("scalar")?;
Expression::Literal(Literal::Scalar(value, full_span))
Expression::Literal(Literal::Scalar(value, full_span, NodeID::default()))
}
// Literal followed by other type suffix, e.g., `42u8`.
Some(suffix) => {
assert_no_whitespace(&suffix.to_string())?;
let int_ty = Self::token_to_int_type(suffix).expect("unknown int type token");
Expression::Literal(Literal::Integer(int_ty, value, full_span))
Expression::Literal(Literal::Integer(int_ty, value, full_span, NodeID::default()))
}
None => return Err(ParserError::implicit_values_not_allowed(value, span).into()),
}
}
Token::True => Expression::Literal(Literal::Boolean(true, span)),
Token::False => Expression::Literal(Literal::Boolean(false, span)),
Token::True => Expression::Literal(Literal::Boolean(true, span, NodeID::default())),
Token::False => Expression::Literal(Literal::Boolean(false, span, NodeID::default())),
Token::AddressLit(address_string) => {
if address_string.parse::<Address<Testnet3>>().is_err() {
self.emit_err(ParserError::invalid_address_lit(&address_string, span));
}
Expression::Literal(Literal::Address(address_string, span))
Expression::Literal(Literal::Address(address_string, span, NodeID::default()))
}
Token::StaticString(value) => Expression::Literal(Literal::String(value, span)),
Token::StaticString(value) => Expression::Literal(Literal::String(value, span, NodeID::default())),
Token::Identifier(name) => {
let ident = Identifier { name, span };
let ident = Identifier { name, span, id: NodeID::default() };
if !self.disallow_struct_construction && self.check(&Token::LeftCurly) {
// Parse struct and records inits as struct expressions.
// Enforce struct or record type later at type checking.
@ -636,10 +664,12 @@ impl ParserContext<'_> {
Expression::Identifier(ident)
}
}
Token::SelfLower => Expression::Identifier(Identifier { name: sym::SelfLower, span }),
Token::Block => Expression::Identifier(Identifier { name: sym::block, span }),
Token::SelfLower => {
Expression::Identifier(Identifier { name: sym::SelfLower, span, id: NodeID::default() })
}
Token::Block => Expression::Identifier(Identifier { name: sym::block, span, id: NodeID::default() }),
t if crate::type_::TYPE_TOKENS.contains(&t) => {
Expression::Identifier(Identifier { name: t.keyword_to_symbol().unwrap(), span })
Expression::Identifier(Identifier { name: t.keyword_to_symbol().unwrap(), span, id: NodeID::default() })
}
token => {
return Err(ParserError::unexpected_str(token, "expression", span).into());

View File

@ -223,7 +223,7 @@ impl ParserContext<'_> {
let (identifier, type_, span) = self.parse_typed_ident()?;
Ok(Member { mode, identifier, type_, span })
Ok(Member { mode, identifier, type_, span, id: NodeID::default() })
}
/// Parses a struct or record definition, e.g., `struct Foo { ... }` or `record Foo { ... }`.
@ -235,7 +235,13 @@ impl ParserContext<'_> {
self.expect(&Token::LeftCurly)?;
let (members, end) = self.parse_struct_members()?;
Ok((struct_name.name, Struct { identifier: struct_name, members, is_record, span: start + end }))
Ok((struct_name.name, Struct {
identifier: struct_name,
members,
is_record,
span: start + end,
id: NodeID::default(),
}))
}
/// Parses a mapping declaration, e.g. `mapping balances: address => u128`.
@ -247,7 +253,7 @@ impl ParserContext<'_> {
self.expect(&Token::BigArrow)?;
let (value_type, _) = self.parse_type()?;
let end = self.expect(&Token::Semicolon)?;
Ok((identifier.name, Mapping { identifier, key_type, value_type, span: start + end }))
Ok((identifier.name, Mapping { identifier, key_type, value_type, span: start + end, id: NodeID::default() }))
}
// TODO: Return a span associated with the mode.
@ -298,11 +304,23 @@ impl ParserContext<'_> {
self.eat(&Token::Record);
span = span + self.prev_token.span;
Ok(functions::Input::External(External { identifier: name, program_name: external, record, span }))
Ok(functions::Input::External(External {
identifier: name,
program_name: external,
record,
span,
id: NodeID::default(),
}))
} else {
let type_ = self.parse_type()?.0;
Ok(functions::Input::Internal(FunctionInput { identifier: name, mode, type_, span: name.span }))
Ok(functions::Input::Internal(FunctionInput {
identifier: name,
mode,
type_,
span: name.span,
id: NodeID::default(),
}))
}
}
@ -311,7 +329,7 @@ impl ParserContext<'_> {
// TODO: Could this span be made more accurate?
let mode = self.parse_mode()?;
let (type_, span) = self.parse_type()?;
Ok(FunctionOutput { mode, type_, span })
Ok(FunctionOutput { mode, type_, span, id: NodeID::default() })
}
/// Returns a [`Output`] AST node if the next tokens represent a function output.
@ -338,6 +356,7 @@ impl ParserContext<'_> {
program_name: external,
record,
span,
id: NodeID::default(),
}))
} else {
Ok(Output::Internal(self.parse_function_output()?))
@ -353,7 +372,9 @@ impl ParserContext<'_> {
// Parse the `@` symbol and identifier.
let start = self.expect(&Token::At)?;
let identifier = match self.token.token {
Token::Program => Identifier { name: sym::program, span: self.expect(&Token::Program)? },
Token::Program => {
Identifier { name: sym::program, span: self.expect(&Token::Program)?, id: NodeID::default() }
}
_ => self.expect_identifier()?,
};
let span = start + identifier.span;
@ -362,7 +383,7 @@ impl ParserContext<'_> {
// Check that there is no whitespace in between the `@` symbol and identifier.
match identifier.span.hi.0 - start.lo.0 > 1 + identifier.name.to_string().len() as u32 {
true => Err(ParserError::space_in_annotation(span).into()),
false => Ok(Annotation { identifier, span }),
false => Ok(Annotation { identifier, span, id: NodeID::default() }),
}
}

View File

@ -82,7 +82,7 @@ impl ParserContext<'_> {
self.expect(&Token::Semicolon)?;
// Return the assertion statement.
Ok(Statement::Assert(AssertStatement { variant, span }))
Ok(Statement::Assert(AssertStatement { variant, span, id: NodeID::default() }))
}
/// Returns a [`AssignStatement`] AST node if the next tokens represent a assign, otherwise expects an expression statement.
@ -124,10 +124,11 @@ impl ParserContext<'_> {
right: Box::new(value),
op,
span,
id: NodeID::default(),
}),
};
Ok(Statement::Assign(Box::new(AssignStatement { span, place, value })))
Ok(Statement::Assign(Box::new(AssignStatement { span, place, value, id: NodeID::default() })))
} else {
// Check for `increment` and `decrement` statements. If found, emit a deprecation warning.
if let Expression::Call(call_expression) = &place {
@ -152,14 +153,21 @@ impl ParserContext<'_> {
// Parse the expression as a statement.
let end = self.expect(&Token::Semicolon)?;
Ok(Statement::Expression(ExpressionStatement { span: place.span() + end, expression: place }))
Ok(Statement::Expression(ExpressionStatement {
span: place.span() + end,
expression: place,
id: NodeID::default(),
}))
}
}
/// Returns a [`Block`] AST node if the next tokens represent a block of statements.
pub(super) fn parse_block(&mut self) -> Result<Block> {
self.parse_list(Delimiter::Brace, None, |p| p.parse_statement().map(Some))
.map(|(statements, _, span)| Block { statements, span })
self.parse_list(Delimiter::Brace, None, |p| p.parse_statement().map(Some)).map(|(statements, _, span)| Block {
statements,
span,
id: NodeID::default(),
})
}
/// Returns a [`ReturnStatement`] AST node if the next tokens represent a return statement.
@ -168,7 +176,9 @@ impl ParserContext<'_> {
let expression = match self.token.token {
// If the next token is a semicolon, implicitly return a unit expression, `()`.
Token::Semicolon | Token::Then => Expression::Unit(UnitExpression { span: self.token.span }),
Token::Semicolon | Token::Then => {
Expression::Unit(UnitExpression { span: self.token.span, id: NodeID::default() })
}
// Otherwise, attempt to parse an expression.
_ => self.parse_expression()?,
};
@ -190,7 +200,7 @@ impl ParserContext<'_> {
};
let end = self.expect(&Token::Semicolon)?;
let span = start + end;
Ok(ReturnStatement { span, expression, finalize_arguments: finalize_args })
Ok(ReturnStatement { span, expression, finalize_arguments: finalize_args, id: NodeID::default() })
}
/// Returns a [`ConditionalStatement`] AST node if the next tokens represent a conditional statement.
@ -215,6 +225,7 @@ impl ParserContext<'_> {
condition: expr,
then: body,
otherwise: next,
id: NodeID::default(),
})
}
@ -245,6 +256,7 @@ impl ParserContext<'_> {
stop_value: Default::default(),
inclusive: false,
block,
id: NodeID::default(),
})
}
@ -286,13 +298,16 @@ impl ParserContext<'_> {
));
(
Default::default(),
ConsoleFunction::Assert(Expression::Err(ErrExpression { span: Default::default() })),
ConsoleFunction::Assert(Expression::Err(ErrExpression {
span: Default::default(),
id: NodeID::default(),
})),
)
}
};
self.expect(&Token::Semicolon)?;
Ok(ConsoleStatement { span: keyword + span, function })
Ok(ConsoleStatement { span: keyword + span, function, id: NodeID::default() })
}
/// Returns a [`DefinitionStatement`] AST node if the next tokens represent a definition statement.
@ -314,6 +329,13 @@ impl ParserContext<'_> {
let value = self.parse_expression()?;
self.expect(&Token::Semicolon)?;
Ok(DefinitionStatement { span: decl_span + value.span(), declaration_type: decl_type, place, type_, value })
Ok(DefinitionStatement {
span: decl_span + value.span(),
declaration_type: decl_type,
place,
type_,
value,
id: NodeID::default(),
})
}
}