Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
Introduce usage tracking in the symbol table
Browse files Browse the repository at this point in the history
  • Loading branch information
alxkzmn committed May 30, 2024
1 parent 97f334b commit 20f12fd
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 84 deletions.
62 changes: 61 additions & 1 deletion src/compiler/semantic/analyser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ impl Analyser {
block,
} => {
let sym = SymTableEntry {
id: id.name(),
definition_ref: dsym,
usages: vec![],
category: SymbolCategory::Machine,
ty: None,
};
Expand Down Expand Up @@ -99,7 +101,9 @@ impl Analyser {
params.iter().for_each(|param| match param {
Statement::SignalDecl(dsym, ids) => ids.iter().for_each(|id| {
let sym = SymTableEntry {
id: id.id.name(),
definition_ref: dsym.clone(),
usages: vec![],
category: SymbolCategory::InputSignal,
ty: id.ty.clone().map(|ty| ty.name()),
};
Expand All @@ -110,7 +114,9 @@ impl Analyser {
}),
Statement::WGVarDecl(dsym, ids) => ids.iter().for_each(|id| {
let sym = SymTableEntry {
id: id.id.name(),
definition_ref: dsym.clone(),
usages: vec![],
category: SymbolCategory::InputWGVar,
ty: id.ty.clone().map(|ty| ty.name()),
};
Expand All @@ -127,7 +133,9 @@ impl Analyser {
params.iter().for_each(|param| match param {
Statement::SignalDecl(dsym, ids) => ids.iter().for_each(|id| {
let sym = SymTableEntry {
id: id.id.name(),
definition_ref: dsym.clone(),
usages: vec![],
category: SymbolCategory::OutputSignal,
ty: id.ty.clone().map(|ty| ty.name()),
};
Expand All @@ -139,7 +147,9 @@ impl Analyser {
}),
Statement::WGVarDecl(dsym, ids) => ids.iter().for_each(|id| {
let sym = SymTableEntry {
id: id.id.name(),
definition_ref: dsym.clone(),
usages: vec![],
category: SymbolCategory::OutputWGVar,
ty: id.ty.clone().map(|ty| ty.name()),
};
Expand All @@ -162,7 +172,9 @@ impl Analyser {
stmts.iter().for_each(|stmt| {
if let Statement::StateDecl(dsym, id, _) = stmt {
let sym = SymTableEntry {
id: id.name(),
definition_ref: dsym.clone(),
usages: vec![],
category: SymbolCategory::State,
ty: None,
};
Expand All @@ -189,7 +201,9 @@ impl Analyser {
);

let sym = SymTableEntry {
id: id.name(),
definition_ref: block.get_dsym(),
usages: vec![],
category: SymbolCategory::State,
ty: None,
};
Expand Down Expand Up @@ -220,7 +234,9 @@ impl Analyser {
match stmt.clone() {
Statement::SignalDecl(dsym, ids) => ids.into_iter().for_each(|id| {
let sym = SymTableEntry {
id: id.id.name(),
category: SymbolCategory::Signal,
usages: vec![],
definition_ref: dsym.clone(),
ty: id.ty.map(|ty| ty.name()),
};
Expand All @@ -231,7 +247,9 @@ impl Analyser {
}),
Statement::WGVarDecl(dsym, ids) => ids.into_iter().for_each(|id| {
let sym = SymTableEntry {
id: id.id.name(),
category: SymbolCategory::WGVar,
usages: vec![],
definition_ref: dsym.clone(),
ty: id.ty.map(|ty| ty.name()),
};
Expand All @@ -243,6 +261,17 @@ impl Analyser {
// State decl symbols are added in
// add_state_decls
Statement::StateDecl(_, _, _) => {}
Statement::Transition(dsym_ref, id, _) => {
// Find the corresponding symbol and add usage
if let Some(entry) = self.symbols.find_symbol(&self.cur_scope, id.name()) {
// TODO implement find by id AND category?
if entry.symbol.category == SymbolCategory::State {
let mut entry = entry.symbol.clone();
entry.usages.push(dsym_ref);
self.symbols.add_symbol(&self.cur_scope, id.name(), entry);
}
}
}
_ => {}
}
}
Expand Down Expand Up @@ -282,9 +311,40 @@ impl Analyser {
}

fn analyse_expression(&mut self, expr: Expression<BigInt, Identifier>) {
self.extract_usages_recursively(&expr);
RULES.apply_expression(self, &expr)
}

fn extract_usages_recursively(&mut self, expr: &Expression<BigInt, Identifier>) {
match expr.clone() {
Expression::Query(dsym_ref, id) => {
// Find the corresponding symbol and add usage
if let Some(entry) = self.symbols.find_symbol(&self.cur_scope, id.name()) {
let mut entry = entry.symbol.clone();
entry.usages.push(dsym_ref);
self.symbols.add_symbol(&self.cur_scope, id.name(), entry);
}
}
Expression::BinOp {
dsym: _,
op: _,
lhs,
rhs,
} => {
self.extract_usages_recursively(&lhs);
self.extract_usages_recursively(&rhs);
}
Expression::UnaryOp {
dsym: _,
op: _,
sub,
} => {
self.extract_usages_recursively(&sub);
}
_ => {}
}
}

pub(super) fn error<S: Into<String>>(&mut self, msg: S, dsym: &DebugSymRef) {
self.messages.push(Message::SemErr {
msg: msg.into(),
Expand Down Expand Up @@ -360,7 +420,7 @@ mod test {

assert_eq!(
format!("{:?}", result),
r#"AnalysisResult { symbols: "/": ScopeTable { symbols: "\"fibo\": SymTableEntry { definition_ref: DebugSymRef { start: \"2:9\", end: \"40:13\" }, category: Machine, ty: None }", scope: Global },"//fibo": ScopeTable { symbols: "\"a\": SymTableEntry { definition_ref: DebugSymRef { line: 5, cols: \"13-32\" }, category: Signal, ty: Some(\"field\") },\"b\": SymTableEntry { definition_ref: DebugSymRef { line: 2, cols: \"33-48\" }, category: OutputSignal, ty: Some(\"field\") },\"final\": SymTableEntry { definition_ref: DebugSymRef { start: \"2:50\", end: \"40:13\" }, category: State, ty: None },\"i\": SymTableEntry { definition_ref: DebugSymRef { line: 5, cols: \"13-32\" }, category: Signal, ty: None },\"initial\": SymTableEntry { definition_ref: DebugSymRef { start: \"10:13\", end: \"18:14\" }, category: State, ty: None },\"middle\": SymTableEntry { definition_ref: DebugSymRef { start: \"20:13\", end: \"34:14\" }, category: State, ty: None },\"n\": SymTableEntry { definition_ref: DebugSymRef { line: 2, cols: \"22-30\" }, category: InputSignal, ty: None }", scope: Machine },"//fibo/final": ScopeTable { symbols: "", scope: State },"//fibo/initial": ScopeTable { symbols: "\"c\": SymTableEntry { definition_ref: DebugSymRef { line: 11, cols: \"14-23\" }, category: Signal, ty: None }", scope: State },"//fibo/middle": ScopeTable { symbols: "\"c\": SymTableEntry { definition_ref: DebugSymRef { line: 21, cols: \"14-23\" }, category: Signal, ty: None }", scope: State }, messages: [] }"#
r#"AnalysisResult { symbols: "/": ScopeTable { symbols: "\\"fibo\\": SymTableEntry { id: \\"fibo\\", definition_ref: DebugSymRef { start: \\"2:9\\", end: \\"40:13\\" }, usages: [], category: Machine, ty: None }", scope: Global },"//fibo": ScopeTable { symbols: "\\"a\\": SymTableEntry { id: \\"a\\", definition_ref: DebugSymRef { line: 5, cols: \\"13-32\\" }, usages: [], category: Signal, ty: Some(\\"field\\") },\\"b\\": SymTableEntry { id: \\"b\\", definition_ref: DebugSymRef { line: 2, cols: \\"33-48\\" }, usages: [], category: OutputSignal, ty: Some(\\"field\\") },\\"final\\": SymTableEntry { id: \\"final\\", definition_ref: DebugSymRef { start: \\"2:50\\", end: \\"40:13\\" }, usages: [], category: State, ty: None },\\"i\\": SymTableEntry { id: \\"i\\", definition_ref: DebugSymRef { line: 5, cols: \\"13-32\\" }, usages: [], category: Signal, ty: None },\\"initial\\": SymTableEntry { id: \\"initial\\", definition_ref: DebugSymRef { start: \\"10:13\\", end: \\"18:14\\" }, usages: [], category: State, ty: None },\\"middle\\": SymTableEntry { id: \\"middle\\", definition_ref: DebugSymRef { start: \\"20:13\\", end: \\"34:14\\" }, usages: [], category: State, ty: None },\\"n\\": SymTableEntry { id: \\"n\\", definition_ref: DebugSymRef { line: 2, cols: \\"22-30\\" }, usages: [], category: InputSignal, ty: None }", scope: Machine },"//fibo/final": ScopeTable { symbols: "", scope: State },"//fibo/initial": ScopeTable { symbols: "\\"b\\": SymTableEntry { id: \\"b\\", definition_ref: DebugSymRef { line: 2, cols: \\"33-48\\" }, usages: [DebugSymRef { line: 16, cols: \\"30-31\\" }], category: OutputSignal, ty: Some(\\"field\\") },\\"c\\": SymTableEntry { id: \\"c\\", definition_ref: DebugSymRef { line: 11, cols: \\"14-23\\" }, usages: [DebugSymRef { line: 16, cols: \\"33-34\\" }], category: Signal, ty: None },\\"middle\\": SymTableEntry { id: \\"middle\\", definition_ref: DebugSymRef { start: \\"20:13\\", end: \\"34:14\\" }, usages: [DebugSymRef { start: \\"15:14\\", end: \\"17:15\\" }], category: State, ty: None },\\"n\\": SymTableEntry { id: \\"n\\", definition_ref: DebugSymRef { line: 2, cols: \\"22-30\\" }, usages: [DebugSymRef { line: 16, cols: \\"36-37\\" }], category: InputSignal, ty: None }", scope: State },"//fibo/initial/middle": ScopeTable { symbols: "", scope: State },"//fibo/middle": ScopeTable { symbols: "\\"a\\": SymTableEntry { id: \\"a\\", definition_ref: DebugSymRef { line: 5, cols: \\"13-32\\" }, usages: [DebugSymRef { line: 23, cols: \\"20-21\\" }], category: Signal, ty: Some(\\"field\\") },\\"b\\": SymTableEntry { id: \\"b\\", definition_ref: DebugSymRef { line: 2, cols: \\"33-48\\" }, usages: [DebugSymRef { line: 23, cols: \\"24-25\\" }, DebugSymRef { line: 31, cols: \\"42-43\\" }], category: OutputSignal, ty: Some(\\"field\\") },\\"c\\": SymTableEntry { id: \\"c\\", definition_ref: DebugSymRef { line: 21, cols: \\"14-23\\" }, usages: [DebugSymRef { line: 27, cols: \\"38-39\\" }, DebugSymRef { line: 31, cols: \\"45-46\\" }], category: Signal, ty: None },\\"final\\": SymTableEntry { id: \\"final\\", definition_ref: DebugSymRef { start: \\"2:50\\", end: \\"40:13\\" }, usages: [DebugSymRef { start: \\"26:15\\", end: \\"28:16\\" }], category: State, ty: None },\\"i\\": SymTableEntry { id: \\"i\\", definition_ref: DebugSymRef { line: 5, cols: \\"13-32\\" }, usages: [DebugSymRef { line: 25, cols: \\"17-18\\" }, DebugSymRef { line: 27, cols: \\"31-32\\" }, DebugSymRef { line: 31, cols: \\"35-36\\" }], category: Signal, ty: None },\\"middle\\": SymTableEntry { id: \\"middle\\", definition_ref: DebugSymRef { start: \\"20:13\\", end: \\"34:14\\" }, usages: [DebugSymRef { start: \\"30:15\\", end: \\"32:16\\" }], category: State, ty: None },\\"n\\": SymTableEntry { id: \\"n\\", definition_ref: DebugSymRef { line: 2, cols: \\"22-30\\" }, usages: [DebugSymRef { line: 25, cols: \\"26-27\\" }, DebugSymRef { line: 27, cols: \\"41-42\\" }, DebugSymRef { line: 31, cols: \\"48-49\\" }], category: InputSignal, ty: None }", scope: State },"//fibo/middle/final": ScopeTable { symbols: "", scope: State },"//fibo/middle/middle": ScopeTable { symbols: "", scope: State }, messages: [] }"#
)
}
}
68 changes: 67 additions & 1 deletion src/compiler/semantic/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
collections::HashMap,
collections::{BTreeMap, HashMap},
fmt::{Debug, Display},
};

Expand Down Expand Up @@ -48,7 +48,9 @@ pub enum ScopeCategory {
/// Information about a symbol
#[derive(Clone, Debug)]
pub struct SymTableEntry {
pub id: String,
pub definition_ref: DebugSymRef,
pub usages: Vec<DebugSymRef>,
pub category: SymbolCategory,
/// Type
pub ty: Option<String>,
Expand Down Expand Up @@ -85,6 +87,7 @@ pub struct FoundSymbol {
pub symbol: SymTableEntry,
pub scope: ScopeCategory,
pub level: usize,
pub usages: Vec<DebugSymRef>,
}

/// Contains the symbols of an scope
Expand Down Expand Up @@ -211,6 +214,7 @@ impl SymTable {
symbol: symbol.clone(),
scope: table.scope.clone(),
level,
usages: symbol.usages.clone(),
});
}

Expand Down Expand Up @@ -286,6 +290,68 @@ impl SymTable {
.join("/")
}
}

pub fn find_symbol_by_offset(&self, filename: String, offset: usize) -> Option<SymTableEntry> {
let mut symbols_by_proximity = BTreeMap::<i32, SymTableEntry>::new();

for scope in self.scopes.values() {
for (_, entry) in &scope.symbols {
// If the entry is not in the same file, check its usages
if entry.definition_ref.get_filename() != filename.clone() {
SymTable::look_in_usages(
entry,
filename.clone(),
offset,
&mut symbols_by_proximity,
);
} else {
let proximity = entry.definition_ref.proximity_score(offset);
// If the current entry is not enclosing the offset, check the usages of that
// entry
if proximity == -1 {
SymTable::look_in_usages(
entry,
filename.clone(),
offset,
&mut symbols_by_proximity,
);
// If the current entry is enclosing the offset, add it to the map
} else {
symbols_by_proximity.insert(proximity, entry.clone());
}
}
}
}

if symbols_by_proximity.is_empty() {
return None;
} else {
// Return the first symbol in the map because BTreeMap is sorted by the key (which is
// the proximity in our case)
return symbols_by_proximity
.iter()
.next()
.map(|(_, entry)| entry.clone());
}
}

fn look_in_usages(
entry: &SymTableEntry,
filename: String,
offset: usize,
symbols_by_proximity: &mut BTreeMap<i32, SymTableEntry>,
) {
for usage in &entry.usages {
if usage.get_filename() != filename {
continue;
}
let usage_proximity = usage.proximity_score(offset);
if usage_proximity != -1 {
symbols_by_proximity.insert(usage_proximity, entry.clone());
break;
}
}
}
}

/// Result from running the semantic analyser.
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/semantic/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ mod test {

assert_eq!(
format!("{:?}", result.messages),
r#"[SemErr { msg: "Cannot declare state nested here", dsym: DebugSymRef { start: 0, end: 0 } }]"#
r#"[SemErr { msg: "Cannot declare state nested here", dsym: DebugSymRef { start: "13:17", end: "15:18" } }]"#
);

let circuit = "
Expand Down Expand Up @@ -687,7 +687,7 @@ mod test {

assert_eq!(
format!("{:?}", result.messages),
r#"[SemErr { msg: "Cannot declare state nested here", dsym: DebugSymRef { start: 0, end: 0 } }]"#
r#"[SemErr { msg: "Cannot declare state nested here", dsym: DebugSymRef { start: "18:1", end: "20:29" } }]"#
);
}

Expand Down
51 changes: 5 additions & 46 deletions src/parser/ast/debug_sym_factory.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::rc::Rc;
use std::sync::Arc;

use codespan_reporting::files::{Files, SimpleFile};
use codespan_reporting::files::SimpleFile;

use super::DebugSymRef;

/// Factory for creating debug symbol references.
pub struct DebugSymRefFactory {
/// Source file reference.
file: Rc<SimpleFile<String, String>>,
file: Arc<SimpleFile<String, String>>,
}

impl DebugSymRefFactory {
Expand All @@ -22,7 +22,7 @@ impl DebugSymRefFactory {
///
/// A new debug symbol reference factory.
pub fn new(file_path: &str, contents: &str) -> DebugSymRefFactory {
let file = Rc::new(SimpleFile::new(file_path.to_string(), contents.to_string()));
let file = Arc::new(SimpleFile::new(file_path.to_string(), contents.to_string()));

DebugSymRefFactory { file }
}
Expand All @@ -34,47 +34,6 @@ impl DebugSymRefFactory {
/// * `start` - Start position of the debug symbol byte reference in the source string.
/// * `end` - End position of the debug symbol byte reference in the source string.
pub fn create(&self, start: usize, end: usize) -> DebugSymRef {
let start_line_index = self.get_line_index(start);
let start_line_number = self.get_line_number(start_line_index);
let start_col_number = self.get_column_number(start_line_index, start);

let end_line_index = self.get_line_index(end);
let end_line_number = self.get_line_number(end_line_index);
let end_col_number = self.get_column_number(end_line_index, end);

DebugSymRef::new(
start_line_number,
start_col_number,
end_line_number,
end_col_number,
Rc::clone(&self.file),
)
}

fn get_column_number(&self, line_index: usize, start: usize) -> usize {
match self.file.column_number((), line_index, start) {
Ok(number) => number,
Err(err) => {
panic!("Column number at {} not found: {}", line_index, err);
}
}
}

fn get_line_index(&self, start: usize) -> usize {
match self.file.line_index((), start) {
Ok(index) => index,
Err(err) => {
panic!("Line index at {} not found: {}", start, err);
}
}
}

fn get_line_number(&self, line_index: usize) -> usize {
match self.file.line_number((), line_index) {
Ok(number) => number,
Err(err) => {
panic!("Line number at {} not found: {}", line_index, err);
}
}
DebugSymRef::new(start, end, Arc::clone(&self.file))
}
}
Loading

0 comments on commit 20f12fd

Please sign in to comment.