Starting work on IR.
This commit is contained in:
parent
8df46eec8d
commit
aefac57b9d
@ -1,5 +1,8 @@
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::ir_call::IrCall;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
@ -74,6 +77,19 @@ impl Call {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) -> IrExpression {
|
||||
let function_name = match self.callee() {
|
||||
Expression::Identifier(identifier) => identifier.name(),
|
||||
_ => panic!("Calling things other than identifiers not yet supported."),
|
||||
};
|
||||
let arguments = self
|
||||
.arguments()
|
||||
.iter()
|
||||
.map(|arg| arg.lower_to_ir(context))
|
||||
.collect();
|
||||
IrExpression::Call(IrCall::new(function_name, arguments))
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
&self.source_range
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::ast::function::Function;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::Ir;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
|
||||
pub struct CompilationUnit {
|
||||
@ -40,4 +41,12 @@ impl CompilationUnit {
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self) -> Vec<Ir> {
|
||||
let mut irs = vec![];
|
||||
for function in &self.functions {
|
||||
irs.append(&mut function.lower_to_ir());
|
||||
}
|
||||
irs
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::ast::identifier::Identifier;
|
||||
use crate::ast::integer_literal::IntegerLiteral;
|
||||
use crate::ast::string_literal::StringLiteral;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
@ -55,4 +57,13 @@ impl Expression {
|
||||
Expression::Identifier(identifier) => identifier.source_range(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) -> IrExpression {
|
||||
match self {
|
||||
Expression::Call(call) => call.lower_to_ir(context),
|
||||
Expression::IntegerLiteral(integer_literal) => integer_literal.lower_to_ir(context),
|
||||
Expression::String(string_literal) => string_literal.lower_to_ir(context),
|
||||
Expression::Identifier(identifier) => identifier.lower_to_ir(context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
dmc-lib/src/ast/expression_statement.rs
Normal file
38
dmc-lib/src/ast/expression_statement.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
|
||||
pub struct ExpressionStatement {
|
||||
expression: Box<Expression>,
|
||||
}
|
||||
|
||||
impl ExpressionStatement {
|
||||
pub fn new(expression: Expression) -> Self {
|
||||
Self {
|
||||
expression: expression.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expression(&self) -> &Expression {
|
||||
&self.expression
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
self.expression.gather_declared_names(symbol_table)
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
self.expression.check_name_usages(symbol_table)
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
self.expression.type_check(symbol_table)
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) {
|
||||
let ir_expression = self.expression.lower_to_ir(context);
|
||||
context.add_statement(IrStatement::Expression(ir_expression));
|
||||
}
|
||||
}
|
||||
15
dmc-lib/src/ast/fqn.rs
Normal file
15
dmc-lib/src/ast/fqn.rs
Normal file
@ -0,0 +1,15 @@
|
||||
pub struct Fqn {
|
||||
parts: Vec<String>,
|
||||
}
|
||||
|
||||
impl Fqn {
|
||||
pub fn new(parts: &[&str]) -> Self {
|
||||
Self {
|
||||
parts: parts.iter().map(|s| s.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parts(&self) -> &[String] {
|
||||
self.parts.as_slice()
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,9 @@
|
||||
use crate::ast::statement::Statement;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::Ir;
|
||||
use crate::ir::ir_constant::IrConstant;
|
||||
use crate::ir::ir_function::IrFunction;
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::FunctionSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
@ -75,4 +79,64 @@ impl Function {
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self) -> Vec<Ir> {
|
||||
let mut context = FunctionLoweringContext::new();
|
||||
for statement in &self.statements {
|
||||
statement.lower_to_ir(&mut context);
|
||||
}
|
||||
let mut irs = vec![];
|
||||
for constant in context.take_constants() {
|
||||
irs.push(Ir::Constant(constant));
|
||||
}
|
||||
let ir_function = IrFunction::new(context.take_statements());
|
||||
irs.push(Ir::Function(ir_function));
|
||||
irs
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionLoweringContext {
|
||||
temp_variable_counter: usize,
|
||||
constant_counter: usize,
|
||||
constants: Vec<IrConstant>,
|
||||
statements: Vec<IrStatement>,
|
||||
}
|
||||
|
||||
impl FunctionLoweringContext {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
temp_variable_counter: 0,
|
||||
constant_counter: 0,
|
||||
constants: vec![],
|
||||
statements: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_temp_variable(&mut self) -> String {
|
||||
let temp_variable = format!("t_{}", self.temp_variable_counter);
|
||||
self.temp_variable_counter += 1;
|
||||
temp_variable
|
||||
}
|
||||
|
||||
pub fn next_constant_name(&mut self) -> String {
|
||||
let constant_name = format!("%const_{}", self.constant_counter);
|
||||
self.constant_counter += 1;
|
||||
constant_name
|
||||
}
|
||||
|
||||
pub fn add_constant(&mut self, constant: IrConstant) {
|
||||
self.constants.push(constant);
|
||||
}
|
||||
|
||||
pub fn take_constants(&mut self) -> Vec<IrConstant> {
|
||||
std::mem::take(&mut self.constants)
|
||||
}
|
||||
|
||||
pub fn add_statement(&mut self, statement: IrStatement) {
|
||||
self.statements.push(statement);
|
||||
}
|
||||
|
||||
pub fn take_statements(&mut self) -> Vec<IrStatement> {
|
||||
std::mem::take(&mut self.statements)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::ExpressibleSymbol;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
@ -58,6 +61,10 @@ impl Identifier {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) -> IrExpression {
|
||||
IrExpression::Variable(IrVariable::new(self.name()))
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
&self.source_range
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::source_range::SourceRange;
|
||||
|
||||
pub struct IntegerLiteral {
|
||||
@ -17,6 +19,10 @@ impl IntegerLiteral {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) -> IrExpression {
|
||||
IrExpression::IntegerLiteral(self.value)
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
&self.source_range
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::ir_assign::IrAssign;
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::VariableSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
@ -68,4 +72,11 @@ impl LetStatement {
|
||||
diagnostics.append(&mut self.initializer.type_check(symbol_table));
|
||||
diagnostics
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) {
|
||||
let data = self.initializer.lower_to_ir(context);
|
||||
let destination = IrVariable::new(self.declared_name());
|
||||
let assign_statement = IrAssign::new(destination, data);
|
||||
context.add_statement(IrStatement::Assign(assign_statement));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
pub mod call;
|
||||
pub mod compilation_unit;
|
||||
pub mod expression;
|
||||
pub mod expression_statement;
|
||||
pub mod fqn;
|
||||
pub mod function;
|
||||
pub mod identifier;
|
||||
pub mod integer_literal;
|
||||
@ -25,6 +27,24 @@ mod name_tests {
|
||||
0
|
||||
);
|
||||
assert_eq!(compilation_unit.check_name_usages(&symbol_table).len(), 0);
|
||||
let irs = compilation_unit.lower_to_ir();
|
||||
for ir in &irs {
|
||||
println!("{:#?}", ir);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hello_world() {
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
let mut compilation_unit =
|
||||
parse_compilation_unit("fn println() end fn main() println(\"Hello, World!\") end");
|
||||
compilation_unit.gather_declared_names(&mut symbol_table);
|
||||
compilation_unit.check_name_usages(&symbol_table);
|
||||
compilation_unit.type_check(&symbol_table);
|
||||
let irs = compilation_unit.lower_to_ir();
|
||||
for ir in &irs {
|
||||
println!("{:#?}", ir);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,32 +1,50 @@
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::expression_statement::ExpressionStatement;
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::ast::let_statement::LetStatement;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
|
||||
pub enum Statement {
|
||||
Let(LetStatement),
|
||||
Expression(Expression),
|
||||
Expression(ExpressionStatement),
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
match self {
|
||||
Statement::Let(let_statement) => let_statement.gather_declared_names(symbol_table),
|
||||
Statement::Expression(expression) => expression.gather_declared_names(symbol_table),
|
||||
Statement::Expression(expression_statement) => {
|
||||
expression_statement.gather_declared_names(symbol_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
match self {
|
||||
Statement::Let(let_statement) => let_statement.check_name_usages(symbol_table),
|
||||
Statement::Expression(expression) => expression.check_name_usages(symbol_table),
|
||||
Statement::Expression(expression_statement) => {
|
||||
expression_statement.check_name_usages(symbol_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
match self {
|
||||
Statement::Let(let_statement) => let_statement.type_check(symbol_table),
|
||||
Statement::Expression(expression) => expression.type_check(symbol_table),
|
||||
Statement::Expression(expression_statement) => {
|
||||
expression_statement.type_check(symbol_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) {
|
||||
match self {
|
||||
Statement::Let(let_statement) => {
|
||||
let_statement.lower_to_ir(context);
|
||||
}
|
||||
Statement::Expression(expression) => {
|
||||
expression.lower_to_ir(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
use crate::ast::function::FunctionLoweringContext;
|
||||
use crate::ir::ir_constant::{IrConstant, IrStringConstant};
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::source_range::SourceRange;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct StringLiteral {
|
||||
content: String,
|
||||
@ -17,6 +21,15 @@ impl StringLiteral {
|
||||
&self.content
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self, context: &mut FunctionLoweringContext) -> IrExpression {
|
||||
let ir_string_constant = Rc::new(IrStringConstant::new(
|
||||
self.content(),
|
||||
&context.next_constant_name(),
|
||||
));
|
||||
context.add_constant(IrConstant::String(ir_string_constant.clone()));
|
||||
IrExpression::Constant(IrConstant::String(ir_string_constant))
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
&self.source_range
|
||||
}
|
||||
|
||||
17
dmc-lib/src/ir/ir_assign.rs
Normal file
17
dmc-lib/src/ir/ir_assign.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IrAssign {
|
||||
destination: Box<IrVariable>,
|
||||
value: Box<IrExpression>,
|
||||
}
|
||||
|
||||
impl IrAssign {
|
||||
pub fn new(destination: IrVariable, value: IrExpression) -> Self {
|
||||
Self {
|
||||
destination: destination.into(),
|
||||
value: value.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
16
dmc-lib/src/ir/ir_call.rs
Normal file
16
dmc-lib/src/ir/ir_call.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IrCall {
|
||||
name: String,
|
||||
arguments: Vec<IrExpression>,
|
||||
}
|
||||
|
||||
impl IrCall {
|
||||
pub fn new(name: &str, arguments: Vec<IrExpression>) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
arguments,
|
||||
}
|
||||
}
|
||||
}
|
||||
21
dmc-lib/src/ir/ir_constant.rs
Normal file
21
dmc-lib/src/ir/ir_constant.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IrConstant {
|
||||
String(Rc<IrStringConstant>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IrStringConstant {
|
||||
value: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl IrStringConstant {
|
||||
pub fn new(value: &str, name: &str) -> Self {
|
||||
Self {
|
||||
value: value.into(),
|
||||
name: name.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
11
dmc-lib/src/ir/ir_expression.rs
Normal file
11
dmc-lib/src/ir/ir_expression.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use crate::ir::ir_call::IrCall;
|
||||
use crate::ir::ir_constant::IrConstant;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IrExpression {
|
||||
Call(IrCall),
|
||||
Constant(IrConstant),
|
||||
IntegerLiteral(i64),
|
||||
Variable(IrVariable),
|
||||
}
|
||||
12
dmc-lib/src/ir/ir_function.rs
Normal file
12
dmc-lib/src/ir/ir_function.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IrFunction {
|
||||
statements: Vec<IrStatement>,
|
||||
}
|
||||
|
||||
impl IrFunction {
|
||||
pub fn new(statements: Vec<IrStatement>) -> Self {
|
||||
Self { statements }
|
||||
}
|
||||
}
|
||||
6
dmc-lib/src/ir/ir_l_value.rs
Normal file
6
dmc-lib/src/ir/ir_l_value.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
|
||||
pub enum IrLhs {
|
||||
Variable(IrVariable),
|
||||
FunctionName(String),
|
||||
}
|
||||
8
dmc-lib/src/ir/ir_r_value.rs
Normal file
8
dmc-lib/src/ir/ir_r_value.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use crate::ir::ir_constant::IrConstant;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
|
||||
pub enum IrRhs {
|
||||
Constant(IrConstant),
|
||||
IntegerLiteral(i64),
|
||||
Variable(IrVariable),
|
||||
}
|
||||
8
dmc-lib/src/ir/ir_statement.rs
Normal file
8
dmc-lib/src/ir/ir_statement.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use crate::ir::ir_assign::IrAssign;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IrStatement {
|
||||
Assign(IrAssign),
|
||||
Expression(IrExpression),
|
||||
}
|
||||
10
dmc-lib/src/ir/ir_variable.rs
Normal file
10
dmc-lib/src/ir/ir_variable.rs
Normal file
@ -0,0 +1,10 @@
|
||||
#[derive(Debug)]
|
||||
pub struct IrVariable {
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl IrVariable {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self { name: name.into() }
|
||||
}
|
||||
}
|
||||
18
dmc-lib/src/ir/mod.rs
Normal file
18
dmc-lib/src/ir/mod.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use crate::ir::ir_constant::IrConstant;
|
||||
use crate::ir::ir_function::IrFunction;
|
||||
|
||||
pub mod ir_assign;
|
||||
pub mod ir_call;
|
||||
pub mod ir_constant;
|
||||
pub mod ir_expression;
|
||||
pub mod ir_function;
|
||||
pub mod ir_l_value;
|
||||
pub mod ir_r_value;
|
||||
pub mod ir_statement;
|
||||
pub mod ir_variable;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Ir {
|
||||
Function(IrFunction),
|
||||
Constant(IrConstant),
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
mod ast;
|
||||
mod diagnostic;
|
||||
mod ir;
|
||||
mod lexer;
|
||||
mod parser;
|
||||
mod scope;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::expression_statement::ExpressionStatement;
|
||||
use crate::ast::function::Function;
|
||||
use crate::ast::identifier::Identifier;
|
||||
use crate::ast::integer_literal::IntegerLiteral;
|
||||
@ -169,7 +170,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn expression_statement(&mut self) -> Statement {
|
||||
Statement::Expression(self.expression())
|
||||
Statement::Expression(ExpressionStatement::new(self.expression()))
|
||||
}
|
||||
|
||||
fn expression(&mut self) -> Expression {
|
||||
@ -246,8 +247,8 @@ mod smoke_tests {
|
||||
assert_eq!(function.declared_name(), "main");
|
||||
let statements = function.statements();
|
||||
assert_eq!(statements.len(), 1);
|
||||
if let Statement::Expression(expression) = statements[0] {
|
||||
if let Expression::Call(call) = expression {
|
||||
if let Statement::Expression(expression_statement) = statements[0] {
|
||||
if let Expression::Call(call) = expression_statement.expression() {
|
||||
let callee = call.callee();
|
||||
match callee {
|
||||
Expression::Identifier(identifier) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user