Cleanup
This commit is contained in:
parent
dbb51fd1d0
commit
f7e4bfa8cf
12 changed files with 55 additions and 409 deletions
|
@ -3,6 +3,14 @@ name = "e0"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "e0c"
|
||||||
|
path = "./bin/e0c.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "e0pkg"
|
||||||
|
path = "./bin/e0pkg.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.56"
|
||||||
clap = { version = "3.1.8", features = ["derive"] }
|
clap = { version = "3.1.8", features = ["derive"] }
|
||||||
|
|
|
@ -1,23 +1,12 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate lalrpop_util;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate anyhow;
|
|
||||||
|
|
||||||
lalrpop_mod!(parser);
|
|
||||||
|
|
||||||
mod ast;
|
|
||||||
pub mod codegen;
|
|
||||||
mod utils;
|
|
||||||
|
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use e0::codegen::CodegenBackend;
|
||||||
use crate::codegen::{llvm_ir::LlvmIrCodegen, CodegenBackend};
|
use e0::codegen::llvm_ir::LlvmIrCodegen;
|
||||||
use crate::parser::ProgramParser;
|
use e0::parser::ProgramParser;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
|
@ -40,7 +29,7 @@ fn main() -> Result<()> {
|
||||||
let parser = ProgramParser::new();
|
let parser = ProgramParser::new();
|
||||||
let ast = parser.parse(&contents).unwrap();
|
let ast = parser.parse(&contents).unwrap();
|
||||||
|
|
||||||
let typed_ast = ast::typed::convert(ast)?;
|
let typed_ast = e0::ast::typed::convert(ast)?;
|
||||||
|
|
||||||
if let Some(path) = opts.emit_ast {
|
if let Some(path) = opts.emit_ast {
|
||||||
let mut file = File::create(&path)?;
|
let mut file = File::create(&path)?;
|
18
bin/e0pkg.rs
Normal file
18
bin/e0pkg.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
struct Opt {
|
||||||
|
#[clap(subcommand)]
|
||||||
|
command: Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Subcommand)]
|
||||||
|
enum Command {
|
||||||
|
/// Compile an e0 package
|
||||||
|
#[clap(name = "build", alias = "b")]
|
||||||
|
Build,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let opts = Opt::parse();
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{ fenix, makeRustPlatform, lib, nix-gitignore, libffi, libgcc }:
|
{ toolchain, makeRustPlatform, lib, nix-gitignore, libffi, libgcc }:
|
||||||
|
|
||||||
let rustPlatform = makeRustPlatform { inherit (fenix.minimal) cargo rustc; };
|
let rustPlatform = makeRustPlatform { inherit (toolchain) cargo rustc; };
|
||||||
|
|
||||||
in rustPlatform.buildRustPackage {
|
in rustPlatform.buildRustPackage {
|
||||||
name = "e0";
|
name = "e0";
|
||||||
|
|
|
@ -12,14 +12,17 @@
|
||||||
inherit system;
|
inherit system;
|
||||||
overlays = [ fenix.overlay ];
|
overlays = [ fenix.overlay ];
|
||||||
};
|
};
|
||||||
myPkgs = rec { e0 = pkgs.callPackage ./. { }; };
|
toolchain = pkgs.fenix.complete;
|
||||||
|
myPkgs = rec { e0 = pkgs.callPackage ./. { inherit toolchain; }; };
|
||||||
|
|
||||||
in rec {
|
in rec {
|
||||||
devShell = pkgs.mkShell {
|
devShell = pkgs.mkShell {
|
||||||
packages = with pkgs;
|
packages = with pkgs;
|
||||||
with pkgs.llvmPackages_12; [
|
with pkgs.llvmPackages_12; [
|
||||||
|
cargo-edit
|
||||||
cargo-watch
|
cargo-watch
|
||||||
clangUseLLVM
|
clangUseLLVM
|
||||||
|
(toolchain.withComponents [ "clippy" "rustc" "rust-src" ])
|
||||||
];
|
];
|
||||||
inputsFrom = with myPkgs; [ e0 ];
|
inputsFrom = with myPkgs; [ e0 ];
|
||||||
CARGO_UNSTABLE_SPARSE_REGISTRY = "true";
|
CARGO_UNSTABLE_SPARSE_REGISTRY = "true";
|
||||||
|
|
25
scripts/e0c
25
scripts/e0c
|
@ -1,25 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
SOURCE=$?
|
|
||||||
BITCODE=$(mktemp -d)
|
|
||||||
OUTPUT=./a.out
|
|
||||||
|
|
||||||
usage() { echo "$0 options:" && grep " .)\ #" $0; exit 0; }
|
|
||||||
|
|
||||||
[ $# -eq 0 ] && usage
|
|
||||||
while getopts ":hs:p:" arg; do
|
|
||||||
case $arg in
|
|
||||||
o) # Binary output
|
|
||||||
OUTPUT=${OPTARG}
|
|
||||||
;;
|
|
||||||
h | *) # Display help.
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
cargo run -- -o $BITCODE $SOURCE
|
|
||||||
clang -o $OUTPUT $BITCODE
|
|
|
@ -1,12 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
use cranelift_codegen::Context as ClifContext;
|
|
||||||
|
|
||||||
use super::{Decl, Type};
|
|
||||||
|
|
||||||
pub fn convert(
|
|
||||||
file_name: String,
|
|
||||||
context: &Context,
|
|
||||||
program: Vec<Decl<Type>>,
|
|
||||||
) -> Result<ClifContext> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
349
src/ast/llvm.rs
349
src/ast/llvm.rs
|
@ -1,349 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use inkwell::{
|
|
||||||
builder::Builder,
|
|
||||||
context::Context,
|
|
||||||
module::Module,
|
|
||||||
types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType},
|
|
||||||
values::{BasicValue, BasicValueEnum, FunctionValue, IntValue},
|
|
||||||
IntPredicate,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::utils::{
|
|
||||||
convert_type_to_metadata_type, convert_value_to_metadata_value,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Decl, ElseClause, Expr, ExprKind, IfElse, Op, Stmt, Type};
|
|
||||||
|
|
||||||
impl Expr<Type> {
|
|
||||||
fn into_llvm<'ctx>(
|
|
||||||
&self,
|
|
||||||
context: &'ctx Context,
|
|
||||||
builder: &'ctx Builder,
|
|
||||||
env: &Env<'_, 'ctx>,
|
|
||||||
) -> Result<BasicValueEnum<'ctx>> {
|
|
||||||
let int_ty = context.i64_type();
|
|
||||||
let bool_ty = context.bool_type();
|
|
||||||
|
|
||||||
match &self.kind {
|
|
||||||
ExprKind::Var(name) => Ok(match env.lookup(&name) {
|
|
||||||
Some(v) => match v.kind {
|
|
||||||
EnvValueKind::Local(l) => l,
|
|
||||||
EnvValueKind::Func(f) => {
|
|
||||||
let ptr = f.as_global_value().as_pointer_value();
|
|
||||||
builder.build_load(ptr, "")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => bail!("Unbound name {name:?}"),
|
|
||||||
}),
|
|
||||||
|
|
||||||
ExprKind::Int(n) => {
|
|
||||||
Ok(BasicValueEnum::IntValue(int_ty.const_int(*n as u64, false)))
|
|
||||||
}
|
|
||||||
|
|
||||||
ExprKind::BinOp(left, op, right) => {
|
|
||||||
if !op.check_types(&left.ty, &right.ty) {
|
|
||||||
// TODO: detailed error message
|
|
||||||
bail!("Invalid types on operation.");
|
|
||||||
}
|
|
||||||
|
|
||||||
match op {
|
|
||||||
Op::Plus => {
|
|
||||||
let left_val =
|
|
||||||
left.into_llvm(context, builder, env)?.into_int_value();
|
|
||||||
let right_val =
|
|
||||||
right.into_llvm(context, builder, env)?.into_int_value();
|
|
||||||
let result: IntValue =
|
|
||||||
builder.build_int_add(left_val, right_val, "");
|
|
||||||
Ok(BasicValueEnum::IntValue(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
Op::LessThan => {
|
|
||||||
let left_val =
|
|
||||||
left.into_llvm(context, builder, env)?.into_int_value();
|
|
||||||
let right_val =
|
|
||||||
right.into_llvm(context, builder, env)?.into_int_value();
|
|
||||||
let result: IntValue = builder.build_int_compare(
|
|
||||||
IntPredicate::SLT,
|
|
||||||
left_val,
|
|
||||||
right_val,
|
|
||||||
"",
|
|
||||||
);
|
|
||||||
Ok(BasicValueEnum::IntValue(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
Op::GreaterThan => {
|
|
||||||
let left_val =
|
|
||||||
left.into_llvm(context, builder, env)?.into_int_value();
|
|
||||||
let right_val =
|
|
||||||
right.into_llvm(context, builder, env)?.into_int_value();
|
|
||||||
let result: IntValue = builder.build_int_compare(
|
|
||||||
IntPredicate::SGT,
|
|
||||||
left_val,
|
|
||||||
right_val,
|
|
||||||
"",
|
|
||||||
);
|
|
||||||
Ok(BasicValueEnum::IntValue(result))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExprKind::Call(func, args) => match env.lookup(func) {
|
|
||||||
Some(EnvValue {
|
|
||||||
ty: func_ty,
|
|
||||||
kind: EnvValueKind::Func(func_ptr),
|
|
||||||
}) => {
|
|
||||||
let args_llvm = args
|
|
||||||
.iter()
|
|
||||||
.map(|arg| {
|
|
||||||
arg
|
|
||||||
.into_llvm(context, builder, env)
|
|
||||||
.map(convert_value_to_metadata_value)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
|
|
||||||
let call_site =
|
|
||||||
builder.build_call(*func_ptr, args_llvm.as_slice(), "");
|
|
||||||
|
|
||||||
let value = call_site.try_as_basic_value().unwrap_left();
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => bail!("No function with name {func:?}"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Type {
|
|
||||||
pub fn into_llvm_basic_type<'ctx>(
|
|
||||||
&self,
|
|
||||||
context: &'ctx Context,
|
|
||||||
) -> BasicTypeEnum<'ctx> {
|
|
||||||
match self {
|
|
||||||
Type::Int => BasicTypeEnum::IntType(context.i64_type()),
|
|
||||||
Type::Bool => BasicTypeEnum::IntType(context.bool_type()),
|
|
||||||
_ => panic!("Tried to convert a function type into a LLVM basic type"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fn_type_basic<'ctx>(
|
|
||||||
return_ty: BasicTypeEnum<'ctx>,
|
|
||||||
args: &[BasicMetadataTypeEnum<'ctx>],
|
|
||||||
is_var_args: bool,
|
|
||||||
) -> FunctionType<'ctx> {
|
|
||||||
match return_ty {
|
|
||||||
BasicTypeEnum::ArrayType(ty) => ty.fn_type(args, is_var_args),
|
|
||||||
BasicTypeEnum::FloatType(ty) => ty.fn_type(args, is_var_args),
|
|
||||||
BasicTypeEnum::IntType(ty) => ty.fn_type(args, is_var_args),
|
|
||||||
BasicTypeEnum::PointerType(ty) => ty.fn_type(args, is_var_args),
|
|
||||||
BasicTypeEnum::StructType(ty) => ty.fn_type(args, is_var_args),
|
|
||||||
BasicTypeEnum::VectorType(ty) => ty.fn_type(args, is_var_args),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum EnvValueKind<'ctx> {
|
|
||||||
Func(FunctionValue<'ctx>),
|
|
||||||
Local(BasicValueEnum<'ctx>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct EnvValue<'a, 'ctx> {
|
|
||||||
ty: &'a Type,
|
|
||||||
kind: EnvValueKind<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct Env<'a, 'ctx> {
|
|
||||||
parent: Option<&'a Env<'a, 'ctx>>,
|
|
||||||
local_type_map: HashMap<String, EnvValue<'a, 'ctx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'ctx> Env<'a, 'ctx> {
|
|
||||||
pub fn lookup(&self, name: impl AsRef<str>) -> Option<&EnvValue<'a, 'ctx>> {
|
|
||||||
match self.local_type_map.get(name.as_ref()) {
|
|
||||||
Some(v) => Some(v),
|
|
||||||
None => match &self.parent {
|
|
||||||
Some(p) => p.lookup(name),
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_if_else(
|
|
||||||
context: &Context,
|
|
||||||
module: &Module,
|
|
||||||
builder: &Builder,
|
|
||||||
function: &FunctionValue,
|
|
||||||
if_else: &IfElse<Type>,
|
|
||||||
env: &Env,
|
|
||||||
) -> Result<()> {
|
|
||||||
let success_branch = context.append_basic_block(*function, "success");
|
|
||||||
let fail_branch = context.append_basic_block(*function, "fail");
|
|
||||||
let exit_block = context.append_basic_block(*function, "exit");
|
|
||||||
|
|
||||||
let cond = if_else
|
|
||||||
.cond
|
|
||||||
.into_llvm(context, builder, env)?
|
|
||||||
.into_int_value();
|
|
||||||
builder.build_conditional_branch(cond, success_branch, fail_branch);
|
|
||||||
|
|
||||||
// build success branch
|
|
||||||
builder.position_at_end(success_branch);
|
|
||||||
convert_stmts(context, module, function, builder, env, &if_else.body)?;
|
|
||||||
// builder.build_unconditional_branch(exit_branch);
|
|
||||||
|
|
||||||
// build fail branch
|
|
||||||
builder.position_at_end(fail_branch);
|
|
||||||
match &if_else.else_clause {
|
|
||||||
Some(ElseClause::If(if_else2)) => {
|
|
||||||
convert_if_else(context, module, builder, function, if_else2, env)?;
|
|
||||||
}
|
|
||||||
Some(ElseClause::Body(body)) => {
|
|
||||||
convert_stmts(context, module, function, builder, env, body)?;
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
builder.position_at_end(fail_branch);
|
|
||||||
builder.build_unconditional_branch(exit_block);
|
|
||||||
|
|
||||||
builder.position_at_end(exit_block);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_stmts(
|
|
||||||
context: &Context,
|
|
||||||
module: &Module,
|
|
||||||
function: &FunctionValue,
|
|
||||||
builder: &Builder,
|
|
||||||
parent_env: &Env,
|
|
||||||
stmts: impl AsRef<[Stmt<Type>]>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let stmts = stmts.as_ref();
|
|
||||||
let mut scope_env = Env {
|
|
||||||
parent: Some(parent_env),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
for stmt in stmts.iter() {
|
|
||||||
match stmt {
|
|
||||||
Stmt::Let(name, _, expr) => {
|
|
||||||
let ty = &expr.ty;
|
|
||||||
let llvm_ty = ty.into_llvm_basic_type(context);
|
|
||||||
// Empty variable name gets LLVM to generate a unique name
|
|
||||||
let alloca = builder.build_alloca(llvm_ty, "");
|
|
||||||
|
|
||||||
let expr_val = expr.into_llvm(context, builder, &scope_env)?;
|
|
||||||
builder.build_store(alloca, expr_val);
|
|
||||||
|
|
||||||
scope_env.local_type_map.insert(
|
|
||||||
name.clone(),
|
|
||||||
EnvValue {
|
|
||||||
ty,
|
|
||||||
kind: EnvValueKind::Local(alloca.as_basic_value_enum()),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Stmt::Return(ret_val) => {
|
|
||||||
if let Some(ret_val) = ret_val {
|
|
||||||
let value = ret_val.into_llvm(context, builder, &scope_env)?;
|
|
||||||
builder.build_return(Some(&value));
|
|
||||||
} else {
|
|
||||||
builder.build_return(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Stmt::IfElse(if_else) => {
|
|
||||||
convert_if_else(
|
|
||||||
context, module, builder, function, if_else, &scope_env,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn convert(
|
|
||||||
file_name: String,
|
|
||||||
context: &Context,
|
|
||||||
program: Vec<Decl<Type>>,
|
|
||||||
) -> Result<Module> {
|
|
||||||
let module = context.create_module(&file_name);
|
|
||||||
let builder = context.create_builder();
|
|
||||||
|
|
||||||
let mut env = Env::default();
|
|
||||||
for func in program.iter().filter_map(|decl| match decl {
|
|
||||||
Decl::Func(v) => Some(v),
|
|
||||||
_ => None,
|
|
||||||
}) {
|
|
||||||
let return_ty = func.return_ty.into_llvm_basic_type(context);
|
|
||||||
let args_ty = func
|
|
||||||
.args
|
|
||||||
.iter()
|
|
||||||
.map(|arg| {
|
|
||||||
convert_type_to_metadata_type(arg.ty.into_llvm_basic_type(context))
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let llvm_func_ty = fn_type_basic(return_ty, &args_ty, false);
|
|
||||||
let llvm_func = module.add_function(&func.name, llvm_func_ty, None);
|
|
||||||
|
|
||||||
env.local_type_map.insert(
|
|
||||||
func.name.clone(),
|
|
||||||
EnvValue {
|
|
||||||
ty: &func.ty,
|
|
||||||
kind: EnvValueKind::Func(llvm_func),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for func in program.iter().filter_map(|decl| match decl {
|
|
||||||
Decl::Func(v) => Some(v),
|
|
||||||
_ => None,
|
|
||||||
}) {
|
|
||||||
let llvm_func = match env.local_type_map.get(&func.name) {
|
|
||||||
Some(EnvValue {
|
|
||||||
kind: EnvValueKind::Func(func),
|
|
||||||
..
|
|
||||||
}) => func.clone(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let entry_block = context.append_basic_block(llvm_func, "entry");
|
|
||||||
|
|
||||||
builder.position_at_end(entry_block);
|
|
||||||
|
|
||||||
let mut scoped_env = Env {
|
|
||||||
parent: Some(&env),
|
|
||||||
local_type_map: HashMap::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (arg, param) in func.args.iter().zip(llvm_func.get_params().into_iter())
|
|
||||||
{
|
|
||||||
scoped_env.local_type_map.insert(
|
|
||||||
arg.name.clone(),
|
|
||||||
EnvValue {
|
|
||||||
ty: &arg.ty,
|
|
||||||
kind: EnvValueKind::Local(param),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_stmts(
|
|
||||||
&context,
|
|
||||||
&module,
|
|
||||||
&llvm_func,
|
|
||||||
&builder,
|
|
||||||
&scoped_env,
|
|
||||||
&func.stmts,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(module)
|
|
||||||
}
|
|
|
@ -1,5 +1,3 @@
|
||||||
// pub mod llvm;
|
|
||||||
// pub mod cranelift;
|
|
||||||
pub mod typed;
|
pub mod typed;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -64,9 +62,11 @@ pub enum Op {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Op {
|
impl Op {
|
||||||
|
/// Check that the types match the current operation. If so, return the type
|
||||||
|
/// that is expected as a result. Otherwise, return None.
|
||||||
pub fn check_types(&self, left_ty: &Type, right_ty: &Type) -> Option<Type> {
|
pub fn check_types(&self, left_ty: &Type, right_ty: &Type) -> Option<Type> {
|
||||||
// TODO: since only binops work on integers right now, just check that the two sides are both
|
// TODO: since only binops work on integers right now, just check that the
|
||||||
// integers. this will have to change once && gets added.
|
// two sides are both integers. this will have to change once && gets added.
|
||||||
match (left_ty, right_ty) {
|
match (left_ty, right_ty) {
|
||||||
(Type::Int, Type::Int) => Some(Type::Int),
|
(Type::Int, Type::Int) => Some(Type::Int),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::io::Write;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::ast::{ElseClause, IfElse, Stmt, Type};
|
use crate::ast::{ElseClause, IfElse, Type};
|
||||||
|
|
||||||
use super::LlvmIrCodegen;
|
use super::LlvmIrCodegen;
|
||||||
|
|
||||||
|
|
10
src/lib.rs
Normal file
10
src/lib.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lalrpop_util;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate anyhow;
|
||||||
|
|
||||||
|
lalrpop_mod!(pub parser);
|
||||||
|
|
||||||
|
pub mod ast;
|
||||||
|
pub mod codegen;
|
||||||
|
mod utils;
|
4
std/e0pkg.yml
Normal file
4
std/e0pkg.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
name: std
|
||||||
|
version: 0.1.0
|
||||||
|
authors:
|
||||||
|
- Michael Zhang <mail@mzhang.io>
|
Loading…
Reference in a new issue