Skip to content

Commit

Permalink
Merge pull request #27857 from AleoHQ/feat/external-mapping
Browse files Browse the repository at this point in the history
[Feat] External mapping
  • Loading branch information
evan-schott authored Mar 29, 2024
2 parents 4a3e89f + f61cfd3 commit 87086a0
Show file tree
Hide file tree
Showing 57 changed files with 923 additions and 255 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ members = [
]

[workspace.dependencies.snarkvm]
version = "0.16.18"
version = "0.16.19"

[lib]
path = "leo/lib.rs"
Expand Down
59 changes: 59 additions & 0 deletions compiler/ast/src/expressions/locator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) 2019-2023 Aleo Systems Inc.
// This file is part of the Leo library.

// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.

use leo_span::{Span, Symbol};

use crate::{simple_node_impl, Node, NodeID, ProgramId};
use serde::{Deserialize, Serialize};
use std::{fmt, hash::Hash};

/// A locator that references an external resource.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct LocatorExpression {
/// The program that the resource is in.
pub program: ProgramId,
/// The name of the resource.
pub name: Symbol,
/// A span indicating where the locator occurred in the source.
pub span: Span,
/// The ID of the node.
pub id: NodeID,
}

simple_node_impl!(LocatorExpression);

impl LocatorExpression {
/// Constructs a new Locator with `name`, `program` and `id` and a default span.
pub fn new(program: ProgramId, name: Symbol, id: NodeID) -> Self {
Self { program, name, span: Span::default(), id }
}

/// Check if the Locator name and program matches the other name and program.
pub fn matches(&self, other: &Self) -> bool {
self.name == other.name && self.program == other.program
}
}

impl fmt::Display for LocatorExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}", self.program, self.name)
}
}
impl fmt::Debug for LocatorExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}", self.program, self.name)
}
}
24 changes: 17 additions & 7 deletions compiler/ast/src/expressions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub use unit::*;
mod literal;
pub use literal::*;

pub mod locator;
pub use locator::*;

