More work on UIR
This commit is contained in:
parent
4480a1973a
commit
2607722686
|
@ -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)],
|
||||||
|
}],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
// IR Test
|
// IR Test
|
||||||
|
|
||||||
def nul (a, b) = ();
|
def nul (a, b) = sin a;
|
||||||
|
|
Loading…
Reference in a new issue