Fold graph::Graph into gg::Graph, add TokenKind::End to lexer

This commit is contained in:
Brian Picciano 2022-12-27 00:01:42 +01:00
parent 6b5f2d7e82
commit e06b20b604
6 changed files with 92 additions and 122 deletions

View File

@ -1,10 +1,39 @@
use std::hash::Hash;
use im_rc::{HashSet};
pub mod lexer;
use super::graph::Graph;
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct OpenEdge(Value, Value); // edge, src
#[derive(Clone, Eq, Hash, PartialEq, Debug)]
pub enum Value<'a>{
Name(&'a str),
#[derive(Clone, Eq, Hash, PartialEq)]
pub enum Value{
Name(String),
Number(i64),
Graph(&'a Graph<Value<'a>, Value<'a>>),
Tuple(Vec<OpenEdge>),
Graph(Graph),
}
#[derive(Clone, Eq, Hash, PartialEq)]
struct Edge<V> {
dst_val: V,
src_val: V,
}
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct Graph {
edges: HashSet<(Value, OpenEdge)>, // dst, src
}
impl Graph {
pub fn new() -> Graph {
Graph{edges: HashSet::new()}
}
pub fn with(&self, dst_val: Value, src_edge: OpenEdge) -> Self {
Graph{
edges: self.edges.update((dst_val, src_edge)),
}
}
}

View File

@ -1,19 +1,27 @@
<name> ::= <letter> | <name-tail>
<name-charset> ::= <letter> | <number> | <mark>
<name-tail> ::= <name-chareset> <name-tail> | ""
<number> ::= "-" <ascii-number> <number-tail>
| <ascii-number> <number-tail>
<number-tail> ::= <ascii-number> <number-tail> | ""
<value> ::= <name> | <number> | <tuple> | <graph>
<tuple> ::= "(" <tuple-open-edge>
<tuple-open-edge> ::= ")" | <tuple-open-edge-incomplete>
<tuple-open-edge-incomplete> ::= <value> ")"
| <value> "," <tuple-open-edge>
| <value> "<" <tuple-open-edge-incomplete>
<tuple> ::= "(" <tuple-edge>
<tuple-edge> ::= ")" | <tuple-edge-incomplete>
<tuple-edge-incomplete> ::= <value> ")"
| <value> "," <tuple-edge>
| <value> "<" <tuple-edge-incomplete>
<graph> ::= "{" <graph-branch>
<graph-branch> ::= "}" | <name> "<" <graph-open-edge-incomplete>
<graph-open-edge-incomplete> ::= <value> "}"
| <value> ";" <graph-branch>
| <value> "<" <graph-open-edge-incomplete>
<graph> ::= "{" <graph-branch>
<graph-branch> ::= "}" | <name> "<" <graph-edge-incomplete>
<graph-edge-incomplete> ::= <value> "}"
| <value> ";" <graph-branch>
| <value> "<" <graph-edge-incomplete>
<outer-graph> ::= <outer-graph-branch>
<outer-graph-branch> ::= <eof> | <name> "<" <outer-graph-open-edge-incomplete>
<outer-graph-open-edge-incomplete> ::= <value> <eof>
| <value> ";" <outer-graph-branch>
| <value> "<" <outer-graph-open-edge-incomplete>
<outer-graph> ::= <outer-graph-branch>
<outer-graph-branch> ::= <end> | <name> "<" <outer-graph-edge-incomplete>
<outer-graph-edge-incomplete> ::= <value> <end>
| <value> ";" <outer-graph-branch>
| <value> "<" <outer-graph-edge-incomplete>

View File

@ -22,7 +22,7 @@ pub enum Error {
IO(io::Error),
}
impl From<io::Error> for Error{
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::IO(e)
}
@ -33,6 +33,7 @@ pub enum TokenKind {
Name,
Number,
Punctuation,
End,
}
#[derive(Debug, PartialEq)]
@ -105,7 +106,7 @@ impl<R: Read> Lexer<R>{
&mut self,
kind: TokenKind,
pred: impl Fn(char) -> bool,
) -> Result<Option<(Token, Location)>, Error> {
) -> Result<(Token, Location), Error> {
let loc = self.next_loc;
self.buf.truncate(0);
@ -115,8 +116,9 @@ impl<R: Read> Lexer<R>{
let (c, ok) = self.peek_a_bool()?;
if !ok || !pred(c) {
return Ok(Some(
(Token{kind: kind, value: self.buf.clone()}, loc)
return Ok((
Token{kind: kind, value: self.buf.clone()},
loc
))
}
@ -129,13 +131,16 @@ impl<R: Read> Lexer<R>{
c == '-' || ('0' <= c && c <= '9')
}
pub fn next(&mut self) -> Result<Option<(Token, Location)>, Error> {
pub fn next(&mut self) -> Result<(Token, Location), Error> {
loop {
let (c, ok) = self.peek_a_bool()?;
if !ok {
return Ok(None);
return Ok((
Token{kind: TokenKind::End, value: String::new()},
self.next_loc,
));
} else if c == '*' {
self.discard_while(|c| c != '\n')?;
@ -155,15 +160,16 @@ impl<R: Read> Lexer<R>{
let loc = self.next_loc;
self.discard();
return Ok(Some(
(Token{kind: TokenKind::Punctuation, value: c.to_string()}, loc)
return Ok((
Token{kind: TokenKind::Punctuation, value: c.to_string()},
loc,
))
} else if c.is_ascii_whitespace() {
self.discard_while(|c| c.is_ascii_whitespace())?;
} else {
return Err(Error::Tokenizing("unexpected character", self.next_loc));
return Err(Error::Tokenizing("invalid character", self.next_loc));
}
}
}
@ -192,26 +198,34 @@ mod tests {
let tests = vec![
Test{
input: "",
exp: vec![],
exp: vec![
tok(TokenKind::End, "", 0, 0),
],
},
Test{
input: "* foo",
exp: vec![],
exp: vec![
tok(TokenKind::End, "", 0, 5),
],
},
Test{
input: "* foo\n",
exp: vec![],
exp: vec![
tok(TokenKind::End, "", 1, 0),
],
},
Test{
input: "* foo\nbar",
exp: vec![
tok(TokenKind::Name, "bar", 1, 0),
tok(TokenKind::End, "", 1, 3),
],
},
Test{
input: "* foo\nbar ",
exp: vec![
tok(TokenKind::Name, "bar", 1, 0),
tok(TokenKind::End, "", 1, 4),
],
},
Test{
@ -222,6 +236,7 @@ mod tests {
tok(TokenKind::Name, "f-o", 1, 0),
tok(TokenKind::Name, "f0O", 1, 4),
tok(TokenKind::Name, "Foo", 1, 8),
tok(TokenKind::End, "", 1, 11),
],
},
Test{
@ -230,6 +245,7 @@ mod tests {
tok(TokenKind::Number, "1", 0, 0),
tok(TokenKind::Number, "100", 0, 2),
tok(TokenKind::Number, "-100", 0, 6),
tok(TokenKind::End, "", 0, 10),
],
},
Test{
@ -242,6 +258,7 @@ mod tests {
tok(TokenKind::Number, "-3", 0, 4),
tok(TokenKind::Punctuation, "(", 0, 7),
tok(TokenKind::Punctuation, ")", 0, 8),
tok(TokenKind::End, "", 0, 9),
],
},
];
@ -253,9 +270,12 @@ mod tests {
let mut res = Vec::new();
loop {
if let Some(token) = l.next().expect("no errors expected") {
res.push(token);
} else {
let (token, loc) = l.next().expect("no errors expected");
let is_end = token.kind == TokenKind::End;
res.push((token, loc));
if is_end {
break;
}
}

View File

@ -1,66 +0,0 @@
use std::hash::Hash;
use im_rc::{HashMap,HashSet};
#[derive(Clone, Eq, Hash, PartialEq, Debug)]
pub enum OpenEdgeSource<E, V>{
Value(V),
Tuple(Vec<OpenEdge<E, V>>),
}
#[derive(Clone, Eq, Hash, PartialEq, Debug)]
pub struct OpenEdge<E, V>{
value: E,
source: OpenEdgeSource<E, V>,
}
#[derive(Clone, Eq, Hash, PartialEq, Debug)]
pub struct Graph<E, V>
where
E: Hash + Eq + Clone,
V: Hash + Eq + Clone,
{
roots: HashMap<V, HashSet<OpenEdge<E, V>>>,
}
impl<E, V> Graph<E, V>
where
E: Hash + Eq + Clone,
V: Hash + Eq + Clone,
{
pub fn new() -> Graph<E, V> {
Graph{roots: HashMap::new()}
}
pub fn from_value(edge_value: E, source_value: V) -> OpenEdge<E, V> {
OpenEdge{
value: edge_value,
source: OpenEdgeSource::Value(source_value),
}
}
pub fn from_tuple(edge_value: E, source_tuple: Vec<OpenEdge<E, V>>) -> OpenEdge<E, V> {
OpenEdge{
value: edge_value,
source: OpenEdgeSource::Tuple(source_tuple),
}
}
pub fn with(&self, root_value: V, open_edge: OpenEdge<E, V>) -> Self {
let new_roots = self.roots.alter(
|set_option: Option<HashSet<OpenEdge<E, V>>>| -> Option<HashSet<OpenEdge<E, V>>> {
match set_option {
None => Some(HashSet::unit(open_edge)),
Some(set) => Some(set.update(open_edge)),
}
},
root_value,
);
Graph{
roots: new_roots,
}
}
}

View File

@ -1,2 +1 @@
pub mod graph;
pub mod gg;

View File

@ -1,22 +1,2 @@
use ginger::graph::Graph;
fn main() {
let g = Graph::new().
with("foo", Graph::from_value(1, "bar"));
let g1 = g.
with("foo", Graph::from_value(1, "bar")).
with("foo", Graph::from_value(2, "baz"));
let g2 = g.
with("bar", Graph::from_tuple(100, vec![
Graph::from_value(20, "a"),
Graph::from_value(40, "b"),
Graph::from_value(60, "c"),
]));
dbg!(g1 == g2);
dbg!(&g1);
dbg!(&g2);
}