/// Expression that evaluates to a value.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Expression {
Expand All @@ -69,15 +72,17 @@ pub enum Expression {
Call(CallExpression),
/// A cast expression, e.g., `42u32 as u8`.
Cast(CastExpression),
/// An expression constructing a struct like `Foo { bar: 42, baz }`.
Struct(StructExpression),
/// An expression of type "error".
/// Will result in a compile error eventually.
Err(ErrExpression),
/// An identifier.
Identifier(Identifier),
/// A literal expression.
Literal(Literal),
/// A locator expression, e.g., `hello.aleo/foo`.
Locator(LocatorExpression),
/// An expression constructing a struct like `Foo { bar: 42, baz }`.
Struct(StructExpression),
/// A ternary conditional expression `cond ? if_expr : else_expr`.
Ternary(TernaryExpression),
/// A tuple expression e.g., `(foo, 42, true)`.
Expand All @@ -97,10 +102,11 @@ impl Node for Expression {
Binary(n) => n.span(),
Call(n) => n.span(),
Cast(n) => n.span(),
Struct(n) => n.span(),
Err(n) => n.span(),
Identifier(n) => n.span(),
Literal(n) => n.span(),
Locator(n) => n.span(),
Struct(n) => n.span(),
Ternary(n) => n.span(),
Tuple(n) => n.span(),
Unary(n) => n.span(),
Expand All @@ -116,10 +122,11 @@ impl Node for Expression {
Binary(n) => n.set_span(span),
Call(n) => n.set_span(span),
Cast(n) => n.set_span(span),
Struct(n) => n.set_span(span),
Identifier(n) => n.set_span(span),
Literal(n) => n.set_span(span),
Locator(n) => n.set_span(span),
Err(n) => n.set_span(span),
Struct(n) => n.set_span(span),
Ternary(n) => n.set_span(span),
Tuple(n) => n.set_span(span),
Unary(n) => n.set_span(span),
Expand All @@ -135,10 +142,11 @@ impl Node for Expression {
Binary(n) => n.id(),
Call(n) => n.id(),
Cast(n) => n.id(),
Struct(n) => n.id(),
Identifier(n) => n.id(),
Literal(n) => n.id(),
Locator(n) => n.id(),
Err(n) => n.id(),
Struct(n) => n.id(),
Ternary(n) => n.id(),
Tuple(n) => n.id(),
Unary(n) => n.id(),
Expand All @@ -154,10 +162,11 @@ impl Node for Expression {
Binary(n) => n.set_id(id),
Call(n) => n.set_id(id),
Cast(n) => n.set_id(id),
Struct(n) => n.set_id(id),
Identifier(n) => n.set_id(id),
Literal(n) => n.set_id(id),
Locator(n) => n.set_id(id),
Err(n) => n.set_id(id),
Struct(n) => n.set_id(id),
Ternary(n) => n.set_id(id),
Tuple(n) => n.set_id(id),
Unary(n) => n.set_id(id),
Expand All @@ -175,10 +184,11 @@ impl fmt::Display for Expression {
Binary(n) => n.fmt(f),
Call(n) => n.fmt(f),
Cast(n) => n.fmt(f),
Struct(n) => n.fmt(f),
Err(n) => n.fmt(f),
Identifier(n) => n.fmt(f),
Literal(n) => n.fmt(f),
Locator(n) => n.fmt(f),
Struct(n) => n.fmt(f),
Ternary(n) => n.fmt(f),
Tuple(n) => n.fmt(f),
Unary(n) => n.fmt(f),
Expand Down
3 changes: 3 additions & 0 deletions compiler/ast/src/passes/consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub trait ExpressionConsumer {
Expression::Err(err) => self.consume_err(err),
Expression::Identifier(identifier) => self.consume_identifier(identifier),
Expression::Literal(value) => self.consume_literal(value),
Expression::Locator(locator) => self.consume_locator(locator),
Expression::Ternary(ternary) => self.consume_ternary(ternary),
Expression::Tuple(tuple) => self.consume_tuple(tuple),
Expression::Unary(unary) => self.consume_unary(unary),
Expand Down Expand Up @@ -61,6 +62,8 @@ pub trait ExpressionConsumer {

fn consume_literal(&mut self, _input: Literal) -> Self::Output;

fn consume_locator(&mut self, _input: LocatorExpression) -> Self::Output;

fn consume_ternary(&mut self, _input: TernaryExpression) -> Self::Output;

fn consume_tuple(&mut self, _input: TupleExpression) -> Self::Output;
Expand Down
5 changes: 5 additions & 0 deletions compiler/ast/src/passes/reconstructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub trait ExpressionReconstructor {
Expression::Err(err) => self.reconstruct_err(err),
Expression::Identifier(identifier) => self.reconstruct_identifier(identifier),
Expression::Literal(value) => self.reconstruct_literal(value),
Expression::Locator(locator) => self.reconstruct_locator(locator),
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
Expression::Tuple(tuple) => self.reconstruct_tuple(tuple),
Expression::Unary(unary) => self.reconstruct_unary(unary),
Expand Down Expand Up @@ -198,6 +199,10 @@ pub trait ExpressionReconstructor {
(Expression::Literal(input), Default::default())
}

fn reconstruct_locator(&mut self, input: LocatorExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Locator(input), Default::default())
}

fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Ternary(TernaryExpression {
Expand Down
5 changes: 5 additions & 0 deletions compiler/ast/src/passes/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub trait ExpressionVisitor<'a> {
Expression::Err(err) => self.visit_err(err, additional),
Expression::Identifier(identifier) => self.visit_identifier(identifier, additional),
Expression::Literal(literal) => self.visit_literal(literal, additional),
Expression::Locator(locator) => self.visit_locator(locator, additional),
Expression::Ternary(ternary) => self.visit_ternary(ternary, additional),
Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
Expression::Unary(unary) => self.visit_unary(unary, additional),
Expand Down Expand Up @@ -107,6 +108,10 @@ pub trait ExpressionVisitor<'a> {
Default::default()
}

fn visit_locator(&mut self, _input: &'a LocatorExpression, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}

fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.condition, additional);
self.visit_expression(&input.if_true, additional);
Expand Down
2 changes: 2 additions & 0 deletions compiler/ast/src/types/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use crate::Type;

use leo_span::Symbol;
use serde::{Deserialize, Serialize};
use std::fmt;

Expand All @@ -24,6 +25,7 @@ use std::fmt;
pub struct MappingType {
pub key: Box<Type>,
pub value: Box<Type>,
pub program: Symbol,
}

impl fmt::Display for MappingType {
Expand Down
1 change: 1 addition & 0 deletions compiler/compiler/tests/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
// Parse the program name from the program string.
let re = Regex::new(r"program\s+([^\s.]+)\.aleo").unwrap();
let program_name = re.captures(program_string).unwrap().get(1).unwrap().as_str();

// Parse the program.
let mut parsed = handler.extend_if_error(parse_program(
program_name.to_string(),
Expand Down
38 changes: 26 additions & 12 deletions compiler/parser/src/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use super::*;
use leo_errors::{ParserError, Result};

use leo_span::{sym, Symbol};
use leo_span::sym;
use snarkvm::console::{account::Address, network::Testnet3};

const INT_TYPES: &[Token] = &[
Expand Down Expand Up @@ -429,32 +429,46 @@ impl ParserContext<'_> {
self.parse_paren_comma_list(|p| p.parse_expression().map(Some))
}

// Parses an external function call `credits.aleo/transfer()` or `board.leo/make_move()`
fn parse_external_call(&mut self, expr: Expression) -> Result<Expression> {
// Parses an external function call `credits.aleo/transfer()` or locator `token.aleo/accounts`.
fn parse_external_resource(&mut self, expr: Expression, network_span: Span) -> Result<Expression> {
// Eat an external function call.
self.eat(&Token::Div); // todo: Make `/` a more general token.

// Parse function name.
// Parse name.
let name = self.expect_identifier()?;

// Parse the parent program identifier.
let program: Identifier = match expr {
Expression::Identifier(identifier) => identifier,
_ => unreachable!("Function called must be preceded by a program identifier."),
};

// Parsing a '{' means that user is trying to illegally define an external record.
if self.token.token == Token::LeftCurly {
return Err(ParserError::cannot_define_external_record(expr.span() + name.span()).into());
}

// If there is no parenthesis, then it is a locator.
if self.token.token != Token::LeftParen {
// Parse an external resource locator.
return Ok(Expression::Locator(LocatorExpression {
program: ProgramId {
name: program,
network: Identifier { name: sym::aleo, span: network_span, id: self.node_builder.next_id() },
},
name: name.name,
span: expr.span() + name.span(),
id: self.node_builder.next_id(),
}));
}

// 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: Symbol = match expr {
Expression::Identifier(identifier) => identifier.name,
_ => unreachable!("Function called must be preceded by a program identifier."),
};

Ok(Expression::Call(CallExpression {
span: expr.span() + span,
function: Box::new(Expression::Identifier(name)),
program: Some(program),
program: Some(program.name),
arguments,
id: self.node_builder.next_id(),
}))
Expand Down Expand Up @@ -483,7 +497,7 @@ impl ParserContext<'_> {
} else if self.eat(&Token::Leo) {
return Err(ParserError::only_aleo_external_calls(expr.span()).into());
} else if self.eat(&Token::Aleo) {
expr = self.parse_external_call(expr)?;
expr = self.parse_external_resource(expr, self.prev_token.span)?;
} else {
// Parse identifier name.
let name = self.expect_identifier()?;
Expand Down
4 changes: 3 additions & 1 deletion compiler/parser/src/parser/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ impl ParserContext<'_> {
Token::Program => {
match parsed_program_scope {
// Only one program scope is allowed per file.
true => return Err(ParserError::only_one_program_scope_is_allowed(self.token.span).into()),
true => {
return Err(ParserError::only_one_program_scope_is_allowed(self.token.span).into());
}
false => {
parsed_program_scope = true;
let program_scope = self.parse_program_scope()?;
Expand Down
11 changes: 9 additions & 2 deletions compiler/passes/src/code_generation/visit_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.

use crate::CodeGenerator;
use crate::{CodeGenerator, Location};
use leo_ast::{
AccessExpression,
ArrayAccess,
Expand All @@ -29,6 +29,7 @@ use leo_ast::{
Expression,
Identifier,
Literal,
LocatorExpression,
MemberAccess,
ProgramScope,
StructExpression,
Expand Down Expand Up @@ -60,6 +61,7 @@ impl<'a> CodeGenerator<'a> {
Expression::Err(expr) => self.visit_err(expr),
Expression::Identifier(expr) => self.visit_identifier(expr),
Expression::Literal(expr) => self.visit_value(expr),
Expression::Locator(expr) => self.visit_locator(expr),
Expression::Ternary(expr) => self.visit_ternary(expr),
Expression::Tuple(expr) => self.visit_tuple(expr),
Expression::Unary(expr) => self.visit_unary(expr),
Expand All @@ -82,6 +84,10 @@ impl<'a> CodeGenerator<'a> {
(format!("{input}"), String::new())
}

fn visit_locator(&mut self, input: &'a LocatorExpression) -> (String, String) {
(format!("{input}"), String::new())
}

fn visit_binary(&mut self, input: &'a BinaryExpression) -> (String, String) {
let (left_operand, left_instructions) = self.visit_expression(&input.left);
let (right_operand, right_instructions) = self.visit_expression(&input.right);
Expand Down Expand Up @@ -533,7 +539,8 @@ impl<'a> CodeGenerator<'a> {
// Initialize storage for the destination registers.
let mut destinations = Vec::new();

let return_type = &self.symbol_table.lookup_fn_symbol(main_program, function_name).unwrap().output_type;
let return_type =
&self.symbol_table.lookup_fn_symbol(Location::new(Some(main_program), function_name)).unwrap().output_type;
match return_type {
Type::Unit => {} // Do nothing
Type::Tuple(tuple) => match tuple.length() {
Expand Down
4 changes: 2 additions & 2 deletions compiler/passes/src/common/symbol_table/function_symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
use crate::SymbolTable;

/// Metadata associated with the finalize block.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FinalizeData {
/// The inputs to the finalize block.
pub(crate) input: Vec<Input>,
Expand All @@ -31,7 +31,7 @@ pub struct FinalizeData {
}

/// An entry for a function in the symbol table.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct FunctionSymbol {
/// The index associated with the scope in the parent symbol table.
pub(crate) id: usize,
Expand Down
Loading

0 comments on commit 87086a0

Please sign in to comment.