A fairly major refactor / simplification.

This commit is contained in:
2023-01-16 20:11:06 -08:00
parent 2e82fcf343
commit afcf3c65cd
26 changed files with 800 additions and 1132 deletions

172
src/ir/ast.rs Normal file
View File

@@ -0,0 +1,172 @@
use internment::ArcIntern;
use pretty::{DocAllocator, Pretty};
use crate::syntax::Location;
type Variable = ArcIntern<String>;
pub struct Program {
pub statements: Vec<Statement>,
}
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Program
where
A: 'a,
D: ?Sized + DocAllocator<'a, A>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> {
let mut result = allocator.nil();
for stmt in self.statements.iter() {
result = result
.append(stmt.pretty(allocator))
.append(allocator.text(";"))
.append(allocator.hardline());
}
result
}
}
pub enum Statement {
Binding(Location, Variable, Expression),
Print(Location, Variable),
}
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Statement
where
A: 'a,
D: ?Sized + DocAllocator<'a, A>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> {
match self {
Statement::Binding(_, var, expr) => allocator
.text(var.as_ref().to_string())
.append(allocator.space())
.append(allocator.text("="))
.append(allocator.space())
.append(expr.pretty(allocator)),
Statement::Print(_, var) => allocator
.text("print")
.append(allocator.space())
.append(allocator.text(var.as_ref().to_string())),
}
}
}
pub enum Expression {
Value(Location, Value),
Reference(Location, Variable),
Primitive(Location, Primitive, Vec<ValueOrRef>),
}
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Expression
where
A: 'a,
D: ?Sized + DocAllocator<'a, A>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> {
match self {
Expression::Value(_, val) => val.pretty(allocator),
Expression::Reference(_, var) => allocator.text(var.as_ref().to_string()),
Expression::Primitive(_, op, exprs) if exprs.len() == 1 => {
op.pretty(allocator).append(exprs[0].pretty(allocator))
}
Expression::Primitive(_, op, exprs) if exprs.len() == 2 => {
let left = exprs[0].pretty(allocator);
let right = exprs[1].pretty(allocator);
left.append(allocator.space())
.append(op.pretty(allocator))
.append(allocator.space())
.append(right)
.parens()
}
Expression::Primitive(_, op, exprs) => {
allocator.text(format!("!!{:?} with {} arguments!!", op, exprs.len()))
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Primitive {
Plus,
Minus,
Times,
Divide,
}
impl<'a> TryFrom<&'a str> for Primitive {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"+" => Ok(Primitive::Plus),
"-" => Ok(Primitive::Minus),
"*" => Ok(Primitive::Times),
"/" => Ok(Primitive::Divide),
_ => Err(format!("Illegal primitive {}", value)),
}
}
}
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Primitive
where
A: 'a,
D: ?Sized + DocAllocator<'a, A>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> {
match self {
Primitive::Plus => allocator.text("+"),
Primitive::Minus => allocator.text("-"),
Primitive::Times => allocator.text("*"),
Primitive::Divide => allocator.text("/"),
}
}
}
pub enum ValueOrRef {
Value(Location, Value),
Ref(Location, ArcIntern<String>),
}
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b ValueOrRef
where
A: 'a,
D: ?Sized + DocAllocator<'a, A>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> {
match self {
ValueOrRef::Value(_, v) => v.pretty(allocator),
ValueOrRef::Ref(_, v) => allocator.text(v.as_ref().to_string()),
}
}
}
pub enum Value {
Number(Option<u8>, i64),
}
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Value
where
A: 'a,
D: ?Sized + DocAllocator<'a, A>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> {
match self {
Value::Number(opt_base, value) => {
let value_str = match opt_base {
None => format!("{}", value),
Some(2) => format!("0b{:b}", value),
Some(8) => format!("0o{:o}", value),
Some(10) => format!("0d{}", value),
Some(16) => format!("0x{:x}", value),
Some(_) => format!("!!{:x}!!", value),
};
allocator.text(value_str)
}
}
}
}

65
src/ir/from_syntax.rs Normal file
View File

@@ -0,0 +1,65 @@
use internment::ArcIntern;
use crate::ir::ast as ir;
use crate::syntax::ast as syntax;
impl From<syntax::Program> for ir::Program {
fn from(mut value: syntax::Program) -> Self {
ir::Program {
statements: value.statements.drain(..).map(Into::into).collect(),
}
}
}
impl From<syntax::Statement> for ir::Statement {
fn from(value: syntax::Statement) -> Self {
match value {
syntax::Statement::Binding(loc, name, expr) => {
ir::Statement::Binding(loc, ArcIntern::from(name), ir::Expression::from(expr))
}
syntax::Statement::Print(loc, name) => ir::Statement::Print(loc, ArcIntern::from(name)),
}
}
}
impl From<syntax::Expression> for ir::Expression {
fn from(value: syntax::Expression) -> Self {
match value {
syntax::Expression::Primitive(loc, name, mut exprs) => ir::Expression::Primitive(
loc,
ir::Primitive::try_from(name.as_str()).unwrap(),
exprs.drain(..).map(Into::into).collect(),
),
syntax::Expression::Reference(loc, name) => {
ir::Expression::Reference(loc, ArcIntern::from(name))
}
syntax::Expression::Value(loc, value) => {
ir::Expression::Value(loc, ir::Value::from(value))
}
}
}
}
impl From<syntax::Expression> for ir::ValueOrRef {
fn from(value: syntax::Expression) -> Self {
match value {
syntax::Expression::Primitive(loc, _, _) => {
panic!("{:?}: couldn't convert to valueorref", loc)
}
syntax::Expression::Reference(loc, var) => {
ir::ValueOrRef::Ref(loc, ArcIntern::new(var))
}
syntax::Expression::Value(loc, val) => ir::ValueOrRef::Value(loc, val.into()),
}
}
}
impl From<syntax::Value> for ir::Value {
fn from(x: syntax::Value) -> Self {
match x {
syntax::Value::Number(base, value) => ir::Value::Number(base, value),
}
}
}

36
src/ir/strings.rs Normal file
View File

@@ -0,0 +1,36 @@
use super::ast::{Expression, Program, Statement};
use internment::ArcIntern;
use std::collections::HashSet;
impl Program {
pub fn strings(&self) -> HashSet<ArcIntern<String>> {
let mut result = HashSet::new();
for stmt in self.statements.iter() {
stmt.register_strings(&mut result);
}
result
}
}
impl Statement {
fn register_strings(&self, string_set: &mut HashSet<ArcIntern<String>>) {
match self {
Statement::Binding(_, name, expr) => {
string_set.insert(name.clone());
expr.register_strings(string_set);
}
Statement::Print(_, name) => {
string_set.insert(name.clone());
}
}
}
}
impl Expression {
fn register_strings(&self, _string_set: &mut HashSet<ArcIntern<String>>) {
// nothing has a string in here, at the moment
}
}