mirror of
https://github.com/HigherOrderCO/Kind1.git
synced 2024-09-11 08:45:32 +03:00
Fix structure
This commit is contained in:
parent
bdd438b8f7
commit
1a02e2d1e3
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -430,7 +430,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kind2"
|
||||
version = "0.2.76"
|
||||
version = "0.2.72"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"highlight_error",
|
||||
|
@ -14,3 +14,4 @@ hvm = "0.1.81"
|
||||
#hvm = { path = "../hvm" }
|
||||
highlight_error = "0.1.1"
|
||||
clap = { version = "3.1.8", features = ["derive"] }
|
||||
rand = "0.8.5"
|
@ -11,7 +11,7 @@ pub fn to_checker_oper(oper: &Operator) -> String {
|
||||
Operator::Div => "Kind.Operator.div".to_string(),
|
||||
Operator::Mod => "Kind.Operator.mod".to_string(),
|
||||
Operator::And => "Kind.Operator.and".to_string(),
|
||||
Operator::Or => "Kind.Operator.or".to_string(),
|
||||
Operator::Or => "Kind.Operator.or".to_string(),
|
||||
Operator::Xor => "Kind.Operator.xor".to_string(),
|
||||
Operator::Shl => "Kind.Operator.shl".to_string(),
|
||||
Operator::Shr => "Kind.Operator.shr".to_string(),
|
||||
|
3
src/codegen.rs
Normal file
3
src/codegen.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod kdl;
|
||||
|
||||
pub mod hvm;
|
263
src/codegen/kdl.rs
Normal file
263
src/codegen/kdl.rs
Normal file
@ -0,0 +1,263 @@
|
||||
pub mod book;
|
||||
|
||||
use crate::book::name::Ident;
|
||||
use crate::book::Book;
|
||||
use crate::codegen::kdl::book::{CompBook, CompEntry, CompRule, CompTerm};
|
||||
|
||||
use rand::Rng;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub const KDL_NAME_LEN: usize = 12;
|
||||
|
||||
pub fn to_kdl_term(kdl_names: &HashMap<String, String>, term: &CompTerm) -> Result<String, String> {
|
||||
let term = match term {
|
||||
CompTerm::Var { name } => {
|
||||
format!("{}", name)
|
||||
}
|
||||
CompTerm::Lam { name, body } => {
|
||||
let body = to_kdl_term(kdl_names, body)?;
|
||||
format!("@{} {}", name, body)
|
||||
}
|
||||
CompTerm::App { func, argm } => {
|
||||
let func = to_kdl_term(kdl_names, func)?;
|
||||
let argm = to_kdl_term(kdl_names, argm)?;
|
||||
format!("({} {})", func, argm)
|
||||
}
|
||||
CompTerm::Dup {
|
||||
nam0,
|
||||
nam1,
|
||||
expr,
|
||||
body,
|
||||
} => {
|
||||
let expr = to_kdl_term(kdl_names, expr)?;
|
||||
let body = to_kdl_term(kdl_names, body)?;
|
||||
format!("dup {} {} = {}; {}", nam0, nam1, expr, body)
|
||||
}
|
||||
CompTerm::Let { name, expr, body } => {
|
||||
let expr = to_kdl_term(kdl_names, expr)?;
|
||||
let body = to_kdl_term(kdl_names, body)?;
|
||||
format!("let {} = {}; {}", name, expr, body)
|
||||
}
|
||||
CompTerm::Ctr { name, args } => {
|
||||
let kdl_name = kdl_names.get(name).expect(&format!("{}", name));
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|x| to_kdl_term(kdl_names, x))
|
||||
.collect::<Result<Vec<String>, String>>()?;
|
||||
let args = args.iter().map(|x| format!(" {}", x)).collect::<String>();
|
||||
format!("{{{}{}}}", kdl_name, args)
|
||||
}
|
||||
CompTerm::Fun { name, args } => {
|
||||
let kdl_name = kdl_names.get(name).expect(&format!("{}", name));
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|x| to_kdl_term(kdl_names, x))
|
||||
.collect::<Result<Vec<String>, String>>()?;
|
||||
let args = args.iter().map(|x| format!(" {}", x)).collect::<String>();
|
||||
format!("({}{})", kdl_name, args)
|
||||
}
|
||||
CompTerm::Num { numb } => {
|
||||
format!("#{}", numb)
|
||||
}
|
||||
CompTerm::Op2 { oper, val0, val1 } => {
|
||||
let val0 = to_kdl_term(kdl_names, val0)?;
|
||||
let val1 = to_kdl_term(kdl_names, val1)?;
|
||||
format!("({} {} {})", oper, val0, val1)
|
||||
}
|
||||
CompTerm::Nil => {
|
||||
return Err("Found nil term in compiled term while converting to kindelia".to_string());
|
||||
}
|
||||
};
|
||||
Ok(term)
|
||||
}
|
||||
|
||||
pub fn to_kdl_rule(
|
||||
_book: &Book,
|
||||
kdl_names: &HashMap<String, String>,
|
||||
rule: &CompRule,
|
||||
) -> Result<String, String> {
|
||||
let name = &rule.name;
|
||||
let kdl_name = kdl_names.get(name).unwrap();
|
||||
let mut pats = vec![]; // stringified pattern args
|
||||
for pat in rule.pats.iter() {
|
||||
let pat = to_kdl_term(kdl_names, &pat)?;
|
||||
pats.push(" ".to_string());
|
||||
pats.push(pat);
|
||||
}
|
||||
let body = to_kdl_term(kdl_names, &rule.body)?;
|
||||
let rule = format!("({}{}) = {}", kdl_name, pats.join(""), body);
|
||||
Ok(rule)
|
||||
}
|
||||
|
||||
pub fn to_kdl_entry(
|
||||
book: &Book,
|
||||
kdl_names: &HashMap<String, String>,
|
||||
entry: &CompEntry,
|
||||
) -> Result<String, String> {
|
||||
let entry = match entry.name.as_str() {
|
||||
// Main is compiled to a run block
|
||||
// TODO: Maybe we should have run blocks come from a specific type of function instead
|
||||
// TODO: run statements should always come last in the block
|
||||
"Main" => format!(
|
||||
"run {{\n {}\n}}\n\n",
|
||||
to_kdl_term(kdl_names, &*entry.rules[0].body)?
|
||||
),
|
||||
|
||||
_ => {
|
||||
let kdl_name = kdl_names.get(&entry.name).unwrap();
|
||||
let args_names = entry
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| format!(" {}", arg))
|
||||
.collect::<String>();
|
||||
// If this entry existed in the original kind code, add some annotations as comments
|
||||
let kind_entry = book.entrs.get(&Ident(entry.name.clone()));
|
||||
let is_knd_ent = matches!(kind_entry, Some(_));
|
||||
let cmnt = if is_knd_ent {
|
||||
let kind_entry = kind_entry.unwrap();
|
||||
let args_typed = kind_entry
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
format!(
|
||||
" {}({}: {})",
|
||||
if arg.eras { "-" } else { "" },
|
||||
arg.name,
|
||||
&arg.tipo
|
||||
)
|
||||
})
|
||||
.collect::<String>();
|
||||
let kind_name = format!("{} #{}", entry.name, kdl_name);
|
||||
format!("// {}{} : {}\n", kind_name, args_typed, &kind_entry.tipo)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
// Entries with no rules become constructors
|
||||
// Entries with rules become functions
|
||||
let fun = if entry.rules.is_empty() {
|
||||
format!("ctr {{{}{}}}\n\n", kdl_name, args_names)
|
||||
} else {
|
||||
let mut rules = vec![];
|
||||
for rule in &entry.rules {
|
||||
rules.push(format!("\n {}", to_kdl_rule(book, kdl_names, rule)?));
|
||||
}
|
||||
format!(
|
||||
"fun ({}{}) {{{}\n}}\n\n",
|
||||
kdl_name,
|
||||
args_names,
|
||||
rules.join("")
|
||||
)
|
||||
};
|
||||
cmnt + &fun
|
||||
}
|
||||
};
|
||||
Ok(entry)
|
||||
}
|
||||
|
||||
pub fn to_kdl_book(
|
||||
book: &Book,
|
||||
kdl_names: &HashMap<String, String>,
|
||||
comp_book: &CompBook,
|
||||
) -> Result<String, String> {
|
||||
let mut lines = vec![];
|
||||
for name in &comp_book.names {
|
||||
let entry = comp_book.entrs.get(name).unwrap();
|
||||
lines.push(to_kdl_entry(book, kdl_names, entry)?);
|
||||
}
|
||||
Ok(lines.join(""))
|
||||
}
|
||||
|
||||
// Utils
|
||||
// -----
|
||||
|
||||
// Returns a map of kind names to kindelia names
|
||||
// Returns an err if any of the names can't be converted
|
||||
pub fn get_kdl_names(book: &CompBook) -> Result<HashMap<String, String>, String> {
|
||||
// Fits a name to the max size allowed by kindelia.
|
||||
// If the name is too large, truncates and replaces the last characters by random chars.
|
||||
// Fails if the namespace is too large.
|
||||
fn rand_shorten(name: &String) -> Result<String, String> {
|
||||
let (ns, fun) = name.rsplit_once('.').unwrap_or(("", name));
|
||||
let ns = if !ns.is_empty() {
|
||||
format!("{}.", ns)
|
||||
} else {
|
||||
ns.to_string()
|
||||
};
|
||||
if ns.len() > KDL_NAME_LEN - 1 {
|
||||
let err = format!(
|
||||
"Namespace for \"{}\" has more than {} characters.",
|
||||
name,
|
||||
KDL_NAME_LEN - 1
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
let max_fn_name = KDL_NAME_LEN - ns.len();
|
||||
// If the name doesn't fit, truncate and insert some random characters at the end
|
||||
let fun = if fun.len() > max_fn_name {
|
||||
let n_rnd_chrs = usize::min(3, max_fn_name);
|
||||
let fun_cut = fun[..max_fn_name - n_rnd_chrs].to_string();
|
||||
let mut rng = rand::thread_rng();
|
||||
let rnd_chrs = (0..n_rnd_chrs)
|
||||
.map(|_| rng.gen_range(0..63))
|
||||
.map(|n| encode_base64(n))
|
||||
.collect::<String>();
|
||||
format!("{}{}", fun_cut, rnd_chrs)
|
||||
} else {
|
||||
fun.to_string()
|
||||
};
|
||||
Ok(format!("{}{}", ns, fun))
|
||||
}
|
||||
|
||||
fn get_kdl_name(entry: &CompEntry) -> Result<String, String> {
|
||||
let kind_name = &entry.name;
|
||||
let kdln = match &entry.kdln {
|
||||
Some(kdln) => {
|
||||
// If the entry uses a kindelia name, use it
|
||||
if !kdln.chars().next().unwrap().is_uppercase() {
|
||||
let err = format!(
|
||||
"Kindelia name \"{}\" doesn't start with an uppercase letter.",
|
||||
kdln
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
if entry.orig {
|
||||
if kdln.len() > KDL_NAME_LEN {
|
||||
let err = format!(
|
||||
"Kindelia name \"{}\" for \"{}\" has more than {} characters.",
|
||||
kdln,
|
||||
kind_name,
|
||||
KDL_NAME_LEN - 1
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
kdln.clone()
|
||||
} else {
|
||||
// For entries created by the flattener, we shorten even the kindelia name
|
||||
// TODO: Since these rules can come first,
|
||||
// if the kdln is too large the err will happen in the generated function,
|
||||
// potentially confusing the user.
|
||||
rand_shorten(kdln)?
|
||||
}
|
||||
}
|
||||
// Otherwise, try to fit the normal kind name
|
||||
None => rand_shorten(kind_name)?,
|
||||
};
|
||||
Ok(kdln)
|
||||
}
|
||||
|
||||
fn encode_base64(num: u8) -> char {
|
||||
match num {
|
||||
0..=9 => (num + b'0') as char,
|
||||
10..=35 => (num - 10 + b'A') as char,
|
||||
36..=61 => (num - 36 + b'a') as char,
|
||||
62.. => '_',
|
||||
}
|
||||
}
|
||||
|
||||
let mut kdl_names = HashMap::new();
|
||||
for name in &book.names {
|
||||
let kdln = get_kdl_name(book.entrs.get(name).unwrap())?;
|
||||
kdl_names.insert(name.clone(), kdln);
|
||||
}
|
||||
Ok(kdl_names)
|
||||
}
|
1131
src/codegen/kdl/book.rs
Normal file
1131
src/codegen/kdl/book.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
pub mod hvm;
|
@ -10,7 +10,7 @@ use crate::driver::loader::File;
|
||||
use crate::codegen;
|
||||
use crate::parser::new_type;
|
||||
|
||||
const CHECKER_HVM: &str = include_str!("../checker.hvm");
|
||||
const CHECKER_HVM: &str = include_str!("checker.hvm");
|
||||
|
||||
pub struct RunResult {
|
||||
output: String,
|
||||
@ -195,3 +195,12 @@ pub fn cmd_run_main(path: &str) -> Result<(), String> {
|
||||
Err("Main not found.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmd_to_kdl(path: &str) -> Result<(), String> {
|
||||
let loaded = load(path)?;
|
||||
let comp_book = codegen::kdl::book::compile_book(&loaded.book)?;
|
||||
let kdl_names = codegen::kdl::get_kdl_names(&comp_book)?;
|
||||
let result = codegen::kdl::to_kdl_book(&loaded.book, &kdl_names, &comp_book)?;
|
||||
print!("{}", result);
|
||||
Ok(())
|
||||
}
|
@ -82,7 +82,6 @@ pub fn load_entry(name: &str, load: &mut Load) -> Result<(), String> {
|
||||
}
|
||||
|
||||
pub fn load(name: &str) -> Result<Load, String> {
|
||||
|
||||
let mut load = Load::new_empty();
|
||||
|
||||
if !std::path::Path::new(name).is_file() {
|
||||
|
@ -62,13 +62,16 @@ pub trait Adjust {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.adjust(false, &mut AdjustState {
|
||||
book,
|
||||
eras: 0,
|
||||
holes: 0,
|
||||
vars: Vec::new(),
|
||||
types: HashMap::new(),
|
||||
})
|
||||
self.adjust(
|
||||
false,
|
||||
&mut AdjustState {
|
||||
book,
|
||||
eras: 0,
|
||||
holes: 0,
|
||||
vars: Vec::new(),
|
||||
types: HashMap::new(),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
pub mod book;
|
||||
pub mod checker;
|
||||
pub mod codegen;
|
||||
pub mod driver;
|
||||
pub mod lowering;
|
||||
pub mod parser;
|
||||
|
||||
pub mod codegen;
|
||||
|
||||
use crate::driver::*;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
@ -62,7 +63,7 @@ fn run_cli() -> Result<(), String> {
|
||||
Command::Derive { file: path } => cmd_derive(&path),
|
||||
Command::GenChecker { file: path } => cmd_gen_checker(&path),
|
||||
Command::Show { file: path } => cmd_show(&path),
|
||||
Command::ToKDL { file: _ } => todo!(),
|
||||
Command::ToKDL { file: path } => cmd_to_kdl(&path),
|
||||
Command::ToHVM { file: path } => cmd_to_hvm(&path),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user