call-graph #1

Merged
dergrimm merged 4 commits from call-graph into main 2022-10-26 09:19:45 +00:00
5 changed files with 69 additions and 51 deletions
Showing only changes of commit 2c67dba4d7 - Show all commits

View file

@ -264,8 +264,8 @@ pub fn parse_binary_expression_arg(tokens: &mut Vec<&lexer::Token>) -> Result<Ar
let mut args: Vec<_> = tokens.drain(..3).collect(); let mut args: Vec<_> = tokens.drain(..3).collect();
let mut bin_expr = Arg::BinaryExpression { let mut bin_expr = Arg::BinaryExpression {
left: Box::new((&parse_args(vec![args[0]])?[0]).clone()), left: Box::new(parse_args(vec![args[0]])?[0].clone()),
right: Box::new((&parse_args(vec![args[2]])?[0]).clone()), right: Box::new(parse_args(vec![args[2]])?[0].clone()),
op: parse_binary_operation(args[1])?, op: parse_binary_operation(args[1])?,
}; };
@ -273,7 +273,7 @@ pub fn parse_binary_expression_arg(tokens: &mut Vec<&lexer::Token>) -> Result<Ar
args = tokens.drain(..2).collect(); args = tokens.drain(..2).collect();
bin_expr = Arg::BinaryExpression { bin_expr = Arg::BinaryExpression {
left: Box::new(bin_expr), left: Box::new(bin_expr),
right: Box::new((&parse_args(vec![args[1]])?[0]).clone()), right: Box::new(parse_args(vec![args[1]])?[0].clone()),
op: parse_binary_operation(args[0])?, op: parse_binary_operation(args[0])?,
} }
} }

View file

