feat: project structure, some gen code

replace/7746dba3cc6b3860afe1faf69e86ed84ee46988d
Natapat Samutpong 2022-02-11 17:38:04 +07:00
parent cb6b35a2dc
commit 4879cc2ffc
13 changed files with 420 additions and 66 deletions

231
Cargo.lock generated
View File

@ -2,6 +2,237 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "clap"
version = "3.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a1132dc3944b31c20dd8b906b3a9f0a5d0243e092d59171414969657ac6aa85"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vyc"
version = "0.1.0"
dependencies = [
"clap",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -6,3 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "3.0.14", features = ["derive"] }

1
example/def.vy Normal file
View File

@ -0,0 +1 @@
(def number 1)

View File

@ -1,3 +1,2 @@
(print '(Hello, World!))
(print (format "Hello" (format "World")))
)
(def message str "Hello, World")
(print message)

27
src/args.rs Normal file
View File

@ -0,0 +1,27 @@
use std::path::PathBuf;
use clap::{ Parser, Subcommand };
const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Vy language compiler.
#[derive(Parser, Debug)]
#[clap(
version = VERSION,
long_about = None)]
pub struct Args {
#[clap(subcommand)]
pub options: Options,
}
#[derive(Subcommand, Debug)]
pub enum Options {
#[clap(about = "Compile a file.")]
Compile {
/// The input file to compile.
#[clap(parse(from_os_str))]
input: PathBuf,
/// Print parsed AST and exit (for debugging).
#[clap(short, long)]
ast: bool,
},
}

View File

1
src/front/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod parser;

View File

@ -175,6 +175,12 @@ impl ParseError {
pub fn at(&self, src: &str) -> String {
let snip = &src[(self.pos.0.saturating_sub(5))..(if self.pos.0 + 5 > src.len() { src.len() } else { self.pos.0 + 5 })];
format!("\n{}..{}\n{}\nError: {} at {}", " ".repeat(3), snip, format!("{}^", " ".repeat(10)), self.kind, self.pos.0)
// Example:
//
// .."))) ) (pr
// ^
// Error: Unexpected ')' at 67
}
}

View File

