Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split project in core crate and interpreter #356

Merged
merged 3 commits into from
Nov 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ libloading = "0.7"

[dev-dependencies]
libc = "0.2"

[[bin]]
name = "jinko"
path = "interpreter/jinko.rs"
File renamed without changes.
36 changes: 10 additions & 26 deletions src/main.rs → interpreter/jinko.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
#[warn(missing_docs)]
// FIXME: Add #![warn(missing_docs)]

mod args;
mod builtins;
mod context;
mod error;
mod ffi;
mod indent;
mod instance;
mod instruction;
mod parser;
mod repl;
mod typechecker;
mod utils;
mod value;

use jinko::{
CheckedType, Context, Error, FromObjectInstance, JkBool, JkFloat, JkInt, ObjectInstance,
};

use args::Args;
use parser::Parser;
use repl::Repl;
use std::{fs, path::Path};

pub use builtins::Builtins;
pub use context::{Context, Scope, ScopeMap};
pub use error::{ErrKind, Error};
pub use indent::Indent;
pub use instance::{FromObjectInstance, ObjectInstance, ToObjectInstance};
pub use instruction::{InstrKind, Instruction};
pub use typechecker::{CheckedType, TypeCheck, TypeCtx};
pub use value::{JkBool, JkChar, JkConstant, JkFloat, JkInt, JkString, Value};

// FIXME: Add documentation
pub type InteractResult = Result<(Option<ObjectInstance>, Context), Error>;

