Rename schala-lib -> schala-repl
This commit is contained in:
25
schala-repl/Cargo.toml
Normal file
25
schala-repl/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "schala-repl"
|
||||
version = "0.1.0"
|
||||
authors = ["greg <greg.shuflin@protonmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
llvm-sys = "*"
|
||||
take_mut = "0.1.3"
|
||||
itertools = "0.5.8"
|
||||
getopts = "*"
|
||||
lazy_static = "0.2.8"
|
||||
maplit = "*"
|
||||
colored = "1.5"
|
||||
serde = "1.0.15"
|
||||
serde_derive = "1.0.15"
|
||||
serde_json = "1.0.3"
|
||||
rocket = "0.3.5"
|
||||
rocket_codegen = "0.3.5"
|
||||
rocket_contrib = "0.3.5"
|
||||
phf = "0.7.12"
|
||||
includedir = "0.2.0"
|
||||
rustyline = "1.0.0"
|
||||
|
||||
[build-dependencies]
|
||||
includedir_codegen = "0.2.0"
|
||||
10
schala-repl/build.rs
Normal file
10
schala-repl/build.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
extern crate includedir_codegen;
|
||||
|
||||
use includedir_codegen::Compression;
|
||||
|
||||
fn main() {
|
||||
includedir_codegen::start("WEBFILES")
|
||||
.dir("../static", Compression::Gzip)
|
||||
.build("static.rs")
|
||||
.unwrap();
|
||||
}
|
||||
155
schala-repl/src/language.rs
Normal file
155
schala-repl/src/language.rs
Normal file
@@ -0,0 +1,155 @@
|
||||
extern crate colored;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use self::colored::*;
|
||||
|
||||
pub struct LLVMCodeString(pub String);
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct EvalOptions {
|
||||
pub debug: DebugOptions,
|
||||
pub execution_method: ExecutionMethod
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ExecutionMethod {
|
||||
Compile,
|
||||
Interpret,
|
||||
}
|
||||
impl Default for ExecutionMethod {
|
||||
fn default() -> ExecutionMethod {
|
||||
ExecutionMethod::Interpret
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct DebugOptions {
|
||||
pub tokens: bool,
|
||||
pub parse_tree: bool,
|
||||
pub ast: bool,
|
||||
pub type_checking: bool,
|
||||
pub symbol_table: bool,
|
||||
pub evaluation: bool,
|
||||
pub llvm_ir: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LanguageOutput {
|
||||
output: String,
|
||||
artifacts: Vec<TraceArtifact>,
|
||||
pub failed: bool,
|
||||
}
|
||||
|
||||
impl LanguageOutput {
|
||||
pub fn add_artifact(&mut self, artifact: TraceArtifact) {
|
||||
self.artifacts.push(artifact);
|
||||
}
|
||||
pub fn add_output(&mut self, output: String) {
|
||||
self.output = output;
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut acc = String::new();
|
||||
for line in self.artifacts.iter() {
|
||||
acc.push_str(&line.debug_output.color(line.text_color).to_string());
|
||||
acc.push_str(&"\n");
|
||||
}
|
||||
acc.push_str(&self.output);
|
||||
acc
|
||||
}
|
||||
|
||||
pub fn print_to_screen(&self) {
|
||||
for line in self.artifacts.iter() {
|
||||
let color = line.text_color;
|
||||
let stage = line.stage_name.color(color).to_string();
|
||||
let output = line.debug_output.color(color).to_string();
|
||||
println!("{}: {}", stage, output);
|
||||
}
|
||||
println!("{}", self.output);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct UnfinishedComputation {
|
||||
artifacts: HashMap<String, TraceArtifact>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FinishedComputation {
|
||||
artifacts: HashMap<String, TraceArtifact>,
|
||||
text_output: Result<String, String>,
|
||||
}
|
||||
|
||||
impl UnfinishedComputation {
|
||||
pub fn add_artifact(&mut self, artifact: TraceArtifact) {
|
||||
self.artifacts.insert(artifact.stage_name.clone(), artifact);
|
||||
}
|
||||
pub fn output(self, output: Result<String, String>) -> FinishedComputation {
|
||||
FinishedComputation {
|
||||
artifacts: self.artifacts,
|
||||
text_output: output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FinishedComputation {
|
||||
pub fn to_repl(&self) -> String {
|
||||
match self.text_output {
|
||||
Ok(ref s) => s.clone(),
|
||||
Err(ref s) => format!("Error: {}", s)
|
||||
}
|
||||
}
|
||||
pub fn to_noninteractive(&self) -> Option<String> {
|
||||
match self.text_output {
|
||||
Ok(ref s) => None,
|
||||
Err(ref s) => Some(format!("Error: {}", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TraceArtifact {
|
||||
stage_name: String,
|
||||
debug_output: String,
|
||||
text_color: &'static str,
|
||||
}
|
||||
|
||||
impl TraceArtifact {
|
||||
pub fn new(stage: &str, debug: String) -> TraceArtifact {
|
||||
let color = match stage {
|
||||
"parse_trace" | "ast" => "red",
|
||||
"tokens" => "green",
|
||||
"type_check" => "magenta",
|
||||
_ => "blue",
|
||||
};
|
||||
TraceArtifact { stage_name: stage.to_string(), debug_output: debug, text_color: color}
|
||||
}
|
||||
|
||||
pub fn new_parse_trace(trace: Vec<String>) -> TraceArtifact {
|
||||
let mut output = String::new();
|
||||
|
||||
for t in trace {
|
||||
output.push_str(&t);
|
||||
output.push_str("\n");
|
||||
}
|
||||
|
||||
TraceArtifact { stage_name: "parse_trace".to_string(), debug_output: output, text_color: "red"}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ProgrammingLanguageInterface {
|
||||
/* old */
|
||||
fn evaluate_in_repl(&mut self, input: &str, eval_options: &EvalOptions) -> LanguageOutput {
|
||||
LanguageOutput { output: format!("Defunct"), artifacts: vec![], failed: false }
|
||||
}
|
||||
fn evaluate_noninteractive(&mut self, input: &str, eval_options: &EvalOptions) -> LanguageOutput {
|
||||
self.evaluate_in_repl(input, eval_options)
|
||||
}
|
||||
/* old */
|
||||
|
||||
|
||||
fn execute(&mut self, input: &str, eval_options: &EvalOptions) -> FinishedComputation {
|
||||
FinishedComputation { artifacts: HashMap::new(), text_output: Err(format!("REPL evaluation not implemented")) }
|
||||
}
|
||||
fn get_language_name(&self) -> String;
|
||||
fn get_source_file_suffix(&self) -> String;
|
||||
}
|
||||
378
schala-repl/src/lib.rs
Normal file
378
schala-repl/src/lib.rs
Normal file
@@ -0,0 +1,378 @@
|
||||
#![feature(link_args)]
|
||||
#![feature(advanced_slice_patterns, slice_patterns, box_patterns, box_syntax)]
|
||||
#![feature(plugin)]
|
||||
#![plugin(rocket_codegen)]
|
||||
extern crate getopts;
|
||||
extern crate rustyline;
|
||||
extern crate itertools;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate maplit;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
extern crate rocket;
|
||||
extern crate rocket_contrib;
|
||||
extern crate includedir;
|
||||
extern crate phf;
|
||||
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::process::exit;
|
||||
use std::default::Default;
|
||||
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
|
||||
mod language;
|
||||
mod webapp;
|
||||
pub mod llvm_wrap;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/static.rs"));
|
||||
|
||||
pub use language::{LLVMCodeString, ProgrammingLanguageInterface, EvalOptions, ExecutionMethod, TraceArtifact, LanguageOutput, FinishedComputation, UnfinishedComputation};
|
||||
pub type PLIGenerator = Box<Fn() -> Box<ProgrammingLanguageInterface> + Send + Sync>;
|
||||
|
||||
pub fn schala_main(generators: Vec<PLIGenerator>) {
|
||||
let languages: Vec<Box<ProgrammingLanguageInterface>> = generators.iter().map(|x| x()).collect();
|
||||
|
||||
let option_matches = program_options().parse(std::env::args()).unwrap_or_else(|e| {
|
||||
println!("{:?}", e);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
if option_matches.opt_present("list-languages") {
|
||||
for lang in languages {
|
||||
println!("{}", lang.get_language_name());
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if option_matches.opt_present("help") {
|
||||
println!("{}", program_options().usage("Schala metainterpreter"));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if option_matches.opt_present("webapp") {
|
||||
webapp::web_main(generators);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let language_names: Vec<String> = languages.iter().map(|lang| {lang.get_language_name()}).collect();
|
||||
let initial_index: usize =
|
||||
option_matches.opt_str("lang")
|
||||
.and_then(|lang| { language_names.iter().position(|x| { x.to_lowercase() == lang.to_lowercase() }) })
|
||||
.unwrap_or(0);
|
||||
|
||||
let mut options = EvalOptions::default();
|
||||
options.execution_method = match option_matches.opt_str("eval-style") {
|
||||
Some(ref s) if s == "compile" => ExecutionMethod::Compile,
|
||||
_ => ExecutionMethod::Interpret,
|
||||
};
|
||||
|
||||
match option_matches.free[..] {
|
||||
[] | [_] => {
|
||||
let mut repl = Repl::new(languages, initial_index);
|
||||
repl.run();
|
||||
}
|
||||
[_, ref filename, _..] => {
|
||||
|
||||
run_noninteractive(filename, languages, options);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn run_noninteractive(filename: &str, languages: Vec<Box<ProgrammingLanguageInterface>>, options: EvalOptions) {
|
||||
let path = Path::new(filename);
|
||||
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or_else(|| {
|
||||
println!("Source file lacks extension");
|
||||
exit(1);
|
||||
});
|
||||
let mut language = Box::new(languages.into_iter().find(|lang| lang.get_source_file_suffix() == ext)
|
||||
.unwrap_or_else(|| {
|
||||
println!("Extension .{} not recognized", ext);
|
||||
exit(1);
|
||||
}));
|
||||
|
||||
let mut source_file = File::open(path).unwrap();
|
||||
let mut buffer = String::new();
|
||||
|
||||
source_file.read_to_string(&mut buffer).unwrap();
|
||||
|
||||
match options.execution_method {
|
||||
ExecutionMethod::Compile => {
|
||||
/*
|
||||
let llvm_bytecode = language.compile(&buffer);
|
||||
compilation_sequence(llvm_bytecode, filename);
|
||||
*/
|
||||
panic!("Not ready to go yet");
|
||||
},
|
||||
ExecutionMethod::Interpret => {
|
||||
let output = language.execute(&buffer, &options);
|
||||
output.to_noninteractive().map(|text| println!("{}", text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Repl {
|
||||
options: EvalOptions,
|
||||
languages: Vec<Box<ProgrammingLanguageInterface>>,
|
||||
current_language_index: usize,
|
||||
interpreter_directive_sigil: char,
|
||||
console: rustyline::Editor<()>,
|
||||
}
|
||||
|
||||
impl Repl {
|
||||
fn new(languages: Vec<Box<ProgrammingLanguageInterface>>, initial_index: usize) -> Repl {
|
||||
let i = if initial_index < languages.len() { initial_index } else { 0 };
|
||||
|
||||
let console = Editor::<()>::new();
|
||||
|
||||
Repl {
|
||||
options: Repl::get_options(),
|
||||
languages: languages,
|
||||
current_language_index: i,
|
||||
interpreter_directive_sigil: '.',
|
||||
console
|
||||
}
|
||||
}
|
||||
|
||||
fn get_options() -> EvalOptions {
|
||||
File::open(".schala_repl")
|
||||
.and_then(|mut file| {
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
Ok(contents)
|
||||
})
|
||||
.and_then(|contents| {
|
||||
let options: EvalOptions = serde_json::from_str(&contents)?;
|
||||
Ok(options)
|
||||
}).unwrap_or(EvalOptions::default())
|
||||
}
|
||||
|
||||
fn save_options(&self) {
|
||||
let ref options = self.options;
|
||||
let read = File::create(".schala_repl")
|
||||
.and_then(|mut file| {
|
||||
let buf = serde_json::to_string(options).unwrap();
|
||||
file.write_all(buf.as_bytes())
|
||||
});
|
||||
|
||||
if let Err(err) = read {
|
||||
println!("Error saving .schala_repl file {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&mut self) {
|
||||
println!("MetaInterpreter v 0.05");
|
||||
|
||||
self.console.get_history().load(".schala_history").unwrap_or(());
|
||||
|
||||
loop {
|
||||
let language_name = self.languages[self.current_language_index].get_language_name();
|
||||
let prompt_str = format!("{} >> ", language_name);
|
||||
|
||||
match self.console.readline(&prompt_str) {
|
||||
Err(ReadlineError::Eof) | Err(ReadlineError::Interrupted) => break,
|
||||
Err(e) => {
|
||||
println!("Terminal read error: {}", e);
|
||||
},
|
||||
Ok(ref input) => {
|
||||
self.console.add_history_entry(input);
|
||||
if self.handle_interpreter_directive(input) {
|
||||
continue;
|
||||
}
|
||||
let output = self.input_handler(input);
|
||||
println!("=> {}", output);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
self.console.get_history().save(".schala_history").unwrap_or(());
|
||||
self.save_options();
|
||||
println!("Exiting...");
|
||||
}
|
||||
|
||||
fn input_handler(&mut self, input: &str) -> String {
|
||||
let ref mut language = self.languages[self.current_language_index];
|
||||
let interpreter_output = language.execute(input, &self.options);
|
||||
interpreter_output.to_repl()
|
||||
}
|
||||
|
||||
fn handle_interpreter_directive(&mut self, input: &str) -> bool {
|
||||
match input.chars().nth(0) {
|
||||
Some(ch) if ch == self.interpreter_directive_sigil => (),
|
||||
_ => return false
|
||||
}
|
||||
|
||||
let mut iter = input.chars();
|
||||
iter.next();
|
||||
let trimmed_sigil: &str = iter.as_str();
|
||||
|
||||
let commands: Vec<&str> = trimmed_sigil
|
||||
.split_whitespace()
|
||||
.collect();
|
||||
|
||||
let cmd: &str = match commands.get(0).clone() {
|
||||
None => return true,
|
||||
Some(s) => s
|
||||
};
|
||||
|
||||
match cmd {
|
||||
"exit" | "quit" => {
|
||||
self.save_options();
|
||||
exit(0)
|
||||
},
|
||||
"help" => {
|
||||
println!("Commands:");
|
||||
println!("exit | quit");
|
||||
println!("lang(uage) [go|show|next|previous]");
|
||||
println!("set [show|hide] [tokens|parse|symbols|eval|llvm]");
|
||||
}
|
||||
"lang" | "language" => {
|
||||
match commands.get(1) {
|
||||
Some(&"show") => {
|
||||
for (i, lang) in self.languages.iter().enumerate() {
|
||||
if i == self.current_language_index {
|
||||
println!("* {}", lang.get_language_name());
|
||||
} else {
|
||||
println!("{}", lang.get_language_name());
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(&"go") => {
|
||||
match commands.get(2) {
|
||||
None => println!("Must specify a language name"),
|
||||
Some(&desired_name) => {
|
||||
for (i, _) in self.languages.iter().enumerate() {
|
||||
let lang_name = self.languages[i].get_language_name();
|
||||
if lang_name.to_lowercase() == desired_name.to_lowercase() {
|
||||
self.current_language_index = i;
|
||||
println!("Switching to {}", self.languages[self.current_language_index].get_language_name());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
println!("Language {} not found", desired_name);
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(&"next") => {
|
||||
self.current_language_index = (self.current_language_index + 1) % self.languages.len();
|
||||
println!("Switching to {}", self.languages[self.current_language_index].get_language_name());
|
||||
}
|
||||
Some(&"prev") | Some(&"previous") => {
|
||||
self.current_language_index = if self.current_language_index == 0 { self.languages.len() - 1 } else { self.current_language_index - 1 };
|
||||
println!("Switching to {}", self.languages[self.current_language_index].get_language_name());
|
||||
},
|
||||
Some(e) => println!("Bad `lang` argument: {}", e),
|
||||
None => println!("`lang` - valid arguments `show`, `next`, `prev`|`previous`"),
|
||||
}
|
||||
},
|
||||
"set" => {
|
||||
let show = match commands.get(1) {
|
||||
Some(&"show") => true,
|
||||
Some(&"hide") => false,
|
||||
Some(e) => {
|
||||
println!("Bad `set` argument: {}", e);
|
||||
return true;
|
||||
}
|
||||
None => {
|
||||
println!("`set` - valid arguments `show {{option}}`, `hide {{option}}`");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
match commands.get(2) {
|
||||
Some(&"tokens") => self.options.debug.tokens = show,
|
||||
Some(&"parse") => self.options.debug.parse_tree = show,
|
||||
Some(&"ast") => self.options.debug.ast = show,
|
||||
Some(&"symbols") => self.options.debug.symbol_table = show,
|
||||
Some(&"llvm") => self.options.debug.llvm_ir = show,
|
||||
Some(e) => {
|
||||
println!("Bad `show`/`hide` argument: {}", e);
|
||||
return true;
|
||||
}
|
||||
None => {
|
||||
println!("`show`/`hide` requires an argument");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
e => println!("Unknown command: {}", e)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn compilation_sequence(llvm_code: LLVMCodeString, sourcefile: &str) {
|
||||
use std::process::Command;
|
||||
|
||||
let ll_filename = "out.ll";
|
||||
let obj_filename = "out.o";
|
||||
let q: Vec<&str> = sourcefile.split('.').collect();
|
||||
let bin_filename = match &q[..] {
|
||||
&[name, "maaru"] => name,
|
||||
_ => panic!("Bad filename {}", sourcefile),
|
||||
};
|
||||
|
||||
let LLVMCodeString(llvm_str) = llvm_code;
|
||||
|
||||
println!("Compilation process finished for {}", ll_filename);
|
||||
File::create(ll_filename)
|
||||
.and_then(|mut f| f.write_all(llvm_str.as_bytes()))
|
||||
.expect("Error writing file");
|
||||
|
||||
let llc_output = Command::new("llc")
|
||||
.args(&["-filetype=obj", ll_filename, "-o", obj_filename])
|
||||
.output()
|
||||
.expect("Failed to run llc");
|
||||
|
||||
|
||||
if !llc_output.status.success() {
|
||||
println!("{}", String::from_utf8_lossy(&llc_output.stderr));
|
||||
}
|
||||
|
||||
let gcc_output = Command::new("gcc")
|
||||
.args(&["-o", bin_filename, &obj_filename])
|
||||
.output()
|
||||
.expect("failed to run gcc");
|
||||
|
||||
if !gcc_output.status.success() {
|
||||
println!("{}", String::from_utf8_lossy(&gcc_output.stdout));
|
||||
println!("{}", String::from_utf8_lossy(&gcc_output.stderr));
|
||||
}
|
||||
|
||||
for filename in [obj_filename].iter() {
|
||||
Command::new("rm")
|
||||
.arg(filename)
|
||||
.output()
|
||||
.expect(&format!("failed to run rm {}", filename));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn program_options() -> getopts::Options {
|
||||
let mut options = getopts::Options::new();
|
||||
options.optopt("s",
|
||||
"eval-style",
|
||||
"Specify whether to compile (if supported) or interpret the language. If not specified, the default is language-specific",
|
||||
"[compile|interpret]"
|
||||
);
|
||||
options.optflag("",
|
||||
"list-languages",
|
||||
"Show a list of all supported languages");
|
||||
options.optopt("l",
|
||||
"lang",
|
||||
"Start up REPL in a language",
|
||||
"LANGUAGE");
|
||||
options.optflag("h",
|
||||
"help",
|
||||
"Show help text");
|
||||
options.optflag("w",
|
||||
"webapp",
|
||||
"Start up web interpreter");
|
||||
options
|
||||
}
|
||||
279
schala-repl/src/llvm_wrap.rs
Normal file
279
schala-repl/src/llvm_wrap.rs
Normal file
@@ -0,0 +1,279 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
extern crate llvm_sys;
|
||||
|
||||
use self::llvm_sys::{LLVMIntPredicate, LLVMRealPredicate};
|
||||
use self::llvm_sys::prelude::*;
|
||||
use self::llvm_sys::core;
|
||||
use std::ptr;
|
||||
use std::ffi::{CString, CStr};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
pub fn create_context() -> LLVMContextRef {
|
||||
unsafe { core::LLVMContextCreate() }
|
||||
}
|
||||
pub fn module_create_with_name(name: &str) -> LLVMModuleRef {
|
||||
unsafe {
|
||||
let n = name.as_ptr() as *const _;
|
||||
core::LLVMModuleCreateWithName(n)
|
||||
}
|
||||
}
|
||||
pub fn CreateBuilderInContext(context: LLVMContextRef) -> LLVMBuilderRef {
|
||||
unsafe { core::LLVMCreateBuilderInContext(context) }
|
||||
}
|
||||
|
||||
pub fn AppendBasicBlockInContext(context: LLVMContextRef,
|
||||
function: LLVMValueRef,
|
||||
name: &str)
|
||||
-> LLVMBasicBlockRef {
|
||||
let c_name = CString::new(name).unwrap();
|
||||
unsafe { core::LLVMAppendBasicBlockInContext(context, function, c_name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn AddFunction(module: LLVMModuleRef, name: &str, function_type: LLVMTypeRef) -> LLVMValueRef {
|
||||
let c_name = CString::new(name).unwrap();
|
||||
unsafe { core::LLVMAddFunction(module, c_name.as_ptr(), function_type) }
|
||||
}
|
||||
|
||||
pub fn FunctionType(return_type: LLVMTypeRef,
|
||||
mut param_types: Vec<LLVMTypeRef>,
|
||||
is_var_rag: bool)
|
||||
-> LLVMTypeRef {
|
||||
let len = param_types.len();
|
||||
unsafe {
|
||||
let pointer = param_types.as_mut_ptr();
|
||||
core::LLVMFunctionType(return_type,
|
||||
pointer,
|
||||
len as u32,
|
||||
if is_var_rag { 1 } else { 0 })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn GetNamedFunction(module: LLVMModuleRef,
|
||||
name: &str) -> Option<LLVMValueRef> {
|
||||
|
||||
let c_name = CString::new(name).unwrap();
|
||||
let ret = unsafe { core::LLVMGetNamedFunction(module, c_name.as_ptr()) };
|
||||
|
||||
if ret.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn VoidTypeInContext(context: LLVMContextRef) -> LLVMTypeRef {
|
||||
unsafe { core::LLVMVoidTypeInContext(context) }
|
||||
}
|
||||
|
||||
pub fn DisposeBuilder(builder: LLVMBuilderRef) {
|
||||
unsafe { core::LLVMDisposeBuilder(builder) }
|
||||
}
|
||||
|
||||
pub fn DisposeModule(module: LLVMModuleRef) {
|
||||
unsafe { core::LLVMDisposeModule(module) }
|
||||
}
|
||||
|
||||
pub fn ContextDispose(context: LLVMContextRef) {
|
||||
unsafe { core::LLVMContextDispose(context) }
|
||||
}
|
||||
|
||||
pub fn PositionBuilderAtEnd(builder: LLVMBuilderRef, basic_block: LLVMBasicBlockRef) {
|
||||
unsafe { core::LLVMPositionBuilderAtEnd(builder, basic_block) }
|
||||
}
|
||||
|
||||
pub fn BuildRet(builder: LLVMBuilderRef, val: LLVMValueRef) -> LLVMValueRef {
|
||||
unsafe { core::LLVMBuildRet(builder, val) }
|
||||
}
|
||||
|
||||
pub fn BuildRetVoid(builder: LLVMBuilderRef) -> LLVMValueRef {
|
||||
unsafe { core::LLVMBuildRetVoid(builder) }
|
||||
}
|
||||
|
||||
pub fn DumpModule(module: LLVMModuleRef) {
|
||||
unsafe { core::LLVMDumpModule(module) }
|
||||
}
|
||||
|
||||
pub fn Int64TypeInContext(context: LLVMContextRef) -> LLVMTypeRef {
|
||||
unsafe { core::LLVMInt64TypeInContext(context) }
|
||||
}
|
||||
|
||||
pub fn ConstInt(int_type: LLVMTypeRef, n: u64, sign_extend: bool) -> LLVMValueRef {
|
||||
unsafe { core::LLVMConstInt(int_type, n, if sign_extend { 1 } else { 0 }) }
|
||||
}
|
||||
|
||||
pub fn BuildAdd(builder: LLVMBuilderRef,
|
||||
lhs: LLVMValueRef,
|
||||
rhs: LLVMValueRef,
|
||||
reg_name: &str)
|
||||
-> LLVMValueRef {
|
||||
let name = CString::new(reg_name).unwrap();
|
||||
unsafe { core::LLVMBuildAdd(builder, lhs, rhs, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildSub(builder: LLVMBuilderRef,
|
||||
lhs: LLVMValueRef,
|
||||
rhs: LLVMValueRef,
|
||||
reg_name: &str)
|
||||
-> LLVMValueRef {
|
||||
let name = CString::new(reg_name).unwrap();
|
||||
unsafe { core::LLVMBuildSub(builder, lhs, rhs, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildMul(builder: LLVMBuilderRef,
|
||||
lhs: LLVMValueRef,
|
||||
rhs: LLVMValueRef,
|
||||
reg_name: &str)
|
||||
-> LLVMValueRef {
|
||||
let name = CString::new(reg_name).unwrap();
|
||||
unsafe { core::LLVMBuildMul(builder, lhs, rhs, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildUDiv(builder: LLVMBuilderRef,
|
||||
lhs: LLVMValueRef,
|
||||
rhs: LLVMValueRef,
|
||||
reg_name: &str)
|
||||
-> LLVMValueRef {
|
||||
let name = CString::new(reg_name).unwrap();
|
||||
unsafe { core::LLVMBuildUDiv(builder, lhs, rhs, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildSRem(builder: LLVMBuilderRef,
|
||||
lhs: LLVMValueRef,
|
||||
rhs: LLVMValueRef,
|
||||
reg_name: &str)
|
||||
-> LLVMValueRef {
|
||||
let name = CString::new(reg_name).unwrap();
|
||||
unsafe { core::LLVMBuildSRem(builder, lhs, rhs, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildCondBr(builder: LLVMBuilderRef,
|
||||
if_expr: LLVMValueRef,
|
||||
then_expr: LLVMBasicBlockRef,
|
||||
else_expr: LLVMBasicBlockRef) -> LLVMValueRef {
|
||||
|
||||
|
||||
unsafe { core::LLVMBuildCondBr(builder, if_expr, then_expr, else_expr) }
|
||||
}
|
||||
|
||||
pub fn BuildBr(builder: LLVMBuilderRef,
|
||||
dest: LLVMBasicBlockRef) -> LLVMValueRef {
|
||||
unsafe { core::LLVMBuildBr(builder, dest) }
|
||||
}
|
||||
|
||||
pub fn GetInsertBlock(builder: LLVMBuilderRef) -> LLVMBasicBlockRef {
|
||||
unsafe { core::LLVMGetInsertBlock(builder) }
|
||||
}
|
||||
|
||||
pub fn BuildPhi(builder: LLVMBuilderRef, ty: LLVMTypeRef, name: &str) -> LLVMValueRef {
|
||||
let name = CString::new(name).unwrap();
|
||||
unsafe { core::LLVMBuildPhi(builder, ty, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn SetValueName(value: LLVMValueRef, name: &str) {
|
||||
let name = CString::new(name).unwrap();
|
||||
unsafe {
|
||||
core::LLVMSetValueName(value, name.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn GetValueName(value: LLVMValueRef) -> String {
|
||||
unsafe {
|
||||
let name_ptr: *const c_char = core::LLVMGetValueName(value);
|
||||
CStr::from_ptr(name_ptr).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn GetParams(function: LLVMValueRef) -> Vec<LLVMValueRef> {
|
||||
let size = CountParams(function);
|
||||
unsafe {
|
||||
let mut container = Vec::with_capacity(size);
|
||||
container.set_len(size);
|
||||
core::LLVMGetParams(function, container.as_mut_ptr());
|
||||
container
|
||||
}
|
||||
}
|
||||
|
||||
pub fn CountParams(function: LLVMValueRef) -> usize {
|
||||
unsafe { core::LLVMCountParams(function) as usize }
|
||||
}
|
||||
|
||||
pub fn BuildFCmp(builder: LLVMBuilderRef,
|
||||
op: LLVMRealPredicate,
|
||||
lhs: LLVMValueRef,
|
||||
rhs: LLVMValueRef,
|
||||
name: &str) -> LLVMValueRef {
|
||||
let name = CString::new(name).unwrap();
|
||||
unsafe { core::LLVMBuildFCmp(builder, op, lhs, rhs, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildZExt(builder: LLVMBuilderRef,
|
||||
val: LLVMValueRef,
|
||||
dest_type: LLVMTypeRef,
|
||||
name: &str) -> LLVMValueRef {
|
||||
let name = CString::new(name).unwrap();
|
||||
unsafe { core::LLVMBuildZExt(builder, val, dest_type, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildUIToFP(builder: LLVMBuilderRef,
|
||||
val: LLVMValueRef,
|
||||
dest_type: LLVMTypeRef,
|
||||
name: &str) -> LLVMValueRef {
|
||||
|
||||
let name = CString::new(name).unwrap();
|
||||
unsafe { core::LLVMBuildUIToFP(builder, val, dest_type, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn BuildICmp(builder: LLVMBuilderRef,
|
||||
op: LLVMIntPredicate,
|
||||
lhs: LLVMValueRef,
|
||||
rhs: LLVMValueRef,
|
||||
name: &str) -> LLVMValueRef {
|
||||
let name = CString::new(name).unwrap();
|
||||
unsafe { core::LLVMBuildICmp(builder, op, lhs, rhs, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn GetBasicBlockParent(block: LLVMBasicBlockRef) -> LLVMValueRef {
|
||||
unsafe { core::LLVMGetBasicBlockParent(block) }
|
||||
}
|
||||
|
||||
pub fn GetBasicBlocks(function: LLVMValueRef) -> Vec<LLVMBasicBlockRef> {
|
||||
let size = CountBasicBlocks(function);
|
||||
unsafe {
|
||||
let mut container = Vec::with_capacity(size);
|
||||
container.set_len(size);
|
||||
core::LLVMGetBasicBlocks(function, container.as_mut_ptr());
|
||||
container
|
||||
}
|
||||
}
|
||||
|
||||
pub fn CountBasicBlocks(function: LLVMValueRef) -> usize {
|
||||
unsafe { core::LLVMCountBasicBlocks(function) as usize }
|
||||
}
|
||||
|
||||
pub fn PrintModuleToString(module: LLVMModuleRef) -> String {
|
||||
unsafe {
|
||||
let str_ptr: *const c_char = core::LLVMPrintModuleToString(module);
|
||||
CStr::from_ptr(str_ptr).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn AddIncoming(phi_node: LLVMValueRef, mut incoming_values: Vec<LLVMValueRef>,
|
||||
mut incoming_blocks: Vec<LLVMBasicBlockRef>) {
|
||||
|
||||
let count = incoming_blocks.len() as u32;
|
||||
if incoming_values.len() as u32 != count {
|
||||
panic!("Bad invocation of AddIncoming");
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let vals = incoming_values.as_mut_ptr();
|
||||
let blocks = incoming_blocks.as_mut_ptr();
|
||||
core::LLVMAddIncoming(phi_node, vals, blocks, count)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn PrintModuleToFile(module: LLVMModuleRef, filename: &str) -> LLVMBool {
|
||||
let out_file = CString::new(filename).unwrap();
|
||||
unsafe { core::LLVMPrintModuleToFile(module, out_file.as_ptr(), ptr::null_mut()) }
|
||||
}
|
||||
45
schala-repl/src/webapp.rs
Normal file
45
schala-repl/src/webapp.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use rocket;
|
||||
use rocket::State;
|
||||
use rocket::response::Content;
|
||||
use rocket::response::NamedFile;
|
||||
use rocket::http::ContentType;
|
||||
use rocket_contrib::Json;
|
||||
use language::{ProgrammingLanguageInterface, EvalOptions};
|
||||
use WEBFILES;
|
||||
use ::PLIGenerator;
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> Content<String> {
|
||||
let path = "static/index.html";
|
||||
let html_contents = String::from_utf8(WEBFILES.get(path).unwrap().into_owned()).unwrap();
|
||||
Content(ContentType::HTML, html_contents)
|
||||
}
|
||||
|
||||
#[get("/bundle.js")]
|
||||
fn js_bundle() -> Content<String> {
|
||||
let path = "static/bundle.js";
|
||||
let js_contents = String::from_utf8(WEBFILES.get(path).unwrap().into_owned()).unwrap();
|
||||
Content(ContentType::JavaScript, js_contents)
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Input {
|
||||
source: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Output {
|
||||
text: String,
|
||||
}
|
||||
|
||||
#[post("/input", format = "application/json", data = "<input>")]
|
||||
fn interpreter_input(input: Json<Input>, generators: State<Vec<PLIGenerator>>) -> Json<Output> {
|
||||
let schala_gen = generators.get(0).unwrap();
|
||||
let mut schala: Box<ProgrammingLanguageInterface> = schala_gen();
|
||||
let code_output = schala.evaluate_in_repl(&input.source, &EvalOptions::default());
|
||||
Json(Output { text: code_output.to_string() })
|
||||
}
|
||||
|
||||
pub fn web_main(language_generators: Vec<PLIGenerator>) {
|
||||
rocket::ignite().manage(language_generators).mount("/", routes![index, js_bundle, interpreter_input]).launch();
|
||||
}
|
||||
Reference in New Issue
Block a user