@ -1,70 +1,44 @@
use std::{process::exit, fs::read_to_string};
use std::fs::read_to_string;
use clap::Parser;
pub mod parser;
pub mod compile;
/// Arguments handler.
pub mod args;
use args::{ Args, Options };
const EXECUTABLE_NAME: &str = env!("CARGO_PKG_NAME");
const HELP_MESSAGE: &str = "\
-h, --help
Print this help message and exit.
-v, --version
Print version information and exit.
-c FILE, --compile FILE
Compile the given file and exit.\
";
/// A front-end for the compiler.
/// Contains parser and tokenizer.
/// TODO: Semantic analysis and Type checking.
pub mod front;
use front::parser::parse;
/// A middle-end for the compiler.
/// Contains instructions generator.
pub mod middle;
use middle::gen::generate_instructions;
fn main() {
let args = std::env::args().collect::<Vec<String>>();
let mut args_index: usize = 0;
match args.len() {
// No argument provided
1 => {
println!("No argument provided.");
display_help(1);
},
_ => {
while args.len() > args_index {
let arg: &str = &args[args_index];
match arg {
"-h" | "--help" => { display_help(0); },
"-v" | "--version" => {
println!("{} version {}", EXECUTABLE_NAME, env!("CARGO_PKG_VERSION"));
exit(0);
},
"-c" | "--compile" => {
args_index += 1;
if args_index < args.len() {
let file_path: &str = &args[args_index];
let file_content: String = read_to_string(file_path).unwrap();
// Used for error reporting
let file_content_joined: String = file_content.split("\n").collect::<Vec<&str>>().join(" ");
let parsed = parser::parse(&file_content);
let mut ast = Vec::new();
for node in parsed {
match node {
Ok(node) => { ast.push(node); },
Err(error) => {
eprintln!("{}", error.at(&file_content_joined));
exit(1);
}
}
}
println!("{:#?}", ast);
} else {
println!("No file provided.");
display_help(1);
let args = Args::parse();
match args.options {
Options::Compile { input, ast } => {
let code = read_to_string(input).unwrap();
let tree = parse(&code);
match ast {
true => for node in tree { println!("{:#?}", node) },
false => {
let mut checked_tree = Vec::new();
for node in tree {
match node {
Ok(node) => checked_tree.push(node),
Err(err) => println!("{:?}", err),
}
}
_ => { args_index += 1; }
}
}
}
}
}
};
fn display_help(exit_code: i32) {
println!("Usage: {} [OPTIONS]", EXECUTABLE_NAME);
println!("{}", HELP_MESSAGE);
exit(exit_code);
let instructions = generate_instructions(checked_tree.into_iter());
for instruction in instructions {
println!("{:#?}", instruction);
}
},
}
},
}
}

56
src/middle/gen.rs Normal file
View File

@ -0,0 +1,56 @@
use std::borrow::Borrow;
use crate::front::parser::Value;
use super::instr::Instructions;
pub fn generate_instructions(ast: impl Iterator<Item = (Value, (usize, usize))>) -> Vec<Instructions> {
let mut instructions: Vec<Instructions> = Vec::new();
for (value, _) in ast {
match value {
Value::List(car, cdr) => {
match &*car.borrow() {
Value::Symbol(ref function_name) => {
match function_name.as_str() {
"def" => {
let name: Box<str> = match &cdr[0].borrow() {
Value::Symbol(name) => name.clone().into(),
_ => panic!("Expected symbol as first argument of define"),
};
match &cdr[1].borrow() {
Value::Int(value) => instructions.push(Instructions::Store {
value: Value::Int(*value),
name,
}),
Value::Float(value) => instructions.push(Instructions::Store {
value: Value::Float(*value),
name,
}),
Value::String(value) => instructions.push(Instructions::Store {
value: Value::String(value.clone()),
name,
}),
_ => todo!(),
};
},
_ => {
dbg!(function_name);
todo!();
}
} // --- End match `function_name` ---
},
_ => {
dbg!(car);
todo!();
}
} // --- End match `car` ---
}
_ => {
dbg!(value);
todo!();
}
} // --- End match `value` ---
}
instructions
}

7
src/middle/instr.rs Normal file
View File

@ -0,0 +1,7 @@
use crate::front::parser::Value;
#[derive(Debug)]
pub enum Instructions {
Store { value: Value, name: Box<str> },
Push { value: Value },
}

2
src/middle/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod instr;
pub mod gen;

49
src/util.rs Normal file
View File

@ -0,0 +1,49 @@
use crate::token::Expr::{self, List};
pub fn cover_paren(s: String) -> String {
format!("({})", s)
}
pub fn unescape(s: String) -> String {
let mut result = String::new();
let mut i = 0;
while i < s.len() {
if s.chars().nth(i).unwrap() == '\\' {
match s.chars().nth(i + 1).unwrap() {
'n' => result.push('\n'),
't' => result.push('\t'),
'r' => result.push('\r'),
'\\' => result.push('\\'),
'"' => result.push('"'),
_ => result.push(s.chars().nth(i + 1).unwrap()),
}
i += 2;
} else {
result.push(s.chars().nth(i).unwrap());
i += 1;
}
}
result
}
pub fn unwrap_list_nest(ast: Expr) -> Vec<Expr> {
let mut result: Vec<Expr> = Vec::new();
match ast.clone() {
List(l, _) => {
for expr in l.iter() {
result.push(expr.clone());
}
}
_ => {
// This probably will not happen because everything is wrapped
// in list. So it would be impossible that the ast is not a list.
eprintln!("Possibly a bug in the compiler, you shouln't get this messages.");
dbg!(ast);
}
};
result
}