feat: most of the constants and better space skipping

This commit is contained in:
rvcas 2022-05-06 00:26:20 -04:00
parent 6fdcd7012d
commit b3318e5f24
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
4 changed files with 75 additions and 22 deletions

7
Cargo.lock generated
View File

@ -107,6 +107,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.8.1" version = "1.8.1"
@ -142,6 +148,7 @@ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"combine", "combine",
"hex",
] ]
[[package]] [[package]]

View File

@ -9,3 +9,4 @@ edition = "2021"
anyhow = "1.0.57" anyhow = "1.0.57"
clap = { version = "3.1.14", features = ["derive"] } clap = { version = "3.1.14", features = ["derive"] }
combine = "4.6.4" combine = "4.6.4"
hex = "0.4.3"

View File

@ -1,3 +1,3 @@
(program 1.0.0 (program 1.0.0
(con integer 4) (con bool False)
) )

View File

@ -1,14 +1,14 @@
use combine::{ use combine::{
between, many1, attempt, between, choice, many1,
parser::char::{digit, spaces, string}, parser::char::{alpha_num, digit, hex_digit, space, spaces, string},
token, ParseError, Parser, Stream, skip_many1, token, EasyParser, ParseError, Parser, Stream,
}; };
use crate::ast::{Constant, Program, Term}; use crate::ast::{Constant, Program, Term};
pub fn program(src: &str) -> anyhow::Result<Program> { pub fn program(src: &str) -> anyhow::Result<Program> {
let mut parser = program_(); let mut parser = program_();
let result = parser.parse(src); let result = parser.easy_parse(src);
match result { match result {
Ok((program, _)) => Ok(program), Ok((program, _)) => Ok(program),
@ -52,7 +52,12 @@ where
Input: Stream<Token = char>, Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{ {
between(token('('), token(')'), constant().or(delay())).skip(spaces()) between(
token('('),
token(')'),
choice((attempt(constant()), attempt(delay()), attempt(force()))),
)
.skip(spaces())
} }
parser! { parser! {
@ -69,19 +74,36 @@ where
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{ {
string("delay") string("delay")
.skip(spaces()) .with(skip_many1(space()))
.with(term_()) .with(term_())
.map(|term| Term::Delay(Box::new(term))) .map(|term| Term::Delay(Box::new(term)))
} }
pub fn force<Input>() -> impl Parser<Input, Output = Term>
where
Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
string("force")
.with(skip_many1(space()))
.with(term_())
.map(|term| Term::Force(Box::new(term)))
}
pub fn constant<Input>() -> impl Parser<Input, Output = Term> pub fn constant<Input>() -> impl Parser<Input, Output = Term>
where where
Input: Stream<Token = char>, Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{ {
string("con") string("con")
.skip(spaces()) .with(skip_many1(space()))
.with(constant_integer().or(unit()).or(constant_bool())) .with(choice((
attempt(constant_integer()),
attempt(constant_bytestring()),
attempt(constant_string()),
attempt(constant_unit()),
attempt(constant_bool()),
)))
.map(Term::Constant) .map(Term::Constant)
} }
@ -91,33 +113,56 @@ where
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{ {
string("integer") string("integer")
.skip(spaces()) .with(skip_many1(space()))
.with(many1(digit())) .with(many1(digit()))
.map(|d: String| Constant::Integer(d.parse::<i64>().unwrap())) .map(|d: String| Constant::Integer(d.parse::<i64>().unwrap()))
} }
pub fn constant_bytestring<Input>() -> impl Parser<Input, Output = Constant>
where
Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
string("bytestring")
.with(skip_many1(space()))
.with(token('#'))
.with(many1(hex_digit()))
.map(|b: String| Constant::ByteString(hex::decode(b).unwrap()))
}
pub fn constant_string<Input>() -> impl Parser<Input, Output = Constant>
where
Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
string("string")
.with(skip_many1(space()))
.with(between(token('"'), token('"'), many1(alpha_num())))
.map(Constant::String)
}
pub fn constant_unit<Input>() -> impl Parser<Input, Output = Constant>
where
Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
string("unit")
.with(skip_many1(space()))
.with(string("()"))
.map(|_| Constant::Unit)
}
pub fn constant_bool<Input>() -> impl Parser<Input, Output = Constant> pub fn constant_bool<Input>() -> impl Parser<Input, Output = Constant>
where where
Input: Stream<Token = char>, Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{ {
string("bool") string("bool")
.skip(spaces()) .with(skip_many1(space()))
.with(string("True").or(string("False"))) .with(string("True").or(string("False")))
.map(|b| Constant::Bool(b == "True")) .map(|b| Constant::Bool(b == "True"))
} }
pub fn unit<Input>() -> impl Parser<Input, Output = Constant>
where
Input: Stream<Token = char>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
string("unit")
.skip(spaces())
.with(string("()"))
.map(|_| Constant::Unit)
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use combine::Parser; use combine::Parser;