Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into wip/jtulach/MaxSta…
Browse files Browse the repository at this point in the history
…ts10539
  • Loading branch information
JaroslavTulach committed Jul 18, 2024
2 parents 1d002b8 + c20eab2 commit 5bc4834
Show file tree
Hide file tree
Showing 23 changed files with 1,366 additions and 649 deletions.
16 changes: 4 additions & 12 deletions app/gui2/shared/ast/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,20 +668,12 @@ export class App extends Ast {
: ensureSpaced(nameSpecification.name, verbatim)
yield ensureSpacedOnlyIf(nameSpecification.equals, spacedEquals, verbatim)
}
yield ensureSpacedOnlyIf(argument, !nameSpecification || spacedEquals, verbatim)
// Some syntax trees, including many error conditions, involve unspaced applications.
// If a parsed input lacked a space before the argument, reproduce it as-is.
const verbatimArgument = true
yield ensureSpacedOnlyIf(argument, !nameSpecification || spacedEquals, verbatimArgument)
if (useParens) yield preferUnspaced(parens.close)
}

printSubtree(
info: SpanMap,
offset: number,
parentIndent: string | undefined,
verbatim?: boolean,
): string {
const verbatim_ =
verbatim ?? (this.function instanceof Invalid || this.argument instanceof Invalid)
return super.printSubtree(info, offset, parentIndent, verbatim_)
}
}
function ensureSpacedOnlyIf<T>(
child: NodeChild<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,7 @@ public void unaryMinus() throws Exception {
main = Date.new day=-
""");

assertSingleSyntaxError(
ir,
new Syntax.UnsupportedSyntax("Strange unary -"),
"Syntax is not supported yet: Strange unary -",
51,
52);
assertSingleSyntaxError(ir, Syntax.UnrecognizedToken$.MODULE$, "Unrecognized token", 51, 52);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -157,21 +159,54 @@ private Type getSupertype() {
return supertype;
}

/**
* All types this type represents including super types.
*
* @param ctx contexts to get Any type (common super class) from
* @return a compilation constant array with all types this type represents
*/
public final Type[] allTypes(EnsoContext ctx) {
if (supertype == null) {
if (builtin) {
return new Type[] {this};
var types = new Type[3];
var realCount = fillInTypes(this, types, ctx);
return Arrays.copyOf(types, realCount);
}

/**
* Fills the provided {@code fill} array with all types the {@code self} type can represent. E.g.
* including super classes.
*
* @param self the type to "enroll"
* @param fill the array to fill
* @param ctx context to obtain Any type from
* @return number of types put into the {@code fill} array
*/
@ExplodeLoop
private static int fillInTypes(Type self, Type[] fill, EnsoContext ctx) {
var at = 0;
while (at < fill.length) {
fill[at++] = self;
if (self.supertype == null) {
if (self.builtin) {
return at;
}
fill[at++] = ctx.getBuiltins().any();
return at;
}
return new Type[] {this, ctx.getBuiltins().any()};
}
if (supertype == ctx.getBuiltins().any()) {
return new Type[] {this, ctx.getBuiltins().any()};
if (self.supertype == ctx.getBuiltins().any()) {
fill[at++] = ctx.getBuiltins().any();
return at;
}
if (self == self.supertype) {
return at;
}
self = self.supertype;
}
var superTypes = supertype.allTypes(ctx);
var allTypes = new Type[superTypes.length + 1];
System.arraycopy(superTypes, 0, allTypes, 1, superTypes.length);
allTypes[0] = this;
return allTypes;
throw CompilerDirectives.shouldNotReachHere(invalidInTypes(self));
}

@CompilerDirectives.TruffleBoundary
private static String invalidInTypes(Type self) {
return "Cannot compute allTypes for " + self;
}

public void generateGetters(EnsoLanguage language) {
Expand Down
91 changes: 60 additions & 31 deletions lib/rust/parser/debug/tests/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ fn type_methods() {
"=" (BodyBlock #((Ident self))))))
];
test(&code.join("\n"), expected);
test!("[foo., bar.]",
(Array (OprSectionBoundary 1 (OprApp (Ident foo) (Ok ".") ()))
#(("," (OprSectionBoundary 1 (OprApp (Ident bar) (Ok ".") ()))))));
}

#[test]
Expand All @@ -365,6 +368,22 @@ fn type_operator_methods() {
(Function (OprApp (Ident Foo) (Ok ".") (Ident #"+"))
#((() (Ident self) () ()) (() (Ident b) () ())) () "=" (Ident b))))];
test(&code.join("\n"), expected);
test!("Any.==", (OprApp (Ident Any) (Ok ".") (Ident #"==")));
expect_invalid_node("x.-y");
expect_invalid_node("x.-1");
expect_invalid_node("x.+y");
expect_invalid_node("x.+1");
expect_invalid_node("x.+'a'");
// Compile-time operators are never operator-identifiers.
test!("x.~y", (OprApp (Ident x) (Ok ".") (UnaryOprApp "~" (Ident y))));
test!("x.~1", (OprApp (Ident x) (Ok ".") (UnaryOprApp "~" (Number () "1" ()))));
}

#[test]
fn unspaced_app() {
test!("js_set_zone arr.at(0)", (App (Ident js_set_zone)
(App (OprApp (Ident arr) (Ok ".") (Ident at))
(Group (Number () "0" ())))));
}

#[test]
Expand Down Expand Up @@ -727,16 +746,13 @@ fn first_line_indented() {

#[test]
fn multiple_operator_error() {
let code = ["x + + x"];
let expected = block![
(OprApp (Ident x) (Err (#("+" "+"))) (Ident x))
];
test(&code.join("\n"), expected);
let code = ["x + + + x"];
let expected = block![
(OprApp (Ident x) (Err (#("+" "+" "+"))) (Ident x))
];
test(&code.join("\n"), expected);
expect_multiple_operator_error("x + + x");
expect_multiple_operator_error("x + + + x");
expect_multiple_operator_error("x + +");
expect_multiple_operator_error("+ + x");
expect_multiple_operator_error("+ +");
expect_multiple_operator_error("+ -");
expect_multiple_operator_error("x + -");
}

#[test]
Expand Down Expand Up @@ -779,12 +795,9 @@ fn pipeline_operators() {
#[test]
fn accessor_operator() {
// Test that the accessor operator `.` is treated like any other operator.
let cases = [
("Console.", block![(OprSectionBoundary 1 (OprApp (Ident Console) (Ok ".") ()))]),
(".", block![(OprSectionBoundary 2 (OprApp () (Ok ".") ()))]),
(".log", block![(OprSectionBoundary 1 (OprApp () (Ok ".") (Ident log)))]),
];
cases.into_iter().for_each(|(code, expected)| test(code, expected));
test!("Console.", (OprSectionBoundary 1 (OprApp (Ident Console) (Ok ".") ())));
test!(".", (OprSectionBoundary 2 (OprApp () (Ok ".") ())));
test!(".log", (OprSectionBoundary 1 (OprApp () (Ok ".") (Ident log))));
}

#[test]
Expand All @@ -808,6 +821,21 @@ fn operator_sections() {
test("increment = 1 +", block![
(Assignment (Ident increment) "="
(OprSectionBoundary 1 (OprApp (Number () "1" ()) (Ok "+") ())))]);
test!("1+ << 2*",
(OprSectionBoundary 1
(OprApp (OprApp (Number () "1" ()) (Ok "+") ())
(Ok "<<")
(OprSectionBoundary 1 (OprApp (Number () "2" ()) (Ok "*") ())))));
test!("+1 << *2",
(OprSectionBoundary 1
(OprApp (OprApp () (Ok "+") (Number () "1" ()))
(Ok "<<")
(OprSectionBoundary 1 (OprApp () (Ok "*") (Number () "2" ()))))));
test!("+1+1 << *2*2",
(OprSectionBoundary 1
(OprApp (OprApp (OprApp () (Ok "+") (Number () "1" ())) (Ok "+") (Number () "1" ()))
(Ok "<<")
(OprSectionBoundary 1 (OprApp (OprApp () (Ok "*") (Number () "2" ())) (Ok "*") (Number () "2" ()))))));
}

#[test]
Expand Down Expand Up @@ -873,13 +901,8 @@ fn unspaced_operator_sequence() {

#[test]
fn minus_binary() {
let cases = [
("x - x", block![(OprApp (Ident x) (Ok "-") (Ident x))]),
("x-x", block![(OprApp (Ident x) (Ok "-") (Ident x))]),
("x.-y", block![(OprApp (Ident x) (Ok ".") (UnaryOprApp "-" (Ident y)))]),
("x.~y", block![(OprApp (Ident x) (Ok ".") (UnaryOprApp "~" (Ident y)))]),
];
cases.into_iter().for_each(|(code, expected)| test(code, expected));
test!("x - x", (OprApp (Ident x) (Ok "-") (Ident x)));
test!("x-x", (OprApp (Ident x) (Ok "-") (Ident x)));
}

#[test]
Expand Down Expand Up @@ -939,6 +962,8 @@ fn autoscope_operator() {
expect_invalid_node("x = f(.. ..)");
expect_invalid_node("x = f(.. *)");
expect_invalid_node("x = f(.. True)");
expect_invalid_node("x = True..");
expect_invalid_node("x = True..True");
expect_multiple_operator_error("x = ..");
expect_multiple_operator_error("x = .. True");
expect_multiple_operator_error("x : .. True");
Expand Down Expand Up @@ -1231,6 +1256,7 @@ fn old_lambdas() {
test("x -> y", block![(OprApp (Ident x) (Ok "->") (Ident y))]);
test("x->y", block![(OprApp (Ident x) (Ok "->") (Ident y))]);
test("x-> y", block![(OprApp (Ident x) (Ok "->") (Ident y))]);
test("x-> x + y", block![(OprApp (Ident x) (Ok "->") (OprApp (Ident x) (Ok "+") (Ident y)))]);
test("x->\n y", block![(OprApp (Ident x) (Ok "->") (BodyBlock #((Ident y))))]);
test("x ->\n y", block![(OprApp (Ident x) (Ok "->") (BodyBlock #((Ident y))))]);
test("f x->\n y", block![
Expand Down Expand Up @@ -1815,9 +1841,8 @@ struct Errors {
}

impl Errors {
fn collect(code: &str) -> Self {
let ast = parse(code);
expect_tree_representing_code(code, &ast);
fn collect(ast: &enso_parser::syntax::Tree, code: &str) -> Self {
expect_tree_representing_code(code, ast);
let errors = core::cell::Cell::new(Errors::default());
ast.visit_trees(|tree| match &*tree.variant {
enso_parser::syntax::tree::Variant::Invalid(_) => {
Expand All @@ -1834,18 +1859,22 @@ impl Errors {

/// Checks that an input contains an `Invalid` node somewhere.
fn expect_invalid_node(code: &str) {
let errors = Errors::collect(code);
assert!(errors.invalid_node, "{:?}", enso_parser::Parser::new().run(code));
let ast = enso_parser::Parser::new().run(code);
let errors = Errors::collect(&ast, code);
assert!(errors.invalid_node, "{}", to_s_expr(&ast, code));
}

/// Checks that an input contains a multiple-operator error somewhere.
fn expect_multiple_operator_error(code: &str) {
let errors = Errors::collect(code);
assert!(errors.multiple_operator, "{:?}", enso_parser::Parser::new().run(code));
let ast = enso_parser::Parser::new().run(code);
let errors = Errors::collect(&ast, code);
assert!(errors.multiple_operator || errors.invalid_node, "{}", to_s_expr(&ast, code));
assert!(errors.multiple_operator, "{:?}", ast);
}

/// Check that the input can be parsed, and doesn't yield any `Invalid` nodes.
fn expect_valid(code: &str) {
let errors = Errors::collect(code);
let ast = enso_parser::Parser::new().run(code);
let errors = Errors::collect(&ast, code);
assert!(!errors.invalid_node);
}
Loading

0 comments on commit 5bc4834

Please sign in to comment.