Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

[WIP] Add a proper REPL #464

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/analyze/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,7 @@ impl PureAnalyzer {
/// This returns an opaque index to the `Metadata`.
fn declare(&mut self, mut decl: Variable, init: bool, location: Location) -> Symbol {
if decl.id == "main".into() {
println!("main: {:?}", decl);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
println!("main: {:?}", decl);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ups 😅

if let Type::Function(ftype) = &decl.ctype {
// int main(int)
if !ftype.is_main_func_signature() {
Expand Down
62 changes: 56 additions & 6 deletions src/bin/repl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ mod commands;
mod helper;

use commands::CommandError;
use cranelift_module::Module;
use cranelift_simplejit::SimpleJITBackend;
use helper::{CommandHinter, ReplHelper};
use rustyline::{
error::ReadlineError, highlight::MatchingBracketHighlighter,
validate::MatchingBracketValidator, CompletionType, Config, EditMode, Editor,
};
use saltwater::{analyze, check_semantics, initialize_jit_module, Opt, Parser, PureAnalyzer};
use saltwater::{
analyze,
data::{self, hir, types},
initialize_jit_module, ir, Opt, Parser, PureAnalyzer, JIT,
};

const PROMPT: &str = ">> ";
const COMMAND_PREFIX: &str = ":";
Expand All @@ -28,7 +30,6 @@ pub struct Repl<'s> {
prompt: &'s str,
opt: Opt,
code: String,
module: Module<SimpleJITBackend>,
}

impl<'s> Repl<'s> {
Expand All @@ -54,7 +55,6 @@ impl<'s> Repl<'s> {
prefix: COMMAND_PREFIX,
prompt: PROMPT,
code: String::new(),
module: initialize_jit_module(),
}
}

Expand Down Expand Up @@ -97,6 +97,56 @@ impl<'s> Repl<'s> {
}

fn execute_code(&mut self, code: &str) {
let program = check_semantics(code, self.opt.clone());
let module = initialize_jit_module();
let expr = match analyze(code, Parser::expr, PureAnalyzer::expr) {
Ok(mut expr) => {
expr.ctype = types::Type::Int(true);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look right. What's this meant to do?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this crashes on strings:

>> "a"
The application panicked (crashed).
Message:  verification error: - inst1 (return v0): arg 0 (v0) has type i64, must match function signature of i32

note: while compiling function u0:0() -> i32 system_v {
    gv0 = symbol colocated u1:0

block0:
    v0 = global_value.i64 gv0
    return v0
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead you could use a function name other than main and set the return type to the type of the expression. Then you decide how to display the result depending on the type. That would also fix the current bug where 'a' is displayed as 99.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea

Copy link
Contributor Author

@Stupremee Stupremee Jun 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had this code there, because otherwise I got an error from cranelift that it expected an i32 but got i64.

verification error: - inst1 (return v0): arg 0 (v0) has type i64, must match function signature of i32

note: while compiling function u0:0() -> i32 system_v {
block0:
    v0 = iconst.i64 1
    return v0
}

expr
}
Err(err) => {
println!("error: {}", err.data);
return;
}
};
let function_type = types::FunctionType {
return_type: Box::new(types::Type::Int(true)),
params: vec![],
varargs: false,
};
let qualifiers = hir::Qualifiers {
volatile: false,
c_const: false,
func: hir::FunctionQualifiers {
inline: false,
no_return: false,
},
};
Comment on lines +116 to +123
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let qualifiers = hir::Qualifiers {
volatile: false,
c_const: false,
func: hir::FunctionQualifiers {
inline: false,
no_return: false,
},
};
let qualifiers = hir::Qualifiers::default();


let main = hir::Variable {
ctype: types::Type::Function(function_type),
storage_class: data::StorageClass::Extern,
qualifiers,
id: saltwater::InternedStr::get_or_intern("main"),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
id: saltwater::InternedStr::get_or_intern("main"),
id: "main".into(),

};

let span = expr.location;
let stmt = span.with(hir::StmtType::Return(Some(expr)));
let init = hir::Initializer::FunctionBody(vec![stmt]);
let decl = hir::Declaration {
symbol: main.insert(),
init: Some(init),
};
let (result, _warns) = ir::compile(module, vec![span.with(decl)], false);
Comment on lines +101 to +139
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks useful on its own, can you make it a function in src/lib.rs called eval() that's implemented on JIT?


if let Err(err) = result {
println!("failed to compile: {}", err.data);
return;
}

let module = result.unwrap();
Comment on lines +141 to +146
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to avoid unwrap if possible.

Suggested change
if let Err(err) = result {
println!("failed to compile: {}", err.data);
return;
}
let module = result.unwrap();
let module = match result {
Err(err) => {
println!("failed to compile: {}", err.data);
return;
}
Ok(module) => module),
};

let mut jit = JIT::from(module);

let result = unsafe { jit.run_main() }.unwrap();
println!("result: {}", result);
}
}
2 changes: 1 addition & 1 deletion src/data/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl Symbol {
}

impl Variable {
pub(crate) fn insert(self) -> Symbol {
pub fn insert(self) -> Symbol {
SYMBOL_TABLE.with(|store| store.borrow_mut().insert(self))
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ struct Compiler<T: Backend> {
}

/// Compile a program from a high level IR to a Cranelift Module
pub(crate) fn compile<B: Backend>(
pub fn compile<B: Backend>(
module: Module<B>,
program: Vec<Locatable<Declaration>>,
debug: bool,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub mod data;
mod fold;
pub mod intern;
#[cfg(feature = "codegen")]
mod ir;
pub mod ir;
mod lex;
mod parse;

Expand Down