More work on UIR

This commit is contained in:
Alex Bethel 2022-08-27 22:16:11 -06:00
parent 4480a1973a
commit 2607722686
5 changed files with 69 additions and 52 deletions

View file

@ -4,8 +4,10 @@
//! simplifies the complexity of the syntax tree, and is used to perform type inference, at which //! simplifies the complexity of the syntax tree, and is used to perform type inference, at which
//! point it is translated into typed IR. //! point it is translated into typed IR.
use std::fmt::Display;
use crate::{ use crate::{
syntax::{self, Identifier, SyntaxTree}, syntax::{self, Identifier, Literal, SyntaxTree},
typeck::Type, typeck::Type,
}; };
@ -143,6 +145,19 @@ enum Location {
/// A compiler-generated temporary location. /// A compiler-generated temporary location.
Temporary(u64), Temporary(u64),
/// A constant value.
Literal(Literal),
}
impl Display for Location {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Location::Named(id) => write!(f, "n`{}`", id),
Location::Temporary(t) => write!(f, "t`{}`", t),
Location::Literal(l) => write!(f, "c`{}`", l),
}
}
} }
/// Converts a program's abstract syntax tree into untyped IR code. /// Converts a program's abstract syntax tree into untyped IR code.
@ -204,7 +219,13 @@ fn convert_fn(
mut arguments: Vec<syntax::Pattern>, mut arguments: Vec<syntax::Pattern>,
definition: syntax::Expr, definition: syntax::Expr,
) -> Vec<Instruction> { ) -> Vec<Instruction> {
if arguments.len() > 1 { if arguments.is_empty() {
let ret_loc = temporary(counter);
eval_expr(counter, definition, &ret_loc)
.into_iter()
.chain(std::iter::once(Instruction::Return { target: ret_loc }))
.collect()
} else {
let first = arguments.remove(0); let first = arguments.remove(0);
let lambda_loc = temporary(counter); let lambda_loc = temporary(counter);
@ -220,12 +241,6 @@ fn convert_fn(
}, },
Instruction::Return { target: lambda_loc }, Instruction::Return { target: lambda_loc },
] ]
} else {
let ret_loc = temporary(counter);
eval_expr(counter, definition, &ret_loc)
.into_iter()
.chain(std::iter::once(Instruction::Return { target: ret_loc }))
.collect()
} }
} }
@ -271,11 +286,6 @@ fn bind_pattern(counter: &mut u64, p: syntax::Pattern, l: &Location) -> Vec<Inst
/// Emits intructions that evaluate the expression `e`, then place the result in location `l`. /// Emits intructions that evaluate the expression `e`, then place the result in location `l`.
fn eval_expr(counter: &mut u64, e: syntax::Expr, l: &Location) -> Vec<Instruction> { fn eval_expr(counter: &mut u64, e: syntax::Expr, l: &Location) -> Vec<Instruction> {
match e { match e {
syntax::Expr::UnaryOp {
kind,
val,
translation,
} => todo!(),
syntax::Expr::BinaryOp { syntax::Expr::BinaryOp {
kind, kind,
left, left,
@ -315,7 +325,13 @@ fn eval_expr(counter: &mut u64, e: syntax::Expr, l: &Location) -> Vec<Instructio
})) }))
.collect() .collect()
} }
syntax::Expr::VariableReference(_) => todo!(), syntax::Expr::VariableReference(name) => vec![Instruction::Collect {
syntax::Expr::Literal(_) => todo!(), target: l.clone(),
source: vec![Location::Named(name)],
}],
syntax::Expr::Literal(lit) => vec![Instruction::Collect {
target: l.clone(),
source: vec![Location::Literal(lit)],
}],
} }
} }

View file

