Skip to content

Commit

Permalink
Parse lambdas
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcelGarus committed Oct 31, 2024
1 parent 5cffe91 commit e8f459d
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 117 deletions.
2 changes: 1 addition & 1 deletion Candy v3, v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ fun map[T, R](list: List[T], f: Fun[T, R]) List[R] {}
fun average[T: Number](list: List[T]) T {
needs(!list.is_empty())
# TODO: maybe implicit `it`
list.reduce(T.zero(), (a, b) { a + b })
# list.reduce(T.zero(), (a: T, b: T) { a + b })
}

trait Number {
Expand Down
40 changes: 21 additions & 19 deletions compiler_v4/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,14 @@ pub struct AstFunction {
pub display_span: Range<Offset>,
pub name: AstResult<AstString>,
pub type_parameters: Option<AstTypeParameters>,
pub opening_parenthesis_error: Option<AstError>,
pub parameters: Vec<AstParameter>,
pub closing_parenthesis_error: Option<AstError>,
pub parameters: AstResult<AstParameters>,
pub return_type: Option<AstType>,
pub body: Option<AstFunctionBody>,
pub body: Option<AstBody>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct AstFunctionBody {
pub body: Vec<AstStatement>,
pub closing_curly_brace_error: Option<AstError>,
pub struct AstParameters {
pub parameters: Vec<AstParameter>,
pub closing_parenthesis_error: Option<AstError>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct AstParameter {
Expand Down Expand Up @@ -211,7 +209,7 @@ pub enum AstExpressionKind {
Parenthesized(AstParenthesized),
Call(AstCall),
Navigation(AstNavigation),
// Lambda(AstLambda),
Lambda(AstLambda),
Body(AstBody),
Switch(AstSwitch),
}
Expand Down Expand Up @@ -278,12 +276,11 @@ pub struct AstNavigation {
pub key: AstResult<AstString>,
}

// #[derive(Clone, Debug, Eq, Hash, PartialEq)]
// pub struct AstLambda {
// pub parameters: Vec<AstParameter>,
// pub body: Vec<AstStatement>,
// pub closing_curly_brace_error: Option<AstError>,
// }
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct AstLambda {
pub parameters: AstParameters,
pub body: AstBody,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct AstBody {
Expand Down Expand Up @@ -463,17 +460,15 @@ impl CollectAstErrors for AstFunction {
fn collect_errors_to(&self, errors: &mut Vec<CompilerError>) {
self.name.collect_errors_to(errors);
self.type_parameters.collect_errors_to(errors);
self.opening_parenthesis_error.collect_errors_to(errors);
self.parameters.collect_errors_to(errors);
self.closing_parenthesis_error.collect_errors_to(errors);
self.return_type.collect_errors_to(errors);
self.body.collect_errors_to(errors);
}
}
impl CollectAstErrors for AstFunctionBody {
impl CollectAstErrors for AstParameters {
fn collect_errors_to(&self, errors: &mut Vec<CompilerError>) {
self.body.collect_errors_to(errors);
self.closing_curly_brace_error.collect_errors_to(errors);
self.parameters.collect_errors_to(errors);
self.closing_parenthesis_error.collect_errors_to(errors);
}
}
impl CollectAstErrors for AstParameter {
Expand Down Expand Up @@ -533,6 +528,7 @@ impl CollectAstErrors for AstExpressionKind {
Self::Parenthesized(parenthesized) => parenthesized.collect_errors_to(errors),
Self::Call(call) => call.collect_errors_to(errors),
Self::Navigation(navigation) => navigation.collect_errors_to(errors),
Self::Lambda(lambda) => lambda.collect_errors_to(errors),
Self::Body(body) => body.collect_errors_to(errors),
Self::Switch(switch) => switch.collect_errors_to(errors),
}
Expand Down Expand Up @@ -600,6 +596,12 @@ impl CollectAstErrors for AstNavigation {
self.key.collect_errors_to(errors);
}
}
impl CollectAstErrors for AstLambda {
fn collect_errors_to(&self, errors: &mut Vec<CompilerError>) {
self.parameters.collect_errors_to(errors);
self.body.collect_errors_to(errors);
}
}
impl CollectAstErrors for AstBody {
fn collect_errors_to(&self, errors: &mut Vec<CompilerError>) {
self.statements.collect_errors_to(errors);
Expand Down
17 changes: 8 additions & 9 deletions compiler_v4/src/ast_to_hir.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use crate::{
ast::{
Ast, AstArguments, AstAssignment, AstBody, AstCall, AstDeclaration, AstEnum, AstExpression,
AstExpressionKind, AstFunction, AstImpl, AstParameter, AstResult, AstStatement, AstString,
AstStruct, AstStructKind, AstSwitch, AstTextPart, AstTrait, AstType, AstTypeArguments,
AstTypeParameter, AstTypeParameters,
Ast, AstArguments, AstAssignment, AstBody, AstCall, AstDeclaration, AstEnum, AstExpression, AstExpressionKind, AstFunction, AstImpl, AstLambda, AstParameter, AstParameters, AstResult, AstStatement, AstString, AstStruct, AstStructKind, AstSwitch, AstTextPart, AstTrait, AstType, AstTypeArguments, AstTypeParameter, AstTypeParameters
},
error::CompilerError,
hir::{
Expand Down Expand Up @@ -1068,8 +1065,8 @@ impl<'a> Context<'a> {
.cloned()
.collect::<Box<_>>();

let parameters =
self.lower_parameters(&all_type_parameters, self_type, &function.parameters);
let parameters = function.parameters.value().map(|it| self.lower_parameters(&all_type_parameters, self_type, it))
.unwrap_or(Box::default());
let return_type = function.return_type.as_ref().map_or_else(
|| NamedType::nothing().into(),
|it| self.lower_type(&all_type_parameters, self_type, it),
Expand All @@ -1088,10 +1085,10 @@ impl<'a> Context<'a> {
&mut self,
type_parameters: &[TypeParameter],
self_type: Option<&NamedType>,
parameters: &'a [AstParameter],
parameters: &'a AstParameters,
) -> Box<[Parameter]> {
let mut parameter_names = FxHashSet::default();
parameters
parameters.parameters
.iter()
.filter_map(|parameter| try {
let name = parameter.name.value()?.clone();
Expand Down Expand Up @@ -1131,7 +1128,7 @@ impl<'a> Context<'a> {
}

if let Some(body) = function.ast.unwrap().body.as_ref() {
builder.lower_statements(&body.body, Some(&function.return_type));
builder.lower_statements(&body.statements, Some(&function.return_type));
} else {
builder.context.add_error(
function.ast.unwrap().display_span.clone(),
Expand Down Expand Up @@ -1710,6 +1707,8 @@ impl<'c, 'a> BodyBuilder<'c, 'a> {
LoweredExpression::Error => LoweredExpression::Error,
}
}
AstExpressionKind::Lambda(AstLambda { parameters, .. }) => { todo!()
}
AstExpressionKind::Body(AstBody { statements, .. }) => {
let (id, type_) = self.lower_statements(statements, context_type);
LoweredExpression::Expression { id, type_ }
Expand Down
59 changes: 51 additions & 8 deletions compiler_v4/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extern crate self as candy_compiler_v4;

use ast::CollectAstErrors;
use ast_to_hir::ast_to_hir;
use clap::{Parser, ValueHint};
use clap::{arg, Parser, Subcommand, ValueHint};
use error::CompilerError;
use hir::Hir;
use hir_to_mono::hir_to_mono;
Expand Down Expand Up @@ -57,6 +57,8 @@ mod utils;
#[derive(Parser, Debug)]
#[command(name = "candy", about = "The 🍭 Candy CLI.")]
enum CandyOptions {
#[command(subcommand)]
Debug(DebugOptions),
Check(CheckOptions),
Compile(CompileOptions),
}
Expand All @@ -67,6 +69,7 @@ fn main() -> ProgramResult {
init_logger();

match options {
CandyOptions::Debug(options) => debug(options),
CandyOptions::Check(options) => check(options),
CandyOptions::Compile(options) => compile(options),
}
Expand All @@ -78,6 +81,53 @@ pub enum Exit {
CodeContainsErrors,
}

#[derive(Subcommand, Debug)]
enum DebugOptions {
Ast(DebugStageOptions),
Hir(DebugStageOptions),
Mono(DebugStageOptions),
}
#[derive(Parser, Debug)]
struct DebugStageOptions {
#[arg(value_hint = ValueHint::FilePath)]
path: PathBuf,
}

#[allow(clippy::needless_pass_by_value)]
fn debug(options: DebugOptions) -> ProgramResult {
match options {
DebugOptions::Ast(options) => {
let source = fs::read_to_string(&options.path).unwrap();
let ast = string_to_ast::string_to_ast(&options.path, &source);
println!("{ast:#?}");
},
DebugOptions::Hir(options) => {
let source = fs::read_to_string(&options.path).unwrap();
let (hir, errors) = compile_hir(&options.path, &source);
if !errors.is_empty() {
for error in errors {
error!("{}", error.to_string_with_location(&source));
}
return Err(Exit::CodeContainsErrors);
}
println!("{}", hir.to_text(true));
},
DebugOptions::Mono(options) => {
let source = fs::read_to_string(&options.path).unwrap();
let (hir, errors) = compile_hir(&options.path, &source);
if !errors.is_empty() {
for error in errors {
error!("{}", error.to_string_with_location(&source));
}
return Err(Exit::CodeContainsErrors);
}
let mono = hir_to_mono(&hir);
println!("{mono:?}");
},
}
Ok(())
}

#[derive(Parser, Debug)]
struct CheckOptions {
/// The file or package to check.
Expand Down Expand Up @@ -106,9 +156,6 @@ fn check(options: CheckOptions) -> ProgramResult {

#[derive(Parser, Debug)]
struct CompileOptions {
#[arg(long)]
debug_print_hir: bool,

/// The file or package to compile to C.
#[arg(value_hint = ValueHint::FilePath)]
path: PathBuf,
Expand All @@ -121,10 +168,6 @@ fn compile(options: CompileOptions) -> ProgramResult {
let started_at = Instant::now();
let (hir, errors) = compile_hir(&options.path, &source);

if options.debug_print_hir {
println!("Hir:\n{}", hir.to_text(true));
}

if !errors.is_empty() {
for error in errors {
error!("{}", error.to_string_with_location(&source));
Expand Down
75 changes: 28 additions & 47 deletions compiler_v4/src/string_to_ast/declarations.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
expression::{expression, statement},
expression::{body, expression},
list::list_of,
literal::{
builtin_keyword, closing_bracket, closing_curly_brace, closing_parenthesis, colon, comma,
Expand All @@ -15,9 +15,7 @@ use super::{
word::raw_identifier,
};
use crate::ast::{
AstAssignment, AstDeclaration, AstEnum, AstEnumVariant, AstError, AstFunction, AstFunctionBody,
AstImpl, AstParameter, AstString, AstStruct, AstStructField, AstStructKind, AstTrait,
AstTypeParameter, AstTypeParameters,
AstAssignment, AstDeclaration, AstEnum, AstEnumVariant, AstError, AstFunction, AstImpl, AstParameter, AstParameters, AstString, AstStruct, AstStructField, AstStructKind, AstTrait, AstTypeParameter, AstTypeParameters
};
use tracing::instrument;

Expand Down Expand Up @@ -331,77 +329,60 @@ fn function<'a>(parser: Parser) -> Option<(Parser, AstFunction)> {
let display_span = name.value().map_or(fun_keyword_span, |it| it.span.clone());

let (parser, type_parameters) = type_parameters(parser).optional(parser);

let (mut parser, opening_parenthesis_error) = opening_parenthesis(parser)
.and_trailing_whitespace()
.unwrap_or_ast_error(parser, "This function is missing an opening parenthesis.");

let mut parameters: Vec<AstParameter> = vec![];
// TODO: error on duplicate parameter names
let mut parser_for_missing_comma_error: Option<Parser> = None;
while let Some((new_parser, variant, new_parser_for_missing_comma_error)) = parameter(parser) {
if let Some(parser_for_missing_comma_error) = parser_for_missing_comma_error {
parameters.last_mut().unwrap().comma_error = Some(
parser_for_missing_comma_error
.error_at_current_offset("This function variant is missing a comma."),
);
}

parser = new_parser.and_trailing_whitespace();
parameters.push(variant);
parser_for_missing_comma_error = new_parser_for_missing_comma_error;
}

let (parser, closing_parenthesis_error) = closing_parenthesis(parser)
.and_trailing_whitespace()
.unwrap_or_ast_error(parser, "This function is missing a closing parenthesis.");

let (parser, parameters) = parameters(parser).unwrap_or_ast_error(parser, "Expected parameters");
let (parser, return_type) = type_(parser).optional(parser).and_trailing_whitespace();

let (parser, body) = function_body(parser).optional(parser);
let (parser, body) = body(parser).optional(parser);

Some((
parser,
AstFunction {
display_span,
name,
type_parameters,
opening_parenthesis_error,
parameters,
closing_parenthesis_error,
return_type,
body,
},
))
}
#[instrument(level = "trace")]
fn function_body<'a>(parser: Parser) -> Option<(Parser, AstFunctionBody)> {
let parser = opening_curly_brace(parser)?.and_trailing_whitespace();
pub fn parameters<'a>(parser: Parser) -> Option<(Parser, AstParameters)> {
let mut parser = opening_parenthesis(parser)?
.and_trailing_whitespace();

let mut parameters: Vec<AstParameter> = vec![];
// TODO: error on duplicate parameter names
let mut parser_for_missing_comma_error: Option<Parser> = None;
while let Some((new_parser, parameter, new_parser_for_missing_comma_error)) = parameter(parser) {
if let Some(parser_for_missing_comma_error) = parser_for_missing_comma_error {
parameters.last_mut().unwrap().comma_error = Some(
parser_for_missing_comma_error
.error_at_current_offset("This parameter is missing a comma."),
);
}

let (parser, body) = list_of(parser, statement);
parser = new_parser.and_trailing_whitespace();
parameters.push(parameter);
parser_for_missing_comma_error = new_parser_for_missing_comma_error;
}

let (parser, closing_curly_brace_error) = closing_curly_brace(parser)
.unwrap_or_ast_error(parser, "This function is missing a closing curly brace.");
let (parser, closing_parenthesis_error) = closing_parenthesis(parser)
.and_trailing_whitespace()
.unwrap_or_ast_error(parser, "This parameter list is missing a closing parenthesis.");

Some((
parser,
AstFunctionBody {
body,
closing_curly_brace_error,
},
))
Some((parser, AstParameters { parameters, closing_parenthesis_error }))
}
#[instrument(level = "trace")]
fn parameter<'a>(parser: Parser) -> Option<(Parser, AstParameter, Option<Parser>)> {
let (parser, name) = raw_identifier(parser)?.and_trailing_whitespace();

let (parser, colon_error) = colon(parser)
.and_trailing_whitespace()
.unwrap_or_ast_error(parser, "This struct field is missing a colon.");
.unwrap_or_ast_error(parser, "This parameter is missing a colon.");

let (parser, type_) = type_(parser)
.and_trailing_whitespace()
.unwrap_or_ast_error(parser, "This struct field is missing a type.");
.unwrap_or_ast_error(parser, "This parameter is missing a type.");

let (parser, parser_for_missing_comma_error) =
comma(parser).map_or((parser, Some(parser)), |parser| (parser, None));
Expand Down
Loading

0 comments on commit e8f459d

Please sign in to comment.