Fold graph::Graph into gg::Graph, add TokenKind::End to lexer
This commit is contained in:
parent
6b5f2d7e82
commit
e06b20b604
@ -1,10 +1,39 @@
|
|||||||
|
use std::hash::Hash;
|
||||||
|
use im_rc::{HashSet};
|
||||||
|
|
||||||
pub mod lexer;
|
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)]
|
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||||
pub enum Value<'a>{
|
pub enum Value{
|
||||||
Name(&'a str),
|
Name(String),
|
||||||
Number(i64),
|
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)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
<value> ::= <name> | <number> | <tuple> | <graph>
|
||||||
|
|
||||||
<tuple> ::= "(" <tuple-open-edge>
|
<tuple> ::= "(" <tuple-edge>
|
||||||
<tuple-open-edge> ::= ")" | <tuple-open-edge-incomplete>
|
<tuple-edge> ::= ")" | <tuple-edge-incomplete>
|
||||||
<tuple-open-edge-incomplete> ::= <value> ")"
|
<tuple-edge-incomplete> ::= <value> ")"
|
||||||
| <value> "," <tuple-open-edge>
|
| <value> "," <tuple-edge>
|
||||||
| <value> "<" <tuple-open-edge-incomplete>
|
| <value> "<" <tuple-edge-incomplete>
|
||||||
|
|
||||||
<graph> ::= "{" <graph-branch>
|
<graph> ::= "{" <graph-branch>
|
||||||
<graph-branch> ::= "}" | <name> "<" <graph-open-edge-incomplete>
|
<graph-branch> ::= "}" | <name> "<" <graph-edge-incomplete>
|
||||||
<graph-open-edge-incomplete> ::= <value> "}"
|
<graph-edge-incomplete> ::= <value> "}"
|
||||||
| <value> ";" <graph-branch>
|
| <value> ";" <graph-branch>
|
||||||
| <value> "<" <graph-open-edge-incomplete>
|
| <value> "<" <graph-edge-incomplete>
|
||||||
|
|
||||||
<outer-graph> ::= <outer-graph-branch>
|
<outer-graph> ::= <outer-graph-branch>
|
||||||
<outer-graph-branch> ::= <eof> | <name> "<" <outer-graph-open-edge-incomplete>
|
<outer-graph-branch> ::= <end> | <name> "<" <outer-graph-edge-incomplete>
|
||||||
<outer-graph-open-edge-incomplete> ::= <value> <eof>
|
<outer-graph-edge-incomplete> ::= <value> <end>
|
||||||
| <value> ";" <outer-graph-branch>
|
| <value> ";" <outer-graph-branch>
|
||||||
| <value> "<" <outer-graph-open-edge-incomplete>
|
| <value> "<" <outer-graph-edge-incomplete>
|
||||||
|
@ -22,7 +22,7 @@ pub enum Error {
|
|||||||
IO(io::Error),
|
IO(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error{
|
impl From<io::Error> for Error {
|
||||||
fn from(e: io::Error) -> Self {
|
fn from(e: io::Error) -> Self {
|
||||||
Error::IO(e)
|
Error::IO(e)
|
||||||
}
|
}
|
||||||
@ -33,6 +33,7 @@ pub enum TokenKind {
|
|||||||
Name,
|
Name,
|
||||||
Number,
|
Number,
|
||||||
Punctuation,
|
Punctuation,
|
||||||
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -105,7 +106,7 @@ impl<R: Read> Lexer<R>{
|
|||||||
&mut self,
|
&mut self,
|
||||||
kind: TokenKind,
|
kind: TokenKind,
|
||||||
pred: impl Fn(char) -> bool,
|
pred: impl Fn(char) -> bool,
|
||||||
) -> Result<Option<(Token, Location)>, Error> {
|
) -> Result<(Token, Location), Error> {
|
||||||
|
|
||||||
let loc = self.next_loc;
|
let loc = self.next_loc;
|
||||||
self.buf.truncate(0);
|
self.buf.truncate(0);
|
||||||
@ -115,8 +116,9 @@ impl<R: Read> Lexer<R>{
|
|||||||
let (c, ok) = self.peek_a_bool()?;
|
let (c, ok) = self.peek_a_bool()?;
|
||||||
|
|
||||||
if !ok || !pred(c) {
|
if !ok || !pred(c) {
|
||||||
return Ok(Some(
|
return Ok((
|
||||||
(Token{kind: kind, value: self.buf.clone()}, loc)
|
Token{kind: kind, value: self.buf.clone()},
|
||||||
|
loc
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,13 +131,16 @@ impl<R: Read> Lexer<R>{
|
|||||||
c == '-' || ('0' <= c && c <= '9')
|
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 {
|
loop {
|
||||||
|
|
||||||
let (c, ok) = self.peek_a_bool()?;
|
let (c, ok) = self.peek_a_bool()?;
|
||||||
if !ok {
|
if !ok {
|
||||||
return Ok(None);
|
return Ok((
|
||||||
|
Token{kind: TokenKind::End, value: String::new()},
|
||||||
|
self.next_loc,
|
||||||
|
));
|
||||||
|
|
||||||
} else if c == '*' {
|
} else if c == '*' {
|
||||||
self.discard_while(|c| c != '\n')?;
|
self.discard_while(|c| c != '\n')?;
|
||||||
@ -155,15 +160,16 @@ impl<R: Read> Lexer<R>{
|
|||||||
let loc = self.next_loc;
|
let loc = self.next_loc;
|
||||||
self.discard();
|
self.discard();
|
||||||
|
|
||||||
return Ok(Some(
|
return Ok((
|
||||||
(Token{kind: TokenKind::Punctuation, value: c.to_string()}, loc)
|
Token{kind: TokenKind::Punctuation, value: c.to_string()},
|
||||||
|
loc,
|
||||||
))
|
))
|
||||||
|
|
||||||
} else if c.is_ascii_whitespace() {
|
} else if c.is_ascii_whitespace() {
|
||||||
self.discard_while(|c| c.is_ascii_whitespace())?;
|
self.discard_while(|c| c.is_ascii_whitespace())?;
|
||||||
|
|
||||||
} else {
|
} 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![
|
let tests = vec![
|
||||||
Test{
|
Test{
|
||||||
input: "",
|
input: "",
|
||||||
exp: vec![],
|
exp: vec![
|
||||||
|
tok(TokenKind::End, "", 0, 0),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
Test{
|
Test{
|
||||||
input: "* foo",
|
input: "* foo",
|
||||||
exp: vec![],
|
exp: vec![
|
||||||
|
tok(TokenKind::End, "", 0, 5),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
Test{
|
Test{
|
||||||
input: "* foo\n",
|
input: "* foo\n",
|
||||||
exp: vec![],
|
exp: vec![
|
||||||
|
tok(TokenKind::End, "", 1, 0),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
Test{
|
Test{
|
||||||
input: "* foo\nbar",
|
input: "* foo\nbar",
|
||||||
exp: vec![
|
exp: vec![
|
||||||
tok(TokenKind::Name, "bar", 1, 0),
|
tok(TokenKind::Name, "bar", 1, 0),
|
||||||
|
tok(TokenKind::End, "", 1, 3),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Test{
|
Test{
|
||||||
input: "* foo\nbar ",
|
input: "* foo\nbar ",
|
||||||
exp: vec![
|
exp: vec![
|
||||||
tok(TokenKind::Name, "bar", 1, 0),
|
tok(TokenKind::Name, "bar", 1, 0),
|
||||||
|
tok(TokenKind::End, "", 1, 4),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Test{
|
Test{
|
||||||
@ -222,6 +236,7 @@ mod tests {
|
|||||||
tok(TokenKind::Name, "f-o", 1, 0),
|
tok(TokenKind::Name, "f-o", 1, 0),
|
||||||
tok(TokenKind::Name, "f0O", 1, 4),
|
tok(TokenKind::Name, "f0O", 1, 4),
|
||||||
tok(TokenKind::Name, "Foo", 1, 8),
|
tok(TokenKind::Name, "Foo", 1, 8),
|
||||||
|
tok(TokenKind::End, "", 1, 11),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Test{
|
Test{
|
||||||
@ -230,6 +245,7 @@ mod tests {
|
|||||||
tok(TokenKind::Number, "1", 0, 0),
|
tok(TokenKind::Number, "1", 0, 0),
|
||||||
tok(TokenKind::Number, "100", 0, 2),
|
tok(TokenKind::Number, "100", 0, 2),
|
||||||
tok(TokenKind::Number, "-100", 0, 6),
|
tok(TokenKind::Number, "-100", 0, 6),
|
||||||
|
tok(TokenKind::End, "", 0, 10),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Test{
|
Test{
|
||||||
@ -242,6 +258,7 @@ mod tests {
|
|||||||
tok(TokenKind::Number, "-3", 0, 4),
|
tok(TokenKind::Number, "-3", 0, 4),
|
||||||
tok(TokenKind::Punctuation, "(", 0, 7),
|
tok(TokenKind::Punctuation, "(", 0, 7),
|
||||||
tok(TokenKind::Punctuation, ")", 0, 8),
|
tok(TokenKind::Punctuation, ")", 0, 8),
|
||||||
|
tok(TokenKind::End, "", 0, 9),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -253,9 +270,12 @@ mod tests {
|
|||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(token) = l.next().expect("no errors expected") {
|
let (token, loc) = l.next().expect("no errors expected");
|
||||||
res.push(token);
|
let is_end = token.kind == TokenKind::End;
|
||||||
} else {
|
|
||||||
|
res.push((token, loc));
|
||||||
|
|
||||||
|
if is_end {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +1 @@
|
|||||||
pub mod graph;
|
|
||||||
pub mod gg;
|
pub mod gg;
|
||||||
|
@ -1,22 +1,2 @@
|
|||||||
use ginger::graph::Graph;
|
|
||||||
|
|
||||||
fn main() {
|
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);
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user