From 040ab13911349640e275d3a2e7db4c70980df3b7 Mon Sep 17 00:00:00 2001 From: Dominic Grimm Date: Wed, 28 Sep 2022 18:31:41 +0200 Subject: [PATCH] [WIP] Callable graph --- Cargo.lock | 1 + henceforth/Cargo.toml | 1 + henceforth/examples/test.fth | 3 + henceforth/src/lib/compiler.rs | 187 +++++++++++++-------- henceforth/src/lib/compiler/instruction.rs | 46 ++--- 5 files changed, 143 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19467d1..9bff2a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,6 +250,7 @@ dependencies = [ "itertools", "lazy_static", "parse_int", + "petgraph", ] [[package]] diff --git a/henceforth/Cargo.toml b/henceforth/Cargo.toml index 3f63dfc..e4cb700 100644 --- a/henceforth/Cargo.toml +++ b/henceforth/Cargo.toml @@ -24,4 +24,5 @@ parse_int = "0.6.0" indexmap = "1.9.1" lazy_static = "1.4.0" dependency-graph = "0.1.5" +petgraph = "0.6.2" diff --git a/henceforth/examples/test.fth b/henceforth/examples/test.fth index c1e936e..c661066 100644 --- a/henceforth/examples/test.fth +++ b/henceforth/examples/test.fth @@ -1,3 +1,6 @@ +: test1 40 ; +: test2 test1 2 ; + 1 1 = debug if 69 else 42 then debug diff --git a/henceforth/src/lib/compiler.rs b/henceforth/src/lib/compiler.rs index b0d5001..5e373a3 100644 --- a/henceforth/src/lib/compiler.rs +++ b/henceforth/src/lib/compiler.rs @@ -1,7 +1,8 @@ -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use indexmap::IndexSet; use itertools::Itertools; use lazy_static::lazy_static; +use petgraph::Graph; use std::collections::HashMap; use crate::parser; @@ -9,31 +10,6 @@ use crate::parser; mod instruction; pub use crate::compiler::instruction::Instruction; -pub trait Compilable { - fn compile(&self, data: &T) -> Result; -} - -#[derive(Debug)] -pub struct Word { - pub id: usize, - pub instructions: Vec, - pub times_used: usize, -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct Condition { - pub if_instructions: Vec, - pub else_instructions: Vec, -} - -#[derive(Debug)] -pub struct Data { - pub words: HashMap, - // pub word_graph: - pub conditions: IndexSet, - pub strings: IndexSet, -} - pub const TEMPLATE_ASM: &str = include_str!("compiler/template.asm"); lazy_static! { @@ -45,12 +21,50 @@ lazy_static! { .body; } +pub trait Compilable { + fn compile(&self, data: &T) -> Result; +} + +#[derive(Debug)] +pub struct Word { + pub id: usize, + pub instructions: Vec, + pub times_used: usize, + pub callable_graph_node: petgraph::graph::NodeIndex, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct Condition { + pub if_instructions: Vec, + pub else_instructions: Vec, + pub callable_graph_node: petgraph::graph::NodeIndex, +} + +#[derive(Debug)] +pub enum CallableId { + Word(String), + Condition(usize), +} + +#[derive(Debug)] +pub struct Data { + // pub words: HashMap, + // pub conditions: IndexSet, + pub strings: IndexSet, + pub callable_graph: Graph, + pub words: HashMap, + pub conditions: Vec, +} + impl Data { pub fn default() -> Self { Self { - words: HashMap::new(), - conditions: IndexSet::new(), + // words: HashMap::new(), + // conditions: IndexSet::new(), strings: IndexSet::new(), + callable_graph: Graph::new(), + words: HashMap::new(), + conditions: vec![], } } @@ -104,28 +118,55 @@ impl Data { bail!("Word already exists as user word definition: {}", name); } - let ins = self.generate_instructions(body, optimize)?; - + let origin = self + .callable_graph + .add_node(CallableId::Word(name.to_string())); self.words.insert( - name, + name.to_string(), Word { id: self.words.len(), - instructions: ins, + instructions: vec![], times_used: 0, + callable_graph_node: origin, }, ); + let ins = self.generate_instructions(body, optimize)?; + self.words + .get_mut(&name) + .context(format!("Could not get word: {}", name))? + .instructions = ins.clone(); + + 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 } => { let if_instructions = self.generate_instructions(if_body, optimize)?; let else_instructions = self.generate_instructions(else_body, optimize)?; - let id = self - .conditions - .insert_full(Condition { - if_instructions, - else_instructions, - }) - .0; + let id = self.conditions.len(); + self.conditions.push(Condition { + if_instructions, + else_instructions, + callable_graph_node: self + .callable_graph + .add_node(CallableId::Condition(id)), + }); instructions.push(Instruction::Condition(id)); + self.callable_graph.add_node(CallableId::Condition(id)); } parser::ast::Node::Word(x) => { if let Some(ins) = Instruction::from_word(&x) { @@ -159,42 +200,42 @@ impl Data { } // conditions - for (id, c) in self.conditions.iter().enumerate() { - x.push(hence::parser::ast::Node::Label(format!( - "conditions_if_{}", - id - ))); - x.extend(c.if_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); - x.push(hence::parser::ast::Node::Label(format!("conditions_else_{}", id))); - x.extend(c.else_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); - } + // for (id, c) in self.conditions.iter().enumerate() { + // x.push(hence::parser::ast::Node::Label(format!( + // "conditions_if_{}", + // id + // ))); + // x.extend(c.if_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); + // x.push(hence::parser::ast::Node::Label(format!("conditions_else_{}", id))); + // x.extend(c.else_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); + // } // words - for (name, word) in &self - .words - .iter() - .filter(|(_, w)| w.times_used > 1) - .sorted_by(|a, b| Ord::cmp(&a.1.id, &b.1.id)) - .collect::>() - { - x.extend(vec![ - hence::parser::ast::Node::Label(format!("words_{}", word.id)), - hence::parser::ast::Node::Comment(format!("word: \"{}\"", name)), - ]); - x.extend( - word.instructions - .iter() - .map(|ins| ins.compile(self)) - .collect::>>() - .unwrap() - .into_iter() - .flatten(), - ); - x.push(hence::parser::ast::Node::MacroCall { - name: "return_call_stack_jump".to_string(), - args: vec![], - }); - } + // for (name, word) in &self + // .words + // .iter() + // .filter(|(_, w)| w.times_used > 1) + // .sorted_by(|a, b| Ord::cmp(&a.1.id, &b.1.id)) + // .collect::>() + // { + // x.extend(vec![ + // hence::parser::ast::Node::Label(format!("words_{}", word.id)), + // hence::parser::ast::Node::Comment(format!("word: \"{}\"", name)), + // ]); + // x.extend( + // word.instructions + // .iter() + // .map(|ins| ins.compile(self)) + // .collect::>>() + // .unwrap() + // .into_iter() + // .flatten(), + // ); + // x.push(hence::parser::ast::Node::MacroCall { + // name: "return_call_stack_jump".to_string(), + // args: vec![], + // }); + // } x.extend([ hence::parser::ast::Node::Label("main".to_string()), diff --git a/henceforth/src/lib/compiler/instruction.rs b/henceforth/src/lib/compiler/instruction.rs index 7f653ab..3f7cad0 100644 --- a/henceforth/src/lib/compiler/instruction.rs +++ b/henceforth/src/lib/compiler/instruction.rs @@ -63,15 +63,16 @@ pub enum Instruction { TwoMinus, Times, Divide, - Mod, - Call(String), + Mod, AsmQuote(String), - Condition(usize), Multiple { instruction: Box, count: usize, }, + + Call(String), + Condition(usize), } impl compiler::Compilable for Instruction { @@ -1222,25 +1223,26 @@ impl compiler::Compilable for Instruct }, ]), Instruction::Mod => Ok(vec![]), - Instruction::Call(x) => match data.words.get(x) { - Some(w) => { - if w.times_used > 1 { - Ok(vec![hence::parser::ast::Node::MacroCall { - name: "call_stack_jump".to_string(), - args: vec![hence::arg::Arg::Variable(format!("words_{}", w.id)), hence::arg::Arg::Variable("OFFSET".to_string())], - }]) - } else { - Ok(w.instructions - .iter() - .map(|ins| ins.compile(data)) - .collect::>>()? - .into_iter() - .flatten() - .collect()) - } - } - None => bail!("Unknown word: {}", x), - }, + // Instruction::Call(x) => match data.words.get(x) { + // Some(w) => { + // if w.times_used > 1 { + // Ok(vec![hence::parser::ast::Node::MacroCall { + // name: "call_stack_jump".to_string(), + // args: vec![hence::arg::Arg::Variable(format!("words_{}", w.id)), hence::arg::Arg::Variable("OFFSET".to_string())], + // }]) + // } else { + // Ok(w.instructions + // .iter() + // .map(|ins| ins.compile(data)) + // .collect::>>()? + // .into_iter() + // .flatten() + // .collect()) + // } + // } + // None => bail!("Unknown word: {}", x), + // }, + Instruction::Call(x) => bail!("Unknown word: {}", x), Instruction::AsmQuote(x) => Ok(hence::parser::parse(hence::lexer::lex(x)?)?.body), Instruction::Condition(x) => Ok(vec![]),