mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 11:12:48 +03:00
error msgs
This commit is contained in:
parent
cf7baa0132
commit
292f890369
@ -429,6 +429,25 @@ impl ParserContext<'_> {
|
||||
self.parse_paren_comma_list(|p| p.parse_expression().map(Some))
|
||||
}
|
||||
|
||||
// Parses an externa function call `credits.aleo/transfer()` or `board.leo/make_move()`
|
||||
fn parse_external_call(&mut self, expr: Expression) -> Result<Expression> {
|
||||
// Eat an external function call.
|
||||
self.eat(&Token::Div); // todo: Make `/` a more general token.
|
||||
|
||||
// Parse function name.
|
||||
let name = self.expect_identifier()?;
|
||||
|
||||
// Parse the function call.
|
||||
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
|
||||
Ok(Expression::Call(CallExpression {
|
||||
span: expr.span() + span,
|
||||
function: Box::new(Expression::Identifier(name)),
|
||||
external: Some(Box::new(expr)),
|
||||
arguments,
|
||||
id: self.node_builder.next_id(),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Returns an [`Expression`] AST node if the next tokens represent an
|
||||
/// array access, struct member access, function call, or static function call expression.
|
||||
///
|
||||
@ -449,22 +468,8 @@ impl ParserContext<'_> {
|
||||
span,
|
||||
id: self.node_builder.next_id(),
|
||||
}))
|
||||
} else if self.eat(&Token::Leo) {
|
||||
// Eat an external function call.
|
||||
self.eat(&Token::Div); // todo: Make `/` a more general token.
|
||||
|
||||
// Parse function name.
|
||||
let name = self.expect_identifier()?;
|
||||
|
||||
// Parse the function call.
|
||||
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
|
||||
expr = Expression::Call(CallExpression {
|
||||
span: expr.span() + span,
|
||||
function: Box::new(Expression::Identifier(name)),
|
||||
external: Some(Box::new(expr)),
|
||||
arguments,
|
||||
id: self.node_builder.next_id(),
|
||||
});
|
||||
} else if self.eat(&Token::Leo) || self.eat(&Token::Aleo) {
|
||||
expr = self.parse_external_call(expr)?;
|
||||
} else {
|
||||
// Parse identifier name.
|
||||
let name = self.expect_identifier()?;
|
||||
|
@ -25,6 +25,7 @@ impl ParserContext<'_> {
|
||||
/// Returns a [`Program`] AST if all tokens can be consumed and represent a valid Leo program.
|
||||
pub fn parse_program(&mut self) -> Result<Program> {
|
||||
let mut imports = IndexMap::new();
|
||||
let mut stubs: IndexMap<Symbol, Stub> = IndexMap::new();
|
||||
let mut program_scopes = IndexMap::new();
|
||||
|
||||
// TODO: Remove restrictions on multiple program scopes
|
||||
@ -36,6 +37,10 @@ impl ParserContext<'_> {
|
||||
let (id, import) = self.parse_import()?;
|
||||
imports.insert(id, import);
|
||||
}
|
||||
Token::Stub => {
|
||||
let (id, stub) = self.parse_stub()?;
|
||||
stubs.insert(id, stub);
|
||||
}
|
||||
Token::Program => {
|
||||
match parsed_program_scope {
|
||||
// Only one program scope is allowed per file.
|
||||
@ -56,7 +61,7 @@ impl ParserContext<'_> {
|
||||
return Err(ParserError::missing_program_scope(self.token.span).into());
|
||||
}
|
||||
|
||||
Ok(Program { imports, program_scopes })
|
||||
Ok(Program { imports, stubs, program_scopes })
|
||||
}
|
||||
|
||||
fn unexpected_item(token: &SpannedToken, expected: &[Token]) -> ParserError {
|
||||
@ -114,25 +119,20 @@ impl ParserContext<'_> {
|
||||
Ok((import_name.name, (program_ast.into_repr(), start + end)))
|
||||
}
|
||||
|
||||
/// Parsers a program scope `program foo.aleo { ... }`.
|
||||
fn parse_program_scope(&mut self) -> Result<ProgramScope> {
|
||||
// Parse `program` keyword.
|
||||
let start = self.expect(&Token::Program)?;
|
||||
|
||||
/// Parses a program body `credits.aleo { ... }`
|
||||
fn parse_program_body(&mut self, start: Span) -> Result<ProgramScope> {
|
||||
// Parse the program name.
|
||||
let name = self.expect_identifier()?;
|
||||
|
||||
// Parse the program network.
|
||||
self.expect(&Token::Dot)?;
|
||||
let network = self.expect_identifier()?;
|
||||
|
||||
// Otherwise throw parser error
|
||||
self.expect(&Token::Aleo).or_else(|_| Err(ParserError::invalid_network(self.token.span)))?;
|
||||
|
||||
// Construct the program id.
|
||||
let program_id = ProgramId { name, network };
|
||||
|
||||
// Check that the program network is valid.
|
||||
if network.name != sym::aleo {
|
||||
return Err(ParserError::invalid_network(network.span).into());
|
||||
}
|
||||
let program_id =
|
||||
ProgramId { name, network: Identifier::new(Symbol::intern("aleo"), self.node_builder.next_id()) };
|
||||
|
||||
// Parse `{`.
|
||||
self.expect(&Token::LeftCurly)?;
|
||||
@ -183,6 +183,23 @@ impl ParserContext<'_> {
|
||||
Ok(ProgramScope { program_id, consts, functions, structs, mappings, span: start + end })
|
||||
}
|
||||
|
||||
/// Parses a stub `stub credits.aleo { ... }`.
|
||||
fn parse_stub(&mut self) -> Result<(Symbol, Stub)> {
|
||||
// Parse `stub` keyword.
|
||||
let start = self.expect(&Token::Stub)?;
|
||||
let stub = Stub::from(self.parse_program_body(start)?);
|
||||
|
||||
Ok((stub.stub_id.name.name, stub))
|
||||
}
|
||||
|
||||
/// Parses a program scope `program foo.aleo { ... }`.
|
||||
fn parse_program_scope(&mut self) -> Result<ProgramScope> {
|
||||
// Parse `program` keyword.
|
||||
let start = self.expect(&Token::Program)?;
|
||||
|
||||
self.parse_program_body(start)
|
||||
}
|
||||
|
||||
/// Returns a [`Vec<Member>`] AST node if the next tokens represent a struct member.
|
||||
fn parse_struct_members(&mut self) -> Result<(Vec<Member>, Span)> {
|
||||
let mut members = Vec::new();
|
||||
@ -433,13 +450,25 @@ impl ParserContext<'_> {
|
||||
}
|
||||
};
|
||||
|
||||
// Parse the function body.
|
||||
let block = self.parse_block()?;
|
||||
// Parse the function body. Allow empty blocks. `fn foo(a:u8);`
|
||||
let (has_empty_block, block) = match &self.token.token {
|
||||
Token::LeftCurly => (false, self.parse_block()?),
|
||||
Token::Semicolon => {
|
||||
let semicolon = self.expect(&Token::Semicolon)?;
|
||||
(true, Block { statements: Vec::new(), span: semicolon, id: self.node_builder.next_id() })
|
||||
}
|
||||
_ => self.unexpected("block or semicolon")?,
|
||||
};
|
||||
|
||||
// Parse the `finalize` block if it exists.
|
||||
let finalize = match self.eat(&Token::Finalize) {
|
||||
false => None,
|
||||
true => {
|
||||
// Make sure has function body. Don't want `fn foo(); finalize foo { ... }` to be valid parsing.
|
||||
if has_empty_block {
|
||||
return Err(ParserError::empty_function_cannot_have_finalize(self.token.span).into());
|
||||
}
|
||||
|
||||
// Get starting span.
|
||||
let start = self.prev_token.span;
|
||||
|
||||
|
@ -379,6 +379,7 @@ impl Token {
|
||||
match &*identifier {
|
||||
x if x.starts_with("aleo1") => Token::AddressLit(identifier),
|
||||
"address" => Token::Address,
|
||||
"aleo" => Token::Aleo,
|
||||
"as" => Token::As,
|
||||
"assert" => Token::Assert,
|
||||
"assert_eq" => Token::AssertEq,
|
||||
|
@ -139,6 +139,7 @@ pub enum Token {
|
||||
Transition,
|
||||
|
||||
// Meta Tokens
|
||||
Aleo,
|
||||
Block,
|
||||
Eof,
|
||||
Leo,
|
||||
@ -150,6 +151,7 @@ pub enum Token {
|
||||
/// because true and false are also boolean literals, which are different tokens from keywords.
|
||||
pub const KEYWORD_TOKENS: &[Token] = &[
|
||||
Token::Address,
|
||||
Token::Aleo,
|
||||
Token::As,
|
||||
Token::Assert,
|
||||
Token::AssertEq,
|
||||
@ -207,6 +209,7 @@ impl Token {
|
||||
pub fn keyword_to_symbol(&self) -> Option<Symbol> {
|
||||
Some(match self {
|
||||
Token::Address => sym::address,
|
||||
Token::Aleo => sym::aleo,
|
||||
Token::As => sym::As,
|
||||
Token::Assert => sym::assert,
|
||||
Token::AssertEq => sym::assert_eq,
|
||||
@ -344,6 +347,7 @@ impl fmt::Display for Token {
|
||||
U128 => write!(f, "u128"),
|
||||
Record => write!(f, "record"),
|
||||
|
||||
Aleo => write!(f, "aleo"),
|
||||
As => write!(f, "as"),
|
||||
Assert => write!(f, "assert"),
|
||||
AssertEq => write!(f, "assert_eq"),
|
||||
|
@ -292,6 +292,14 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Enforce that empty functions cannot have finalize functions attached to them
|
||||
@formatted
|
||||
empty_function_cannot_have_finalize {
|
||||
args: (),
|
||||
msg: format!("Empty functions cannot have finalize functions attached to them."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
array_must_have_at_least_one_element {
|
||||
args: (kind: impl Display),
|
||||
|
Loading…
Reference in New Issue
Block a user