Skip to content

Commit

Permalink
end-to-end testing for function calls, definitions, let-exprs, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
dhconnelly committed Jan 21, 2024
1 parent f8ca9c8 commit 55657c6
Show file tree
Hide file tree
Showing 13 changed files with 77 additions and 29 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "june-lang"
version = "0.1.0"
edition = "2021"
default-run = "main"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
7 changes: 7 additions & 0 deletions examples/calls.june
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn foo(x: int, y: int) {
println(x + y);
}

fn main() {
foo(5, 7);
}
6 changes: 1 addition & 5 deletions examples/ints.june
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
fn foo(x: int, y: int) {
printi(x + y);
}

fn main() {
foo(5, 7);
println(5 + 7);
}
2 changes: 2 additions & 0 deletions examples/noop.june
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fn main() {
}
9 changes: 6 additions & 3 deletions src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,12 @@ impl Analyzer {
}
}

fn program(&mut self, Program { defs }: Program) -> Result<TypedProgram> {
fn program(&mut self, Program { defs, .. }: Program) -> Result<TypedProgram> {
let defs = self.try_map(defs, |a, def| a.def(def))?;
if defs.iter().any(|d| matches!(d, Def::FnDef(f) if &f.name == "main")) {
Ok(Program { defs })
if let Some(main_def) =
defs.iter().position(|d| matches!(d, Def::FnDef(f) if &f.name == "main"))
{
Ok(Program { main_def, defs })
} else {
Err(Error::NoMain)
}
Expand Down Expand Up @@ -238,6 +240,7 @@ mod test {
";
let program = parse(input).program().unwrap();
let expected = Program {
main_def: 1,
defs: vec![
Def::FnDef(Func {
name: String::from("greet"),
Expand Down
4 changes: 4 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub trait ASTSpec {
type FuncCargo: fmt::Debug + PartialEq + Eq + Clone;
type LetCargo: fmt::Debug + PartialEq + Eq + Clone;
type BinaryCargo: fmt::Debug + PartialEq + Eq + Clone;
type ProgramCargo: fmt::Debug + PartialEq + Eq + Clone;
}

#[derive(Debug, PartialEq, Eq, Clone)]
Expand All @@ -40,6 +41,7 @@ impl ASTSpec for UntypedAST {
type FuncCargo = ();
type LetCargo = ();
type BinaryCargo = ();
type ProgramCargo = ();
}

#[derive(Debug, PartialEq, Eq, Clone)]
Expand All @@ -53,6 +55,7 @@ impl ASTSpec for TypedAST {
type FuncCargo = FnDef;
type LetCargo = LocalBinding;
type BinaryCargo = Type;
type ProgramCargo = usize;
}

// =============================================================================
Expand Down Expand Up @@ -336,6 +339,7 @@ pub type TypedDef = Def<TypedAST>;
#[derive(Debug, PartialEq, Clone)]
pub struct Program<AST: ASTSpec = UntypedAST> {
pub defs: Vec<Def<AST>>,
pub main_def: AST::ProgramCargo,
}

pub type TypedProgram = Program<TypedAST>;
15 changes: 15 additions & 0 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::path::Path;

fn main() {
for arg in std::env::args().skip(1) {
let path = Path::new(&arg);
if let Err(err) = june_lang::driver::compile_file(&path) {
eprintln!("junec: {}", err);
std::process::exit(1);
}
if let Err(err) = june_lang::driver::execute(&path.with_extension("wasm")) {
eprintln!("junec: {}", err);
std::process::exit(1);
}
}
}
20 changes: 17 additions & 3 deletions src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ use crate::symbol_table::*;
use crate::types::*;
use crate::wasm::*;

fn install_function(name: impl ToString, typ: FnType, ctx: &mut SymbolTable) {
ctx.def_global(name, Type::Fn(typ.clone()));
ctx.def_fn(typ.params, typ.ret.map(|ret| *ret));
}

pub fn install_symbols(ctx: &mut SymbolTable) {
// TODO: generic println
ctx.def_global(
install_function(
"println",
Type::Fn(FnType { index: 0, params: vec![Type::Str], ret: None }),
FnType { index: 0, params: vec![Type::Int], ret: None },
ctx,
);
}

Expand All @@ -18,7 +24,15 @@ pub fn install_imports(module: &mut Module) {
});
module.imports.0.push(Import {
module: String::from("june"),
name: String::from("print"),
name: String::from("println"),
import: ImportedValue::Func(0),
});
}

pub fn make_imports<T>(
mut store: impl wasmtime::AsContextMut<Data = T>,
) -> Vec<wasmtime::Extern> {
// TODO: make |print| generic
let print = wasmtime::Func::wrap(&mut store, |x: i64| println!("{}", x));
vec![wasmtime::Extern::Func(print)]
}
6 changes: 2 additions & 4 deletions src/driver.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::analyzer;
use crate::builtins;
use crate::emitter;
use crate::imports;
use crate::parser;
use crate::scanner;
use crate::translator;
Expand Down Expand Up @@ -45,10 +45,8 @@ fn make_output_path(p: &path::Path) -> Result<path::PathBuf> {
pub fn compile<W: io::Write, R: io::Read>(mut w: W, r: R) -> Result<()> {
let toks = scanner::scan(io::BufReader::new(r));
let ast = parser::parse(toks)?;
// TODO: must inject the imports to the analyzer
let typed_ast = analyzer::analyze(ast)?;
let wasm = translator::translate(typed_ast)?;
println!("{:#?}", wasm);
Ok(emitter::emit(&mut w, wasm)?)
}

Expand All @@ -67,7 +65,7 @@ pub fn execute<P: AsRef<path::Path>>(input_path: P) -> Result<()> {
let engine = wasmtime::Engine::default();
let module = wasmtime::Module::from_file(&engine, input_path)?;
let mut store = wasmtime::Store::new(&engine, ());
let imports = imports::make_imports(&mut store);
let imports = builtins::make_imports(&mut store);
wasmtime::Instance::new(&mut store, &module, &imports)?;
Ok(())
}
9 changes: 0 additions & 9 deletions src/imports.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pub mod ast;
pub mod builtins;
pub mod driver;
pub mod emitter;
pub mod imports;
pub mod parser;
pub mod scanner;
pub mod symbol_table;
Expand Down
5 changes: 3 additions & 2 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl<R: io::BufRead> Parser<R> {
while !self.eof() {
defs.push(self.def()?);
}
Ok(Program { defs })
Ok(Program { main_def: (), defs })
}
}

Expand All @@ -208,7 +208,7 @@ mod test {
";
let mut p = parse(input);
let ast = p.program().unwrap();
assert_eq!(Program { defs: Vec::new() }, ast);
assert_eq!(Program { main_def: (), defs: Vec::new() }, ast);
}

#[test]
Expand Down Expand Up @@ -371,6 +371,7 @@ mod test {

let ast = parse(input).program().unwrap();
let expected = Program {
main_def: (),
defs: vec![
Def::FnDef(Func::untyped(
"foo",
Expand Down
21 changes: 19 additions & 2 deletions src/translator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::ast;
use crate::ast::TypedDef;
use crate::builtins;
use crate::types;
use crate::types::Typed;
use crate::wasm;
use std::result;
use thiserror::Error;
Expand All @@ -22,6 +24,15 @@ impl Default for Translator {
}
}

fn find_main(defs: &[TypedDef]) -> Option<usize> {
defs.iter().find_map(|def| match def {
ast::TypedDef::FnDef(func) if func.name == "main" => {
Some(func.resolved_type.typ.index)
}
_ => None,
})
}

impl Translator {
fn new() -> Self {
Self { module: wasm::Module::default() }
Expand Down Expand Up @@ -122,8 +133,10 @@ impl Translator {
match stmt {
ast::Stmt::Block(_) => todo!(),
ast::Stmt::Expr(expr) => {
if expr.typ() != types::Type::Void {
body.push(wasm::Instr::Drop);
}
self.expr(expr, body)?;
body.push(wasm::Instr::Drop);
Ok(())
}
ast::Stmt::Let(lett) => self.let_stmt(lett, body),
Expand All @@ -139,6 +152,7 @@ impl Translator {
for stmt in func.body.0 {
self.stmt(stmt, &mut body)?;
}
body.push(wasm::Instr::End);
// TODO: store the types of |locals|
self.module.code.0.push(wasm::Code {
locals: vec![wasm::ValType::NumType(wasm::NumType::I64); locals],
Expand All @@ -154,6 +168,9 @@ impl Translator {
}

fn program(&mut self, program: ast::TypedProgram) -> Result<()> {
// TODO: encode this in the ast
self.module.start.0 =
find_main(&program.defs).expect("main not found") as u32;
for def in program.defs {
self.def(def)?;
}
Expand Down Expand Up @@ -376,7 +393,7 @@ mod test {
wasm::Instr::SetLocal(2),
wasm::Instr::GetLocal(2),
wasm::Instr::Call(0),
wasm::Instr::Drop,
wasm::Instr::End,
]
},
&translator.module.code.0[0]
Expand Down

0 comments on commit 55657c6

Please sign in to comment.