A fairly major refactor / simplification.
This commit is contained in:
172
src/ir/ast.rs
Normal file
172
src/ir/ast.rs
Normal 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
65
src/ir/from_syntax.rs
Normal 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
36
src/ir/strings.rs
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user