| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311 |
- // SPDX-License-Identifier: Apache-2.0
- use crate::sema::{
- ast::*,
- symtable::Symtable,
- yul::{
- ast::{YulBlock, YulExpression, YulStatement},
- builtin::YulBuiltInFunction,
- },
- };
- use solang_parser::{pt, pt::Loc};
- use std::fmt::Write;
- struct Node {
- name: String,
- labels: Vec<String>,
- }
- impl Node {
- fn new(name: &str, labels: Vec<String>) -> Self {
- Node {
- name: name.to_owned(),
- labels,
- }
- }
- }
- struct Edge {
- from: usize,
- to: usize,
- label: Option<String>,
- }
- struct Dot {
- filename: String,
- nodes: Vec<Node>,
- edges: Vec<Edge>,
- }
- impl Dot {
- fn write(&self) -> String {
- let mut result = format!("strict digraph \"{}\" {{\n", self.filename);
- for node in &self.nodes {
- if !node.labels.is_empty() {
- writeln!(
- result,
- "\t{} [label=\"{}\"]",
- node.name,
- node.labels.join("\\n")
- )
- .unwrap();
- }
- }
- for edge in &self.edges {
- if let Some(label) = &edge.label {
- writeln!(
- result,
- "\t{} -> {} [label=\"{}\"]",
- self.nodes[edge.from].name, self.nodes[edge.to].name, label
- )
- .unwrap();
- } else {
- writeln!(
- result,
- "\t{} -> {}",
- self.nodes[edge.from].name, self.nodes[edge.to].name
- )
- .unwrap();
- }
- }
- result.push_str("}\n");
- result
- }
- fn add_node(
- &mut self,
- mut node: Node,
- parent: Option<usize>,
- parent_rel: Option<String>,
- ) -> usize {
- let no = self.nodes.len();
- debug_assert!(
- !node.name.chars().any(|c| c.is_whitespace()),
- "{} contains whitespace",
- node.name
- );
- if node.name.is_empty() || node.name == "node" {
- node.name = format!("node_{}", no);
- } else {
- while self.nodes.iter().any(|n| n.name == node.name) {
- node.name = format!("{}_{}", node.name, no);
- }
- }
- self.nodes.push(node);
- if let Some(parent) = parent {
- self.edges.push(Edge {
- from: parent,
- to: no,
- label: parent_rel,
- })
- }
- no
- }
- fn add_tags(&mut self, tags: &[Tag], parent: usize) {
- if !tags.is_empty() {
- let labels = tags
- .iter()
- .map(|tag| format!("{}: {}", tag.tag, tag.value.replace('\n', " ")))
- .collect();
- self.add_node(
- Node::new("tags", labels),
- Some(parent),
- Some(String::from("tags")),
- );
- }
- }
- fn add_function(&mut self, func: &Function, ns: &Namespace, parent: usize) {
- let mut labels = vec![
- format!("{} {}", func.ty, func.name),
- ns.loc_to_string(&func.loc),
- ];
- if let Some(contract) = func.contract_no {
- labels.insert(1, format!("contract: {}", ns.contracts[contract].name));
- }
- if func.ty == pt::FunctionTy::Constructor || func.ty == pt::FunctionTy::Function {
- labels.push(format!("signature {}", func.signature));
- labels.push(format!("visibility {}", func.visibility));
- }
- labels.push(format!("mutability {}", func.mutability));
- if func.is_virtual {
- labels.push(String::from("virtual"));
- }
- if let Some((_, is_overrides)) = &func.is_override {
- if is_overrides.is_empty() {
- labels.push(String::from("override"));
- } else {
- for is_override in is_overrides {
- labels.push(format!("override {}", ns.contracts[*is_override].name));
- }
- }
- }
- let func_node = self.add_node(
- Node::new(&func.name, labels),
- Some(parent),
- Some(format!("{}", func.ty)),
- );
- self.add_tags(&func.tags, func_node);
- // parameters
- if !func.params.is_empty() {
- let mut labels = vec![String::from("parameters")];
- for param in &*func.params {
- labels.push(format!(
- "{} {}",
- param.ty.to_string(ns),
- param.name_as_str()
- ));
- }
- self.add_node(
- Node::new("parameters", labels),
- Some(func_node),
- Some(String::from("parameters")),
- );
- }
- // returns
- if !func.returns.is_empty() {
- let mut labels = vec![String::from("returns")];
- for param in &*func.returns {
- labels.push(format!(
- "{} {}",
- param.ty.to_string(ns),
- param.name_as_str()
- ));
- }
- self.add_node(
- Node::new("returns", labels),
- Some(func_node),
- Some(String::from("returns")),
- );
- }
- // bases
- for (base_no, (_, _, args)) in &func.bases {
- let node = self.add_node(
- Node::new(
- &ns.contracts[*base_no].name,
- vec![ns.contracts[*base_no].name.to_string()],
- ),
- Some(func_node),
- Some(String::from("base")),
- );
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, Some(func), ns, node, format!("arg #{}", no));
- }
- }
- // body
- self.add_statement(&func.body, func, ns, func_node, String::from("body"));
- }
- fn add_expression(
- &mut self,
- expr: &Expression,
- func: Option<&Function>,
- ns: &Namespace,
- parent: usize,
- parent_rel: String,
- ) {
- match expr {
- Expression::BoolLiteral(loc, val) => {
- let labels = vec![
- format!("bool literal: {}", if *val { "true" } else { "false" }),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("bool_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::BytesLiteral(loc, ty, val) => {
- let labels = vec![
- format!("{} literal: {}", ty.to_string(ns), hex::encode(val)),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("bytes_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::CodeLiteral(loc, contract_no, runtime) => {
- let labels = vec![
- format!(
- "code {}literal contract {}",
- if *runtime { "runtime " } else { "" },
- ns.contracts[*contract_no].name,
- ),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("code_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::NumberLiteral(loc, ty, val) => {
- let labels = vec![
- format!("{} literal: {}", ty.to_string(ns), val),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("number_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::RationalNumberLiteral(loc, ty, val) => {
- let labels = vec![
- format!("rational {} literal: {}", ty.to_string(ns), val),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("rational_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::StructLiteral(loc, ty, args) => {
- let labels = vec![
- format!("struct literal: {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("struct_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- }
- Expression::ArrayLiteral(loc, ty, _, args) => {
- let labels = vec![
- format!("array literal: {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("array_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- }
- Expression::ConstArrayLiteral(loc, ty, _, args) => {
- let labels = vec![
- format!("array literal: {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("array_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- }
- Expression::Add(loc, ty, unchecked, left, right) => {
- let mut labels = vec![String::from("add"), ty.to_string(ns), ns.loc_to_string(loc)];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node = self.add_node(Node::new("add", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Subtract(loc, ty, unchecked, left, right) => {
- let mut labels = vec![
- String::from("subtract"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node = self.add_node(
- Node::new("subtract", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Multiply(loc, ty, unchecked, left, right) => {
- let mut labels = vec![
- String::from("multiply"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node = self.add_node(
- Node::new("multiply", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Divide(loc, ty, left, right) => {
- let labels = vec![
- String::from("divide"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node =
- self.add_node(Node::new("divide", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Modulo(loc, ty, left, right) => {
- let labels = vec![
- String::from("modulo"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node =
- self.add_node(Node::new("modulo", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Power(loc, ty, unchecked, left, right) => {
- let mut labels = vec![
- String::from("power"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node =
- self.add_node(Node::new("power", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::BitwiseOr(loc, ty, left, right) => {
- let labels = vec![
- String::from("bitwise or"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("bitwise_or", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::BitwiseAnd(loc, ty, left, right) => {
- let labels = vec![
- String::from("bitwise and"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("bitwise_and", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::BitwiseXor(loc, ty, left, right) => {
- let labels = vec![
- String::from("bitwise xor"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("bitwise_xor", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::ShiftLeft(loc, ty, left, right) => {
- let labels = vec![
- String::from("shift left"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("shift_left", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::ShiftRight(loc, ty, left, right, _) => {
- let labels = vec![
- String::from("shift right"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("shift_right", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::ConstantVariable(loc, ty, contract, var_no) => {
- self.add_constant_variable(loc, ty, contract, var_no, parent, parent_rel, ns);
- }
- Expression::Variable(loc, ty, var_no) => {
- let labels = vec![
- format!("variable: {}", func.unwrap().symtable.vars[var_no].id.name),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("variable", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::StorageVariable(loc, ty, contract, var_no) => {
- self.add_storage_variable(loc, ty, contract, var_no, parent, parent_rel, ns);
- }
- Expression::Load(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "load",
- vec![format!("load {}", ty.to_string(ns)), ns.loc_to_string(loc)],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::GetRef(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "getref",
- vec![
- format!("getref {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::StorageLoad(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "storage_load",
- vec![
- format!("storage load {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::ZeroExt(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "zero_ext",
- vec![
- format!("zero extend {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::SignExt(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "sign_ext",
- vec![
- format!("sign extend {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::Trunc(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "trunc",
- vec![
- format!("truncate {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::CheckingTrunc(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "trunc",
- vec![
- format!("checking truncate {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::Cast(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "cast",
- vec![format!("cast {}", ty.to_string(ns)), ns.loc_to_string(loc)],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::BytesCast(loc, from, to, expr) => {
- let node = self.add_node(
- Node::new(
- "bytes_cast",
- vec![
- format!(
- "bytes cast from {} to {}",
- from.to_string(ns),
- to.to_string(ns)
- ),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::PreIncrement(loc, ty, unchecked, expr) => {
- let mut labels = vec![
- String::from("pre increment"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node = self.add_node(
- Node::new("pre_increment", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::PreDecrement(loc, ty, unchecked, expr) => {
- let mut labels = vec![
- String::from("pre decrement"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node = self.add_node(
- Node::new("pre_decrement", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::PostIncrement(loc, ty, unchecked, expr) => {
- let mut labels = vec![
- String::from("post increment"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node = self.add_node(
- Node::new("post_increment", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::PostDecrement(loc, ty, unchecked, expr) => {
- let mut labels = vec![
- String::from("post decrement"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- let node = self.add_node(
- Node::new("post_decrement", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::Assign(loc, ty, left, right) => {
- let labels = vec![
- String::from("assign"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- let node =
- self.add_node(Node::new("assign", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::More(loc, left, right) => {
- let labels = vec![String::from("more"), ns.loc_to_string(loc)];
- let node = self.add_node(Node::new("more", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Less(loc, left, right) => {
- let labels = vec![String::from("less"), ns.loc_to_string(loc)];
- let node = self.add_node(Node::new("less", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::MoreEqual(loc, left, right) => {
- let labels = vec![String::from("more equal"), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("more_equal", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::LessEqual(loc, left, right) => {
- let labels = vec![String::from("less equal"), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("less_equal", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Equal(loc, left, right) => {
- let labels = vec![String::from("equal"), ns.loc_to_string(loc)];
- let node =
- self.add_node(Node::new("equal", labels), Some(parent), Some(parent_rel));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::NotEqual(loc, left, right) => {
- let labels = vec![String::from("not equal"), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("not_qual", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Not(loc, expr) => {
- let node = self.add_node(
- Node::new("not", vec![String::from("not"), ns.loc_to_string(loc)]),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::Complement(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "complement",
- vec![
- format!("complement {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::UnaryMinus(loc, ty, expr) => {
- let node = self.add_node(
- Node::new(
- "unary_minus",
- vec![
- format!("unary minus {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(expr, func, ns, node, String::from("expr"));
- }
- Expression::Ternary(loc, ty, cond, left, right) => {
- let node = self.add_node(
- Node::new(
- "conditional",
- vec![
- format!("conditiona {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(cond, func, ns, node, String::from("cond"));
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::Subscript(loc, _, ty, array, index) => {
- let node = self.add_node(
- Node::new(
- "subscript",
- vec![
- format!("subscript {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(array, func, ns, node, String::from("array"));
- self.add_expression(index, func, ns, node, String::from("index"));
- }
- Expression::StructMember(loc, ty, var, member) => {
- let node = self.add_node(
- Node::new(
- "structmember",
- vec![
- format!("struct member #{} {}", member, ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(var, func, ns, node, String::from("var"));
- }
- Expression::AllocDynamicArray(loc, ty, length, initializer) => {
- let mut labels = vec![
- format!("alloc array {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ];
- if let Some(initializer) = initializer {
- labels.insert(1, format!("initializer: {}", hex::encode(initializer)));
- }
- let node = self.add_node(
- Node::new("alloc_array", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(length, func, ns, node, String::from("length"));
- }
- Expression::StorageArrayLength {
- loc,
- ty,
- array,
- elem_ty,
- } => {
- let node = self.add_node(
- Node::new(
- "array_length",
- vec![
- format!("array length {}", ty.to_string(ns)),
- format!("element {}", elem_ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(array, func, ns, node, String::from("array"));
- }
- Expression::StringCompare(loc, left, right) => {
- let node = self.add_node(
- Node::new(
- "string_cmp",
- vec![String::from("string compare"), ns.loc_to_string(loc)],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_string_location(left, func, ns, node, String::from("left"));
- self.add_string_location(right, func, ns, node, String::from("right"));
- }
- Expression::StringConcat(loc, ty, left, right) => {
- let node = self.add_node(
- Node::new(
- "string_concat",
- vec![
- format!("string concat {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ],
- ),
- Some(parent),
- Some(parent_rel),
- );
- self.add_string_location(left, func, ns, node, String::from("left"));
- self.add_string_location(right, func, ns, node, String::from("right"));
- }
- Expression::Or(loc, left, right) => {
- let labels = vec![String::from("logical or"), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("logical_or", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::And(loc, left, right) => {
- let labels = vec![String::from("logical and"), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("logical_and", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(left, func, ns, node, String::from("left"));
- self.add_expression(right, func, ns, node, String::from("right"));
- }
- Expression::InternalFunction {
- loc,
- ty,
- function_no,
- signature,
- } => {
- let mut labels = vec![ty.to_string(ns), ns.loc_to_string(loc)];
- let func = &ns.functions[*function_no];
- if let Some(contract_no) = func.contract_no {
- labels.insert(
- 1,
- format!("{}.{}", ns.contracts[contract_no].name, func.name),
- )
- } else {
- labels.insert(1, format!("free function {}", func.name))
- }
- if let Some(signature) = signature {
- labels.insert(1, format!("signature {}", signature))
- }
- self.add_node(
- Node::new("internal_function", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::ExternalFunction {
- loc,
- ty,
- function_no,
- address,
- } => {
- let mut labels = vec![ty.to_string(ns), ns.loc_to_string(loc)];
- let f = &ns.functions[*function_no];
- if let Some(contract_no) = f.contract_no {
- labels.insert(1, format!("{}.{}", ns.contracts[contract_no].name, f.name))
- }
- let node = self.add_node(
- Node::new("external_function", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(address, func, ns, node, String::from("address"));
- }
- Expression::InternalFunctionCall {
- loc,
- function,
- args,
- ..
- } => {
- let labels = vec![
- String::from("call internal function"),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("call_internal_function", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(function, func, ns, node, String::from("function"));
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- }
- Expression::ExternalFunctionCall {
- loc,
- function,
- args,
- call_args,
- ..
- } => {
- let labels = vec![
- String::from("call external function"),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("call_external_function", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(function, func, ns, node, String::from("function"));
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- self.add_call_args(call_args, func, ns, node);
- }
- Expression::ExternalFunctionCallRaw {
- loc,
- address,
- args,
- call_args,
- ..
- } => {
- let labels = vec![
- String::from("call external function"),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("call_external_function", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_expression(address, func, ns, node, String::from("address"));
- self.add_expression(args, func, ns, node, String::from("args"));
- self.add_call_args(call_args, func, ns, node);
- }
- Expression::Constructor {
- loc,
- contract_no,
- args,
- call_args,
- ..
- } => {
- let labels = vec![
- format!("constructor contract {}", ns.contracts[*contract_no].name),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("constructor", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- self.add_call_args(call_args, func, ns, node);
- }
- Expression::FormatString(loc, args) => {
- let labels = vec![String::from("string format"), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("string_format", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (no, (_, arg)) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- }
- Expression::Builtin(loc, _, builtin, args) => {
- let labels = vec![format!("builtin {:?}", builtin), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("builtins", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, func, ns, node, format!("arg #{}", no));
- }
- }
- Expression::InterfaceId(loc, contract_no) => {
- let labels = vec![
- format!("interfaceid contract {}", ns.contracts[*contract_no].name),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("interfaceid", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Expression::List(loc, list) => {
- let labels = vec![String::from("list"), ns.loc_to_string(loc)];
- let node = self.add_node(Node::new("list", labels), Some(parent), Some(parent_rel));
- for (no, expr) in list.iter().enumerate() {
- self.add_expression(expr, func, ns, node, format!("entry #{}", no));
- }
- }
- }
- }
- fn add_call_args(
- &mut self,
- call_args: &CallArgs,
- func: Option<&Function>,
- ns: &Namespace,
- node: usize,
- ) {
- if let Some(gas) = &call_args.gas {
- self.add_expression(gas, func, ns, node, String::from("gas"));
- }
- if let Some(value) = &call_args.value {
- self.add_expression(value, func, ns, node, String::from("value"));
- }
- if let Some(salt) = &call_args.salt {
- self.add_expression(salt, func, ns, node, String::from("salt"));
- }
- if let Some(space) = &call_args.space {
- self.add_expression(space, func, ns, node, String::from("space"));
- }
- if let Some(accounts) = &call_args.accounts {
- self.add_expression(accounts, func, ns, node, String::from("accounts"));
- }
- }
- fn add_string_location(
- &mut self,
- loc: &StringLocation<Expression>,
- func: Option<&Function>,
- ns: &Namespace,
- parent: usize,
- parent_rel: String,
- ) {
- match loc {
- StringLocation::CompileTime(val) => {
- self.add_node(
- Node::new(
- "compile_time_string",
- vec![format!("const string {}", hex::encode(val))],
- ),
- Some(parent),
- Some(parent_rel),
- );
- }
- StringLocation::RunTime(expr) => {
- self.add_expression(expr, func, ns, parent, parent_rel);
- }
- }
- }
- fn add_statement(
- &mut self,
- stmts: &[Statement],
- func: &Function,
- ns: &Namespace,
- parent: usize,
- parent_rel: String,
- ) {
- let mut parent = parent;
- let mut parent_rel = parent_rel;
- for stmt in stmts {
- match stmt {
- Statement::Block {
- loc,
- unchecked,
- statements,
- } => {
- let mut labels = vec![String::from("block"), ns.loc_to_string(loc)];
- if *unchecked {
- labels.push(String::from("unchecked"));
- }
- parent =
- self.add_node(Node::new("block", labels), Some(parent), Some(parent_rel));
- self.add_statement(statements, func, ns, parent, String::from("statements"));
- }
- Statement::VariableDecl(loc, _, param, init) => {
- let labels = vec![
- format!(
- "variable decl {} {}",
- param.ty.to_string(ns),
- param.name_as_str()
- ),
- ns.loc_to_string(loc),
- ];
- parent = self.add_node(
- Node::new("var_decl", labels),
- Some(parent),
- Some(parent_rel),
- );
- if let Some(init) = init {
- self.add_expression(init, Some(func), ns, parent, String::from("init"));
- }
- }
- Statement::If(loc, _, cond, then, else_) => {
- let labels = vec![String::from("if"), ns.loc_to_string(loc)];
- parent = self.add_node(Node::new("if", labels), Some(parent), Some(parent_rel));
- self.add_expression(cond, Some(func), ns, parent, String::from("cond"));
- self.add_statement(then, func, ns, parent, String::from("then"));
- self.add_statement(else_, func, ns, parent, String::from("else"));
- }
- Statement::While(loc, _, cond, body) => {
- let labels = vec![String::from("while"), ns.loc_to_string(loc)];
- parent =
- self.add_node(Node::new("while", labels), Some(parent), Some(parent_rel));
- self.add_expression(cond, Some(func), ns, parent, String::from("cond"));
- self.add_statement(body, func, ns, parent, String::from("body"));
- }
- Statement::For {
- loc,
- init,
- cond,
- next,
- body,
- ..
- } => {
- let labels = vec![String::from("for"), ns.loc_to_string(loc)];
- parent =
- self.add_node(Node::new("for", labels), Some(parent), Some(parent_rel));
- self.add_statement(init, func, ns, parent, String::from("init"));
- if let Some(cond) = cond {
- self.add_expression(cond, Some(func), ns, parent, String::from("cond"));
- }
- self.add_statement(next, func, ns, parent, String::from("next"));
- self.add_statement(body, func, ns, parent, String::from("body"));
- }
- Statement::DoWhile(loc, _, body, cond) => {
- let labels = vec![String::from("do while"), ns.loc_to_string(loc)];
- parent =
- self.add_node(Node::new("dowhile", labels), Some(parent), Some(parent_rel));
- self.add_statement(body, func, ns, parent, String::from("body"));
- self.add_expression(cond, Some(func), ns, parent, String::from("cond"));
- }
- Statement::Expression(loc, _, expr) => {
- let labels = vec![String::from("expression"), ns.loc_to_string(loc)];
- parent =
- self.add_node(Node::new("expr", labels), Some(parent), Some(parent_rel));
- self.add_expression(expr, Some(func), ns, parent, String::from("expr"));
- }
- Statement::Delete(loc, ty, expr) => {
- let labels = vec![
- String::from("delete"),
- format!("ty: {}", ty.to_string(ns)),
- ns.loc_to_string(loc),
- ];
- parent =
- self.add_node(Node::new("delete", labels), Some(parent), Some(parent_rel));
- self.add_expression(expr, Some(func), ns, parent, String::from("expr"));
- }
- Statement::Destructure(loc, fields, expr) => {
- let labels = vec![String::from("destructure"), ns.loc_to_string(loc)];
- parent = self.add_node(
- Node::new("destructure", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (no, field) in fields.iter().enumerate() {
- let parent_rel = format!("arg #{}", no);
- match field {
- DestructureField::None => {
- self.add_node(
- Node::new("none", vec![String::from("none")]),
- Some(parent),
- Some(parent_rel),
- );
- }
- DestructureField::Expression(expr) => {
- self.add_expression(expr, Some(func), ns, parent, parent_rel);
- }
- DestructureField::VariableDecl(_, param) => {
- self.add_node(
- Node::new(
- "param",
- vec![format!(
- "{} {}",
- param.ty.to_string(ns),
- param.name_as_str()
- )],
- ),
- Some(parent),
- Some(parent_rel),
- );
- }
- }
- }
- self.add_expression(expr, Some(func), ns, parent, String::from("expr"));
- }
- Statement::Continue(loc) => {
- let labels = vec![String::from("continue"), ns.loc_to_string(loc)];
- parent = self.add_node(
- Node::new("continue", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Statement::Break(loc) => {
- let labels = vec![String::from("break"), ns.loc_to_string(loc)];
- parent =
- self.add_node(Node::new("break", labels), Some(parent), Some(parent_rel));
- }
- Statement::Return(loc, expr) => {
- let labels = vec![String::from("return"), ns.loc_to_string(loc)];
- parent =
- self.add_node(Node::new("return", labels), Some(parent), Some(parent_rel));
- if let Some(expr) = expr {
- self.add_expression(expr, Some(func), ns, parent, String::from("expr"));
- }
- }
- Statement::Emit {
- loc,
- event_no,
- args,
- ..
- } => {
- let mut labels = vec![String::from("emit"), ns.loc_to_string(loc)];
- let event = &ns.events[*event_no];
- if let Some(contract) = event.contract {
- labels.insert(
- 1,
- format!("event {}.{}", ns.contracts[contract].name, event.name),
- );
- } else {
- labels.insert(1, format!("event {}", event.name));
- }
- parent =
- self.add_node(Node::new("emit", labels), Some(parent), Some(parent_rel));
- for (no, arg) in args.iter().enumerate() {
- self.add_expression(arg, Some(func), ns, parent, format!("arg #{}", no));
- }
- }
- Statement::TryCatch(loc, _, try_catch) => {
- let labels = vec![String::from("try"), ns.loc_to_string(loc)];
- self.add_expression(
- &try_catch.expr,
- Some(func),
- ns,
- parent,
- String::from("expr"),
- );
- parent =
- self.add_node(Node::new("try", labels), Some(parent), Some(parent_rel));
- for (no, (_, param)) in try_catch.returns.iter().enumerate() {
- let parent_rel = format!("return #{}", no);
- self.add_node(
- Node::new(
- "return",
- vec![format!(
- "{} {}",
- param.ty.to_string(ns),
- param.name_as_str()
- )],
- ),
- Some(parent),
- Some(parent_rel),
- );
- }
- self.add_statement(&try_catch.ok_stmt, func, ns, parent, String::from("ok"));
- for (_, param, stmt) in &try_catch.errors {
- self.add_node(
- Node::new(
- "error_param",
- vec![format!(
- "{} {}",
- param.ty.to_string(ns),
- param.name_as_str()
- )],
- ),
- Some(parent),
- Some(String::from("error parameter")),
- );
- self.add_statement(stmt, func, ns, parent, String::from("error"));
- }
- if let Some(param) = &try_catch.catch_param {
- self.add_node(
- Node::new(
- "catch_param",
- vec![format!(
- "{} {}",
- param.ty.to_string(ns),
- param.name_as_str()
- )],
- ),
- Some(parent),
- Some(String::from("catch parameter")),
- );
- }
- self.add_statement(
- &try_catch.catch_stmt,
- func,
- ns,
- parent,
- String::from("catch"),
- );
- }
- Statement::Underscore(loc) => {
- let labels = vec![String::from("undersore"), ns.loc_to_string(loc)];
- parent = self.add_node(
- Node::new("underscore", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- Statement::Assembly(inline_assembly, ..) => {
- let labels = vec![
- "inline assembly".to_string(),
- ns.loc_to_string(&inline_assembly.loc),
- ];
- parent = self.add_node(
- Node::new("inline_assembly", labels),
- Some(parent),
- Some(parent_rel),
- );
- let mut local_parent = parent;
- for n in inline_assembly.functions.start..inline_assembly.functions.end {
- self.add_yul_function(
- n,
- ns,
- local_parent,
- format!("func def #{}", inline_assembly.functions.end - n),
- );
- }
- local_parent = parent;
- for (item_no, item) in inline_assembly.body.iter().enumerate() {
- local_parent = self.add_yul_statement(
- item,
- local_parent,
- format!("statement #{}", item_no),
- &func.symtable,
- ns,
- );
- }
- }
- }
- parent_rel = String::from("next");
- }
- }
- fn add_yul_function(
- &mut self,
- func_no: usize,
- ns: &Namespace,
- parent: usize,
- parent_rel: String,
- ) {
- let labels = vec![
- format!("function definition {}", ns.yul_functions[func_no].name),
- ns.loc_to_string(&ns.yul_functions[func_no].loc),
- ];
- let func_node = self.add_node(
- Node::new("yul_function_definition", labels),
- Some(parent),
- Some(parent_rel),
- );
- let mut local_parent = func_node;
- for (item_no, item) in (*ns.yul_functions[func_no].params).iter().enumerate() {
- let labels = vec![
- format!(
- "function parameter {}: {}",
- item.ty.to_string(ns),
- item.id.as_ref().unwrap().name,
- ),
- ns.loc_to_string(&item.loc),
- ];
- local_parent = self.add_node(
- Node::new("yul_function_parameter", labels),
- Some(local_parent),
- Some(format!("parameter #{}", item_no)),
- );
- }
- local_parent = func_node;
- for (item_no, item) in (*ns.yul_functions[func_no].returns).iter().enumerate() {
- let labels = vec![
- format!(
- "return parameter {}: {}",
- item.ty.to_string(ns),
- item.id.as_ref().unwrap().name
- ),
- ns.loc_to_string(&item.loc),
- ];
- local_parent = self.add_node(
- Node::new("yul_function_return", labels),
- Some(local_parent),
- Some(format!("return #{}", item_no)),
- );
- }
- local_parent = func_node;
- for (item_no, item) in ns.yul_functions[func_no].body.iter().enumerate() {
- local_parent = self.add_yul_statement(
- item,
- local_parent,
- format!("statement #{}", item_no),
- &ns.yul_functions[func_no].symtable,
- ns,
- );
- }
- }
- fn add_yul_expression(
- &mut self,
- expr: &YulExpression,
- symtable: &Symtable,
- ns: &Namespace,
- parent: usize,
- parent_rel: String,
- ) {
- match expr {
- YulExpression::BoolLiteral(loc, value, ty) => {
- let labels = vec![
- format!(
- "bool literal: {} of type {}",
- if *value { "true" } else { "false" },
- ty.to_string(ns)
- ),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("yul_bool_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- YulExpression::NumberLiteral(loc, value, ty) => {
- let labels = vec![
- format!("{} literal: {}", ty.to_string(ns), value),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("yul_number_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- YulExpression::StringLiteral(loc, value, ty) => {
- let labels = vec![
- format!("{} literal: {}", ty.to_string(ns), hex::encode(value)),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("bytes_literal", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- YulExpression::YulLocalVariable(loc, ty, var_no) => {
- let labels = vec![
- format!("yul variable: {}", symtable.vars[var_no].id.name),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("yul_variable", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- YulExpression::SolidityLocalVariable(loc, ty, _, var_no) => {
- let labels = vec![
- format!("solidity variable: {}", symtable.vars[var_no].id.name),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("solidity_variable", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- YulExpression::ConstantVariable(loc, ty, contract, var_no) => {
- self.add_constant_variable(loc, ty, contract, var_no, parent, parent_rel, ns);
- }
- YulExpression::StorageVariable(loc, ty, contract, var_no) => {
- self.add_storage_variable(loc, ty, contract, var_no, parent, parent_rel, ns);
- }
- YulExpression::BuiltInCall(loc, builtin_ty, args) => {
- self.add_yul_builtin_call(loc, builtin_ty, args, parent, parent_rel, symtable, ns);
- }
- YulExpression::FunctionCall(loc, func_no, args, _) => {
- self.add_yul_function_call(loc, func_no, args, parent, parent_rel, symtable, ns);
- }
- YulExpression::SuffixAccess(loc, member, suffix) => {
- let labels = vec![
- format!("yul suffix '{}' access", suffix.to_string()),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("yul_suffix_access", labels),
- Some(parent),
- Some(parent_rel),
- );
- self.add_yul_expression(member, symtable, ns, node, "parent".to_string());
- }
- }
- }
- fn add_constant_variable(
- &mut self,
- loc: &Loc,
- ty: &Type,
- contract: &Option<usize>,
- var_no: &usize,
- parent: usize,
- parent_rel: String,
- ns: &Namespace,
- ) {
- let mut labels = vec![
- String::from("constant variable"),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- if let Some(contract) = contract {
- labels.insert(
- 1,
- format!(
- "{}.{}",
- ns.contracts[*contract].name, ns.contracts[*contract].variables[*var_no].name
- ),
- );
- } else {
- labels.insert(1, ns.constants[*var_no].name.to_string());
- }
- self.add_node(
- Node::new("constant", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- fn add_storage_variable(
- &mut self,
- loc: &Loc,
- ty: &Type,
- contract: &usize,
- var_no: &usize,
- parent: usize,
- parent_rel: String,
- ns: &Namespace,
- ) {
- let labels = vec![
- String::from("storage variable"),
- format!(
- "{}.{}",
- ns.contracts[*contract].name, ns.contracts[*contract].variables[*var_no].name
- ),
- ty.to_string(ns),
- ns.loc_to_string(loc),
- ];
- self.add_node(
- Node::new("storage_var", labels),
- Some(parent),
- Some(parent_rel),
- );
- }
- fn add_yul_statement(
- &mut self,
- statement: &YulStatement,
- parent: usize,
- parent_rel: String,
- symtable: &Symtable,
- ns: &Namespace,
- ) -> usize {
- match statement {
- YulStatement::FunctionCall(loc, _, func_no, args) => {
- self.add_yul_function_call(loc, func_no, args, parent, parent_rel, symtable, ns)
- }
- YulStatement::BuiltInCall(loc, _, builtin_ty, args) => {
- self.add_yul_builtin_call(loc, builtin_ty, args, parent, parent_rel, symtable, ns)
- }
- YulStatement::Block(block) => {
- self.add_yul_block(block, parent, parent_rel, symtable, ns)
- }
- YulStatement::VariableDeclaration(loc, _, declared_vars, initializer) => {
- let labels = vec![
- "yul variable declaration".to_string(),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("yul_var_decl", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (decl_no, item) in declared_vars.iter().enumerate() {
- let var = &symtable.vars[&item.0];
- self.add_node(
- Node::new(
- "var_decl_item",
- vec![
- format!(
- "yul variable declaration {} {}",
- var.ty.to_string(ns),
- var.id.name
- ),
- ns.loc_to_string(&var.id.loc),
- ],
- ),
- Some(node),
- Some(format!("decl item #{}", decl_no)),
- );
- }
- if let Some(init) = initializer {
- self.add_yul_expression(init, symtable, ns, node, "init".to_string());
- }
- node
- }
- YulStatement::Assignment(loc, _, lhs, rhs) => {
- let labels = vec!["yul assignment".to_string(), ns.loc_to_string(loc)];
- let node = self.add_node(
- Node::new("yul_assignment", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (item_no, item) in lhs.iter().enumerate() {
- self.add_yul_expression(item, symtable, ns, node, format!("rhs #{}", item_no));
- }
- self.add_yul_expression(rhs, symtable, ns, node, "lhs".to_string());
- node
- }
- YulStatement::IfBlock(loc, _, condition, block) => {
- let labels = vec!["yul if".to_string(), ns.loc_to_string(loc)];
- let node = self.add_node(Node::new("if", labels), Some(parent), Some(parent_rel));
- self.add_yul_expression(condition, symtable, ns, node, "cond".to_string());
- self.add_yul_block(block, node, "if-block".to_string(), symtable, ns);
- node
- }
- YulStatement::Switch {
- loc,
- condition,
- cases,
- default,
- ..
- } => {
- let labels = vec!["yul switch".to_string(), ns.loc_to_string(loc)];
- let node =
- self.add_node(Node::new("switch", labels), Some(parent), Some(parent_rel));
- self.add_yul_expression(condition, symtable, ns, node, "cond".to_string());
- for (item_no, item) in cases.iter().enumerate() {
- let case_block = self.add_node(
- Node::new(
- "case",
- vec!["yul switch case".to_string(), ns.loc_to_string(&item.loc)],
- ),
- Some(node),
- Some(format!("case #{}", item_no)),
- );
- self.add_yul_expression(
- &item.condition,
- symtable,
- ns,
- case_block,
- "case-condition".to_string(),
- );
- self.add_yul_block(
- &item.block,
- case_block,
- "case block".to_string(),
- symtable,
- ns,
- );
- }
- if let Some(default_block) = default {
- let default_node = self.add_node(
- Node::new(
- "default",
- vec![
- "yul switch default".to_string(),
- ns.loc_to_string(&default_block.loc),
- ],
- ),
- Some(node),
- Some("default".to_string()),
- );
- self.add_yul_block(
- default_block,
- default_node,
- "default block".to_string(),
- symtable,
- ns,
- );
- }
- node
- }
- YulStatement::For {
- loc,
- init_block,
- condition,
- post_block,
- execution_block,
- ..
- } => {
- let labels = vec!["yul for".to_string(), ns.loc_to_string(loc)];
- let node = self.add_node(Node::new("for", labels), Some(parent), Some(parent_rel));
- self.add_yul_block(init_block, node, "init block".to_string(), symtable, ns);
- self.add_yul_expression(condition, symtable, ns, node, "for condition".to_string());
- self.add_yul_block(post_block, node, "post block".to_string(), symtable, ns);
- self.add_yul_block(
- execution_block,
- node,
- "execution block".to_string(),
- symtable,
- ns,
- );
- node
- }
- YulStatement::Leave(loc, _) => {
- let labels = vec!["leave".to_string(), ns.loc_to_string(loc)];
- self.add_node(Node::new("leave", labels), Some(parent), Some(parent_rel))
- }
- YulStatement::Break(loc, _) => {
- let labels = vec!["break".to_string(), ns.loc_to_string(loc)];
- self.add_node(Node::new("break", labels), Some(parent), Some(parent_rel))
- }
- YulStatement::Continue(loc, _) => {
- let labels = vec!["continue".to_string(), ns.loc_to_string(loc)];
- self.add_node(
- Node::new("continue", labels),
- Some(parent),
- Some(parent_rel),
- )
- }
- }
- }
- fn add_yul_block(
- &mut self,
- block: &YulBlock,
- mut parent: usize,
- parent_rel: String,
- symtable: &Symtable,
- ns: &Namespace,
- ) -> usize {
- let label = vec!["assembly block".to_string(), ns.loc_to_string(&block.loc)];
- let node = self.add_node(
- Node::new("assembly_block", label),
- Some(parent),
- Some(parent_rel),
- );
- parent = node;
- for (statement_no, child_statement) in block.body.iter().enumerate() {
- parent = self.add_yul_statement(
- child_statement,
- parent,
- format!("statement #{}", statement_no),
- symtable,
- ns,
- );
- }
- node
- }
- fn add_yul_function_call(
- &mut self,
- loc: &Loc,
- func_no: &usize,
- args: &[YulExpression],
- parent: usize,
- parent_rel: String,
- symtable: &Symtable,
- ns: &Namespace,
- ) -> usize {
- let labels = vec![
- format!("yul function call '{}'", ns.yul_functions[*func_no].name),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("yul_function_call", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (arg_no, arg) in args.iter().enumerate() {
- self.add_yul_expression(arg, symtable, ns, node, format!("arg #{}", arg_no));
- }
- node
- }
- fn add_yul_builtin_call(
- &mut self,
- loc: &Loc,
- builtin_ty: &YulBuiltInFunction,
- args: &[YulExpression],
- parent: usize,
- parent_rel: String,
- symtable: &Symtable,
- ns: &Namespace,
- ) -> usize {
- let labels = vec![
- format!("yul builtin call '{}'", builtin_ty.to_string()),
- ns.loc_to_string(loc),
- ];
- let node = self.add_node(
- Node::new("yul_builtin_call", labels),
- Some(parent),
- Some(parent_rel),
- );
- for (arg_no, arg) in args.iter().enumerate() {
- self.add_yul_expression(arg, symtable, ns, node, format!("arg #{}", arg_no));
- }
- node
- }
- }
- impl Namespace {
- pub fn dotgraphviz(&self) -> String {
- let mut dot = Dot {
- filename: format!("{}", self.files[self.top_file_no()].path.display()),
- nodes: Vec::new(),
- edges: Vec::new(),
- };
- // enums
- if !self.enums.is_empty() {
- let enums = dot.add_node(Node::new("enums", Vec::new()), None, None);
- for decl in &self.enums {
- let mut labels = vec![String::new(); decl.values.len()];
- for (name, (_, pos)) in &decl.values {
- labels[*pos] = format!("value: {}", name);
- }
- labels.insert(0, self.loc_to_string(&decl.loc));
- if let Some(contract) = &decl.contract {
- labels.insert(0, format!("contract: {}", contract));
- }
- labels.insert(0, format!("name: {}", decl.name));
- let e = Node::new(&decl.name, labels);
- let node = dot.add_node(e, Some(enums), None);
- dot.add_tags(&decl.tags, node);
- }
- }
- // structs
- if !self.structs.is_empty() {
- let structs = dot.add_node(Node::new("structs", Vec::new()), None, None);
- for decl in &self.structs {
- if let pt::Loc::File(..) = &decl.loc {
- let mut labels =
- vec![format!("name:{}", decl.name), self.loc_to_string(&decl.loc)];
- if let Some(contract) = &decl.contract {
- labels.insert(1, format!("contract: {}", contract));
- }
- for field in &decl.fields {
- labels.push(format!(
- "field name:{} ty:{}",
- field.name_as_str(),
- field.ty.to_string(self)
- ));
- }
- let e = Node::new(&decl.name, labels);
- let node = dot.add_node(e, Some(structs), None);
- dot.add_tags(&decl.tags, node);
- }
- }
- }
- // events
- if !self.events.is_empty() {
- let events = dot.add_node(Node::new("events", Vec::new()), None, None);
- for decl in &self.events {
- let mut labels = vec![format!("name:{}", decl.name), self.loc_to_string(&decl.loc)];
- if let Some(contract) = &decl.contract {
- labels.insert(1, format!("contract: {}", contract));
- }
- if decl.anonymous {
- labels.push(String::from("anonymous"));
- }
- for field in &decl.fields {
- labels.push(format!(
- "field name:{} ty:{} indexed:{}",
- field.name_as_str(),
- field.ty.to_string(self),
- if field.indexed { "yes" } else { "no" }
- ));
- }
- let e = Node::new(&decl.name, labels);
- let node = dot.add_node(e, Some(events), None);
- dot.add_tags(&decl.tags, node);
- }
- }
- // user types
- if !self.user_types.is_empty() {
- let types = dot.add_node(Node::new("types", Vec::new()), None, None);
- for decl in &self.user_types {
- let mut labels = vec![
- format!("name:{} ty:{}", decl.name, decl.ty.to_string(self)),
- self.loc_to_string(&decl.loc),
- ];
- if let Some(contract) = &decl.contract {
- labels.insert(1, format!("contract: {}", contract));
- }
- let e = Node::new(&decl.name, labels);
- let node = dot.add_node(e, Some(types), None);
- dot.add_tags(&decl.tags, node);
- }
- }
- // free functions
- if self
- .functions
- .iter()
- .any(|func| func.contract_no.is_none() && func.loc != pt::Loc::Builtin)
- {
- let functions = dot.add_node(Node::new("free_functions", Vec::new()), None, None);
- for func in &self.functions {
- if func.contract_no.is_none() && func.loc != pt::Loc::Builtin {
- dot.add_function(func, self, functions);
- }
- }
- }
- let contracts = dot.add_node(Node::new("contracts", Vec::new()), None, None);
- // contracts
- for c in &self.contracts {
- let contract = dot.add_node(
- Node::new(
- "contract",
- vec![format!("contract {}", c.name), self.loc_to_string(&c.loc)],
- ),
- Some(contracts),
- None,
- );
- dot.add_tags(&c.tags, contract);
- for base in &c.bases {
- let node = dot.add_node(
- Node::new(
- "base",
- vec![
- format!("base {}", self.contracts[base.contract_no].name),
- self.loc_to_string(&base.loc),
- ],
- ),
- Some(contract),
- Some(String::from("base")),
- );
- if let Some((_, args)) = &base.constructor {
- for (no, arg) in args.iter().enumerate() {
- dot.add_expression(arg, None, self, node, format!("arg #{}", no));
- }
- }
- }
- for var in &c.variables {
- let mut labels = vec![
- format!("variable {}", var.name),
- format!("visibility {}", var.visibility),
- self.loc_to_string(&var.loc),
- ];
- if var.immutable {
- labels.insert(2, String::from("immutable"));
- }
- if var.constant {
- labels.insert(2, String::from("constant"));
- }
- let node = dot.add_node(
- Node::new("var", labels),
- Some(contract),
- Some(String::from("variable")),
- );
- if let Some(initializer) = &var.initializer {
- dot.add_expression(initializer, None, self, node, String::from("initializer"));
- }
- dot.add_tags(&var.tags, node);
- }
- for using in &c.using {
- let mut labels = match &using.list {
- UsingList::Functions(functions) => functions
- .iter()
- .map(|func_no| {
- let func = &self.functions[*func_no];
- format!("function {} {}", func.name, self.loc_to_string(&func.loc))
- })
- .collect(),
- UsingList::Library(library_no) => {
- let library = &self.contracts[*library_no];
- vec![format!("library {}", library.name)]
- }
- };
- if let Some(ty) = &using.ty {
- labels.insert(0, format!("using for {}", ty.to_string(self)));
- }
- dot.add_node(
- Node::new("using", labels),
- Some(contract),
- Some(String::from("base")),
- );
- }
- for func in &c.functions {
- dot.add_function(&self.functions[*func], self, contract);
- }
- }
- // diagnostics
- if !self.diagnostics.is_empty() {
- let diagnostics = dot.add_node(Node::new("diagnostics", Vec::new()), None, None);
- for diag in self.diagnostics.iter() {
- let mut labels = vec![diag.message.to_string(), format!("level {:?}", diag.level)];
- labels.push(self.loc_to_string(&diag.loc));
- let node = dot.add_node(
- Node::new("diagnostic", labels),
- Some(diagnostics),
- Some(format!("{:?}", diag.level)),
- );
- for note in &diag.notes {
- dot.add_node(
- Node::new(
- "note",
- vec![note.message.to_string(), self.loc_to_string(¬e.loc)],
- ),
- Some(node),
- Some(String::from("note")),
- );
- }
- }
- }
- dot.write()
- }
- }
|