Skip to content

Commit

Permalink
Exposing SPPF as output from GLR parsing (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
woutersl committed Sep 26, 2023
1 parent a866e24 commit 4428d81
Show file tree
Hide file tree
Showing 13 changed files with 1,366 additions and 431 deletions.
100 changes: 38 additions & 62 deletions runtime-rust/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use crate::symbols::{SemanticElementTrait, Symbol};
use crate::text::{TextContext, TextPosition, TextSpan};
use crate::tokens::{Token, TokenRepository};
use crate::utils::biglist::BigList;
use crate::utils::EitherMut;

/// Represents a type of symbol table
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
Expand All @@ -53,7 +52,7 @@ impl From<usize> for TableType {
}

/// Represents a compact reference to an element in a table
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct TableElemRef {
/// The backend data
data: usize
Expand Down Expand Up @@ -131,20 +130,39 @@ impl AstImpl {
pub fn has_root(&self) -> bool {
self.root.is_some()
}

/// Stores the root of this tree
pub fn store_root(&mut self, node: AstCell) {
self.root = Some(self.nodes.push(node));
}

/// Stores some children nodes in this AST
#[must_use]
pub fn store(&mut self, nodes: &[AstCell], index: usize, count: usize) -> usize {
if count == 0 {
0
} else {
let result = self.nodes.push(nodes[index]);
for i in 1..count {
self.nodes.push(nodes[index + i]);
}
result
}
}
}

/// Represents a simple AST with a tree structure
/// The nodes are stored in sequential arrays where the children of a node are an inner sequence.
/// The linkage is represented by each node storing its number of children and the index of its first child.
pub struct Ast<'s, 't, 'a> {
/// The table of tokens
tokens: Option<TokenRepository<'s, 't, 'a>>,
tokens: TokenRepository<'s, 't, 'a>,
/// The table of variables
pub variables: &'a [Symbol<'s>],
variables: &'a [Symbol<'s>],
/// The table of virtuals
pub virtuals: &'a [Symbol<'s>],
virtuals: &'a [Symbol<'s>],
/// The data of the implementation
data: EitherMut<'a, AstImpl>
data: &'a AstImpl
}

impl<'s, 't, 'a> Ast<'s, 't, 'a> {
Expand All @@ -157,33 +175,16 @@ impl<'s, 't, 'a> Ast<'s, 't, 'a> {
data: &'a AstImpl
) -> Ast<'s, 't, 'a> {
Ast {
tokens: Some(tokens),
tokens,
variables,
virtuals,
data: EitherMut::Immutable(data)
}
}

/// Creates a new AST proxy structure
pub fn new_mut(
variables: &'a [Symbol<'s>],
virtuals: &'a [Symbol<'s>],
data: &'a mut AstImpl
) -> Ast<'s, 't, 'a> {
Ast {
tokens: None,
variables,
virtuals,
data: EitherMut::Mutable(data)
data
}
}

/// Gets the i-th token in the associated repository
fn get_token(&'a self, index: usize) -> Token<'s, 't, 'a> {
self.tokens
.as_ref()
.expect("Missing token repository")
.get_token(index)
self.tokens.get_token(index)
}

/// Gets whether a root has been defined for this AST
Expand Down Expand Up @@ -237,7 +238,6 @@ impl<'s, 't, 'a> Ast<'s, 't, 'a> {
#[must_use]
pub fn find_node_at_index(&self, index: usize) -> Option<AstNode> {
self.tokens
.as_ref()?
.find_token_at(index)
.and_then(|token| self.find_node_for(&token))
}
Expand All @@ -246,9 +246,8 @@ impl<'s, 't, 'a> Ast<'s, 't, 'a> {
/// a token label that contains the specified index in the input text
#[must_use]
pub fn find_node_at_position(&self, position: TextPosition) -> Option<AstNode> {
let tokens = self.tokens.as_ref()?;
let index = tokens.text.get_line_index(position.line) + position.column - 1;
tokens
let index = self.tokens.text.get_line_index(position.line) + position.column - 1;
self.tokens
.find_token_at(index)
.and_then(|token| self.find_node_for(&token))
}
Expand Down Expand Up @@ -317,7 +316,7 @@ impl<'s, 't, 'a> Ast<'s, 't, 'a> {
for i in (0..cell.count).rev() {
stack.push((cell.first + i) as usize);
}
action(&self.data, current);
action(self.data, current);
}
}

Expand Down Expand Up @@ -346,24 +345,6 @@ impl<'s, 't, 'a> Ast<'s, 't, 'a> {
_ => None
}
}

/// Stores some children nodes in this AST
pub fn store(&mut self, nodes: &[AstCell], index: usize, count: usize) -> usize {
if count == 0 {
0
} else {
let result = self.data.nodes.push(nodes[index]);
for i in 1..count {
self.data.nodes.push(nodes[index + i]);
}
result
}
}

/// Stores the root of this tree
pub fn store_root(&mut self, node: AstCell) {
self.data.root = Some(self.data.nodes.push(node));
}
}

