Skip to content

Commit

Permalink
Merge branch 'ast-semantic-analysis' of github.com:pile-lang/rusted-p…
Browse files Browse the repository at this point in the history
…ile into ast-semantic-analysis

Signed-off-by: Felipi Lima Matozinho <[email protected]>
  • Loading branch information
Matozinho committed Jul 20, 2023
2 parents 20c4c09 + f9e63ef commit bad4768
Show file tree
Hide file tree
Showing 16 changed files with 297 additions and 81 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ anyhow = "1.0.69"
singleton-manager = "0.1.4"
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3.3"
clap = { version = "4.3.16", features = ["derive", "color"] }

# inkwell = { version = "0.2", features = ["llvm15-0"] }
# llvm-sys-150 = { package = "llvm-sys", version = "150.1.0", features = ["prefer-dynamic"] }
inkwell = { version = "0.2", features = ["llvm15-0"] }
llvm-sys-150 = { package = "llvm-sys", version = "150.1.0", features = ["prefer-dynamic"] }
lazy_static = "1.4"
once_cell = "1.17"
14 changes: 11 additions & 3 deletions assets/lang/conditional_and_branching.pile
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
\ vim: ft=forth

1 2 < dump
2 1 < dump
2.1 1 > dump
\ 1 2 < dump
\ 2 1 < dump
\ 2.1 1 > dump

2 1 < if
1 dump
else
2 dump
end

3 dump
Binary file added output.bin
Binary file not shown.
64 changes: 64 additions & 0 deletions src/cli/compile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use clap::{Args, ValueEnum};
use miette::Result as MietteResult;

use crate::{
codegen::{self, CodeGeneratorTarget},
grammar, lexer,
parser::SLR::SLR,
semantic::SemanticAnalyzer,
};

use super::PileCompiler;

#[allow(clippy::upper_case_acronyms)]
#[derive(ValueEnum, Clone)]
pub enum Codegen {
VM,
LLVM,
}

#[derive(Args)]
pub struct Compile {
#[arg(required = true, short, long)]
pub filename: String,

#[arg(short, long, default_value = "vm")]
pub codegen: Codegen,

#[arg(short, long, default_value = "output")]
pub output: String,
}

impl PileCompiler {
pub fn compile(
Compile {
filename,
codegen,
output,
}: &Compile,
) -> MietteResult<(), Box<dyn std::error::Error>> {
// Lexer
let lang_contents = std::fs::read_to_string(filename)?;
let tokens = lexer::generate::compute_tokens(&lang_contents)?;

// Parser
let glc_contents = std::fs::read_to_string("assets/glc/lang.glc")?;
let mut glc = grammar::parser::parse(&glc_contents)?;

glc.compute_follow_set().expand();

let abstract_syntax_tree = SLR::new(glc)
.parse(tokens, &lang_contents)?
.ok_or("Failed to parse")?;

SemanticAnalyzer::new(lang_contents).analyze(&abstract_syntax_tree)?;

match codegen {
Codegen::VM => codegen::code_generator(CodeGeneratorTarget::VirtualMachine),
Codegen::LLVM => codegen::code_generator(CodeGeneratorTarget::LLVM),
}
.generate(abstract_syntax_tree, output.clone())?;

Ok(())
}
}
20 changes: 20 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use clap::{Parser, Subcommand};

pub mod compile;
pub mod run;

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
Compile(compile::Compile),
Run(run::Run),
}

pub struct PileCompiler;
20 changes: 20 additions & 0 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use clap::Args;

use crate::interpreter::vm;
use miette::Result as MietteResult;

use super::PileCompiler;

#[derive(Args)]
pub struct Run {
#[arg(required = true, short, long)]
pub filename: String,
}

impl PileCompiler {
pub fn run(Run { filename }: &Run) -> MietteResult<(), Box<dyn std::error::Error>> {
vm::VMInterpreter::run(filename)?;

Ok(())
}
}
2 changes: 1 addition & 1 deletion src/codegen/llvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub mod globals;
pub struct LLVMCodeGenerator;

