mirror of
https://github.com/ProvableHQ/leo.git
synced 2025-01-02 07:02:12 +03:00
Convert programCore->AST vs string->string
This commit is contained in:
parent
cc60421482
commit
562d6da2bb
@ -16,368 +16,68 @@
|
||||
|
||||
use snarkvm::{
|
||||
console::network::Testnet3,
|
||||
prelude::{Itertools, Network, RegisterType, ValueType},
|
||||
synthesizer::{
|
||||
program::{CommandTrait, InstructionTrait, Program, ProgramCore},
|
||||
Command,
|
||||
Instruction,
|
||||
},
|
||||
prelude::{Itertools, Network},
|
||||
synthesizer::program::{CommandTrait, InstructionTrait, Program, ProgramCore},
|
||||
};
|
||||
use snarkvm::console::program::Identifier as IdentifierCore;
|
||||
use leo_span::Symbol;
|
||||
use std::{ops::Add, str::FromStr};
|
||||
use std::str::FromStr;
|
||||
|
||||
use leo_ast::{Identifier, ProgramId, Struct, Stub};
|
||||
use leo_ast::Type::Identifier as IdentifierType;
|
||||
use leo_ast::{FunctionStub, Identifier, ProgramId, Struct, Stub};
|
||||
use leo_span::symbol::create_session_if_not_set_then;
|
||||
|
||||
type CurrentNetwork = Testnet3;
|
||||
|
||||
fn main() {
|
||||
let a = Symbol::intern("aleo");
|
||||
}
|
||||
fn main() {}
|
||||
|
||||
// fn old() {
|
||||
// // let credits_aleo =
|
||||
// // std::fs::read_to_string("/Users/evanschott/work/leo/utils/disassembler/src/tests/credits.aleo").unwrap();
|
||||
// // println!("{}", code_gen(credits_aleo));
|
||||
// let aleo_prog_1 = r"import credits.aleo;
|
||||
//
|
||||
// import battleship.aleo;
|
||||
// import juice.aleo;
|
||||
//
|
||||
// program to_parse.aleo;
|
||||
//
|
||||
// function new_board_state:
|
||||
// input r0 as u64.private;
|
||||
// input r1 as address.private;
|
||||
// cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
|
||||
// output r2 as board_state.record;
|
||||
//
|
||||
// closure add_up:
|
||||
// input r0 as u8;
|
||||
// input r1 as u8;
|
||||
// add r0 r1 into r2;
|
||||
// output r2 as u8;
|
||||
//
|
||||
// function transfer_public_to_private:
|
||||
// input r0 as address.private;
|
||||
// input r1 as u64.public;
|
||||
// cast r0 r1 into r2 as credits.record;
|
||||
// async transfer_public_to_private self.caller r1 into r3;
|
||||
// output r2 as credits.record;
|
||||
// output r3 as credits.aleo/transfer_public_to_private.future;
|
||||
//
|
||||
// finalize transfer_public_to_private:
|
||||
// input r0 as address.public;
|
||||
// input r1 as u64.public;
|
||||
// get.or_use account[r0] 0u64 into r2;
|
||||
// sub r2 r1 into r3;
|
||||
// set r3 into account[r0];
|
||||
// ";
|
||||
// let program = Program::<CurrentNetwork>::from_str(aleo_prog_1);
|
||||
// match program {
|
||||
// Ok(p) => {
|
||||
// let disassembled = disassemble(p);
|
||||
// println!("{}", disassembled)
|
||||
// }
|
||||
// Err(e) => {
|
||||
// println!("{}", e);
|
||||
// }
|
||||
// }
|
||||
// // println!("{}", disassemble(Program::<CurrentNetwork>::from_str(aleo_prog_1).unwrap()));
|
||||
// }
|
||||
|
||||
// fn disassemble<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>>(
|
||||
// program: ProgramCore<N, Instruction, Command>,
|
||||
// ) -> Stub {
|
||||
// dbg!(program.records());
|
||||
//
|
||||
// let mut stub = Stub {
|
||||
// imports: Vec::new(),
|
||||
// stub_id: ProgramId::from(program.id()),
|
||||
// consts: Vec::new(),
|
||||
// structs: Vec::new(),
|
||||
// mappings: Vec::new(),
|
||||
// functions: Vec::new(),
|
||||
// span: Default::default(),
|
||||
// };
|
||||
//
|
||||
//
|
||||
// let structs = program.structs().iter().map(|(id,s)| {
|
||||
// (Identifier::from(id).name, Struct::from(s))
|
||||
// }).collect_vec();
|
||||
// let records = program.records().iter().map(|(id,s)| {
|
||||
// dbg!(id.clone());
|
||||
// dbg!(s);
|
||||
// println!("{}", id.clone());
|
||||
// let id_str = id.clone().to_string();
|
||||
// let id_sym = Symbol::intern(&id_str);
|
||||
// ((id_sym, Struct::from(s)))
|
||||
// }).collect_vec();
|
||||
//
|
||||
//
|
||||
// stub
|
||||
//
|
||||
// // Stub {
|
||||
// // imports: program.imports().into_iter().map(|(id, import)| ProgramId::from(id)).collect(),
|
||||
// // stub_id: ProgramId::from(program.id()),
|
||||
// // consts: Vec::new(),
|
||||
// // structs: [structs,records].concat(),
|
||||
// // mappings: Vec::new(),
|
||||
// // functions: Vec::new(), // TODO: Add functions AND closures
|
||||
// // span: Default::default(),
|
||||
// // }
|
||||
// }
|
||||
|
||||
fn print_visibility<N: Network>(visibility: &ValueType<N>) -> String {
|
||||
match visibility {
|
||||
ValueType::Public(_) => "public ".to_string(),
|
||||
_ => "".to_string(),
|
||||
pub fn disassemble<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>>(
|
||||
program: ProgramCore<N, Instruction, Command>,
|
||||
) -> Stub {
|
||||
Stub {
|
||||
imports: program.imports().into_iter().map(|(id, _)| ProgramId::from(id)).collect(),
|
||||
stub_id: ProgramId::from(program.id()),
|
||||
consts: Vec::new(),
|
||||
structs: [
|
||||
program.structs().iter().map(|(id, s)| (Identifier::from(id).name, Struct::from(s))).collect_vec(),
|
||||
program.records().iter().map(|(id, s)| (Identifier::from(id).name, Struct::from(s))).collect_vec(),
|
||||
]
|
||||
.concat(),
|
||||
mappings: Vec::new(),
|
||||
functions: [
|
||||
program
|
||||
.closures()
|
||||
.iter()
|
||||
.map(|(id, closure)| (Identifier::from(id).name, FunctionStub::from(closure)))
|
||||
.collect_vec(),
|
||||
program
|
||||
.functions()
|
||||
.iter()
|
||||
.map(|(id, function)| (Identifier::from(id).name, FunctionStub::from(function)))
|
||||
.collect_vec(),
|
||||
]
|
||||
.concat(),
|
||||
span: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_transition_input<N: Network>(input: &ValueType<N>, index: usize, len: usize) -> String {
|
||||
format!("{}a{}: {}", print_visibility(input), index + 1, print_transition_value(input, index, len))
|
||||
}
|
||||
|
||||
fn print_transition_value<N: Network>(value: &ValueType<N>, index: usize, len: usize) -> String {
|
||||
let value_str = match value {
|
||||
ValueType::Constant(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
ValueType::Public(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
ValueType::Private(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
ValueType::Record(id) => format!("{}", id.to_string()),
|
||||
ValueType::ExternalRecord(loc) => format!("{}.aleo/{}", loc.name(), loc.resource().to_string()),
|
||||
ValueType::Future(_) => panic!("Futures must be filtered out by this stage"),
|
||||
};
|
||||
let situational_comma = if index == len - 1 { "" } else { ", " };
|
||||
format!("{}{}", value_str, situational_comma)
|
||||
}
|
||||
|
||||
fn print_transition_output<N: Network>(output: &ValueType<N>, index: usize, len: usize) -> String {
|
||||
let (left, right) = if len == 1 {
|
||||
(" -> ", "")
|
||||
} else if index == 0 {
|
||||
(" -> (", "")
|
||||
} else if index == len - 1 {
|
||||
("", ")")
|
||||
} else {
|
||||
("", "")
|
||||
};
|
||||
format!("{}{}{}", left, print_transition_value(output, index, len), right)
|
||||
}
|
||||
|
||||
fn print_function_output<N: Network>(output: &RegisterType<N>, index: usize, len: usize) -> String {
|
||||
let (left, right) = if len == 1 {
|
||||
(" -> ", "")
|
||||
} else if index == 0 {
|
||||
(" -> (", "")
|
||||
} else if index == len - 1 {
|
||||
("", ")")
|
||||
} else {
|
||||
("", "")
|
||||
};
|
||||
format!("{}{}{}", left, print_function_value(output, index, len), right)
|
||||
}
|
||||
|
||||
fn print_function_input<N: Network>(input: &RegisterType<N>, index: usize, len: usize) -> String {
|
||||
format!("a{}: {}", index + 1, print_function_value(input, index, len))
|
||||
}
|
||||
|
||||
fn print_function_value<N: Network>(value: &RegisterType<N>, index: usize, len: usize) -> String {
|
||||
let value_str = match value {
|
||||
RegisterType::Plaintext(val) => format!("{}", val.to_string().replace("boolean", "bool")),
|
||||
RegisterType::Record(val) => format!("{}", val.to_string()),
|
||||
RegisterType::ExternalRecord(loc) => format!("{}.aleo/{}", loc.name(), loc.resource().to_string()),
|
||||
RegisterType::Future(_) => panic!("Futures must be filtered out by this stage"),
|
||||
};
|
||||
let situational_comma = if index == len - 1 { "" } else { ", " };
|
||||
format!("{}{}", value_str, situational_comma)
|
||||
}
|
||||
|
||||
fn code_gen(input: String) -> String {
|
||||
// Parse a new program.
|
||||
let result = Program::<CurrentNetwork>::from_str(&input).unwrap();
|
||||
|
||||
let mut output = format!("stub {}.aleo {{", result.id().name());
|
||||
|
||||
// Write imports
|
||||
output.push_str(
|
||||
&result.imports().into_iter().map(|(name, _)| format!("\n import {};\n", name)).collect::<String>(),
|
||||
);
|
||||
|
||||
// Write records
|
||||
output.push_str(
|
||||
&result
|
||||
.records()
|
||||
.into_iter()
|
||||
.map(|(name, fields)| {
|
||||
format!("\n record {} {{\n owner: address,\n", name).add(
|
||||
&(fields
|
||||
.entries()
|
||||
.into_iter()
|
||||
.map(|(id, entry_type)| {
|
||||
if entry_type.plaintext_type().to_string() == "boolean" {
|
||||
return format!(" {}: bool,\n", id);
|
||||
} else {
|
||||
format!(" {}: {},\n", id, entry_type.plaintext_type().to_string())
|
||||
}
|
||||
})
|
||||
.collect::<String>()
|
||||
+ " }\n")
|
||||
.to_string(),
|
||||
)
|
||||
})
|
||||
.collect::<String>(),
|
||||
);
|
||||
|
||||
// Write transitions
|
||||
output.push_str(
|
||||
&result
|
||||
.functions()
|
||||
.into_iter()
|
||||
.map(|(name, value)| {
|
||||
let (inputs, outputs) = (value.inputs(), value.outputs().clone());
|
||||
|
||||
// Can assume that last output is a future if the function has associated finalize
|
||||
let outputs_vec = if value.finalize_logic().is_some() {
|
||||
outputs[..outputs.len() - 1].iter().collect_vec()
|
||||
} else {
|
||||
outputs.iter().collect_vec()
|
||||
};
|
||||
let len = outputs_vec.len();
|
||||
|
||||
format!("\n transition {}(", name).add(
|
||||
&(inputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, input)| print_transition_input(&input.value_type(), index, inputs.len()))
|
||||
.collect::<String>()
|
||||
+ ")")
|
||||
.add(
|
||||
&(outputs_vec
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, output)| print_transition_output(&output.value_type(), index, len))
|
||||
.collect::<String>()
|
||||
+ ";\n")
|
||||
.to_string(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect::<String>(),
|
||||
);
|
||||
|
||||
// Write functions
|
||||
output.push_str(
|
||||
&result
|
||||
.closures()
|
||||
.into_iter()
|
||||
.map(|(name, value)| {
|
||||
let (inputs, outputs) = (value.inputs(), value.outputs().clone());
|
||||
let len = outputs.len();
|
||||
|
||||
format!("\n function {}(", name).add(
|
||||
&(inputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, input)| print_function_input(&input.register_type(), index, inputs.len()))
|
||||
.collect::<String>()
|
||||
+ ")")
|
||||
.add(
|
||||
&(outputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, output)| print_function_output(&output.register_type(), index, len))
|
||||
.collect::<String>()
|
||||
+ ";\n")
|
||||
.to_string(),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect::<String>(),
|
||||
);
|
||||
|
||||
// Append final closing bracket
|
||||
output.push_str("}\n");
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn code_gen_test() {
|
||||
let aleo_prog_1 = r"import credits.aleo;
|
||||
|
||||
import battleship.aleo;
|
||||
import juice.aleo;
|
||||
|
||||
program to_parse.aleo;
|
||||
|
||||
record board_state:
|
||||
owner as address.private;
|
||||
hits_and_misses as u64.private;
|
||||
played_tiles as u64.private;
|
||||
ships as u64.private;
|
||||
player_1 as address.private;
|
||||
player_2 as address.private;
|
||||
game_started as boolean.private;
|
||||
|
||||
function new_board_state:
|
||||
input r0 as u64.private;
|
||||
input r1 as address.private;
|
||||
cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
|
||||
output r2 as board_state.record;
|
||||
|
||||
closure add_up:
|
||||
input r0 as u8;
|
||||
input r1 as u8;
|
||||
add r0 r1 into r2;
|
||||
output r2 as u8;
|
||||
|
||||
function transfer_public_to_private:
|
||||
input r0 as address.private;
|
||||
input r1 as u64.public;
|
||||
cast r0 r1 into r2 as credits.record;
|
||||
async transfer_public_to_private self.caller r1 into r3;
|
||||
output r2 as credits.record;
|
||||
output r3 as credits.aleo/transfer_public_to_private.future;
|
||||
|
||||
finalize transfer_public_to_private:
|
||||
input r0 as address.public;
|
||||
input r1 as u64.public;
|
||||
get.or_use account[r0] 0u64 into r2;
|
||||
sub r2 r1 into r3;
|
||||
set r3 into account[r0];
|
||||
";
|
||||
let leo_stub_1: &str = r"stub to_parse.aleo {
|
||||
import credits.aleo;
|
||||
|
||||
import battleship.aleo;
|
||||
|
||||
import juice.aleo;
|
||||
|
||||
record board_state {
|
||||
owner: address,
|
||||
hits_and_misses: u64,
|
||||
played_tiles: u64,
|
||||
ships: u64,
|
||||
player_1: address,
|
||||
player_2: address,
|
||||
game_started: bool,
|
||||
}
|
||||
|
||||
transition new_board_state(a1: u64, a2: address) -> board_state;
|
||||
|
||||
transition transfer_public_to_private(a1: address, public a2: u64) -> credits;
|
||||
|
||||
function add_up(a1: u8, a2: u8) -> u8;
|
||||
}
|
||||
";
|
||||
let code_gen_1 = code_gen(aleo_prog_1.to_string());
|
||||
assert_eq!(code_gen_1, leo_stub_1);
|
||||
|
||||
fn credits_test() {
|
||||
create_session_if_not_set_then(|_| {
|
||||
let aleo_prog_1 =
|
||||
std::fs::read_to_string("/Users/evanschott/work/leo/utils/disassembler/src/tests/credits.aleo")
|
||||
.unwrap();
|
||||
let program = Program::<CurrentNetwork>::from_str(&*aleo_prog_1);
|
||||
match program {
|
||||
Ok(p) => {
|
||||
let disassembled = disassemble(p);
|
||||
println!("{}", disassembled);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user