diff --git a/Cargo.lock b/Cargo.lock index 0839789f..12d30458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + [[package]] name = "atty" version = "0.2.14" @@ -25,6 +31,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "clap" version = "3.1.14" @@ -64,6 +76,16 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -107,11 +129,19 @@ version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "neptune" version = "0.1.0" dependencies = [ + "anyhow", "clap", + "combine", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 56a6eb4f..5793c20b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.57" clap = { version = "3.1.14", features = ["derive"] } +combine = "4.6.4" diff --git a/src/ast.rs b/src/ast.rs index 9911163f..482eca5b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,8 +1,10 @@ +#[derive(Debug)] pub struct Program<'a> { pub version: String, - pub term: &'a Term<'a>, + pub term: Term<'a>, } +#[derive(Debug)] pub enum Term<'a> { // tag: 0 Var(String), @@ -28,6 +30,7 @@ pub enum Term<'a> { // Builtin } +#[derive(Debug)] pub enum Constant { // TODO: figure out the right size for this // tag: 0 diff --git a/src/lib.rs b/src/lib.rs index edde5527..5fdd7584 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod ast; pub mod cli; +pub mod parser; diff --git a/src/main.rs b/src/main.rs index 49a63cc4..b3282e4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,14 @@ use neptune::cli::Cli; +use neptune::parser; -fn main() { +fn main() -> anyhow::Result<()> { let args = Cli::default(); - println!("loading {}", args.input.display()); + let code = std::fs::read_to_string(&args.input)?; + + let program = parser::program(&code)?; + + println!("{:#?}", program); + + Ok(()) } diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 00000000..6f0ca5b3 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,63 @@ +use combine::{ + between, + parser::char::{digit, spaces, string}, + sep_by, token, ParseError, Parser, Stream, +}; + +use crate::ast::{Program, Term}; + +pub fn program(src: &str) -> anyhow::Result { + let mut parser = program_(); + let result = parser.parse(src); + + match result { + Ok((program, _)) => Ok(program), + Err(err) => Err(anyhow::anyhow!("{}", err)), + } +} + +pub fn program_<'a, Input>() -> impl Parser> +where + Input: Stream, + Input::Error: ParseError, +{ + let prog = string("program") + .with(spaces()) + .with((version(), spaces(), term()).map(|(version, _, term)| Program { version, term })); + + between(token('('), token(')'), prog).skip(spaces()) +} + +pub fn version() -> impl Parser +where + Input: Stream, + Input::Error: ParseError, +{ + sep_by(digit(), token('.')) +} + +pub fn term<'a, Input>() -> impl Parser> +where + Input: Stream, + Input::Error: ParseError, +{ + string("var").map(|x| Term::Var(x.to_string())) +} + +#[cfg(test)] +mod test { + use combine::Parser; + + const CODE: &str = include_str!("../example/plutus-core"); + + #[test] + fn parse_program() { + let result = super::program_().parse(CODE); + + assert!(result.is_ok()); + + let program = result.unwrap().0; + + assert_eq!(program.version, "1.0.0"); + } +}