@ -158,7 +158,7 @@ impl Data {
bail!("First argument of define macro needs to be a variable") bail!("First argument of define macro needs to be a variable")
} }
}; };
self.constants.insert(name.clone(), (&args[1]).clone()); self.constants.insert(name.clone(), args[1].clone());
Ok(None) Ok(None)
} }
@ -181,7 +181,7 @@ impl Data {
bail!("First argument of define macro needs to be a literal-like value") bail!("First argument of define macro needs to be a literal-like value")
} }
}; };
let args = (&args[1..]) let args = args[1..]
.iter() .iter()
.map(|a| match a { .map(|a| match a {
arg::Arg::Variable(x) => Ok(x.clone()), arg::Arg::Variable(x) => Ok(x.clone()),
@ -380,20 +380,17 @@ impl Data {
while !self.body_stack.is_empty() { while !self.body_stack.is_empty() {
self.constants self.constants
.insert(offset_name.clone(), arg::Arg::Number(self.offset)); .insert(offset_name.clone(), arg::Arg::Number(self.offset));
match self.resolve_node()? { if let Some(x) = self.resolve_node()? {
Some(x) => { if self.offset + (x.len() as u16) > 32 * 1024 {
if self.offset + (x.len() as u16) > 32 * 1024 { bail!(
bail!( "Offset out of bounds: 0x{} > 0x8000",
"Offset out of bounds: 0x{} > 0x8000", radix(self.offset, 16)
radix(self.offset, 16) );
); }
} for byte in x {
for byte in x { self.program[self.offset as usize] = byte;
self.program[self.offset as usize] = byte; self.offset += 1;
self.offset += 1;
}
} }
None => {}
} }
} }

View file

@ -20,7 +20,7 @@ pub fn parse(tokens: Vec<lexer::Token>) -> Result<ast::AST> {
iter.next(); iter.next();
body.push(ast::Node::MacroCall { body.push(ast::Node::MacroCall {
name: (&x[1..]).to_string(), name: x[1..].to_string(),
args: arg::parse_args( args: arg::parse_args(
iter.by_ref() iter.by_ref()
.take_while(|t| !matches!(t, lexer::Token::Newline(_))) .take_while(|t| !matches!(t, lexer::Token::Newline(_)))

View file

@ -2,7 +2,7 @@ use anyhow::{bail, Context, Result};
use indexmap::IndexSet; use indexmap::IndexSet;
use itertools::Itertools; use itertools::Itertools;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use petgraph::Graph; use petgraph::{graph::NodeIndex, Graph};
use std::collections::HashMap; use std::collections::HashMap;
use crate::parser; use crate::parser;
@ -10,7 +10,7 @@ use crate::parser;
mod instruction; mod instruction;
pub use crate::compiler::instruction::Instruction; pub use crate::compiler::instruction::Instruction;
pub const TEMPLATE_ASM: &str = include_str!("compiler/template.asm"); pub const TEMPLATE_ASM: &str = include_str!("compiler/templates/default.asm");
lazy_static! { lazy_static! {
#[derive(Debug)] #[derive(Debug)]
@ -30,14 +30,14 @@ pub struct Word {
pub id: usize, pub id: usize,
pub instructions: Vec<Instruction>, pub instructions: Vec<Instruction>,
pub times_used: usize, pub times_used: usize,
pub callable_graph_node: petgraph::graph::NodeIndex, pub callable_graph_node: NodeIndex,
} }
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
pub struct Condition { pub struct Condition {
pub if_instructions: Vec<Instruction>, pub if_instructions: Vec<Instruction>,
pub else_instructions: Vec<Instruction>, pub else_instructions: Vec<Instruction>,
pub callable_graph_node: petgraph::graph::NodeIndex, pub callable_graph_node: NodeIndex,
} }
#[derive(Debug)] #[derive(Debug)]
@ -48,8 +48,6 @@ pub enum CallableId {
#[derive(Debug)] #[derive(Debug)]
pub struct Data { pub struct Data {
// pub words: HashMap<String, Word>,
// pub conditions: IndexSet<Condition>,
pub strings: IndexSet<String>, pub strings: IndexSet<String>,
pub callable_graph: Graph<CallableId, ()>, pub callable_graph: Graph<CallableId, ()>,
pub words: HashMap<String, Word>, pub words: HashMap<String, Word>,
@ -68,6 +66,45 @@ impl Data {
} }
} }
pub fn add_graph_edge(&mut self, origin: NodeIndex, instruction: Instruction) -> Result<()> {
match instruction {
Instruction::Call(x) => {
self.callable_graph.add_edge(
origin,
self.words
.get(&x)
.context(format!("Could not get referenced word: {}", x))?
.callable_graph_node,
(),
);
}
Instruction::Condition(x) => {
self.callable_graph.add_edge(
origin,
self.conditions
.get(x)
.context(format!("Could not get referenced condition: {}", x))?
.callable_graph_node,
(),
);
}
Instruction::Multiple { instruction, count: _ } => {
self.add_graph_edge(origin, *instruction)?;
}
_ => {}
}
Ok(())
}
pub fn add_graph_edges(&mut self, origin: NodeIndex, ins: Vec<Instruction>) -> Result<()> {
for instruction in ins {
self.add_graph_edge(origin, instruction)?;
}
Ok(())
}
pub fn generate_instructions( pub fn generate_instructions(
&mut self, &mut self,
body: parser::ast::Body, body: parser::ast::Body,
@ -135,45 +172,29 @@ impl Data {
.get_mut(&name) .get_mut(&name)
.context(format!("Could not get word: {}", name))? .context(format!("Could not get word: {}", name))?
.instructions = ins.clone(); .instructions = ins.clone();
self.add_graph_edges(origin, ins)?;
for instruction in ins {
match instruction {
Instruction::Call(x) => {
self.callable_graph.add_edge(
origin,
self.words
.get(&x)
.context(format!("Could not get referenced word: {}", x))?
.callable_graph_node,
(),
);
}
Instruction::Condition(x) => {}
_ => {}
}
}
dbg!(&self);
} }
parser::ast::Node::Condition { if_body, else_body } => { parser::ast::Node::Condition { if_body, else_body } => {
let if_instructions = self.generate_instructions(if_body, optimize)?; let if_instructions = self.generate_instructions(if_body, optimize)?;
let else_instructions = self.generate_instructions(else_body, optimize)?; let else_instructions = self.generate_instructions(else_body, optimize)?;
let id = self.conditions.len(); let id = self.conditions.len();
let origin = self.callable_graph.add_node(CallableId::Condition(id));
self.conditions.push(Condition { self.conditions.push(Condition {
if_instructions, if_instructions: if_instructions.clone(),
else_instructions, else_instructions: else_instructions.clone(),
callable_graph_node: self callable_graph_node: origin,
.callable_graph
.add_node(CallableId::Condition(id)),
}); });
instructions.push(Instruction::Condition(id)); instructions.push(Instruction::Condition(id));
self.callable_graph.add_node(CallableId::Condition(id)); self.add_graph_edges(origin, if_instructions)?;
self.add_graph_edges(origin, else_instructions)?;
dbg!(&self);
} }
parser::ast::Node::Word(x) => { parser::ast::Node::Word(x) => {
if let Some(ins) = Instruction::from_word(&x) { if let Some(ins) = Instruction::from_word(&x) {
instructions.push(ins); instructions.push(ins);
} else if let Some(w) = self.words.get_mut(&x) { } else if let Some(w) = self.words.get_mut(&x) {
instructions.push(Instruction::Call(x));
w.times_used += 1; w.times_used += 1;
instructions.push(Instruction::Call(x));
} else { } else {
bail!("Word does not exist: {}", x); bail!("Word does not exist: {}", x);
} }
@ -229,7 +250,7 @@ impl Data {
// .collect::<Result<Vec<hence::parser::ast::Body>>>() // .collect::<Result<Vec<hence::parser::ast::Body>>>()
// .unwrap() // .unwrap()
// .into_iter() // .into_iter()
// .flatten(), // .flatten()
// ); // );
// x.push(hence::parser::ast::Node::MacroCall { // x.push(hence::parser::ast::Node::MacroCall {
// name: "return_call_stack_jump".to_string(), // name: "return_call_stack_jump".to_string(),