Skip to content

Commit

Permalink
Fullfills milestone 1
Browse files Browse the repository at this point in the history
  • Loading branch information
lochbrunner committed Aug 18, 2019
1 parent 60364b0 commit 7e07f93
Show file tree
Hide file tree
Showing 16 changed files with 596 additions and 42 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ matrix:
script:
- cargo build --verbose --all
- cargo test --verbose --all
- cargo clippy --verbose --all
cache:
directories:
- /home/travis/.cargo
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"astified",
"ichop"
]
}
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Reference implementation for chop-lang

![](https://travis-ci.org/lochbrunner/chop-compiler.svg?branch=master)
<p align="center">
<a href="https://travis-ci.org/lochbrunner/chop-compiler"><img src="https://travis-ci.org/lochbrunner/chop-compiler.svg?branch=master" alt="Build Status"></a>
</p>



See [Language Specifications](https://github.com/lochbrunner/chop-specs/blob/master/README.md)
4 changes: 1 addition & 3 deletions examples/hello-world.ch
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import iostream
import * from iostream

"Hello World!" | stdout

Expand All @@ -25,5 +25,3 @@ stdin.once | split | i32.parse | + | stdout

// a+b*c*d
stdin.once | split | i32.parse | + | * | stdout

true false
2 changes: 2 additions & 0 deletions interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = "2.33.0"
maplit = "^1.0.1"
nom = "5.0.0"
nom_locate = "0.4.0"

Expand Down
18 changes: 18 additions & 0 deletions interpreter/src/compiler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Compiler

## Architecture

The Compiler for has these data flow chain

* *Lexer*
* *Parser*
* *Generator* (also planed: *Injector* & *Checker*)
* *Exporter*
* Interpreter byte-code
* planed: llvm
* planed: chop IR

## Challenges

* How to propagate information (from *Generator* and *Injector*) back to the *Parser* and *Lexer*?

16 changes: 16 additions & 0 deletions interpreter/src/compiler/ast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::compiler::token::Token;

#[derive(Debug, PartialEq)]
pub struct Node {
pub root: Token,
pub args: Vec<Token>,
}
#[derive(Debug, PartialEq)]
pub struct Statement {
pub root: Node,
}

#[derive(Debug, PartialEq)]
pub struct Ast {
pub statements: Vec<Statement>,
}
109 changes: 109 additions & 0 deletions interpreter/src/compiler/exporter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use crate::compiler::ast::Ast;
use crate::compiler::token::TokenPayload;
use crate::compiler::CompilerError;
use crate::evaluation::bytecode::ByteCode;

pub fn export(ast: Ast) -> Result<Vec<ByteCode>, CompilerError> {
let mut bytecode = vec![];
for mut statement in ast.statements.into_iter() {
match statement.root.root.token {
TokenPayload::Ident(ident) => match ident.as_ref() {
"stdout" => match statement.root.args.pop() {
Some(arg) => {
if !statement.root.args.is_empty() {
return Err(CompilerError {
location: statement.root.root.begin.clone(),
msg: format!(
"Exporter Error: Function {} has tow many arguments",
ident
),
});
}
match arg.token {
TokenPayload::Int32(v) => {
bytecode.push(ByteCode::PushInt32(v));
}
_ => {
return Err(CompilerError {
location: statement.root.root.begin.clone(),
msg: format!(
"Exporter Error: Function {} expects an int as argument but got {:?}",
ident, arg.token
),
})
}
}
bytecode.push(ByteCode::StdOut);
}
None => {
return Err(CompilerError {
location: statement.root.root.begin.clone(),
msg: format!("Exporter Error: Function {} has no argument", ident),
})
}
},
_ => {
return Err(CompilerError {
location: statement.root.root.begin.clone(),
msg: format!("Exporter Error: Unknown ident: {}", ident),
})
}
},
_ => {
return Err(CompilerError {
location: statement.root.root.begin.clone(),
msg: format!(
"Exporter Error: Unknown token {:?}",
statement.root.root.token
),
})
}
}
}
Ok(bytecode)
}

#[cfg(test)]
mod specs {
use super::*;
use crate::compiler::ast::{Node, Statement};
use crate::compiler::token::{Location, Token, TokenPayload};

#[test]
fn milestone_1() {
let input = Ast {
statements: vec![Statement {
root: Node {
root: Token {
token: TokenPayload::Ident("stdout".to_owned()),
begin: Location {
line: 3,
offset: 33,
},
end: Location {
line: 3,
offset: 39,
},
},
args: vec![Token {
token: TokenPayload::Int32(42),
begin: Location {
line: 3,
offset: 28,
},
end: Location {
line: 3,
offset: 30,
},
}],
},
}],
};
let actual = export(input);
assert!(actual.is_ok());
let actual = actual.unwrap();
let expected = vec![ByteCode::PushInt32(42), ByteCode::StdOut];

assert_eq!(actual, expected);
}
}
111 changes: 111 additions & 0 deletions interpreter/src/compiler/generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use crate::compiler::ast::{Ast, Node, Statement};
use crate::compiler::token::TokenPayload;
use crate::compiler::CompilerError;

/// Fills out the macros and runs all the custom compiler stuff.
pub fn generate(ast: Ast) -> Result<Ast, CompilerError> {
let statements = ast
.statements
.into_iter()
.map(|statement| match statement.root.root.token {
TokenPayload::Pipe => Ok(Statement {
root: Node {
root: statement.root.args[1].clone(),
args: vec![statement.root.args[0].clone()],
},
}),
_ => Err(CompilerError {
location: statement.root.root.begin.clone(),
msg: format!(
"Generator Error: Token {:?} is not implemented yet!",
statement.root.root.token
),
}),
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Ast { statements })
}

#[cfg(test)]
mod specs {
use super::*;
use crate::compiler::token::{Location, Token, TokenPayload};

#[test]
fn milestone_1() {
let input = Ast {
statements: vec![Statement {
root: Node {
root: Token {
token: TokenPayload::Pipe,
begin: Location {
line: 3,
offset: 31,
},
end: Location {
line: 3,
offset: 32,
},
},
args: vec![
Token {
token: TokenPayload::Int32(42),
begin: Location {
line: 3,
offset: 28,
},
end: Location {
line: 3,
offset: 30,
},
},
Token {
token: TokenPayload::Ident("stdout".to_owned()),
begin: Location {
line: 3,
offset: 33,
},
end: Location {
line: 3,
offset: 39,
},
},
],
},
}],
};

let actual = generate(input);
assert!(actual.is_ok());
let actual = actual.unwrap();
let expected = Ast {
statements: vec![Statement {
root: Node {
root: Token {
token: TokenPayload::Ident("stdout".to_owned()),
begin: Location {
line: 3,
offset: 33,
},
end: Location {
line: 3,
offset: 39,
},
},
args: vec![Token {
token: TokenPayload::Int32(42),
begin: Location {
line: 3,
offset: 28,
},
end: Location {
line: 3,
offset: 30,
},
}],
},
}],
};
assert_eq!(actual, expected);
}
}
Loading

0 comments on commit 7e07f93

Please sign in to comment.