/// Represents a node in an Abstract Syntax Tree
Expand Down Expand Up @@ -439,12 +420,12 @@ impl<'s, 't, 'a> AstNode<'s, 't, 'a> {
impl<'s, 't, 'a> SemanticElementTrait<'s, 'a> for AstNode<'s, 't, 'a> {
/// Gets the position in the input text of this element
fn get_position(&self) -> Option<TextPosition> {
self.tree.get_position_at(&self.tree.data, self.index)
self.tree.get_position_at(self.tree.data, self.index)
}

/// Gets the span in the input text of this element
fn get_span(&self) -> Option<TextSpan> {
self.tree.get_span_at(&self.tree.data, self.index)
self.tree.get_span_at(self.tree.data, self.index)
}

/// Gets the context of this element in the input
Expand All @@ -470,10 +451,8 @@ impl<'s, 't, 'a> SemanticElementTrait<'s, 'a> for AstNode<'s, 't, 'a> {
TableType::Variable => self.tree.variables[cell.label.index()],
TableType::Virtual => self.tree.virtuals[cell.label.index()],
TableType::None => {
match &self.tree.tokens {
None => panic!("Missing token repository"),
Some(repository) => repository.terminals[0] // terminal epsilon
}
// terminal epsilon
self.tree.tokens.terminals[0]
}
}
}
Expand Down Expand Up @@ -531,12 +510,9 @@ impl<'s, 't, 'a> Display for AstNode<'s, 't, 'a> {
let symbol = self.tree.virtuals[cell.label.index()];
write!(f, "{}", symbol.name)
}
TableType::None => match &self.tree.tokens {
None => panic!("Missing token repository"),
Some(repository) => {
let symbol = repository.terminals[0];
write!(f, "{}", symbol.name)
}
TableType::None => {
let symbol = self.tree.tokens.terminals[0];
write!(f, "{}", symbol.name)
}
}
}
Expand Down Expand Up @@ -572,7 +548,7 @@ pub struct AstFamilyIterator<'s, 't, 'a> {
tree: &'a Ast<'s, 't, 'a>,
/// The index of the current child in the parse tree
current: usize,
/// the index of the last child (excluded) in the parse tree
/// The index of the last child (excluded) in the parse tree
end: usize
}

