Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions crates/as2/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ impl From<ParseError<Tokens<'_>, ContextError>> for ParsingError {
pub(crate) struct ErrorSet {
files: IndexMap<String, (String, Vec<ParsingError>)>,
io_errors: Vec<(String, std::io::Error)>,
misc_errors: Vec<String>,
}

impl ErrorSet {
pub fn new() -> Self {
Self {
files: IndexMap::new(),
io_errors: vec![],
misc_errors: vec![],
}
}

Expand All @@ -60,6 +62,10 @@ impl ErrorSet {
self.io_errors.push((filename.to_owned(), error));
}

pub fn add_misc_error(&mut self, error: String) {
self.misc_errors.push(error);
}

pub fn report<'a>(&'a self) -> Vec<Group<'a>> {
let mut report = vec![];
for (filename, (source, errors)) in &self.files {
Expand All @@ -80,6 +86,13 @@ impl ErrorSet {
.element(annotate_snippets::Origin::path(filename)),
)
}
for error in &self.misc_errors {
report.push(
annotate_snippets::Level::ERROR
.primary_title(error.clone())
.element(annotate_snippets::Level::ERROR.message(error.clone())),
);
}
report
}

Expand Down
146 changes: 144 additions & 2 deletions crates/as2/src/program.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::error::{Error, ErrorSet};
use crate::hir::Document;
use crate::hir::{ConstantKind, Document, Expr, ExprKind, StatementKind};
use crate::lexer::Lexer;
use crate::resolver::resolve_hir;
use crate::{hir, parser, type_path_to_file_path};
use indexmap::IndexSet;
use rascal_common::span::Span;
use serde::Serialize;
use std::path::PathBuf;

Expand Down Expand Up @@ -128,13 +129,16 @@ impl<P: SourceProvider> ProgramBuilder<P> {
}
}

let mut entry_point_class = vec![];

while let Some(type_name) = pending_classes.pop() {
let filename = type_path_to_file_path(&type_name);
if let Some(document) = load_file(
&self.provider,
&mut errors,
&mut loaded_classes,
&mut pending_classes,
&type_path_to_file_path(&type_name),
&filename,
&type_name,
false,
) {
Expand All @@ -143,13 +147,31 @@ impl<P: SourceProvider> ProgramBuilder<P> {
interfaces.push(interface);
}
Document::Class(class) => {
if let Some(main) = class.functions.get("main")
&& main.is_static
{
entry_point_class.push(class.name.clone());
}
classes.push(*class);
}
_ => {}
}
}
}

match entry_point_class.len() {
0 => {
if initial_script.is_empty() {
errors.add_misc_error("No entry point found (either 'static function main()' inside a class, or the initial file must be a script)".to_owned());
}
}
1 => initial_script.push(call_main_method(entry_point_class.first().unwrap())),
_ => errors.add_misc_error(format!(
"Conflicting entry points found on classes: {}",
entry_point_class.join(", ")
)),
};

errors.error_unless_empty()?;

Ok(Program {
Expand All @@ -160,6 +182,46 @@ impl<P: SourceProvider> ProgramBuilder<P> {
}
}

fn call_main_method(class: &str) -> StatementKind {
let mut path = class.split(".").collect::<Vec<&str>>();
path.push("main");
let path: Vec<String> = path.into_iter().map(|s| s.to_owned()).collect();

let mut name = None;
for part in path.into_iter() {
if let Some(prev) = name.take() {
name = Some(Expr::new(
Span::default(),
ExprKind::Field(
Box::new(prev),
Box::new(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::String(part)),
)),
),
));
} else {
name = Some(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::Identifier(part)),
));
}
}
// Name has to be something, as we always added 'main' to the path
let name = name.unwrap();

StatementKind::Expr(Expr::new(
Span::default(),
ExprKind::Call {
name: Box::new(name),
args: vec![Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::This),
)],
},
))
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -202,4 +264,84 @@ mod tests {
insta::assert_snapshot!(parsed);
});
}

#[test]
fn test_main_method_simple() {
assert_eq!(
call_main_method("foo"),
StatementKind::Expr(Expr::new(
Span::default(),
ExprKind::Call {
name: Box::new(Expr::new(
Span::default(),
ExprKind::Field(
Box::new(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::Identifier("foo".to_owned()))
)),
Box::new(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::String("main".to_owned()))
))
)
)),
args: vec![Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::This)
)]
}
))
);
}

#[test]
fn test_main_method_path() {
assert_eq!(
call_main_method("foo.bar.baz"),
StatementKind::Expr(Expr::new(
Span::default(),
ExprKind::Call {
name: Box::new(Expr::new(
Span::default(),
ExprKind::Field(
Box::new(Expr::new(
Span::default(),
ExprKind::Field(
Box::new(Expr::new(
Span::default(),
ExprKind::Field(
Box::new(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::Identifier(
"foo".to_owned()
))
)),
Box::new(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::String(
"bar".to_owned()
))
))
)
)),
Box::new(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::String("baz".to_owned()))
)),
)
)),
Box::new(Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::String("main".to_owned()))
))
)
)),
args: vec![Expr::new(
Span::default(),
ExprKind::Constant(ConstantKind::This)
)]
}
))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
source: crates/as2/src/program.rs
expression: parsed
input_file: samples/as2_classes/MtascStyle.as
---
Ok:
initial_script:
- Expr:
span:
start: 0
end: 0
value:
Call:
name:
span:
start: 0
end: 0
value:
Field:
- span:
start: 0
end: 0
value:
Constant:
Identifier: MtascStyle
- span:
start: 0
end: 0
value:
Constant:
String: main
args:
- span:
start: 0
end: 0
value:
Constant: This
interfaces: []
classes:
- name: MtascStyle
extends: ~
implements: []
functions:
main:
function:
signature:
name:
span:
start: 46
end: 50
value: main
args: []
return_type: ~
body:
- Expr:
span:
start: 63
end: 84
value:
Trace:
span:
start: 69
end: 83
value:
Constant:
String: Main method!
is_static: true
virtual_properties: {}
fields: {}
constructor:
signature:
name:
span:
start: 6
end: 16
value: MtascStyle
args: []
return_type: ~
body: []
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
source: crates/as2/src/program.rs
expression: parsed
input_file: samples/as2_classes/NotMtascStyle.as
---
Ok:
initial_script: []
interfaces: []
classes:
- name: NotMtascStyle
extends: ~
implements: []
functions:
main:
function:
signature:
name:
span:
start: 42
end: 46
value: main
args: []
return_type: ~
body:
- Expr:
span:
start: 59
end: 97
value:
Trace:
span:
start: 65
end: 96
value:
Constant:
String: Not actually the main method!
is_static: false
virtual_properties: {}
fields: {}
constructor:
signature:
name:
span:
start: 6
end: 19
value: NotMtascStyle
args: []
return_type: ~
body: []
Loading