Skip to content

Commit

Permalink
specializer supports operators
Browse files Browse the repository at this point in the history
  • Loading branch information
lochbrunner committed Oct 5, 2020
1 parent bfb2555 commit 15f9d5e
Show file tree
Hide file tree
Showing 8 changed files with 425 additions and 103 deletions.
2 changes: 2 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
BasedOnStyle: Google
ColumnLimit: 120
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# will have compiled files and executables
/target/
/build/
tmp

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ cchop <code filename> -o <output filename>

## Milestones

### Basics

1. [Interpret MVP](./milestones/1) :heavy_check_mark:
1. [Compile MVP via LLVM](./milestones/2) :heavy_check_mark:
1. [Mathematical operations and build-in functions](./milestones/3) :heavy_check_mark:
Expand All @@ -53,13 +55,22 @@ cchop <code filename> -o <output filename>
1. [Code generation from intermediate steps](./milestones/8)
1. Enums
1. Control flow
1. Arrays and Strings
1. Heap
1. Caching
1. Imports and Exports
1. Meta Programming
1. Hooks
1. Borrowing (and checks)
1. FFI
1. FFI (foreign function interface)
1. Debugging

### Advanced

1. Standard Library
* Container
* IO

## Goal - Self hosted language

* Rewrite compiler and interpreter in chop.
Expand Down
60 changes: 31 additions & 29 deletions core/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,33 +155,21 @@ fn unroll_node<'a>(
}
Ok(signature.return_type)
}
AstTokenPayload::DefineLocal(_) => {
AstTokenPayload::DefineLocal(ref dtype) => {
// Compile argument
if node.args.len() != 2 && node.args.len() != 3 {
if node.args.len() != 2 {
// TODO: Handle Type declaration
return Err(CompilerError::from_token::<DenseToken>(
&node.root,
format!(
"Exporter Error: DefineLocal need two arguments but got {}",
node.args.len()
),
));
return Err(node.root.loc.to_error(format!(
"Exporter Error: DefineLocal need two arguments but got {}",
node.args.len()
)));
}
let has_type = node.args.len() == 3;
let _arg = unroll_node(
node.args
.get(if has_type { 2 } else { 1 })
.expect("Definition"),
)?;
let dtype = dtype.clone().unwrap_or(Type::Int32);
unroll_node(node.args.get(1).expect("Definition"))?;

let decl_type = if has_type {
Type::from_dense_token(&node.args.get(1).expect("Type Declaration").root)
} else {
Type::Int32
};
bytecode.push(ByteCode::Alloca(decl_type.clone()));
bytecode.push(ByteCode::Alloca(dtype.clone()));
let index = register_map.len();
bytecode.push(ByteCode::Store(decl_type, index));
bytecode.push(ByteCode::Store(dtype, index));
register_map.insert(
&node
.args
Expand Down Expand Up @@ -292,6 +280,10 @@ mod specs {

#[test]
fn milestone_4_main() {
// a := 3
// b := a + 5
// c := 7
// stdout max(b,c)
let input = DenseAst {
statements: vec![
Node {
Expand Down Expand Up @@ -374,18 +366,24 @@ mod specs {
let input = DenseAst {
statements: vec![
Node {
root: DenseToken::stub(DefineLocal),
root: DenseToken {
payload: AstTokenPayload::DefineLocal(Some(Type::Int32)),
return_type: Type::Void,
loc: Location::default(),
},
args: vec![
Node::leaf(DenseToken::stub(Ident("a".to_string()))),
Node::leaf(DenseToken::stub(Ident("i32".to_string()))),
Node::leaf(DenseToken::stub(Integer(3))),
],
},
Node {
root: DenseToken::stub(DefineLocal),
root: DenseToken {
payload: AstTokenPayload::DefineLocal(Some(Type::Int8)),
return_type: Type::Void,
loc: Location::default(),
},
args: vec![
Node::leaf(DenseToken::stub(Ident("b".to_string()))),
Node::leaf(DenseToken::stub(Ident("i8".to_string()))),
Node {
root: DenseToken::stub(TokenPayload::Add),
args: vec![
Expand All @@ -408,10 +406,13 @@ mod specs {
],
},
Node {
root: DenseToken::stub(DefineLocal),
root: DenseToken {
payload: AstTokenPayload::DefineLocal(Some(Type::Int8)),
return_type: Type::Void,
loc: Location::default(),
},
args: vec![
Node::leaf(DenseToken::stub(Ident("c".to_string()))),
Node::leaf(DenseToken::stub(Ident("i8".to_string()))),
Node {
root: DenseToken::stub(Cast),
args: vec![
Expand Down Expand Up @@ -440,7 +441,8 @@ mod specs {
"max".to_string() => Declaration::full_template_function(2),
"a".to_string() => Declaration::variable(Type::Int32),
"b".to_string() => Declaration::variable(Type::Int8),
"c".to_string() => Declaration::variable(Type::Int8)
"c".to_string() => Declaration::variable(Type::Int8),
"i8".to_string() => Declaration::variable(Type::Type),
},
};

Expand Down
36 changes: 36 additions & 0 deletions core/src/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,36 @@ impl Type {
_ => Type::Int32,
}
}

pub fn merge(a: &Option<Self>, b: &Option<Self>) -> Result<Option<Self>, ()> {
if let Some(a) = a {
if let Some(b) = b {
if b != a {
Err(())
} else {
Ok(Some(a.clone()))
}
} else {
Ok(Some(a.clone()))
}
} else {
Ok(b.clone())
}
}
}

impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Type::Int8 => "int8",
Type::Int16 => "int16",
Type::Int32 => "int32",
Type::Int64 => "int64",
Type::Void => "void",
Type::Type => "type",
};
write!(f, "{}", s)
}
}

#[derive(PartialEq, Clone)]
Expand Down Expand Up @@ -250,4 +280,10 @@ impl Context {
Some(dec) => Ok(dec),
}
}

pub fn new() -> Self {
Self {
declarations: HashMap::new(),
}
}
}
98 changes: 95 additions & 3 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod parser;
mod simplifier;
mod specializer;
pub mod token;
use declaration::{Context, Declaration};
use declaration::{Context, Declaration, Type};
pub use error::CompilerError;

pub use bytecode::ByteCode;
Expand All @@ -25,13 +25,17 @@ pub fn build(code: &str) -> Result<Vec<ByteCode>, CompilerError> {
"stdout".to_string() => Declaration::full_template_statement(1),
"max".to_string() => Declaration::full_template_function(2),
"min".to_string() => Declaration::full_template_function(2),
"i8".to_string() => Declaration::variable(Type::Type),
"i16".to_string() => Declaration::variable(Type::Type),
"i32".to_string() => Declaration::variable(Type::Type),
"i64".to_string() => Declaration::variable(Type::Type),
},
};

let tokens = lexer::lex(code)?;
let ast = parser::parse(&mut context, &tokens)?;
let ast = generator::generate_sparse(ast)?;
let ast = specializer::specialize(ast)?;
let ast = specializer::specialize(ast, &mut context)?;
let ast = simplifier::simplify(ast)?;
// TODO: cache
bytecode::compile(&context, ast)
Expand Down Expand Up @@ -116,11 +120,99 @@ mod e2e {
let expected = vec![
PushInt32(3),
PushInt32(5),
Call2("max".to_string(), Type::Int32, Type::Int32, Type::Int32),
Call2("max".to_owned(), Type::Int32, Type::Int32, Type::Int32),
StdOut,
];
let expected = [&HEADER[..], &expected].concat();

assert_eq!(actual, expected);
}

#[test]
fn print_addition_of_variables() {
let code = &"#!/usr/bin/env ichop
a := 3
b := 5
stdout a+b";

let actual = build(code);

assert!(actual.is_ok());
let actual = actual.unwrap();

let expected = vec![
// head
Alloca(Type::Int32),
PushInt32(0),
Store(Type::Int32, 0),
// a := 3
PushInt32(3),
Alloca(Type::Int32),
Store(Type::Int32, 1),
// b := 5
PushInt32(5),
Alloca(Type::Int32),
Store(Type::Int32, 2),
// stdout a+b"
Load(Type::Int32, 1),
Load(Type::Int32, 2),
Add(Type::Int32),
StdOut,
];
}

// #[test]
// fn milestone_5_main() {
// let code = "#!/usr/bin/env ichop

// a: i32 := 3
// b:= a as i8 + 5
// c: i8 := 7
// stdout max(b,c)";

// let mut context = Context {
// declarations: hashmap! {
// "stdout".to_string() => Declaration::full_template_statement(1),
// "max".to_string() => Declaration::full_template_function(2),
// "min".to_string() => Declaration::full_template_function(2),
// "i8".to_string() => Declaration::variable(Type::Type),
// "i32".to_string() => Declaration::variable(Type::Type),
// },
// };
// let tokens = lexer::lex(code).unwrap();

// parser::parse(&mut context, &tokens).unwrap().statements.iter()
// .map()
// .collect();

// let ast = parser::parse(&mut context, &tokens).unwrap();
// let ast = generator::generate_sparse(ast).unwrap();
// // dbg!(&ast);
// let ast = specializer::specialize(ast, &mut context).unwrap();
// let ast = simplifier::simplify(ast).unwrap();
// let actual = bytecode::compile(&context, ast);

// // dbg!(&actual);
// assert!(actual.is_ok());
// let actual = actual.unwrap();

// let expected = vec![
// // a: i32 := 3
// Alloca(Type::Int32),
// PushInt32(0),
// Store(Type::Int32, 0),
// Alloca(Type::Int32),
// Store(Type::Int32, 1),
// Alloca(Type::Int8),
// Store(Type::Int8, 2),
// Alloca(Type::Int8),
// Store(Type::Int8, 3),
// // stdout max(b,c)
// Load(Type::Int8, 2),
// Load(Type::Int8, 3),
// Call2("max".to_owned(), Type::Int8, Type::Int8, Type::Int8),
// StdOut,
// ];
// }
}
Loading

0 comments on commit 15f9d5e

Please sign in to comment.