mirror of
https://github.com/ParkerTenBroeck/automata.git
synced 2026-06-07 05:28:45 -04:00
Merge branch 'main' into gh-pages
This commit is contained in:
commit
2ba45986a7
5 changed files with 198 additions and 11 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use std::ops::Range;
|
use std::{borrow::Cow, ops::Range};
|
||||||
|
|
||||||
use super::Spanned;
|
use super::Spanned;
|
||||||
|
|
||||||
|
|
@ -23,6 +23,7 @@ pub enum Symbol<'a> {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Item<'a> {
|
pub enum Item<'a> {
|
||||||
Symbol(Symbol<'a>),
|
Symbol(Symbol<'a>),
|
||||||
|
String(Cow<'a, str>),
|
||||||
Tuple(Tuple<'a>),
|
Tuple(Tuple<'a>),
|
||||||
List(List<'a>),
|
List(List<'a>),
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +47,14 @@ pub enum Regex<'a> {
|
||||||
pub struct List<'a>(pub Vec<Spanned<Item<'a>>>, pub ListKind);
|
pub struct List<'a>(pub Vec<Spanned<Item<'a>>>, pub ListKind);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ProductionGroup<'a>(pub Vec<Spanned<Symbol<'a>>>);
|
pub enum ProductionUnit<'a> {
|
||||||
|
Epsilon(&'a str),
|
||||||
|
Ident(&'a str),
|
||||||
|
String(Cow<'a, str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ProductionGroup<'a>(pub Vec<Spanned<ProductionUnit<'a>>>);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum TopLevel<'a> {
|
pub enum TopLevel<'a> {
|
||||||
|
|
@ -70,6 +78,7 @@ impl<'a> Spanned<Item<'a>> {
|
||||||
Item::Symbol(sym) => return Some(*sym),
|
Item::Symbol(sym) => return Some(*sym),
|
||||||
Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1),
|
Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1),
|
||||||
Item::List(_) => _ = ctx.emit_error("expected ident found list", self.1),
|
Item::List(_) => _ = ctx.emit_error("expected ident found list", self.1),
|
||||||
|
Item::String(_) => _ = ctx.emit_error("expected ident found string", self.1),
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -82,6 +91,7 @@ impl<'a> Spanned<Item<'a>> {
|
||||||
}
|
}
|
||||||
Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1),
|
Item::Tuple(_) => _ = ctx.emit_error("expected ident found tuple", self.1),
|
||||||
Item::List(_) => _ = ctx.emit_error("expected ident found list", self.1),
|
Item::List(_) => _ = ctx.emit_error("expected ident found list", self.1),
|
||||||
|
Item::String(_) => _ = ctx.emit_error("expected ident found string", self.1),
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -95,6 +105,7 @@ impl<'a> Spanned<Item<'a>> {
|
||||||
_ = ctx.emit_error("expected set found epsilon", self.1)
|
_ = ctx.emit_error("expected set found epsilon", self.1)
|
||||||
}
|
}
|
||||||
Item::Tuple(_) => _ = ctx.emit_error("expected set found tuple", self.1),
|
Item::Tuple(_) => _ = ctx.emit_error("expected set found tuple", self.1),
|
||||||
|
Item::String(_) => _ = ctx.emit_error("expected set found string", self.1),
|
||||||
Item::List(list) => return Some(&list.0),
|
Item::List(list) => return Some(&list.0),
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
@ -109,6 +120,7 @@ impl<'a> Spanned<Item<'a>> {
|
||||||
_ = ctx.emit_error("expected list found epsilon", self.1)
|
_ = ctx.emit_error("expected list found epsilon", self.1)
|
||||||
}
|
}
|
||||||
Item::Tuple(_) => _ = ctx.emit_error("expected list found tuple", self.1),
|
Item::Tuple(_) => _ = ctx.emit_error("expected list found tuple", self.1),
|
||||||
|
Item::String(_) => _ = ctx.emit_error("expected list found string", self.1),
|
||||||
Item::List(list) => return Some(&list.0),
|
Item::List(list) => return Some(&list.0),
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
@ -138,6 +150,7 @@ impl<'a> Spanned<Item<'a>> {
|
||||||
}
|
}
|
||||||
Item::Tuple(tuple) => return Some(Spanned(tuple, self.1)),
|
Item::Tuple(tuple) => return Some(Spanned(tuple, self.1)),
|
||||||
Item::List(_) => _ = ctx.emit_error("expected tuple found list", self.1),
|
Item::List(_) => _ = ctx.emit_error("expected tuple found list", self.1),
|
||||||
|
Item::String(_) => _ = ctx.emit_error("expected tuple found string", self.1),
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
use crate::loader::{Span, Spanned};
|
use crate::loader::{Span, Spanned};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, Default)]
|
||||||
|
pub enum StringKind{
|
||||||
|
#[default]
|
||||||
|
Regular,
|
||||||
|
Regex
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
|
||||||
pub enum Token<'a> {
|
pub enum Token<'a> {
|
||||||
LPar,
|
LPar,
|
||||||
|
|
@ -14,6 +22,7 @@ pub enum Token<'a> {
|
||||||
Tilde,
|
Tilde,
|
||||||
Eq,
|
Eq,
|
||||||
Comma,
|
Comma,
|
||||||
|
Dash,
|
||||||
|
|
||||||
Or,
|
Or,
|
||||||
Plus,
|
Plus,
|
||||||
|
|
@ -26,6 +35,8 @@ pub enum Token<'a> {
|
||||||
Comment(&'a str),
|
Comment(&'a str),
|
||||||
|
|
||||||
Ident(&'a str),
|
Ident(&'a str),
|
||||||
|
|
||||||
|
String(&'a str, StringKind, bool),
|
||||||
LineEnd,
|
LineEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,13 +54,19 @@ impl<'a> std::fmt::Display for Token<'a> {
|
||||||
Token::Comma => write!(f, "','"),
|
Token::Comma => write!(f, "','"),
|
||||||
Token::Or => write!(f, "'|'"),
|
Token::Or => write!(f, "'|'"),
|
||||||
Token::Plus => write!(f, "'+'"),
|
Token::Plus => write!(f, "'+'"),
|
||||||
|
Token::Dash => write!(f, "'-'"),
|
||||||
Token::Star => write!(f, "'*'"),
|
Token::Star => write!(f, "'*'"),
|
||||||
Token::And => write!(f, "'&'"),
|
Token::And => write!(f, "'&'"),
|
||||||
Token::LSmallArrow => write!(f, "'->'"),
|
Token::LSmallArrow => write!(f, "'->'"),
|
||||||
Token::LBigArrow => write!(f, "'=>'"),
|
Token::LBigArrow => write!(f, "'=>'"),
|
||||||
Token::Comment(_) => write!(f, "<comment>"),
|
Token::Comment(_) => write!(f, "<comment>"),
|
||||||
|
|
||||||
Token::Ident(ident) if f.alternate() => write!(f, "{ident:?}"),
|
Token::Ident(ident) if f.alternate() => write!(f, "{ident:?}"),
|
||||||
Token::Ident(_) => write!(f, "ident"),
|
Token::Ident(_) => write!(f, "ident"),
|
||||||
|
|
||||||
|
Token::String(string, kind, _) if f.alternate() => write!(f, "{}{string:?}", if *kind==StringKind::Regex {"r"} else {""}),
|
||||||
|
Token::String(_, _, _) => write!(f, "string"),
|
||||||
|
|
||||||
Token::LineEnd => write!(f, "eol"),
|
Token::LineEnd => write!(f, "eol"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,6 +82,7 @@ pub struct Lexer<'a> {
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
InvalidChar(char),
|
InvalidChar(char),
|
||||||
UnclosedMultiLine,
|
UnclosedMultiLine,
|
||||||
|
UnclosedString,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lexer<'a> {
|
impl<'a> Lexer<'a> {
|
||||||
|
|
@ -145,8 +163,22 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
|
||||||
self.consume();
|
self.consume();
|
||||||
Ok(Token::LSmallArrow)
|
Ok(Token::LSmallArrow)
|
||||||
}
|
}
|
||||||
_ => Err(Error::InvalidChar('-')),
|
_ => Ok(Token::Dash),
|
||||||
},
|
},
|
||||||
|
'"' => {
|
||||||
|
let mut escaped = false;
|
||||||
|
loop {
|
||||||
|
match self.consume() {
|
||||||
|
Some('"') => break Ok(Token::String(&self.input[start+1..self.position], StringKind::Regular, escaped)),
|
||||||
|
None => break Err(Error::UnclosedString),
|
||||||
|
Some('\\') => {
|
||||||
|
_ = self.consume();
|
||||||
|
escaped = true;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
'/' => match self.consume() {
|
'/' => match self.consume() {
|
||||||
Some('/') => loop {
|
Some('/') => loop {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::epsilon;
|
use crate::epsilon;
|
||||||
use crate::loader::log::LogSink;
|
use crate::loader::log::LogSink;
|
||||||
use crate::loader::{Context, Span};
|
use crate::loader::{Context, Span};
|
||||||
|
|
@ -139,19 +141,38 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
S(Tuple(items), start.join(end))
|
S(Tuple(items), start.join(end))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_as_string(&mut self, tok: S<T<'a>>) -> S<Cow<'a, str>>{
|
||||||
|
let (r, k, e, s) = match tok {
|
||||||
|
S(T::String(r, k, e), s) => (r, k, e, s),
|
||||||
|
S(t, s) => {
|
||||||
|
self.ctx.emit_error(format!("unexpected {:#} expected {:}", t, T::String("", Default::default(), false)), s);
|
||||||
|
return S("<INVALID>".into(), s)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
S(r.into(), s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_string(&mut self) -> S<Cow<'a, str>>{
|
||||||
|
let tok = self.next_token();
|
||||||
|
self.parse_as_string(tok)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_item(&mut self) -> S<Item<'a>> {
|
fn parse_item(&mut self) -> S<Item<'a>> {
|
||||||
match self.peek_token().0 {
|
match self.peek_token().0 {
|
||||||
T::Ident(_) | T::Tilde => self.parse_symbol().map(Item::Symbol),
|
T::Ident(_) | T::Tilde => self.parse_symbol().map(Item::Symbol),
|
||||||
|
T::String(_, _, _) => self.parse_string().map(Item::String),
|
||||||
T::LPar => self.parse_tupple().map(Item::Tuple),
|
T::LPar => self.parse_tupple().map(Item::Tuple),
|
||||||
T::LBrace | T::LBracket => self.parse_list().map(Item::List),
|
T::LBrace | T::LBracket => self.parse_list().map(Item::List),
|
||||||
_ => {
|
_ => {
|
||||||
let S(got, span) = self.next_token();
|
let S(got, span) = self.next_token();
|
||||||
self.ctx.emit_error(
|
self.ctx.emit_error(
|
||||||
format!(
|
format!(
|
||||||
"unexpected {:#} expected item ( {:} | {:} | {:} | {:} | {:} )",
|
"unexpected {:#} expected item ( {:} | {:} | {:} | {:} | {:} | {:} )",
|
||||||
got,
|
got,
|
||||||
T::Tilde,
|
T::Tilde,
|
||||||
T::Ident(""),
|
T::Ident(""),
|
||||||
|
T::String("", Default::default(), false),
|
||||||
T::LPar,
|
T::LPar,
|
||||||
T::LBrace,
|
T::LBrace,
|
||||||
T::LBracket,
|
T::LBracket,
|
||||||
|
|
@ -225,11 +246,39 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_production_rule(&mut self, S(sym, start): S<Symbol<'a>>) -> Option<S<TopLevel<'a>>> {
|
fn parse_as_production_unit(&mut self, tok: S<T<'a>>) -> S<ProductionUnit<'a>>{
|
||||||
|
match tok {
|
||||||
|
S(T::Tilde, r) => S(ProductionUnit::Epsilon("~"), r),
|
||||||
|
S(T::Ident(repr @ epsilon!(pat)), r) => S(ProductionUnit::Epsilon(repr), r),
|
||||||
|
S(T::Ident(ident), r) => S(ProductionUnit::Ident(ident), r),
|
||||||
|
S(T::String(_, _, _), _) => self.parse_as_string(tok).map(ProductionUnit::String),
|
||||||
|
S(got, span) => {
|
||||||
|
self.ctx.emit_error(
|
||||||
|
format!(
|
||||||
|
"unexpected {:#} expected production unit ( {:} | {:} | {:} )",
|
||||||
|
got,
|
||||||
|
T::Tilde,
|
||||||
|
T::Ident(""),
|
||||||
|
T::String("", Default::default(), false)
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
S(ProductionUnit::Ident("<INVALID>"), span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_production_unit(&mut self) -> S<ProductionUnit<'a>>{
|
||||||
|
let tok = self.next_token();
|
||||||
|
self.parse_as_production_unit(tok)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_production_rule(&mut self, S(sym, start): S<ProductionUnit<'a>>) -> Option<S<TopLevel<'a>>> {
|
||||||
let mut lhs_group = ProductionGroup(vec![S(sym, start)]);
|
let mut lhs_group = ProductionGroup(vec![S(sym, start)]);
|
||||||
let mut lhs_group_end = start;
|
let mut lhs_group_end = start;
|
||||||
while !matches!(self.peek_token().0, T::LSmallArrow | T::LineEnd) {
|
while !matches!(self.peek_token().0, T::LSmallArrow | T::LineEnd) {
|
||||||
let sym = self.parse_symbol();
|
let sym = self.parse_production_unit();
|
||||||
lhs_group_end = sym.1;
|
lhs_group_end = sym.1;
|
||||||
lhs_group.0.push(sym);
|
lhs_group.0.push(sym);
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +297,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
loop {
|
loop {
|
||||||
let mut group = ProductionGroup(vec![]);
|
let mut group = ProductionGroup(vec![]);
|
||||||
while !matches!(self.peek_token().0, T::LineEnd | T::Or) {
|
while !matches!(self.peek_token().0, T::LineEnd | T::Or) {
|
||||||
group.0.push(self.parse_symbol());
|
group.0.push(self.parse_production_unit());
|
||||||
}
|
}
|
||||||
|
|
||||||
if group.0.is_empty() {
|
if group.0.is_empty() {
|
||||||
|
|
@ -327,10 +376,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
}
|
}
|
||||||
// production rule
|
// production rule
|
||||||
(
|
(
|
||||||
sym @ S(T::Ident(_) | T::Tilde, _),
|
sym @ S(T::Ident(_) | T::Tilde | T::String(_, _, _), _),
|
||||||
S(T::LSmallArrow | T::Ident(_) | T::Tilde, _),
|
S(T::LSmallArrow | T::Ident(_) | T::Tilde, _),
|
||||||
) => {
|
) => {
|
||||||
let sym = self.parse_as_symbol(sym);
|
let sym = self.parse_as_production_unit(sym);
|
||||||
if let Some(pr) = self.parse_production_rule(sym) {
|
if let Some(pr) = self.parse_production_rule(sym) {
|
||||||
break Some(pr);
|
break Some(pr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ export type Category =
|
||||||
| "DPDA"
|
| "DPDA"
|
||||||
| "NPDA"
|
| "NPDA"
|
||||||
| "TM"
|
| "TM"
|
||||||
| "NTM";
|
| "NTM"
|
||||||
|
| "CFG";
|
||||||
|
|
||||||
export class Example {
|
export class Example {
|
||||||
readonly category: Category;
|
readonly category: Category;
|
||||||
|
|
@ -48,6 +49,56 @@ d(qb, b) = qb
|
||||||
|
|
||||||
d(qb', a) = qb'
|
d(qb', a) = qb'
|
||||||
d(qb', b) = qb`,
|
d(qb', b) = qb`,
|
||||||
|
),
|
||||||
|
|
||||||
|
new Example(
|
||||||
|
"Tutorial",
|
||||||
|
"NFA",
|
||||||
|
`// strings of 1's whos length is divisible by two or three and longer than 1
|
||||||
|
|
||||||
|
type = NFA // type of machine
|
||||||
|
Q = {q0, q2, q2f, q3, q3', q3f} // set of states
|
||||||
|
E = {1} // alphabet
|
||||||
|
F = {q2f, q3f} // set of final states
|
||||||
|
q0 = q0 // initial state
|
||||||
|
|
||||||
|
// transition function (state, letter) -> state
|
||||||
|
|
||||||
|
// non deterministic part
|
||||||
|
d(q0, 1) = q2
|
||||||
|
d(q0, 1) = q3
|
||||||
|
|
||||||
|
d(q2, 1) = q2f
|
||||||
|
d(q2f, 1) = q2
|
||||||
|
|
||||||
|
d(q3, 1) = q3'
|
||||||
|
d(q3', 1) = q3f
|
||||||
|
d(q3f, 1) = q3
|
||||||
|
`,
|
||||||
|
),
|
||||||
|
|
||||||
|
new Example(
|
||||||
|
"Tutorial",
|
||||||
|
"NFA w/ epsilon",
|
||||||
|
`// strings containing only all a's, or all b's, or all c's
|
||||||
|
|
||||||
|
type = NFA // type of machine
|
||||||
|
Q = {q0, qa, qb, qc} // set of states
|
||||||
|
E = {a, b, c} // alphabet
|
||||||
|
F = {qa, qb, qc} // set of final states
|
||||||
|
q0 = q0 // initial state
|
||||||
|
|
||||||
|
// transition function (state, letter) -> state
|
||||||
|
|
||||||
|
// non deterministic part
|
||||||
|
d(q0, epsilon) = qa
|
||||||
|
d(q0, epsilon) = qb
|
||||||
|
d(q0, epsilon) = qc
|
||||||
|
|
||||||
|
d(qa, a) = qa
|
||||||
|
d(qb, b) = qb
|
||||||
|
d(qc, c) = qc
|
||||||
|
`,
|
||||||
),
|
),
|
||||||
|
|
||||||
new Example(
|
new Example(
|
||||||
|
|
@ -128,9 +179,18 @@ d(q0, a, B) = (q0, [A B])
|
||||||
d(q0, b, B) = (q0, [B B])
|
d(q0, b, B) = (q0, [B B])
|
||||||
|
|
||||||
// transition to q1
|
// transition to q1
|
||||||
|
// even
|
||||||
d(q0, epsilon, z0) = { (q1, z0) }
|
d(q0, epsilon, z0) = { (q1, z0) }
|
||||||
d(q0, epsilon, A) = { (q1, A) }
|
d(q0, epsilon, A) = { (q1, A) }
|
||||||
d(q0, epsilon, B) = { (q1, B) }
|
d(q0, epsilon, B) = { (q1, B) }
|
||||||
|
// odd
|
||||||
|
d(q0, a, z0) = { (q1, z0) }
|
||||||
|
d(q0, a, A) = { (q1, A) }
|
||||||
|
d(q0, a, B) = { (q1, B) }
|
||||||
|
|
||||||
|
d(q0, b, z0) = { (q1, z0) }
|
||||||
|
d(q0, b, A) = { (q1, A) }
|
||||||
|
d(q0, b, B) = { (q1, B) }
|
||||||
|
|
||||||
// consume stack until empty
|
// consume stack until empty
|
||||||
d(q1, a, A) = { (q1, epsilon) }
|
d(q1, a, A) = { (q1, epsilon) }
|
||||||
|
|
@ -186,6 +246,35 @@ d(q2,X)=(q0,x,R)
|
||||||
d(q0,Y)=(q3,y,R)
|
d(q0,Y)=(q3,y,R)
|
||||||
d(q3,Y)=(q3,y,R)
|
d(q3,Y)=(q3,y,R)
|
||||||
d(q3,B)=(q4,B,R)
|
d(q3,B)=(q4,B,R)
|
||||||
|
`),
|
||||||
|
|
||||||
|
new Example("CFG", "definition",
|
||||||
|
`// CFG's aren't supported yet, and this definition is not complete.
|
||||||
|
// This is the definition for the grammar the definition has itself
|
||||||
|
|
||||||
|
type=CFG
|
||||||
|
|
||||||
|
S -> TopLevel | TopLevel S
|
||||||
|
|
||||||
|
TopLevel -> Ident "=" Item // Item
|
||||||
|
TopLevel -> Ident Tuple "=" Item // Transition Functions
|
||||||
|
TopLevel -> Production | Table
|
||||||
|
|
||||||
|
Item -> Symbol | String | Tuple | List
|
||||||
|
|
||||||
|
Symbol -> Ident | "~"
|
||||||
|
String -> "\"" "\""
|
||||||
|
Tuple -> "(" ItemList ")"
|
||||||
|
List -> "{" ItemList "}" | "[" ItemList "]"
|
||||||
|
|
||||||
|
ItemList -> ~ | Item ItemList | Item "," ItemList
|
||||||
|
|
||||||
|
Production -> ProductionGroup "->" ProductionGroupList
|
||||||
|
ProductionGroupList -> ProductionGroup | ProductionGroupList "|" ProductionGroup
|
||||||
|
ProductionGroup -> ProductionUnit | ProductionGroup ProductionUnit
|
||||||
|
ProductionUnit -> Ident | "~" | String
|
||||||
|
|
||||||
|
|
||||||
`)
|
`)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -197,6 +286,7 @@ const CATEGORY_ORDER: Category[] = [
|
||||||
"NPDA",
|
"NPDA",
|
||||||
"TM",
|
"TM",
|
||||||
"NTM",
|
"NTM",
|
||||||
|
"CFG",
|
||||||
];
|
];
|
||||||
|
|
||||||
function buildExamplesDropdown(
|
function buildExamplesDropdown(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ pub fn init() {
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Ident = "ident",
|
Ident = "ident",
|
||||||
Keyword = "keyword",
|
Keyword = "keyword",
|
||||||
|
String = "string",
|
||||||
Error = "error",
|
Error = "error",
|
||||||
Comment = "comment",
|
Comment = "comment",
|
||||||
Punc = "punc",
|
Punc = "punc",
|
||||||
|
|
@ -77,11 +78,13 @@ pub fn lex(input: &str) -> Vec<Tok> {
|
||||||
Token::Comma => Kind::Punc,
|
Token::Comma => Kind::Punc,
|
||||||
Token::Or => Kind::Punc,
|
Token::Or => Kind::Punc,
|
||||||
Token::Plus => Kind::Punc,
|
Token::Plus => Kind::Punc,
|
||||||
|
Token::Dash => Kind::Punc,
|
||||||
Token::Star => Kind::Punc,
|
Token::Star => Kind::Punc,
|
||||||
Token::And => Kind::Punc,
|
Token::And => Kind::Punc,
|
||||||
Token::LSmallArrow => Kind::Punc,
|
Token::LSmallArrow => Kind::Punc,
|
||||||
Token::LBigArrow => Kind::Punc,
|
Token::LBigArrow => Kind::Punc,
|
||||||
Token::Comment(_) => Kind::Comment,
|
Token::Comment(_) => Kind::Comment,
|
||||||
|
Token::String(_, _, _) => Kind::String,
|
||||||
Token::Ident(_)
|
Token::Ident(_)
|
||||||
if input[..start_utf8]
|
if input[..start_utf8]
|
||||||
.split("\n")
|
.split("\n")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue