diff --git a/drimc_rs/src/ir_untyped.rs b/drimc_rs/src/ir_untyped.rs index 17349d7..2affdce 100644 --- a/drimc_rs/src/ir_untyped.rs +++ b/drimc_rs/src/ir_untyped.rs @@ -4,8 +4,10 @@ //! simplifies the complexity of the syntax tree, and is used to perform type inference, at which //! point it is translated into typed IR. +use std::fmt::Display; + use crate::{ - syntax::{self, Identifier, SyntaxTree}, + syntax::{self, Identifier, Literal, SyntaxTree}, typeck::Type, }; @@ -143,6 +145,19 @@ enum Location { /// A compiler-generated temporary location. 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. @@ -204,7 +219,13 @@ fn convert_fn( mut arguments: Vec, definition: syntax::Expr, ) -> Vec { - 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 lambda_loc = temporary(counter); @@ -220,12 +241,6 @@ fn convert_fn( }, 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 Vec { match e { - syntax::Expr::UnaryOp { - kind, - val, - translation, - } => todo!(), syntax::Expr::BinaryOp { kind, left, @@ -315,7 +325,13 @@ fn eval_expr(counter: &mut u64, e: syntax::Expr, l: &Location) -> Vec todo!(), - syntax::Expr::Literal(_) => todo!(), + syntax::Expr::VariableReference(name) => vec![Instruction::Collect { + target: l.clone(), + source: vec![Location::Named(name)], + }], + syntax::Expr::Literal(lit) => vec![Instruction::Collect { + target: l.clone(), + source: vec![Location::Literal(lit)], + }], } } diff --git a/drimc_rs/src/main.rs b/drimc_rs/src/main.rs index 5d47a25..1273d60 100644 --- a/drimc_rs/src/main.rs +++ b/drimc_rs/src/main.rs @@ -4,8 +4,8 @@ use std::{error::Error, fmt::Display, process::exit, str::FromStr}; use clap::Parser; use drimc_rs::{ + ir_untyped::ast_to_untyped_ir, parser::{parser, ParserError, ParserMeta}, - typeck::typeck, ir_untyped::ast_to_untyped_ir, }; /// Optimization levels. @@ -98,6 +98,10 @@ impl FromStr for Optimization { /// Targets for compiling to. #[derive(Debug)] enum Target { + // -------------------- IR generation -------------------- + /// Generate untyped intermediate representation (UIR) code. + UIR, + // -------------------- C generation -------------------- // Highest priority codegen, since it allows us to compile to the vast majority of possible @@ -138,25 +142,26 @@ enum Target { Wasm, // -------------------- 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 // scripts in some software, and it is difficult to generate efficient Lua without direct // support from the compiler. + /// Directly generate Lua code. Lua, - /// Directly generate Python code. // 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 // alternatives. + /// Directly generate Python code. Python, - /// Directly generate Go code. // Extremely low-priority codegen; almost no valid use cases. + /// Directly generate Go code. Go, - /// Directly generate Ada code. // Currently zero-priority codegen; no valid use cases whatsoever as far as I (Alex) can // determine. + /// Directly generate Ada code. Ada, } @@ -166,6 +171,7 @@ impl Display for Target { f, "{}", match self { + Target::UIR => "uir", Target::CSource => "c", Target::Assembly => "asm", Target::ObjectFile => "obj", @@ -190,6 +196,7 @@ impl FromStr for Target { use Target::*; let targets = [ + ("uir", "Untyped intermediate representation.", UIR), ("c", "C source code.", CSource), ("asm", "Assembly code.", Assembly), ("obj", "Object file.", ObjectFile), diff --git a/drimc_rs/src/parser.rs b/drimc_rs/src/parser.rs index 2ef4cc0..dc55231 100644 --- a/drimc_rs/src/parser.rs +++ b/drimc_rs/src/parser.rs @@ -379,9 +379,7 @@ fn parse_expression<'a>( .unwrap() }); - let unary = parse_unary(m, application); - - let binary = (0..=10).rev().fold(unary.boxed(), |p, precedence| { + let binary = (0..=10).rev().fold(application.boxed(), |p, precedence| { parse_binary(m, precedence, p).boxed() }); @@ -389,22 +387,6 @@ fn parse_expression<'a>( }) } -fn parse_unary( - _m: &ParserMeta, - base: impl Parser> + Clone, -) -> impl Parser> + 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>( m: &'a ParserMeta, prec: u32, diff --git a/drimc_rs/src/syntax.rs b/drimc_rs/src/syntax.rs index 8bbdda7..e671cf2 100644 --- a/drimc_rs/src/syntax.rs +++ b/drimc_rs/src/syntax.rs @@ -1,5 +1,7 @@ //! Syntax tree for Drim code. +use std::fmt::Display; + use num_bigint::BigUint; /// 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. #[derive(Clone, Debug)] pub enum Expr { - /// Unary operators, e.g., `-5`. - UnaryOp { - /// The text of the operator. - kind: String, - - /// The value being operated upon. - val: Box, - - /// The function that the unary operator translates to. - translation: String, - }, - /// Binary operators, e.g., `5 + 5`. BinaryOp { /// The text of the operator. @@ -258,6 +248,18 @@ pub struct Identifier { pub elems: Vec, } +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. #[derive(Clone, Debug)] pub enum Literal { @@ -270,3 +272,13 @@ pub enum Literal { /// `123.456` 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), + } + } +} diff --git a/drimc_rs/uir_test.drim b/drimc_rs/uir_test.drim index b0539f3..c1c973f 100644 --- a/drimc_rs/uir_test.drim +++ b/drimc_rs/uir_test.drim @@ -1,3 +1,3 @@ // IR Test -def nul (a, b) = (); +def nul (a, b) = sin a;