Expand Down
1 change: 1 addition & 0 deletions runtime-rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub mod errors;
pub mod lexers;
pub mod parsers;
pub mod result;
pub mod sppf;
pub mod symbols;
pub mod text;
pub mod tokens;
Expand Down
40 changes: 23 additions & 17 deletions runtime-rust/src/parsers/lrk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use super::{
TREE_ACTION_NONE, TREE_ACTION_PROMOTE, TREE_ACTION_REPLACE_BY_CHILDREN,
TREE_ACTION_REPLACE_BY_EPSILON
};
use crate::ast::{Ast, TableElemRef, TableType};
use crate::ast::{AstImpl, TableElemRef, TableType};
use crate::errors::ParseErrorUnexpectedToken;
use crate::lexers::{Lexer, TokenKernel, DEFAULT_CONTEXT};
use crate::symbols::{SemanticBody, SemanticElement, SemanticElementTrait};
Expand Down Expand Up @@ -175,10 +175,14 @@ impl LRkAstReduction {
struct LRkAstBuilder<'s, 't, 'a> {
/// Lexer associated to this parser
lexer: &'a mut Lexer<'s, 't, 'a>,
/// The table of variables
variables: &'a [Symbol<'s>],
/// The table of virtuals
virtuals: &'a [Symbol<'s>],
/// The stack of semantic objects
stack: Vec<SubTree>,
/// The AST being built
result: Ast<'s, 't, 'a>,
result: &'a mut AstImpl,
/// The reduction handle represented as the indices of the sub-trees in the cache
handle: Vec<usize>,
/// The data of the current reduction
Expand All @@ -195,12 +199,8 @@ impl<'s, 't, 'a> SemanticBody for LRkAstBuilder<'s, 't, 'a> {
TableType::Token => SemanticElement::Token(
self.lexer.get_data().repository.get_token(label.index())
),
TableType::Variable => {
SemanticElement::Variable(self.result.variables[label.index()])
}
TableType::Virtual => {
SemanticElement::Virtual(self.result.virtuals[label.index()])
}
TableType::Variable => SemanticElement::Variable(self.variables[label.index()]),
TableType::Virtual => SemanticElement::Virtual(self.virtuals[label.index()]),
TableType::None => {
SemanticElement::Terminal(self.lexer.get_data().repository.terminals[0])
}
Expand All @@ -218,10 +218,14 @@ impl<'s, 't, 'a> LRkAstBuilder<'s, 't, 'a> {
/// Initializes the builder with the given stack size
pub fn new(
lexer: &'a mut Lexer<'s, 't, 'a>,
result: Ast<'s, 't, 'a>
variables: &'a [Symbol<'s>],
virtuals: &'a [Symbol<'s>],
result: &'a mut AstImpl
) -> LRkAstBuilder<'s, 't, 'a> {
LRkAstBuilder {
lexer,
variables,
virtuals,
stack: Vec::new(),
result,
handle: Vec::new(),
Expand Down Expand Up @@ -321,7 +325,7 @@ impl<'s, 't, 'a> LRkAstBuilder<'s, 't, 'a> {
if reduction.cache.get_action_at(0) == TREE_ACTION_REPLACE_BY_CHILDREN {
reduction.cache.set_children_count_at(0, self.handle.len());
} else {
LRkAstBuilder::reduce_tree(reduction, &self.handle, &mut self.result);
LRkAstBuilder::reduce_tree(reduction, &self.handle, self.result);
}
// Put it on the stack
self.stack.truncate(stack_size - reduction.length);
Expand All @@ -333,7 +337,7 @@ impl<'s, 't, 'a> LRkAstBuilder<'s, 't, 'a> {
}

/// Applies the promotion tree actions to the cache and commits to the final AST
pub fn reduce_tree(reduction: &mut LRkAstReduction, handle: &[usize], result: &mut Ast) {
pub fn reduce_tree(reduction: &mut LRkAstReduction, handle: &[usize], result: &mut AstImpl) {
// apply the epsilon replace, if any
if reduction.cache.get_action_at(0) == TREE_ACTION_REPLACE_BY_EPSILON {
reduction
Expand Down Expand Up @@ -382,7 +386,7 @@ impl<'s, 't, 'a> LRkAstBuilder<'s, 't, 'a> {
let length = self.stack.len();
if length > 1 {
let head = &mut self.stack[length - 2];
head.commit(&mut self.result);
head.commit(self.result);
}
}
}
Expand Down Expand Up @@ -580,7 +584,7 @@ impl<'s, 't, 'a> LRkParserData<'s, 'a> {
stack.truncate(length - production.reduction_length);
let action = self.automaton.get_action(
stack[stack.len() - 1].state,
builder.result.variables[production.head].id
builder.variables[production.head].id
);
stack.push(LRkHead {
state: u32::from(action.get_data()),
Expand All @@ -595,7 +599,7 @@ impl<'s, 't, 'a> LRkParserData<'s, 'a> {
builder: &mut LRkAstBuilder<'s, 't, 'a>,
actions: &mut dyn FnMut(usize, Symbol, &dyn SemanticBody)
) -> Symbol<'s> {
let variable = builder.result.variables[production.head];
let variable = builder.variables[production.head];
builder.reduction_prepare(
production.head,
production.reduction_length,
Expand Down Expand Up @@ -638,8 +642,10 @@ impl<'s, 't, 'a> LRkParser<'s, 't, 'a> {
/// Initializes a new instance of the parser
pub fn new(
lexer: &'a mut Lexer<'s, 't, 'a>,
variables: &'a [Symbol<'s>],
virtuals: &'a [Symbol<'s>],
automaton: LRkAutomaton,
ast: Ast<'s, 't, 'a>,
ast: &'a mut AstImpl,
actions: &'a mut dyn FnMut(usize, Symbol, &dyn SemanticBody)
) -> LRkParser<'s, 't, 'a> {
LRkParser {
Expand All @@ -649,10 +655,10 @@ impl<'s, 't, 'a> LRkParser<'s, 't, 'a> {
state: 0,
identifier: 0
}],
variables: ast.variables,
variables,
actions
},
builder: LRkAstBuilder::<'s, 't, 'a>::new(lexer, ast)
builder: LRkAstBuilder::<'s, 't, 'a>::new(lexer, variables, virtuals, ast)
}
}

Expand Down
Loading

0 comments on commit 4428d81

Please sign in to comment.