mirror of
https://github.com/AleoHQ/leo.git
synced 2024-09-21 03:57:39 +03:00
usage changes
This commit is contained in:
parent
c3c5ff152e
commit
278f59bba7
@ -434,7 +434,11 @@ pub trait ProgramReconstructor: StatementReconstructor {
|
||||
structs: input.structs,
|
||||
mappings: input.mappings,
|
||||
span: input.span,
|
||||
functions: input.functions.into_iter().map(|(i, f)| (i, self.reconstruct_function_stub(f))).collect(),
|
||||
functions: input
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|(i, f)| (i, self.reconstruct_function_stub(f, input.stub_id)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,7 +483,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_function_stub(&mut self, input: FunctionStub) -> FunctionStub {
|
||||
fn reconstruct_function_stub(&mut self, input: FunctionStub, _program: ProgramId) -> FunctionStub {
|
||||
input
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
//! given the type of node its visiting.
|
||||
|
||||
use crate::*;
|
||||
use leo_span::Symbol;
|
||||
|
||||
/// A Visitor trait for expressions in the AST.
|
||||
pub trait ExpressionVisitor<'a> {
|
||||
@ -253,7 +254,7 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_function_stub(&mut self, _input: &'a FunctionStub) {}
|
||||
fn visit_function_stub(&mut self, _input: &'a FunctionStub, _program: ProgramId) {}
|
||||
|
||||
fn visit_struct_stub(&mut self, _input: &'a Struct) {}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
use crate::Identifier;
|
||||
|
||||
use core::fmt;
|
||||
use leo_span::Symbol;
|
||||
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use snarkvm::{console::program::ProgramID, prelude::Network};
|
||||
use std::collections::BTreeMap;
|
||||
@ -99,3 +100,12 @@ impl<N: Network> From<&ProgramID<N>> for ProgramId {
|
||||
Self { name: Identifier::from(program.name()), network: Identifier::from(program.network()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Identifier> for ProgramId {
|
||||
fn from(name: Identifier) -> Self {
|
||||
Self {
|
||||
name,
|
||||
network: Identifier { name: Symbol::intern("aleo"), span: Default::default(), id: Default::default() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ impl<'a> ExpressionVisitor<'a> for CheckUniqueNodeIds<'a> {
|
||||
self.visit_expression(argument, &Default::default());
|
||||
}
|
||||
if let Some(external) = external {
|
||||
self.visit_expression(external, &Default::default());
|
||||
self.visit_identifier(&external.name, &Default::default());
|
||||
}
|
||||
self.check(*id);
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ 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()`
|
||||
// Parses an external 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.
|
||||
@ -439,10 +439,17 @@ impl ParserContext<'_> {
|
||||
|
||||
// Parse the function call.
|
||||
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
|
||||
|
||||
// Parse the parent program identifier.
|
||||
let program: Option<ProgramId> = match expr {
|
||||
Expression::Identifier(identifier) => Some(ProgramId::from(identifier)),
|
||||
_ => unreachable!("Function called must be preceded by a program identifier."),
|
||||
};
|
||||
|
||||
Ok(Expression::Call(CallExpression {
|
||||
span: expr.span() + span,
|
||||
function: Box::new(Expression::Identifier(name)),
|
||||
external: Some(Box::new(expr)),
|
||||
external: program,
|
||||
arguments,
|
||||
id: self.node_builder.next_id(),
|
||||
}))
|
||||
|
@ -39,7 +39,7 @@ use leo_ast::{
|
||||
UnaryOperation,
|
||||
UnitExpression,
|
||||
};
|
||||
use leo_span::sym;
|
||||
use leo_span::{sym, Symbol};
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use std::fmt::Write as _;
|
||||
@ -524,10 +524,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
Some(external) => {
|
||||
// If the function is an external call, then check whether or not it has an associated finalize block.
|
||||
// Extract the program name from the external call.
|
||||
let program_name = match **external {
|
||||
Expression::Identifier(identifier) => identifier.name,
|
||||
_ => unreachable!("Parsing guarantees that a program name is always an identifier."),
|
||||
};
|
||||
let program_name: Symbol = external.name.name;
|
||||
let stub_scope: ProgramScope;
|
||||
// Lookup the imported program scope.
|
||||
// TODO: Needs refactor. All imports are stubs now.
|
||||
@ -557,7 +554,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
Some((_, function)) => function.finalize.is_some(),
|
||||
None => unreachable!("Type checking guarantees that imported functions are well defined."),
|
||||
};
|
||||
(format!(" call {external}.aleo/{}", input.function), has_finalize)
|
||||
(format!(" call {external}/{}", input.function), has_finalize)
|
||||
}
|
||||
None => (format!(" call {}", input.function), false),
|
||||
};
|
||||
@ -578,7 +575,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
// Initialize storage for the destination registers.
|
||||
let mut destinations = Vec::new();
|
||||
|
||||
let return_type = &self.symbol_table.lookup_fn_symbol(function_name).unwrap().output_type;
|
||||
let return_type = &self.symbol_table.lookup_fn_symbol(function_name, input.external).unwrap().output_type;
|
||||
match return_type {
|
||||
Type::Unit => {} // Do nothing
|
||||
Type::Tuple(tuple) => match tuple.length() {
|
||||
@ -607,14 +604,9 @@ impl<'a> CodeGenerator<'a> {
|
||||
let future_register = format!("r{}", self.next_register);
|
||||
self.next_register += 1;
|
||||
|
||||
// Construct the future type.
|
||||
let program_id = match input.external.as_deref() {
|
||||
Some(Expression::Identifier(identifier)) => identifier,
|
||||
_ => unreachable!("If `has_finalize` is true, then the external call must be an identifier."),
|
||||
};
|
||||
|
||||
// Add the futures register to the list of futures.
|
||||
self.futures.push((future_register.clone(), format!("{program_id}.aleo/{function_name}")));
|
||||
self.futures
|
||||
.push((future_register.clone(), format!("{}.aleo/{function_name}", input.external.unwrap().name)));
|
||||
|
||||
// Add the future register to the list of destinations.
|
||||
destinations.push(future_register);
|
||||
|
@ -35,10 +35,11 @@ impl ProgramReconstructor for Unroller<'_> {
|
||||
}
|
||||
|
||||
// Don't need to reconstruct anything, just need to add child scopes for constant propagation table
|
||||
fn reconstruct_function_stub(&mut self, input: FunctionStub) -> FunctionStub {
|
||||
fn reconstruct_function_stub(&mut self, input: FunctionStub, program: ProgramId) -> FunctionStub {
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(input.identifier.name).unwrap().id;
|
||||
let function_index =
|
||||
self.symbol_table.borrow().lookup_fn_symbol(input.identifier.name, Some(program)).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
let previous_function_index = self.enter_scope(function_index);
|
||||
@ -52,7 +53,7 @@ impl ProgramReconstructor for Unroller<'_> {
|
||||
fn reconstruct_function(&mut self, function: Function) -> Function {
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name).unwrap().id;
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name, None).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
let previous_function_index = self.enter_scope(function_index);
|
||||
|
@ -68,19 +68,20 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
|
||||
}
|
||||
|
||||
fn visit_function(&mut self, input: &'a Function) {
|
||||
if let Err(err) = self.symbol_table.insert_fn(input.name(), input) {
|
||||
if let Err(err) = self.symbol_table.insert_fn(input.name(), None, input) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_stub(&mut self, input: &'a Stub) {
|
||||
input.functions.iter().for_each(|(_, c)| (self.visit_function_stub(c)));
|
||||
input.functions.iter().for_each(|(_, c)| (self.visit_function_stub(c, input.stub_id)));
|
||||
|
||||
input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
|
||||
}
|
||||
|
||||
fn visit_function_stub(&mut self, input: &'a FunctionStub) {
|
||||
if let Err(err) = self.symbol_table.insert_fn(input.name(), &Function::from(input.clone())) {
|
||||
fn visit_function_stub(&mut self, input: &'a FunctionStub, program_name: ProgramId) {
|
||||
if let Err(err) = self.symbol_table.insert_fn(input.name(), Some(program_name), &Function::from(input.clone()))
|
||||
{
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
|
@ -566,8 +566,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
Expression::Identifier(ident) => {
|
||||
// Note: The function symbol lookup is performed outside of the `if let Some(func) ...` block to avoid a RefCell lifetime bug in Rust.
|
||||
// Do not move it into the `if let Some(func) ...` block or it will keep `self.symbol_table_creation` alive for the entire block and will be very memory inefficient!
|
||||
let func = self.symbol_table.borrow().lookup_fn_symbol(ident.name).cloned();
|
||||
|
||||
let func = self.symbol_table.borrow().lookup_fn_symbol(ident.name, input.external).cloned();
|
||||
if let Some(func) = func {
|
||||
// Check that the call is valid.
|
||||
// Note that this unwrap is safe since we always set the variant before traversing the body of the function.
|
||||
@ -614,7 +613,12 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
None => unreachable!("`self.function` is set every time a function is visited."),
|
||||
Some(func) => func,
|
||||
};
|
||||
self.call_graph.add_edge(caller_name, ident.name);
|
||||
|
||||
// Don't add external functions to call graph.
|
||||
// We check that there is no dependency cycle of imports, so we know that external functions can never lead to a call graph cycle
|
||||
if input.external.is_none() {
|
||||
self.call_graph.add_edge(caller_name, ident.name);
|
||||
}
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
|
@ -55,10 +55,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
input.structs.iter().for_each(|(_, function)| self.visit_struct_stub(function));
|
||||
|
||||
// Typecheck the program's functions.
|
||||
input.functions.iter().for_each(|(_, function)| self.visit_function_stub(function));
|
||||
input.functions.iter().for_each(|(_, function)| self.visit_function_stub(function, input.stub_id));
|
||||
}
|
||||
|
||||
fn visit_function_stub(&mut self, input: &'a FunctionStub) {
|
||||
fn visit_function_stub(&mut self, input: &'a FunctionStub, program: ProgramId) {
|
||||
// Must not be an inline function
|
||||
if input.variant == Variant::Inline {
|
||||
self.emit_err(TypeCheckerError::stub_functions_must_not_be_inlines(input.span));
|
||||
@ -66,7 +66,8 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(input.identifier.name).unwrap().id;
|
||||
let function_index =
|
||||
self.symbol_table.borrow().lookup_fn_symbol(input.identifier.name, Some(program)).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
self.enter_scope(function_index);
|
||||
@ -269,7 +270,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name).unwrap().id;
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name, None).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
self.enter_scope(function_index);
|
||||
|
@ -372,7 +372,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// We can safely unwrap all self.parent instances because
|
||||
// statements should always have some parent block
|
||||
let parent = self.function.unwrap();
|
||||
let return_type = &self.symbol_table.borrow().lookup_fn_symbol(parent).map(|f| match self.is_finalize {
|
||||
let return_type = &self.symbol_table.borrow().lookup_fn_symbol(parent, None).map(|f| match self.is_finalize {
|
||||
// TODO: Check this.
|
||||
// Note that this `unwrap()` is safe since we checked that the function has a finalize block.
|
||||
true => f.finalize.as_ref().unwrap().output_type.clone(),
|
||||
@ -410,7 +410,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// Note that `self.function.unwrap()` is safe since every `self.function` is set for every function.
|
||||
// Note that `(self.function.unwrap()).unwrap()` is safe since all functions have been checked to exist.
|
||||
let finalize =
|
||||
self.symbol_table.borrow().lookup_fn_symbol(self.function.unwrap()).unwrap().finalize.clone();
|
||||
self.symbol_table.borrow().lookup_fn_symbol(self.function.unwrap(), None).unwrap().finalize.clone();
|
||||
match finalize {
|
||||
None => self.emit_err(TypeCheckerError::finalize_without_finalize_block(input.span())),
|
||||
Some(finalize) => {
|
||||
|
Loading…
Reference in New Issue
Block a user