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))
|
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
|
/// Returns an [`Expression`] AST node if the next tokens represent an
|
||||||
/// array access, struct member access, function call, or static function call expression.
|
/// array access, struct member access, function call, or static function call expression.
|
||||||
///
|
///
|
||||||
@ -449,22 +468,8 @@ impl ParserContext<'_> {
|
|||||||
span,
|
span,
|
||||||
id: self.node_builder.next_id(),
|
id: self.node_builder.next_id(),
|
||||||
}))
|
}))
|
||||||
} else if self.eat(&Token::Leo) {
|
} else if self.eat(&Token::Leo) || self.eat(&Token::Aleo) {
|
||||||
// Eat an external function call.
|
expr = self.parse_external_call(expr)?;
|
||||||
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 {
|
} else {
|
||||||
// Parse identifier name.
|
// Parse identifier name.
|
||||||
let name = self.expect_identifier()?;
|
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.
|
/// Returns a [`Program`] AST if all tokens can be consumed and represent a valid Leo program.
|
||||||
pub fn parse_program(&mut self) -> Result<Program> {
|
pub fn parse_program(&mut self) -> Result<Program> {
|
||||||
let mut imports = IndexMap::new();
|
let mut imports = IndexMap::new();
|
||||||
|
let mut stubs: IndexMap<Symbol, Stub> = IndexMap::new();
|
||||||
let mut program_scopes = IndexMap::new();
|
let mut program_scopes = IndexMap::new();
|
||||||
|
|
||||||
// TODO: Remove restrictions on multiple program scopes
|
// TODO: Remove restrictions on multiple program scopes
|
||||||
@ -36,6 +37,10 @@ impl ParserContext<'_> {
|
|||||||
let (id, import) = self.parse_import()?;
|
let (id, import) = self.parse_import()?;
|
||||||
imports.insert(id, import);
|
imports.insert(id, import);
|
||||||
}
|
}
|
||||||
|
Token::Stub => {
|
||||||
|
let (id, stub) = self.parse_stub()?;
|
||||||
|
stubs.insert(id, stub);
|
||||||
|
}
|
||||||
Token::Program => {
|
Token::Program => {
|
||||||
match parsed_program_scope {
|
match parsed_program_scope {
|
||||||
// Only one program scope is allowed per file.
|
// Only one program scope is allowed per file.
|
||||||
@ -56,7 +61,7 @@ impl ParserContext<'_> {
|
|||||||
return Err(ParserError::missing_program_scope(self.token.span).into());
|
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 {
|
fn unexpected_item(token: &SpannedToken, expected: &[Token]) -> ParserError {
|
||||||
@ -114,25 +119,20 @@ impl ParserContext<'_> {
|
|||||||
Ok((import_name.name, (program_ast.into_repr(), start + end)))
|
Ok((import_name.name, (program_ast.into_repr(), start + end)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parsers a program scope `program foo.aleo { ... }`.
|
/// Parses a program body `credits.aleo { ... }`
|
||||||
fn parse_program_scope(&mut self) -> Result<ProgramScope> {
|
fn parse_program_body(&mut self, start: Span) -> Result<ProgramScope> {
|
||||||
// Parse `program` keyword.
|
|
||||||
let start = self.expect(&Token::Program)?;
|
|
||||||
|
|
||||||
// Parse the program name.
|
// Parse the program name.
|
||||||
let name = self.expect_identifier()?;
|
let name = self.expect_identifier()?;
|
||||||
|
|
||||||
// Parse the program network.
|
// Parse the program network.
|
||||||
self.expect(&Token::Dot)?;
|
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.
|
// Construct the program id.
|
||||||
let program_id = ProgramId { name, network };
|
let program_id =
|
||||||
|
ProgramId { name, network: Identifier::new(Symbol::intern("aleo"), self.node_builder.next_id()) };
|
||||||
// Check that the program network is valid.
|
|
||||||
if network.name != sym::aleo {
|
|
||||||
return Err(ParserError::invalid_network(network.span).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse `{`.
|
// Parse `{`.
|
||||||
self.expect(&Token::LeftCurly)?;
|
self.expect(&Token::LeftCurly)?;
|
||||||
@ -183,6 +183,23 @@ impl ParserContext<'_> {
|
|||||||
Ok(ProgramScope { program_id, consts, functions, structs, mappings, span: start + end })
|
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.
|
/// Returns a [`Vec<Member>`] AST node if the next tokens represent a struct member.
|
||||||
fn parse_struct_members(&mut self) -> Result<(Vec<Member>, Span)> {
|
fn parse_struct_members(&mut self) -> Result<(Vec<Member>, Span)> {
|
||||||
let mut members = Vec::new();
|
let mut members = Vec::new();
|
||||||
@ -433,13 +450,25 @@ impl ParserContext<'_> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse the function body.
|
// Parse the function body. Allow empty blocks. `fn foo(a:u8);`
|
||||||
let block = self.parse_block()?;
|
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.
|
// Parse the `finalize` block if it exists.
|
||||||
let finalize = match self.eat(&Token::Finalize) {
|
let finalize = match self.eat(&Token::Finalize) {
|
||||||
false => None,
|
false => None,
|
||||||
true => {
|
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.
|
// Get starting span.
|
||||||
let start = self.prev_token.span;
|
let start = self.prev_token.span;
|
||||||
|
|
||||||
|
@ -379,6 +379,7 @@ impl Token {
|
|||||||
match &*identifier {
|
match &*identifier {
|
||||||
x if x.starts_with("aleo1") => Token::AddressLit(identifier),
|
x if x.starts_with("aleo1") => Token::AddressLit(identifier),
|
||||||
"address" => Token::Address,
|
"address" => Token::Address,
|
||||||
|
"aleo" => Token::Aleo,
|
||||||
"as" => Token::As,
|
"as" => Token::As,
|
||||||
"assert" => Token::Assert,
|
"assert" => Token::Assert,
|
||||||
"assert_eq" => Token::AssertEq,
|
"assert_eq" => Token::AssertEq,
|
||||||
|
@ -139,6 +139,7 @@ pub enum Token {
|
|||||||
Transition,
|
Transition,
|
||||||
|
|
||||||
// Meta Tokens
|
// Meta Tokens
|
||||||
|
Aleo,
|
||||||
Block,
|
Block,
|
||||||
Eof,
|
Eof,
|
||||||
Leo,
|
Leo,
|
||||||
@ -150,6 +151,7 @@ pub enum Token {
|
|||||||
/// because true and false are also boolean literals, which are different tokens from keywords.
|
/// because true and false are also boolean literals, which are different tokens from keywords.
|
||||||
pub const KEYWORD_TOKENS: &[Token] = &[
|
pub const KEYWORD_TOKENS: &[Token] = &[
|
||||||
Token::Address,
|
Token::Address,
|
||||||
|
Token::Aleo,
|
||||||
Token::As,
|
Token::As,
|
||||||
Token::Assert,
|
Token::Assert,
|
||||||
Token::AssertEq,
|
Token::AssertEq,
|
||||||
@ -207,6 +209,7 @@ impl Token {
|
|||||||
pub fn keyword_to_symbol(&self) -> Option<Symbol> {
|
pub fn keyword_to_symbol(&self) -> Option<Symbol> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
Token::Address => sym::address,
|
Token::Address => sym::address,
|
||||||
|
Token::Aleo => sym::aleo,
|
||||||
Token::As => sym::As,
|
Token::As => sym::As,
|
||||||
Token::Assert => sym::assert,
|
Token::Assert => sym::assert,
|
||||||
Token::AssertEq => sym::assert_eq,
|
Token::AssertEq => sym::assert_eq,
|
||||||
@ -344,6 +347,7 @@ impl fmt::Display for Token {
|
|||||||
U128 => write!(f, "u128"),
|
U128 => write!(f, "u128"),
|
||||||
Record => write!(f, "record"),
|
Record => write!(f, "record"),
|
||||||
|
|
||||||
|
Aleo => write!(f, "aleo"),
|
||||||
As => write!(f, "as"),
|
As => write!(f, "as"),
|
||||||
Assert => write!(f, "assert"),
|
Assert => write!(f, "assert"),
|
||||||
AssertEq => write!(f, "assert_eq"),
|
AssertEq => write!(f, "assert_eq"),
|
||||||
|
@ -292,6 +292,14 @@ create_messages!(
|
|||||||
help: None,
|
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
|
@formatted
|
||||||
array_must_have_at_least_one_element {
|
array_must_have_at_least_one_element {
|
||||||
args: (kind: impl Display),
|
args: (kind: impl Display),
|
||||||
|
Loading…
Reference in New Issue
Block a user