Expand All @@ -42,10 +26,10 @@ fn handle_exit_code(result: Option<ObjectInstance>) -> ! {
// If it's an expression, return if you can (if it's an int)
Some(i) => match i.ty() {
CheckedType::Resolved(ty) => match ty.id() {
"int" => exit(JkInt::from_instance(&i).0 as i32),
"float" => exit(JkFloat::from_instance(&i).0 as i32),
"int" => exit(JkInt::from_instance(&i).rust_value() as i32),
"float" => exit(JkFloat::from_instance(&i).rust_value() as i32),
"bool" => {
let b_value = JkBool::from_instance(&i).0;
let b_value = JkBool::from_instance(&i).rust_value();
match b_value {
true => exit(0),
false => exit(1),
Expand All @@ -68,7 +52,7 @@ fn handle_input(args: &Args, file: &Path) -> InteractResult {
ctx.init_stdlib()?;
}

Parser::parse(&mut ctx, &input)?;
jinko::parse(&mut ctx, &input)?;

ctx.set_path(Some(file.to_owned()));
ctx.set_args(args.project_args());
Expand Down
35 changes: 17 additions & 18 deletions src/repl.rs → interpreter/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,31 @@ mod prompt;
use prompt::Prompt;
use std::path::PathBuf;

use jinko::{CheckedType, TypeCheck, TypeCtx};
use jinko::{
Construct, Context, Error, FromObjectInstance, Instruction, JkConstant, ObjectInstance,
};

use linefeed::{DefaultTerminal, Interface, ReadResult};

use crate::args::Args;
use crate::typechecker::{CheckedType, TypeCheck, TypeCtx};
use crate::{
parser::Construct, Context, Error, FromObjectInstance, Instruction, InteractResult, JkConstant,
ObjectInstance,
};
use crate::InteractResult;

struct ReplInstance(ObjectInstance);

// FIXME:
// - Is Display really how we want to go about it?
// - Cleanup the code
// - This should not be here
impl std::fmt::Display for ObjectInstance {
impl std::fmt::Display for ReplInstance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self.ty() {
match self.0.ty() {
CheckedType::Resolved(ty) => match ty.id() {
"int" => JkConstant::<i64>::from_instance(self).print(),
"float" => JkConstant::<f64>::from_instance(self).print(),
"char" => JkConstant::<char>::from_instance(self).print(),
"string" => JkConstant::<String>::from_instance(self).print(),
"bool" => JkConstant::<bool>::from_instance(self).print(),
_ => self.as_string(),
"int" => JkConstant::<i64>::from_instance(&self.0).print(),
"float" => JkConstant::<f64>::from_instance(&self.0).print(),
"char" => JkConstant::<char>::from_instance(&self.0).print(),
"string" => JkConstant::<String>::from_instance(&self.0).print(),
"bool" => JkConstant::<bool>::from_instance(&self.0).print(),
_ => self.0.as_string(),
},
_ => format!(""),
}
Expand Down Expand Up @@ -124,7 +123,7 @@ impl<'args> Repl<'args> {
// }

if let Some(result) = inst.execute(&mut ctx) {
println!("{}", result);
println!("{}", ReplInstance(result));
};

ctx.emit_errors();
Expand Down
2 changes: 1 addition & 1 deletion src/repl/prompt.rs → interpreter/repl/prompt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Creates a prompt based on the context's current status

use crate::context::Context;
use colored::Colorize;
use jinko::Context;

pub struct Prompt;

Expand Down
4 changes: 2 additions & 2 deletions src/instruction/if_else.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! `IfElse`s are used to represent an if/else statement in the source code. They have
//! a condition, a body and an optional else body.
//!
//! ```
//! ```ignore
//! if condition {
//! condition_evaluates_to_true();
//! } else {
Expand All @@ -11,7 +11,7 @@
//!
//! They can be used to return values, just like you would with any block.
//!
//! ```
//! ```ignore
//! x = if condition { 12 } else { 13 };
//! ```
Expand Down
4 changes: 2 additions & 2 deletions src/instruction/jk_return.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Return construct is used to return early from a function
//! ```
//! ```ignore
//! return
//! ```
//!
//! It can be used to return values
//!
//! ```
//! ```ignore
//! return 42
//! ```
Expand Down
3 changes: 1 addition & 2 deletions src/instruction/loop_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ mod tests {
use super::*;
use crate::instruction::FunctionCall;
use crate::jinko;
use crate::{JkInt, ToObjectInstance};

#[test]
fn pretty_print_loop() {
Expand Down Expand Up @@ -244,7 +243,7 @@ mod tests {

#[test]
fn valid_for_block() {
let ctx = jinko! {
let _ctx = jinko! {
mut counter = 0;
for i in range(0, 15) {
counter = counter + 1;
Expand Down
4 changes: 2 additions & 2 deletions src/instruction/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//!
//! For some simple constructs, this simply means renaming self's name, such as a TypeDec:
//!
//! ```
//! ```ignore
//! // some_type.jk
//! type SomeType(...);
//!
Expand All @@ -28,7 +28,7 @@
//! ```
//!
//! Other instructions also have owernship of other instructions, such as blocks:
//! ```
//! ```ignore
//! // source.jk
//! { // block enter
//! type InBlock(...);
Expand Down
2 changes: 1 addition & 1 deletion src/instruction/var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl Instruction for Var {
base = format!("{} /* : {} */", base, ty.id());
}

format!("{} = {}", base, self.instance)
format!("{} = {}", base, self.instance.as_string())
}

fn as_bool(&self, ctx: &mut Context) -> Option<bool> {
Expand Down
23 changes: 23 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// FIXME: Make crate attribute `#![warn(missing_docs)]`

mod builtins;
mod context;
mod error;
mod ffi;
mod indent;
mod instance;
mod instruction;
mod parser;
mod typechecker;
mod utils;
mod value;

pub use builtins::Builtins;
pub use context::{Context, Scope, ScopeMap};
pub use error::{ErrKind, Error};
pub use indent::Indent;
pub use instance::{FromObjectInstance, ObjectInstance, ToObjectInstance};
pub use instruction::{InstrKind, Instruction};
pub use parser::{parse, Construct};
pub use typechecker::{CheckedType, TypeCheck, TypeCtx};
pub use value::{JkBool, JkChar, JkConstant, JkFloat, JkInt, JkString, Value};
23 changes: 11 additions & 12 deletions src/parser/constructs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl Construct {
/// Parse a function call
/// When a function is called in the source code.
///
/// ```
/// ```ignore
/// fn(); // Function call
/// fn() // Call the function `fn` and use the return result as an instruction
/// x = fn(); // Assign the result of the function call to the variable x
Expand Down Expand Up @@ -169,14 +169,14 @@ impl Construct {
/// When a variable is assigned a value. Ideally, a variable cannot be assigned the
/// `void` type.
///
/// ```
/// ```ignore
/// x = 12; // Store 12 into the variable `x`
/// x = 456; // Forbidden, `x` is immutable
/// ```
///
/// A variable assignment is a Statement. It cannot be used as an Expression
///
/// ```
/// ```ignore
/// {
/// x = 12; // Block returns void
/// }
Expand Down Expand Up @@ -346,7 +346,7 @@ impl Construct {

/// When a type is instantiated in the source code.
///
/// ```
/// ```ignore
/// type A(n: int); // Declare type A
/// val = A(1); // Instantiate a new A type variable
/// ```
Expand All @@ -373,14 +373,14 @@ impl Construct {
/// When a variable is assigned a value. Ideally, a variable cannot be assigned the
/// `void` type.
///
/// ```
/// ```ignore
/// mut n = 12; // Store 12 into `n`, a mutable variable
/// n = 1586; // Allowed
/// ```
///
/// A variable assignment is a Statement. It cannot be used as an Expression
///
/// ```
/// ```ignore
/// {
/// x = 12; // Block returns void
/// }
Expand Down Expand Up @@ -464,7 +464,7 @@ impl Construct {
/// A block of code is a new inner scope that contains instructions. You can use
/// them in If/Else blocks, in function declarations, or just as is.
///
/// ```
/// ```ignore
/// func return_nothing() {
/// compute_stuff();
/// } // Block returns void, so does the function
Expand Down Expand Up @@ -610,7 +610,7 @@ impl Construct {
/// Parse a function declaration. This includes the function's signature and the
/// associated code block
///
/// ```
/// ```ignore
/// func fn_name(arg0: int) -> int {
/// do_something(arg0);
///
Expand All @@ -635,7 +635,7 @@ impl Construct {
/// invoke them. Therefore, naming the test the same as the tested function is fine
/// and is not any form of overloading whatsoever.
///
/// ```
/// ```ignore
/// test add() {
/// assert_eq(12 + 2, add(12, 2));
/// }
Expand Down Expand Up @@ -665,8 +665,7 @@ impl Construct {
/// Parse a mock declaration. This returns a FunctionDec as well, but of
/// kind `FunctionDec::Mock`.
///
///
/// ```
/// ```ignore
/// mock add(lhs: int, rhs: int) -> int {
/// mock_stuff()
/// }
Expand Down Expand Up @@ -838,7 +837,7 @@ impl Construct {
///
/// `<expr> <op> <expr>`
///
/// ```
/// ```ignore
/// x + y; // Add x and y together
/// a << 2; // Shift a by 2 bits
/// a > 2; // Is a greater than 2?
Expand Down
40 changes: 18 additions & 22 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,24 @@ pub use tokens::Token;

pub type ParseResult<T, I> = nom::IResult<T, I, Error>;

pub struct Parser;

impl Parser {
/// Parses the entire user input and returns a hashmap corresponding to the user
/// program
pub fn parse(ctx: &mut Context, input: &str) -> Result<(), Error> {
let entry_block = ctx.entry_point.block_mut().unwrap();

let (_, instructions) = Construct::many_instructions(input)?;

entry_block.add_instructions(instructions);

// We must create the block "manually", by checking if the last parsed operation
// is an expression or not. If it is an expression, then use it as the return
// value. If not, simply execute it.
if let Some(last) = entry_block.pop_instruction() {
match last.kind() {
InstrKind::Expression(_) => entry_block.set_last(Some(last)),
InstrKind::Statement => entry_block.add_instruction(last),
}
/// Parses the entire user input and returns a hashmap corresponding to the user
/// program
pub fn parse(ctx: &mut Context, input: &str) -> Result<(), Error> {
let entry_block = ctx.entry_point.block_mut().unwrap();

let (_, instructions) = Construct::many_instructions(input)?;

entry_block.add_instructions(instructions);

// We must create the block "manually", by checking if the last parsed operation
// is an expression or not. If it is an expression, then use it as the return
// value. If not, simply execute it.
if let Some(last) = entry_block.pop_instruction() {
match last.kind() {
InstrKind::Expression(_) => entry_block.set_last(Some(last)),
InstrKind::Statement => entry_block.add_instruction(last),
}

Ok(())
}

Ok(())
}
4 changes: 2 additions & 2 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub use stack::Stack;
#[macro_export]
macro_rules! jk_parse {
($ctx:expr, $($tokens:tt)*) => {
$crate::Parser::parse($ctx, stringify!($($tokens)*)).unwrap()
$crate::parse($ctx, stringify!($($tokens)*)).unwrap()
}
}

Expand Down Expand Up @@ -56,7 +56,7 @@ macro_rules! jk_execute {
let mut ctx = $crate::Context::new();
ctx.init_stdlib().unwrap();

$crate::Parser::parse(&mut ctx, stringify!($($tokens)*)).unwrap();
$crate::parse(&mut ctx, stringify!($($tokens)*)).unwrap();

ctx.execute().unwrap()
}
Expand Down
Loading