Skip to content

Commit

Permalink
Brought parsers to use a common abstraction
Browse files Browse the repository at this point in the history
Improved `Parser` trait definition
  • Loading branch information
Hirevo committed Jul 21, 2020
1 parent a90aa6e commit fcbb9d9
Show file tree
Hide file tree
Showing 19 changed files with 261 additions and 579 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
.vscode
/*.som
.DS_Store
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
"som-core",
"som-interpreter",
"som-lexer",
"som-parser-text",
"som-parser-core",
"som-parser-symbols",
"som-parser-text",
]
9 changes: 3 additions & 6 deletions som-interpreter/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ struct Options {
#[structopt(short, long)]
classpath: Vec<PathBuf>,

// /// enable disassembling
// #[structopt(short = "d")]
// disassembling: bool,
/// Enable verbose output (with timing information).
#[structopt(short = "v")]
verbose: bool,
Expand Down Expand Up @@ -71,11 +68,11 @@ fn main() -> anyhow::Result<()> {
});

// let class = universe.load_class_from_path(file)?;
// let instance = som_interpreter::instance::Instance::from_class(class);
// let instance = Value::Instance(Rc::new(std::cell::RefCell::new(instance)));
// let instance = Instance::from_class(class);
// let instance = Value::Instance(Rc::new(RefCell::new(instance)));

// let invokable = instance.lookup_method(&universe, "run").unwrap();
// let output = som_interpreter::invokable::Invoke::invoke(invokable.as_ref(), &mut universe, vec![instance]);
// let output = invokable.invoke(&mut universe, vec![instance]);

match output {
Return::Exception(message) => println!("ERROR: {}", message),
Expand Down
7 changes: 3 additions & 4 deletions som-interpreter/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use anyhow::Error;

use som_lexer::{Lexer, Token};
use som_parser::lang;
use som_parser::Parser;

use som_interpreter::evaluate::Evaluate;
use som_interpreter::frame::FrameKind;
Expand Down Expand Up @@ -57,9 +56,9 @@ pub fn interactive(universe: &mut Universe, verbose: bool) -> Result<(), Error>
}

let start = Instant::now();
let expr = match lang::expression().parse(tokens.as_slice()) {
Some((expr, rest)) if rest.is_empty() => expr,
Some(_) | None => {
let expr = match som_parser::apply(lang::expression(), tokens.as_slice()) {
Some(expr) => expr,
None => {
println!("ERROR: could not fully parse the given expression");
continue;
}
Expand Down
10 changes: 10 additions & 0 deletions som-parser-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "som-parser-core"
version = "0.1.0"
description = "The parsing core library for the Simple Object Machine"
authors = ["Nicolas Polomack <[email protected]>"]
edition = "2018"
publish = false
license = "MIT OR Apache-2.0"

[dependencies]
4 changes: 4 additions & 0 deletions som-parser-core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The SOM Parser Core Library
===========================

This crate serves as the collection of parser primitives shared between the various SOM parsers.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use som_lexer::Token;

use crate::parser::Parser;
use crate::Parser;

/// Represents a value of either type A (Left) or type B (Right).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand All @@ -10,46 +8,49 @@ pub enum Either<A, B> {
}

/// Transforms a parser into a non-consuming one, allowing to parse ahead without consuming anything.
pub fn peek<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, A> {
move |input: &'a [Token]| {
let (value, _) = parser.parse(input)?;
pub fn peek<A, I: Clone>(mut parser: impl Parser<A, I>) -> impl Parser<A, I> {
move |input: I| {
let (value, _) = parser.parse(input.clone())?;
Some((value, input))
}
}

/// Runs the given parser, fails if it succeeded, and succeeds otherwise.
pub fn not<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, ()> {
move |input: &'a [Token]| match parser.parse(input) {
pub fn not<A, I: Clone>(mut parser: impl Parser<A, I>) -> impl Parser<(), I> {
move |input: I| match parser.parse(input.clone()) {
Some(_) => None,
None => Some(((), input)),
}
}

/// Sequences two parsers, one after the other, collecting both results.
pub fn sequence<'a, A, B>(
fst: impl Parser<'a, A>,
snd: impl Parser<'a, B>,
) -> impl Parser<'a, (A, B)> {
pub fn sequence<A, B, I>(
mut fst: impl Parser<A, I>,
mut snd: impl Parser<B, I>,
) -> impl Parser<(A, B), I> {
// equivalent to: `fst.and(snd)`
move |input: &'a [Token]| {
move |input: I| {
let (a, input) = fst.parse(input)?;
let (b, input) = snd.parse(input)?;
Some(((a, b), input))
}
}

/// Tries to apply the first parser, if it fails, it tries to apply the second parser.
pub fn alternative<'a, A>(fst: impl Parser<'a, A>, snd: impl Parser<'a, A>) -> impl Parser<'a, A> {
move |input: &'a [Token]| fst.parse(input).or_else(|| snd.parse(input))
pub fn alternative<A, I: Clone>(
mut fst: impl Parser<A, I>,
mut snd: impl Parser<A, I>,
) -> impl Parser<A, I> {
move |input: I| fst.parse(input.clone()).or_else(|| snd.parse(input))
}

/// Same as `either`, but allows for different output types for the parsers.
pub fn either<'a, A, B>(
fst: impl Parser<'a, A>,
snd: impl Parser<'a, B>,
) -> impl Parser<'a, Either<A, B>> {
move |input: &'a [Token]| {
if let Some((a, input)) = fst.parse(input) {
pub fn either<A, B, I: Clone>(
mut fst: impl Parser<A, I>,
mut snd: impl Parser<B, I>,
) -> impl Parser<Either<A, B>, I> {
move |input: I| {
if let Some((a, input)) = fst.parse(input.clone()) {
Some((Either::Left(a), input))
} else if let Some((b, input)) = snd.parse(input) {
Some((Either::Right(b), input))
Expand All @@ -60,27 +61,35 @@ pub fn either<'a, A, B>(
}

/// Tries to apply a parser, or fallback to a constant value (making it an always-succeeding parser).
pub fn fallback<'a, A: Clone>(def: A, parser: impl Parser<'a, A>) -> impl Parser<'a, A> {
move |input: &'a [Token]| parser.parse(input).or_else(|| Some((def.clone(), input)))
pub fn fallback<A: Clone, I: Clone>(def: A, mut parser: impl Parser<A, I>) -> impl Parser<A, I> {
move |input: I| {
parser
.parse(input.clone())
.or_else(|| Some((def.clone(), input)))
}
}

/// Tries to apply a parser, or fallback to its default value (making it an always-succeeding parser).
pub fn default<'a, A: Default>(parser: impl Parser<'a, A>) -> impl Parser<'a, A> {
pub fn default<A: Default, I: Clone>(parser: impl Parser<A, I>) -> impl Parser<A, I> {
optional(parser).map(Option::unwrap_or_default)
}

/// Tries every parser in a slice, from left to right, and returns the output of the first succeeding one.
pub fn any<'a: 'b, 'b, A>(parsers: &'b [impl Parser<'a, A>]) -> impl Parser<'a, A> + 'b {
move |input: &'a [Token]| parsers.iter().find_map(|parser| parser.parse(input))
pub fn any<'a, A, I: Clone>(parsers: &'a mut [impl Parser<A, I>]) -> impl Parser<A, I> + 'a {
move |input: I| {
parsers
.iter_mut()
.find_map(|parser| parser.parse(input.clone()))
}
}

/// Applies every parser in a slice, from left to right, and returns the output from all of them.
/// If one parser fails, the whole sequence is considered failed.
pub fn all<'a: 'b, 'b, A>(parsers: &'b [impl Parser<'a, A>]) -> impl Parser<'a, Vec<A>> + 'b {
move |input: &'a [Token]| {
pub fn all<'a, A, I>(parsers: &'a mut [impl Parser<A, I>]) -> impl Parser<Vec<A>, I> + 'a {
move |input: I| {
let output = Vec::<A>::with_capacity(parsers.len());
parsers
.iter()
.iter_mut()
.try_fold((output, input), |(mut output, input), parser| {
let (value, input) = parser.parse(input)?;
output.push(value);
Expand All @@ -90,9 +99,9 @@ pub fn all<'a: 'b, 'b, A>(parsers: &'b [impl Parser<'a, A>]) -> impl Parser<'a,
}

/// Tries to apply a parser, but fails gracefully (with an `Option` output).
pub fn optional<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, Option<A>> {
move |input: &'a [Token]| {
if let Some((value, input)) = parser.parse(input) {
pub fn optional<A, I: Clone>(mut parser: impl Parser<A, I>) -> impl Parser<Option<A>, I> {
move |input: I| {
if let Some((value, input)) = parser.parse(input.clone()) {
Some((Some(value), input))
} else {
Some((None, input))
Expand All @@ -101,10 +110,10 @@ pub fn optional<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, Option<A>>
}

/// Applies a parser zero or more times.
pub fn many<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, Vec<A>> {
move |mut input: &'a [Token]| {
pub fn many<A, I: Clone>(mut parser: impl Parser<A, I>) -> impl Parser<Vec<A>, I> {
move |mut input: I| {
let mut output = Vec::<A>::new();
while let Some((value, next)) = parser.parse(input) {
while let Some((value, next)) = parser.parse(input.clone()) {
input = next;
output.push(value);
}
Expand All @@ -113,11 +122,11 @@ pub fn many<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, Vec<A>> {
}

/// Applies a parser one or more times.
pub fn some<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, Vec<A>> {
move |input: &'a [Token]| {
pub fn some<A, I: Clone>(mut parser: impl Parser<A, I>) -> impl Parser<Vec<A>, I> {
move |input: I| {
let (value, mut input) = parser.parse(input)?;
let mut output = vec![value];
while let Some((value, next)) = parser.parse(input) {
while let Some((value, next)) = parser.parse(input.clone()) {
input = next;
output.push(value);
}
Expand All @@ -126,12 +135,12 @@ pub fn some<'a, A>(parser: impl Parser<'a, A>) -> impl Parser<'a, Vec<A>> {
}

/// Parses something that is enclosed between two other things.
pub fn between<'a, A, B, C>(
before: impl Parser<'a, A>,
within: impl Parser<'a, B>,
after: impl Parser<'a, C>,
) -> impl Parser<'a, B> {
move |input: &'a [Token]| {
pub fn between<A, B, C, I>(
mut before: impl Parser<A, I>,
mut within: impl Parser<B, I>,
mut after: impl Parser<C, I>,
) -> impl Parser<B, I> {
move |input: I| {
let (_, input) = before.parse(input)?;
let (value, input) = within.parse(input)?;
let (_, input) = after.parse(input)?;
Expand All @@ -140,16 +149,16 @@ pub fn between<'a, A, B, C>(
}

/// Parses zero or more things, separated by an arbitrary delimiter.
pub fn sep_by<'a, A, B>(
delim: impl Parser<'a, A>,
within: impl Parser<'a, B>,
) -> impl Parser<'a, Vec<B>> {
move |input: &'a [Token]| {
pub fn sep_by<A, B, I: Clone>(
mut delim: impl Parser<A, I>,
mut within: impl Parser<B, I>,
) -> impl Parser<Vec<B>, I> {
move |input: I| {
let mut output = Vec::<B>::new();
if let Some((value, mut input)) = within.parse(input) {
if let Some((value, mut input)) = within.parse(input.clone()) {
output.push(value);
while let Some((value, next)) = delim
.parse(input)
.parse(input.clone())
.and_then(|(_, input)| within.parse(input))
{
input = next;
Expand All @@ -163,16 +172,16 @@ pub fn sep_by<'a, A, B>(
}

/// Parses one or more things, separated by an arbitrary delimiter.
pub fn sep_by1<'a, A, B>(
delim: impl Parser<'a, A>,
within: impl Parser<'a, B>,
) -> impl Parser<'a, Vec<B>> {
move |input: &'a [Token]| {
pub fn sep_by1<A, B, I: Clone>(
mut delim: impl Parser<A, I>,
mut within: impl Parser<B, I>,
) -> impl Parser<Vec<B>, I> {
move |input: I| {
let mut output = Vec::<B>::new();
let (value, mut input) = within.parse(input)?;
output.push(value);
while let Some((value, next)) = delim
.parse(input)
.parse(input.clone())
.and_then(|(_, input)| within.parse(input))
{
input = next;
Expand All @@ -183,8 +192,8 @@ pub fn sep_by1<'a, A, B>(
}

/// Transforms the output value of a parser.
pub fn map<'a, A, B>(parser: impl Parser<'a, A>, func: impl Fn(A) -> B) -> impl Parser<'a, B> {
move |input: &'a [Token]| {
pub fn map<A, B, I>(mut parser: impl Parser<A, I>, func: impl Fn(A) -> B) -> impl Parser<B, I> {
move |input: I| {
let (value, input) = parser.parse(input)?;
Some((func(value), input))
}
Expand Down
Loading

0 comments on commit fcbb9d9

Please sign in to comment.