@ -4,8 +4,8 @@ use std::{error::Error, fmt::Display, process::exit, str::FromStr};
use clap::Parser; use clap::Parser;
use drimc_rs::{ use drimc_rs::{
ir_untyped::ast_to_untyped_ir,
parser::{parser, ParserError, ParserMeta}, parser::{parser, ParserError, ParserMeta},
typeck::typeck, ir_untyped::ast_to_untyped_ir,
}; };
/// Optimization levels. /// Optimization levels.
@ -98,6 +98,10 @@ impl FromStr for Optimization {
/// Targets for compiling to. /// Targets for compiling to.
#[derive(Debug)] #[derive(Debug)]
enum Target { enum Target {
// -------------------- IR generation --------------------
/// Generate untyped intermediate representation (UIR) code.
UIR,
// -------------------- C generation -------------------- // -------------------- C generation --------------------
// Highest priority codegen, since it allows us to compile to the vast majority of possible // Highest priority codegen, since it allows us to compile to the vast majority of possible
@ -138,25 +142,26 @@ enum Target {
Wasm, Wasm,
// -------------------- Other language generation -------------------- // -------------------- Other language generation --------------------
/// Directly generate Lua code.
// Medium-priority codegen, since Lua is the only type of code that runs in e.g. plugins and // Medium-priority codegen, since Lua is the only type of code that runs in e.g. plugins and
// scripts in some software, and it is difficult to generate efficient Lua without direct // scripts in some software, and it is difficult to generate efficient Lua without direct
// support from the compiler. // support from the compiler.
/// Directly generate Lua code.
Lua, Lua,
/// Directly generate Python code.
// Low-priority codegen; the same situation as Lua, but situations that require Python code with // Low-priority codegen; the same situation as Lua, but situations that require Python code with
// no alternatives are much less common than situations that require Lua code with no // no alternatives are much less common than situations that require Lua code with no
// alternatives. // alternatives.
/// Directly generate Python code.
Python, Python,
/// Directly generate Go code.
// Extremely low-priority codegen; almost no valid use cases. // Extremely low-priority codegen; almost no valid use cases.
/// Directly generate Go code.
Go, Go,
/// Directly generate Ada code.
// Currently zero-priority codegen; no valid use cases whatsoever as far as I (Alex) can // Currently zero-priority codegen; no valid use cases whatsoever as far as I (Alex) can
// determine. // determine.
/// Directly generate Ada code.
Ada, Ada,
} }
@ -166,6 +171,7 @@ impl Display for Target {
f, f,
"{}", "{}",
match self { match self {
Target::UIR => "uir",
Target::CSource => "c", Target::CSource => "c",
Target::Assembly => "asm", Target::Assembly => "asm",
Target::ObjectFile => "obj", Target::ObjectFile => "obj",
@ -190,6 +196,7 @@ impl FromStr for Target {
use Target::*; use Target::*;
let targets = [ let targets = [
("uir", "Untyped intermediate representation.", UIR),
("c", "C source code.", CSource), ("c", "C source code.", CSource),
("asm", "Assembly code.", Assembly), ("asm", "Assembly code.", Assembly),
("obj", "Object file.", ObjectFile), ("obj", "Object file.", ObjectFile),

View file

@ -379,9 +379,7 @@ fn parse_expression<'a>(
.unwrap() .unwrap()
}); });
let unary = parse_unary(m, application); let binary = (0..=10).rev().fold(application.boxed(), |p, precedence| {
let binary = (0..=10).rev().fold(unary.boxed(), |p, precedence| {
parse_binary(m, precedence, p).boxed() parse_binary(m, precedence, p).boxed()
}); });
@ -389,22 +387,6 @@ fn parse_expression<'a>(
}) })
} }
fn parse_unary(
_m: &ParserMeta,
base: impl Parser<char, Expr, Error = Simple<char>> + Clone,
) -> impl Parser<char, Expr, Error = Simple<char>> + Clone {
pad(just("-").to("-"))
.repeated()
.then(base)
.map(|(ops, exp)| {
ops.into_iter().fold(exp, |exp, op| Expr::UnaryOp {
kind: op.to_string(),
val: Box::new(exp),
translation: "negate".to_string(),
})
})
}
fn parse_binary<'a>( fn parse_binary<'a>(
m: &'a ParserMeta, m: &'a ParserMeta,
prec: u32, prec: u32,

View file

@ -1,5 +1,7 @@
//! Syntax tree for Drim code. //! Syntax tree for Drim code.
use std::fmt::Display;
use num_bigint::BigUint; use num_bigint::BigUint;
/// A concrete syntax tree. This represents the full content of a Drim program, including all /// A concrete syntax tree. This represents the full content of a Drim program, including all
@ -90,18 +92,6 @@ pub struct TypeConstructor {
/// The different kinds of expressions. /// The different kinds of expressions.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Expr { pub enum Expr {
/// Unary operators, e.g., `-5`.
UnaryOp {
/// The text of the operator.
kind: String,
/// The value being operated upon.
val: Box<Expr>,
/// The function that the unary operator translates to.
translation: String,
},
/// Binary operators, e.g., `5 + 5`. /// Binary operators, e.g., `5 + 5`.
BinaryOp { BinaryOp {
/// The text of the operator. /// The text of the operator.
@ -258,6 +248,18 @@ pub struct Identifier {
pub elems: Vec<String>, pub elems: Vec<String>,
} }
impl Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (n, e) in self.elems.iter().enumerate() {
if n != 0 {
write!(f, "::")?;
}
write!(f, "{}", e)?;
}
Ok(())
}
}
/// Literal values included in source code. /// Literal values included in source code.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Literal { pub enum Literal {
@ -270,3 +272,13 @@ pub enum Literal {
/// `123.456` /// `123.456`
Float(f64), Float(f64),
} }
impl Display for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Literal::String(s) => write!(f, "{}", s),
Literal::Integer(i) => write!(f, "{}", i),
Literal::Float(fl) => write!(f, "{}", fl),
}
}
}

View file

@ -1,3 +1,3 @@
// IR Test // IR Test
def nul (a, b) = (); def nul (a, b) = sin a;