impl CodeGenerator for LLVMCodeGenerator {
fn generate(&mut self, ast: AstNode) -> anyhow::Result<()> {
fn generate(&mut self, ast: AstNode, _filename: String) -> anyhow::Result<()> {
// This trick is to ensure that stack is dropped before context
let stack;
{
Expand Down
8 changes: 4 additions & 4 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
use crate::parser::parse::AstNode;

pub trait CodeGenerator {
fn generate(&mut self, ast: AstNode) -> anyhow::Result<()>;
fn generate(&mut self, ast: AstNode, filename: String) -> anyhow::Result<()>;
}

pub enum CodeGeneratorTarget {
// LLVM,
LLVM,
Wasm,
VirtualMachine,
}

// pub mod llvm;
pub mod llvm;
pub mod vm;
pub mod wasm;

// Choose the code generator based on the target
pub fn code_generator(target: CodeGeneratorTarget) -> Box<dyn CodeGenerator> {
match target {
// CodeGeneratorTarget::LLVM => Box::<llvm::LLVMCodeGenerator>::default(),
CodeGeneratorTarget::LLVM => Box::<llvm::LLVMCodeGenerator>::default(),
CodeGeneratorTarget::Wasm => Box::<wasm::WasmCodeGenerator>::default(),
CodeGeneratorTarget::VirtualMachine => Box::<vm::VMCodeGenerator>::default(),
}
Expand Down
97 changes: 80 additions & 17 deletions src/codegen/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,54 @@ pub enum ByteCode {
Gt,
Leq,
Geq,

// Branching
JumpIfNotTrue(usize),
Jump(usize),

// Ignore
Ignore,
}

pub struct VMCodeGenerator;
pub struct VMCodeGenerator {
branching_blocks: Vec<usize>,
instructions_count: usize,
bytecode: Vec<ByteCode>,
}

impl VMCodeGenerator {
pub fn new() -> Self {
Self {}
Self {
branching_blocks: vec![],
instructions_count: 0,
bytecode: vec![],
}
}

pub fn generate_two_children_code(
&mut self,
left: &AstNode,
right: &AstNode,
opcode: ByteCode,
) -> anyhow::Result<Vec<ByteCode>> {
let mut bytecode = VMCodeGenerator::generate_byte_code(left)?;
bytecode.append(&mut VMCodeGenerator::generate_byte_code(right)?);
let mut bytecode = self.generate_byte_code(left)?;
bytecode.append(&mut self.generate_byte_code(right)?);
bytecode.push(opcode);
self.instructions_count += 2;
Ok(bytecode)
}

pub fn generate_byte_code(ast: &AstNode) -> anyhow::Result<Vec<ByteCode>> {
pub fn generate_byte_code(&mut self, ast: &AstNode) -> anyhow::Result<Vec<ByteCode>> {
match ast.token.clone() {
Token::Program => {
let mut bytecode = vec![];

for child in ast.children.iter() {
bytecode.append(&mut VMCodeGenerator::generate_byte_code(child)?);
self.instructions_count += 1;
let mut bytecode = self.generate_byte_code(child)?;

self.bytecode.append(&mut bytecode);
}

Ok(bytecode)
Ok(self.bytecode.clone())
}
Token::Integer(value) => Ok(vec![ByteCode::PushInt(value)]),
Token::Float(value) => Ok(vec![ByteCode::PushFloat(value)]),
Expand Down Expand Up @@ -90,7 +108,7 @@ impl VMCodeGenerator {
.collect::<HashMap<_, _>>()
.get(&operator)
{
Self::generate_two_children_code(&ast.children[0], &ast.children[1], opcode.clone())
self.generate_two_children_code(&ast.children[0], &ast.children[1], opcode.clone())
} else {
Err(anyhow::anyhow!(
"Currently unsupported token: {:?}",
Expand All @@ -114,28 +132,72 @@ impl VMCodeGenerator {
.collect::<HashMap<_, _>>()
.get(&operator)
{
Self::generate_two_children_code(&ast.children[0], &ast.children[1], opcode.clone())
self.generate_two_children_code(&ast.children[0], &ast.children[1], opcode.clone())
} else {
Err(anyhow::anyhow!(
"Currently unsupported token: {:?}",
ast.token
))
}
}
Token::If => {
let mut bytecode = vec![];
let mut condition = self.generate_byte_code(&ast.children[0])?;

self.branching_blocks.push(self.instructions_count);
bytecode.append(&mut condition);
bytecode.push(ByteCode::JumpIfNotTrue(usize::MAX)); // Placeholder position for now
self.instructions_count += 1;

Ok(bytecode)
}
Token::Else => {
if let Some(if_intruction_location) = self.branching_blocks.pop() {
if let ByteCode::JumpIfNotTrue(_) = &mut self.bytecode[if_intruction_location] {
self.bytecode[if_intruction_location] =
ByteCode::JumpIfNotTrue(self.instructions_count);
}
} else {
return Err(anyhow::anyhow!("Mismatched 'else'"));
}
self.branching_blocks.push(self.instructions_count - 1);

Ok(vec![ByteCode::Jump(usize::MAX)])
}
Token::End => {
if let Some(branch_intruction_location) = self.branching_blocks.pop() {
match &mut self.bytecode[branch_intruction_location] {
ByteCode::JumpIfNotTrue(_) => {
self.bytecode[branch_intruction_location] =
ByteCode::JumpIfNotTrue(self.instructions_count);
}
ByteCode::Jump(_) => {
self.bytecode[branch_intruction_location] = ByteCode::Jump(self.instructions_count);
}
_ => {
return Err(anyhow::anyhow!("Mismatched 'end' (1)"));
}
}

Ok(vec![ByteCode::Ignore])
} else {
Err(anyhow::anyhow!("Mismatched 'end' (2)"))
}
}
_ => Err(anyhow::anyhow!(
"Currently unsupported token: {:?}",
ast.token
)),
}
}

pub fn encode_byte_code(bytecode: Vec<ByteCode>) -> anyhow::Result<()> {
pub fn encode_byte_code(bytecode: Vec<ByteCode>, filename: String) -> anyhow::Result<()> {
let encoded: Vec<u8> = bincode::serialize(&bytecode).unwrap();

use std::io::Write;

let mut file =
File::create("bytecode.bin").map_err(|e| anyhow::anyhow!("Error creating file: {}", e))?;
let mut file = File::create(format!("{filename}.bin"))
.map_err(|e| anyhow::anyhow!("Error creating file: {}", e))?;
file
.write_all(&encoded)
.map_err(|e| anyhow::anyhow!("Error writing to file: {}", e))?;
Expand All @@ -151,10 +213,11 @@ impl Default for VMCodeGenerator {
}

impl CodeGenerator for VMCodeGenerator {
fn generate(&mut self, ast: AstNode) -> anyhow::Result<()> {
let bytecode = VMCodeGenerator::generate_byte_code(&ast)?;
fn generate(&mut self, ast: AstNode, filename: String) -> anyhow::Result<()> {
let mut generator = VMCodeGenerator::new();
let bytecode = generator.generate_byte_code(&ast)?;
println!("{:?}", bytecode);
VMCodeGenerator::encode_byte_code(bytecode)?;
VMCodeGenerator::encode_byte_code(bytecode, filename)?;

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl Default for WasmCodeGenerator {
}

impl CodeGenerator for WasmCodeGenerator {
fn generate(&mut self, _ast: AstNode) -> anyhow::Result<()> {
fn generate(&mut self, _ast: AstNode, _filename: String) -> anyhow::Result<()> {
Ok(())
}
}
Loading

0 comments on commit bad4768

Please sign in to comment.