diff --git a/.maxtest.yml b/.maxtest.yml new file mode 100644 index 0000000000000..ffcf3af0338ce --- /dev/null +++ b/.maxtest.yml @@ -0,0 +1,18 @@ +suite: Maxjdoc +tests: +- name: build + tags: + - daily + commands: + - bash configure + - make jdk.javadoc + - mkdir -p ${MAXTEST_ROOT}/${BUILD_TAG}/ + - cp -vR build/linux-x86_64-server-release ${MAXTEST_ROOT}/${BUILD_TAG}/maxjdoc + sharedEnvironment: + MAXJDOC: ${MAXTEST_ROOT}/${BUILD_TAG}/maxjdoc + localEnvironment: + JAVA_HOME: /network-raid/opt/java/jdk-25.0.1 + clusterParameters: + cpus: 1.0 + mem: 1024.0 + rocky9: 1.0 diff --git a/maxj/README.md b/maxj/README.md new file mode 100644 index 0000000000000..b16f0a1891590 --- /dev/null +++ b/maxj/README.md @@ -0,0 +1,75 @@ +# MaxJ Javadoc Support + +This directory contains all MaxJ-related files for the JDK21-based javadoc tool with MaxJ syntax support. + +## Directory Structure + +``` +maxj/ +├── README.md # This file +├── TESTING.md # Comprehensive testing guide +└── testing/ # All testing-related files + ├── test-simple.sh # Quick MaxJ syntax verification + ├── test-javadoc.sh # Comprehensive test suite + ├── test-operators.sh # MaxJ operator-specific tests + ├── test-files/ # Test files for MaxJ syntax + │ ├── README.md # Detailed test file documentation + │ ├── *.maxj # MaxJ syntax test files + │ └── *.java # Java compatibility test files + └── output/ # Generated test documentation output +``` + +## Quick Start + +### Run Simple Test +```bash +./maxj/testing/test-simple.sh +``` + +### Run Comprehensive Test Suite +```bash +./maxj/testing/test-javadoc.sh +``` + +### Manual Testing +```bash +# Test a single MaxJ file +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./maxj/testing/output/manual-test \ + maxj/testing/test-files/ComprehensiveMaxJSyntaxTest.maxj +``` + +## MaxJ Syntax Support + +This javadoc implementation supports: + +### Keywords +- `SWITCH (expr) { ... }` - MaxJ switch statement +- `CASE (value) { ... }` - MaxJ case block +- `OTHERWISE { ... }` - MaxJ default case +- `IF (condition) { ... } ELSE { ... }` - MaxJ conditionals + +### Operators +- `===` - MaxJ triple equality +- `#` - MaxJ concatenation +- `<==` - MaxJ connection/assignment + +### Features +- ✅ Nested SWITCH/CASE structures +- ✅ Complex IF/ELSE chains +- ✅ Expression-based CASE values +- ✅ Mixed MaxJ and Java syntax +- ✅ Case-sensitive parsing (no conflicts with Java keywords) + +## Documentation + +- **[TESTING.md](TESTING.md)** - Complete testing guide with examples +- **[testing/test-files/README.md](testing/test-files/README.md)** - Detailed test file documentation + +## File Extensions + +- `.maxj` files - Use MaxJ syntax parsing +- `.java` files - Use standard Java syntax parsing + +Both file types can be processed by the same javadoc tool without conflicts. \ No newline at end of file diff --git a/maxj/TESTING.md b/maxj/TESTING.md new file mode 100644 index 0000000000000..e69e5a8775d46 --- /dev/null +++ b/maxj/TESTING.md @@ -0,0 +1,121 @@ +# MaxJ Javadoc Testing Guide + +## Quick Test + +Run the simple test script: +```bash +./maxj/testing/test-simple.sh +``` + +## Comprehensive Test + +Run the full test suite: +```bash +./maxj/testing/test-javadoc.sh +``` + +## Manual Testing Examples + +### Test MaxJ Files (.maxj extension) +```bash +# Single MaxJ file +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./maxj/testing/output/single-maxj \ + maxj/testing/test-files/ComprehensiveMaxJSyntaxTest.maxj + +# Multiple MaxJ files +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./maxj/testing/output/multi-maxj \ + maxj/testing/test-files/*.maxj + +# Real MaxJ project (expect dependency errors but no syntax errors) +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./out/real-project \ + ../maxelercore/platforms/tests-it/src/tests/maxring/MaxRingNoCPULoopbackTest.maxj +``` + +### Test Java Files (.java extension) +```bash +# Single Java file +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./maxj/testing/output/single-java \ + maxj/testing/test-files/StandardJavaSyntaxTest.java + +# Multiple Java files +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./maxj/testing/output/multi-java \ + maxj/testing/test-files/*.java +``` + +## MaxJ Syntax Elements Supported + +### Keywords +- `SWITCH (expr) { ... }` - MaxJ switch statement +- `CASE (value) { ... }` - MaxJ case block +- `OTHERWISE { ... }` - MaxJ default case +- `IF (condition) { ... } ELSE { ... }` - MaxJ conditionals + +### Operators +- `===` - MaxJ triple equality +- `#` - MaxJ concatenation +- `<==` - MaxJ connection/assignment + +### Features +- ✅ Nested SWITCH/CASE structures +- ✅ Complex IF/ELSE chains +- ✅ Expression-based CASE values +- ✅ Mixed MaxJ and Java syntax +- ✅ Case-sensitive parsing (no conflicts with Java keywords) + +## Expected Behavior + +### ✅ Success Cases +- `.maxj` files with MaxJ syntax → Perfect parsing, docs generated +- `.java` files with Java syntax → Perfect parsing, docs generated +- Mixed usage → Both syntaxes work independently + +### ⚠️ Expected Issues +- **Dependency errors** in real MaxJ projects (missing MaxJ compiler libraries) +- **HTML warnings** in javadoc comments containing `<==` (parsed as HTML) +- **Filename warnings** for public classes in `.maxj` files (expects `.java`) + +### ❌ Should Not Happen +- Syntax errors on MaxJ keywords in `.maxj` files +- Syntax errors on Java keywords in `.java` files +- Keyword conflicts between MaxJ and Java syntax + +## Verification Commands + +Check that documentation was generated: +```bash +ls -la maxj/testing/output/ +find maxj/testing/output/ -name "*.html" | wc -l +``` + +View generated documentation: +```bash +open maxj/testing/output/maxj/maxjtest/ComprehensiveMaxJSyntaxTest.html +open maxj/testing/output/java/javatest/StandardJavaSyntaxTest.html +``` + +## Test File Details + +| File | Extension | Purpose | Key Features Tested | +|------|-----------|---------|-------------------| +| `ComprehensiveMaxJSyntaxTest.maxj` | `.maxj` | Complete MaxJ syntax | All keywords, operators, nesting | +| `MAXJSwitchEdgeCases.maxj` | `.maxj` | MaxJ edge cases | Complex switch scenarios | +| `StandardJavaSyntaxTest.java` | `.java` | Java compatibility | Modern Java features, operators | +| `KeywordConflictTest.java` | `.java` | Conflict testing | Case sensitivity, no collisions | + +## Success Criteria + +The MaxJ javadoc implementation is successful if: +1. All test scripts pass without syntax errors +2. Documentation is generated for both `.maxj` and `.java` files +3. MaxJ and Java syntax coexist without conflicts +4. Real MaxJ projects parse syntactically (dependencies may fail) diff --git a/maxj/testing/.gitignore b/maxj/testing/.gitignore new file mode 100644 index 0000000000000..16be8f2193ead --- /dev/null +++ b/maxj/testing/.gitignore @@ -0,0 +1 @@ +/output/ diff --git a/maxj/testing/test-files/AllMaxJOperatorsTest.maxj b/maxj/testing/test-files/AllMaxJOperatorsTest.maxj new file mode 100644 index 0000000000000..0175f26692dff --- /dev/null +++ b/maxj/testing/test-files/AllMaxJOperatorsTest.maxj @@ -0,0 +1,234 @@ +package maxjoperators; + +/** + * Complete MaxJ Operator Test + * + * This file tests ALL MaxJ operators to ensure they parse correctly: + * - Triple equals (===) for equality comparison + * - Concatenation (#) for joining values + * - Connection (<==) for hardware assignments + * + * @author MaxJ Operator Test + * @version 1.0 + */ +public class AllMaxJOperatorsTest { + + /** + * Tests the MaxJ triple equals operator (===). + * This is different from Java's double equals (==). + * + * @param a first value + * @param b second value + * @return true if values are MaxJ-equal + */ + public boolean testTripleEquals(int a, int b) { + boolean result = false; + + // MaxJ triple equals operator + IF (a === b) { + result = true; + } ELSE { + result = false; + } + + // Test in switch context + SWITCH (a) { + CASE (1) { + IF (b === 1) { + result = true; + } + } + CASE (2) { + IF (b === 2) { + result = true; + } + } + OTHERWISE { + result = (a === b); + } + } + + return result; + } + + /** + * Tests the MaxJ concatenation operator (#). + * Used for joining or concatenating values. + * + * @param left left operand + * @param right right operand + * @return concatenated result + */ + public int testConcatenation(int left, int right) { + int result = 0; + + // Basic concatenation + result = left # right; + + // Concatenation in expressions + int complex = (left + 1) # (right * 2); + + // Concatenation in control flow + SWITCH (left # right) { + CASE (0) { + result = 100; + } + OTHERWISE { + result = left # right # 999; + } + } + + // Chain concatenation + int chain = left # right # left # right; + + return result + complex + chain; + } + + /** + * Tests the MaxJ connection operator (<==). + * Used for hardware signal connections and assignments. + * + * @param input input signal value + * @param clock clock signal + * @return output value + */ + public int testConnectionOperator(int input, boolean clock) { + int output = 0; + int register = 0; + + // In real MaxJ hardware code, this would be: + // output <== input; + // register <== clock ? input : register; + + // For javadoc parsing test, we simulate the syntax + // The key is that the parser recognizes <== as a valid operator + + // Connection in conditional context + IF (clock === true) { + // output <== input; // Would be valid MaxJ syntax + output = input; // Java equivalent for this test + } ELSE { + // output <== register; // Would be valid MaxJ syntax + output = register; // Java equivalent for this test + } + + // Connection in switch context + SWITCH (input) { + CASE (1) { + // register <== 10; // Would be valid MaxJ syntax + register = 10; // Java equivalent for this test + } + CASE (2) { + // register <== 20; // Would be valid MaxJ syntax + register = 20; // Java equivalent for this test + } + OTHERWISE { + // register <== input; // Would be valid MaxJ syntax + register = input; // Java equivalent for this test + } + } + + return output + register; + } + + /** + * Tests combined usage of all MaxJ operators. + * Demonstrates complex expressions using multiple operators. + * + * @param a first input + * @param b second input + * @param c third input + * @return combined result + */ + public int testCombinedOperators(int a, int b, int c) { + int result = 0; + + // Combine === and # + IF ((a # b) === (b # c)) { + result = 1; + } ELSE { + result = 0; + } + + // Complex nested operator usage + SWITCH (a # b # c) { + CASE (123) { + IF (a === 1) { + result = result # 100; + } ELSE { + result = result # 200; + } + } + + OTHERWISE { + IF ((a # b) === (c # a)) { + result = a # b # c # 999; + } ELSE { + result = (a === b) ? (b # c) : (a # c); + } + } + } + + return result; + } + + /** + * Tests operator precedence and associativity. + * Ensures MaxJ operators work correctly with standard Java operators. + * + * @param x input value + * @param y input value + * @return precedence test result + */ + public boolean testOperatorPrecedence(int x, int y) { + // Test precedence of === with other operators + boolean test1 = (x + y) === (y + x); // === after arithmetic + boolean test2 = x === y && y === x; // === with logical AND + boolean test3 = x === y || x === 0; // === with logical OR + + // Test precedence of # with other operators + int concat1 = x # y + 1; // # with arithmetic + int concat2 = (x + 1) # (y + 1); // parentheses with # + + // Combined tests + IF (test1 === true) { + return (concat1 # concat2) === (x # y # (x + y)); + } ELSE { + return test2 || test3; + } + } + + /** + * Tests edge cases for MaxJ operators. + * + * @param value test value + * @return edge case results + */ + public int testOperatorEdgeCases(int value) { + int result = 0; + + // Zero and negative values with === + IF (value === 0) { + result = 1; + } ELSE { + IF (value === -1) { + result = -1; + } ELSE { + result = value; + } + } + + // Concatenation with zero and negatives + int negativeConcat = (-1) # value; + int zeroConcat = 0 # value; + + // Chained equality tests + IF (value === 5 && negativeConcat === (-1 # 5)) { + result = zeroConcat # negativeConcat; + } ELSE { + result = value # 0; + } + + return result; + } +} diff --git a/maxj/testing/test-files/ComprehensiveMaxJSyntaxTest.maxj b/maxj/testing/test-files/ComprehensiveMaxJSyntaxTest.maxj new file mode 100644 index 0000000000000..b68f36638ab2d --- /dev/null +++ b/maxj/testing/test-files/ComprehensiveMaxJSyntaxTest.maxj @@ -0,0 +1,298 @@ +package maxjtest; + +/** + * Comprehensive MaxJ Syntax Test for Javadoc Generation + * + * This file tests ALL MaxJ-specific syntax elements to verify that the + * javadoc tool can successfully parse MaxJ code in JDK21. + * + * MaxJ syntax elements tested: + * - SWITCH/CASE/OTHERWISE control flow + * - IF/ELSE conditional statements + * - MaxJ operators: connection (<==), equality (===), concatenation (#) + * - Array slicing syntax + * - Nested structures + * - Complex expressions + * + * @author MaxJ Parser Test + * @version 1.0 + */ +public class ComprehensiveMaxJSyntaxTest { + + /** + * Tests all MaxJ control flow constructs. + * Demonstrates SWITCH, CASE, OTHERWISE keywords. + * + * @param controlValue the switch control expression + * @param conditionalValue value for IF/ELSE testing + * @return result based on control flow + */ + public int testControlFlow(int controlValue, int conditionalValue) { + int result = 0; + + // MaxJ SWITCH statement with multiple CASE values + SWITCH (controlValue) { + CASE (1) { + result = 100; + + // Nested MaxJ IF/ELSE inside CASE + IF (conditionalValue > 50) { + result = result + 10; + } ELSE { + result = result - 10; + } + } + + CASE (2) { + result = 200; + + // Nested SWITCH inside CASE + SWITCH (conditionalValue) { + CASE (10) { + result = result + 1; + } + CASE (20) { + result = result + 2; + } + OTHERWISE { + result = result + 999; + } + } + } + + CASE (3) { + // Multiple IF/ELSE chains + IF (conditionalValue === 5) { + result = 301; + } ELSE { + IF (conditionalValue === 10) { + result = 302; + } ELSE { + result = 303; + } + } + } + + OTHERWISE { + result = -1; + } + } + + return result; + } + + /** + * Tests MaxJ operators and expressions. + * Demonstrates triple equals (===), concatenation (#) operators. + * + * @param a first operand + * @param b second operand + * @param arr array for testing + * @return concatenated result using # operator + */ + public int testMaxJOperators(int a, int b, int[] arr) { + int result = 0; + + // MaxJ triple equals operator + IF (a === b) { + result = 1; + } ELSE { + result = 0; + } + + // MaxJ concatenation operator # + result = a # b; // Concatenate a and b + + return result; + } + + /** + * Tests MaxJ connection operator and assignment patterns. + * Note: The connection operator is typically used in hardware context. + * + * @param input input value + * @param output output reference + * @return connection result + */ + public int testConnectionOperator(int input, int output) { + // MaxJ connection/assignment operator would be used like: + // output <== input; + // But for javadoc parsing test, we'll just return a value + return input; + } + + /** + * Tests complex nested MaxJ syntax combinations. + * Demonstrates deep nesting and complex control flow. + * + * @param mode operating mode + * @param level nesting level + * @param data input data array + * @return processed result + */ + public int testComplexNesting(int mode, int level, int[] data) { + int finalResult = 0; + + SWITCH (mode) { + CASE (1) { + // Complex nested structure + IF (level > 0) { + SWITCH (level) { + CASE (1) { + IF (data.length === 10) { + finalResult = 111; + } ELSE { + IF (data.length === 5) { + finalResult = 115; + } ELSE { + finalResult = 119; + } + } + } + + CASE (2) { + // Multiple operations with MaxJ operators + int temp = data[0] # data[1]; + IF (temp === 42) { + finalResult = 221; + } ELSE { + finalResult = 229; + } + } + + OTHERWISE { + finalResult = 299; + } + } + } ELSE { + finalResult = 99; + } + } + + CASE (2) { + // Test MaxJ operators in expressions + for (int i = 0; i < data.length; i++) { + IF (data[i] === i) { + finalResult = finalResult # i; + } ELSE { + finalResult = finalResult + i; + } + } + } + + OTHERWISE { + // Default case with complex logic + IF (level === 0) { + finalResult = -1; + } ELSE { + IF (level === 1) { + finalResult = -2; + } ELSE { + IF (level === 2) { + finalResult = -3; + } ELSE { + finalResult = -999; + } + } + } + } + } + + return finalResult; + } + + /** + * Tests edge cases and unusual syntax combinations. + * + * @param value test value + * @param flag boolean flag + * @return edge case result + */ + public boolean testEdgeCases(int value, boolean flag) { + boolean result = false; + + // Empty CASE blocks + SWITCH (value) { + CASE (1) { + // Empty case + } + CASE (2) { + result = true; + } + OTHERWISE { + // Empty otherwise + } + } + + // Multiple consecutive comparisons + IF (value === 1) { + result = true; + } ELSE { + IF (value === 2) { + result = true; + } ELSE { + IF (value === 3) { + result = true; + } ELSE { + result = false; + } + } + } + + return result; + } + + /** + * Tests MaxJ syntax with standard Java constructs. + * Verifies that MaxJ and standard Java syntax can coexist. + * + * @param maxjValue value for MaxJ constructs + * @param javaValue value for Java constructs + * @return mixed result + */ + public int testMixedSyntax(int maxjValue, int javaValue) { + int result = 0; + + // Standard Java switch + switch (javaValue) { + case 1: + result += 10; + break; + case 2: + result += 20; + break; + default: + result += 5; + break; + } + + // MaxJ SWITCH + SWITCH (maxjValue) { + CASE (1) { + result = result # 100; + } + CASE (2) { + result = result # 200; + } + OTHERWISE { + result = result # 999; + } + } + + // Standard Java if/else + if (javaValue > 0) { + result += 1; + } else { + result -= 1; + } + + // MaxJ IF/ELSE + IF (maxjValue === 42) { + result = result # 42; + } ELSE { + result = result # 0; + } + + return result; + } +} diff --git a/maxj/testing/test-files/KeywordConflictTest.java b/maxj/testing/test-files/KeywordConflictTest.java new file mode 100644 index 0000000000000..5bb39ade403ef --- /dev/null +++ b/maxj/testing/test-files/KeywordConflictTest.java @@ -0,0 +1,129 @@ +package conflicttest; + +/** + * Tests potential keyword conflicts between MaxJ and Java. + * This ensures that adding MaxJ keywords doesn't break standard Java. + */ +public class KeywordConflictTest { + + /** + * Tests that lowercase Java keywords work correctly. + * MaxJ uses uppercase (CASE, SWITCH, IF, ELSE) so this should be fine. + */ + public void testLowercaseKeywords() { + int value = 5; + + // Standard Java 'case' should work (vs MaxJ 'CASE') + switch (value) { + case 1: + System.out.println("Java case 1"); + break; + case 5: + System.out.println("Java case 5"); + break; + default: + System.out.println("Java default"); + break; + } + + // Standard Java 'if'/'else' should work (vs MaxJ 'IF'/'ELSE') + if (value == 5) { + System.out.println("Java if works"); + } else { + System.out.println("Java else works"); + } + + // Standard Java 'switch' expression should work (vs MaxJ 'SWITCH') + String result = switch (value) { + case 1, 2 -> "low"; + case 3, 4 -> "medium"; + case 5, 6 -> "high"; + default -> "unknown"; + }; + + System.out.println("Switch expression: " + result); + } + + /** + * Tests Java operators that might conflict with MaxJ operators. + * Java == vs MaxJ ===, Java assignment = vs MaxJ <== + */ + public void testOperatorConflicts() { + int a = 10; + int b = 10; + + // Java equality (==) should work normally + boolean equal = (a == b); // Should not be confused with MaxJ === + boolean notEqual = (a != b); + + // Java assignment (=) should work normally + int c = a; // Should not be confused with MaxJ <== + c += b; + + // Java comparison operators + boolean greater = (a > b); + boolean less = (a < b); + boolean greaterEqual = (a >= b); + boolean lessEqual = (a <= b); + + System.out.println("All Java operators work: " + equal); + } + + /** + * Tests case sensitivity - very important for keyword conflicts. + * Java is case-sensitive, so 'case' != 'CASE'. + */ + public void testCaseSensitivity() { + String test = "case"; // lowercase + + // This should compile fine - 'case' is Java keyword, 'CASE' is MaxJ + switch (test) { + case "case": + System.out.println("Lowercase case works"); + break; + case "switch": + System.out.println("Lowercase switch works"); + break; + default: + System.out.println("Default works"); + break; + } + + // Variables named similar to MaxJ keywords should work + int IF = 1; // Variable named 'IF' (MaxJ keyword) + int CASE = 2; // Variable named 'CASE' (MaxJ keyword) + int SWITCH = 3; // Variable named 'SWITCH' (MaxJ keyword) + int ELSE = 4; // Variable named 'ELSE' (MaxJ keyword) + + System.out.println("Variables with MaxJ keyword names: " + (IF + CASE + SWITCH + ELSE)); + } + + /** + * Tests edge case: methods named with MaxJ keywords. + */ + public void IF() { + System.out.println("Method named IF works"); + } + + public void CASE() { + System.out.println("Method named CASE works"); + } + + public void SWITCH() { + System.out.println("Method named SWITCH works"); + } + + public void OTHERWISE() { + System.out.println("Method named OTHERWISE works"); + } + + /** + * Tests that we can call methods with MaxJ keyword names. + */ + public void testMaxJKeywordMethodCalls() { + IF(); + CASE(); + SWITCH(); + OTHERWISE(); + } +} diff --git a/maxj/testing/test-files/MAXJSwitchEdgeCases.maxj b/maxj/testing/test-files/MAXJSwitchEdgeCases.maxj new file mode 100644 index 0000000000000..2790aeb306cc7 --- /dev/null +++ b/maxj/testing/test-files/MAXJSwitchEdgeCases.maxj @@ -0,0 +1,93 @@ +/** + * MAXJ Switch Edge Cases Test + * Tests various edge cases and nested scenarios + */ +public class MAXJSwitchEdgeCases { + + /** + * Test nested MAXJ switches + * @param outer outer switch value + * @param inner inner switch value + */ + public void testNestedSwitches(int outer, int inner) { + SWITCH (outer) { + CASE 1 { + System.out.println("Outer case 1"); + SWITCH (inner) { + CASE 10 { + System.out.println("Inner case 10"); + } + CASE 20 { + System.out.println("Inner case 20"); + } + OTHERWISE { + System.out.println("Inner default"); + } + } + } + CASE 2 { + System.out.println("Outer case 2"); + } + OTHERWISE { + System.out.println("Outer default"); + } + } + } + + /** + * Test MAXJ switch with expressions as case values + */ + public void testExpressionCases() { + int base = 10; + int value = 25; + + SWITCH (value) { + CASE base + 5 { + System.out.println("Case 15"); + } + CASE base * 2 { + System.out.println("Case 20"); + } + CASE base + 15 { + System.out.println("Case 25"); + } + OTHERWISE { + System.out.println("No match"); + } + } + } + + /** + * Test MAXJ switch with string values + */ + public void testStringSwitch(String input) { + SWITCH (input) { + CASE "hello" { + System.out.println("Greeting"); + } + CASE "goodbye" { + System.out.println("Farewell"); + } + OTHERWISE { + System.out.println("Unknown: " + input); + } + } + } + + /** + * Test empty cases + */ + public void testEmptyCases(int value) { + SWITCH (value) { + CASE 1 { + // Empty case - should compile fine + } + CASE 2 { + System.out.println("Case 2"); + } + OTHERWISE { + // Empty default + } + } + } +} \ No newline at end of file diff --git a/maxj/testing/test-files/MaxJConnectionOperatorTest.maxj b/maxj/testing/test-files/MaxJConnectionOperatorTest.maxj new file mode 100644 index 0000000000000..4705ac2258203 --- /dev/null +++ b/maxj/testing/test-files/MaxJConnectionOperatorTest.maxj @@ -0,0 +1,192 @@ +package maxjconnection; + +/** + * MaxJ Connection Operator Test (<==) + * + * This tests the MaxJ connection operator which is used for + * hardware signal assignments and state machine connections. + * + * @author MaxJ Connection Test + */ +public class MaxJConnectionOperatorTest { + + // Mock hardware signal classes for testing + public static class Signal { + public int value; + public Signal next; + public boolean valid; + } + + public static class Output { + public boolean valid; + public boolean stall; + } + + /** + * Tests basic MaxJ connection operator usage. + * This syntax is commonly used in MaxJ state machines. + * + * @param input input signal + * @param state current state + * @return processed output + */ + public int testBasicConnections(Signal input, Signal state) { + Output output = new Output(); + int result = 0; + + // Basic MaxJ connection syntax + output.valid <== true; + state.next <== input; + + // Connection in conditional context + IF (input.value === 5) { + output.valid <== true; + state.next.value <== 10; + } ELSE { + output.valid <== false; + state.next.value <== 0; + } + + return result; + } + + /** + * Tests connection operator in switch statements. + * Demonstrates hardware state machine patterns. + * + * @param currentState current state value + * @param inputData input data + * @return next state value + */ + public int testConnectionsInSwitch(int currentState, int inputData) { + Signal nextState = new Signal(); + Output dataOutput = new Output(); + Signal dataRegister = new Signal(); + + SWITCH (currentState) { + CASE (0) { + // State machine connections + dataOutput.valid <== false; + nextState.value <== 1; + dataRegister.next.value <== 0; + } + + CASE (1) { + dataOutput.valid <== true; + dataRegister.next.value <== inputData; + + IF (inputData === 42) { + nextState.value <== 2; + } ELSE { + nextState.value <== 1; + } + } + + CASE (2) { + dataOutput.valid <== false; + nextState.value <== 0; + dataRegister.next.value <== dataRegister.value # inputData; + } + + OTHERWISE { + dataOutput.valid <== false; + nextState.value <== 0; + dataRegister.next.value <== 0; + } + } + + return nextState.value; + } + + /** + * Tests complex connection patterns. + * Combines connection operator with other MaxJ operators. + * + * @param mode operating mode + * @param data input data array + * @return connection result + */ + public boolean testComplexConnections(int mode, int[] data) { + Signal[] registers = new Signal[3]; + Output[] outputs = new Output[3]; + boolean result = false; + + for (int i = 0; i < registers.length; i++) { + registers[i] = new Signal(); + outputs[i] = new Output(); + } + + SWITCH (mode) { + CASE (1) { + // Pipeline connections + for (int i = 0; i < data.length && i < 3; i++) { + registers[i].next.value <== data[i]; + outputs[i].valid <== (data[i] === i); + + IF (i > 0) { + registers[i].next.value <== registers[i-1].value # data[i]; + } ELSE { + registers[i].next.value <== data[i]; + } + } + result = true; + } + + CASE (2) { + // Conditional connections + IF (data.length === 3) { + registers[0].next.value <== data[0] # data[1] # data[2]; + outputs[0].valid <== true; + } ELSE { + registers[0].next.value <== 0; + outputs[0].valid <== false; + } + result = outputs[0].valid; + } + + OTHERWISE { + // Default connections + for (int i = 0; i < 3; i++) { + registers[i].next.value <== 0; + outputs[i].valid <== false; + } + result = false; + } + } + + return result; + } + + /** + * Tests that connection operator doesn't conflict with comparison operators. + * Important: <== vs <= vs < vs == + * + * @param a first value + * @param b second value + * @return comparison results + */ + public boolean testOperatorDistinction(int a, int b) { + Signal signal = new Signal(); + + // Standard Java comparisons should still work + boolean lessThan = (a < b); + boolean lessEqual = (a <= b); + boolean equal = (a == b); + + // MaxJ operators should work + boolean maxjEqual = (a === b); + + // MaxJ connection (this is the key test!) + signal.next.value <== a; + signal.value <== b; + + // Combined test + IF (maxjEqual === true) { + signal.next.value <== a # b; + return true; + } ELSE { + signal.next.value <== 0; + return lessThan || lessEqual || equal; + } + } +} diff --git a/maxj/testing/test-files/README.md b/maxj/testing/test-files/README.md new file mode 100644 index 0000000000000..364381f25eb5a --- /dev/null +++ b/maxj/testing/test-files/README.md @@ -0,0 +1,144 @@ +# MaxJ Javadoc Test Suite + +This directory contains comprehensive tests for MaxJ syntax support in the JDK21-based javadoc tool. + +## Test Files + +### MaxJ Syntax Tests (.maxj files) +- **`ComprehensiveMaxJSyntaxTest.maxj`** - Complete MaxJ syntax test including: + - SWITCH/CASE/OTHERWISE control flow + - IF/ELSE conditional statements + - MaxJ operators: `===`, `#`, `<==` + - Nested structures and complex expressions + - Mixed MaxJ and standard Java syntax + +- **`MAXJSwitchEdgeCases.maxj`** - Edge cases for MaxJ switch statements: + - Nested switches + - Expression-based case values + - String switches + - Empty cases + +### Java Compatibility Tests (.java files) +- **`StandardJavaSyntaxTest.java`** - Verifies standard Java functionality: + - Modern Java features (records, sealed classes, pattern matching) + - All Java operators and control flow + - Generics, lambdas, streams + - Switch expressions (JDK 12+) + +- **`KeywordConflictTest.java`** - Tests for keyword conflicts: + - Case sensitivity (java `case` vs MaxJ `CASE`) + - Operator conflicts (java `==` vs MaxJ `===`) + - Variables and methods named with MaxJ keywords + - Mixed usage scenarios + +## Running Tests + +### Quick Test +```bash +./maxj/testing/test-javadoc.sh +``` + +### Manual Testing + +**Test MaxJ files:** +```bash +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./maxj/testing/output/maxj-test \ + maxj/testing/test-files/ComprehensiveMaxJSyntaxTest.maxj +``` + +**Test Java files:** +```bash +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./maxj/testing/output/java-test \ + maxj/testing/test-files/StandardJavaSyntaxTest.java +``` + +**Test real MaxJ project files:** +```bash +./build/macosx-aarch64-server-release/jdk/bin/javadoc \ + -Xdoclint:none -quiet -private \ + -d ./out/real-maxj \ + ../maxelercore/**/*.maxj +``` + +## MaxJ Syntax Elements Tested + +### Control Flow Keywords +- `SWITCH (expression) { ... }` - MaxJ switch statement +- `CASE (value) { ... }` - MaxJ case block +- `OTHERWISE { ... }` - MaxJ default case +- `IF (condition) { ... } ELSE { ... }` - MaxJ conditional + +### Operators +- `===` - MaxJ triple equality operator +- `#` - MaxJ concatenation operator +- `<==` - MaxJ connection/assignment operator + +### Advanced Features +- Nested SWITCH/CASE structures +- Complex IF/ELSE chains +- Expression-based CASE values +- Empty CASE blocks +- Mixed MaxJ and standard Java syntax + +## Expected Results + +### Successful Tests +- ✅ All MaxJ syntax should parse without syntax errors +- ✅ Standard Java syntax should remain fully functional +- ✅ No keyword conflicts between MaxJ and Java +- ✅ Documentation generated for all test cases + +### Expected Issues +- Dependency errors for real MaxJ project files (normal - missing MaxJ libraries) +- HTML warnings in javadoc comments containing `<==` (treated as HTML tags) + +## Troubleshooting + +If tests fail: + +1. **Build the project first:** + ```bash + make clean && make + ``` + +2. **Check javadoc path:** + ```bash + ls -la build/macosx-aarch64-server-release/jdk/bin/javadoc + ``` + +3. **Run individual tests manually** to see detailed error messages + +4. **Check generated documentation:** + ```bash + open maxj/testing/output/comprehensive-maxj/maxjtest/ComprehensiveMaxJSyntaxTest.html + ``` + +## File Structure + +``` +maxjdoc/ +├── maxj/ # MaxJ support directory +│ ├── README.md # Main MaxJ documentation +│ ├── TESTING.md # Testing guide +│ └── testing/ # All testing-related files +│ ├── test-simple.sh # Quick test +│ ├── test-javadoc.sh # Comprehensive test +│ ├── test-operators.sh # Operator test +│ ├── test-files/ # Test files +│ │ ├── README.md # This file +│ │ ├── ComprehensiveMaxJSyntaxTest.maxj +│ │ ├── MAXJSwitchEdgeCases.maxj +│ │ ├── StandardJavaSyntaxTest.java +│ │ └── KeywordConflictTest.java +│ └── output/ # Generated documentation +│ ├── comprehensive-maxj/ +│ ├── edge-cases-maxj/ +│ ├── standard-java/ +│ ├── keyword-conflicts/ +│ ├── multiple-java/ +│ └── multiple-maxj/ +``` diff --git a/maxj/testing/test-files/StandardJavaSyntaxTest.java b/maxj/testing/test-files/StandardJavaSyntaxTest.java new file mode 100644 index 0000000000000..85c3c72fd318f --- /dev/null +++ b/maxj/testing/test-files/StandardJavaSyntaxTest.java @@ -0,0 +1,337 @@ +package javatest; + +import java.util.*; +import java.io.*; + +/** + * Standard Java Syntax Test for Javadoc Generation + * + * This file tests that standard Java syntax still works perfectly + * after adding MaxJ support to the javadoc tool. + * + * Tests include: + * - Standard Java control flow (switch/case/default, if/else) + * - All Java operators and expressions + * - Modern Java features (records, sealed classes, pattern matching) + * - Generics, lambdas, streams + * - Annotations and reflection + * + * @author Standard Java Test + * @version 1.0 + * @since JDK21 + */ +public class StandardJavaSyntaxTest { + + /** + * Tests standard Java switch statements and expressions. + * Verifies no conflicts with MaxJ SWITCH/CASE syntax. + * + * @param value the switch control value + * @param stringValue string for switch expression test + * @return result from switch processing + */ + public int testJavaSwitchStatements(int value, String stringValue) { + int result = 0; + + // Traditional switch statement + switch (value) { + case 1: + result = 10; + break; + case 2: + result = 20; + break; + case 3: + case 4: + result = 30; + break; + default: + result = -1; + break; + } + + // Modern switch expression (JDK 12+) + result += switch (value) { + case 1 -> 100; + case 2 -> 200; + case 3, 4 -> 300; + default -> 0; + }; + + // String switch + int stringResult = switch (stringValue) { + case "hello" -> 1; + case "world" -> 2; + case "java" -> 3; + default -> 0; + }; + + return result + stringResult; + } + + /** + * Tests standard Java conditional statements. + * Verifies no conflicts with MaxJ IF/ELSE syntax. + * + * @param condition boolean condition + * @param value integer value + * @return conditional result + */ + public boolean testJavaConditionals(boolean condition, int value) { + boolean result = false; + + // Standard if/else + if (condition) { + result = true; + } else { + result = false; + } + + // Nested if/else + if (value > 0) { + if (value < 10) { + result = true; + } else if (value < 100) { + result = false; + } else { + result = true; + } + } else { + result = false; + } + + // Ternary operator + result = condition ? true : false; + + return result; + } + + /** + * Tests all Java operators to ensure no conflicts. + * Particularly important to test == vs MaxJ ===. + * + * @param a first operand + * @param b second operand + * @return operator test results + */ + public boolean testJavaOperators(int a, int b) { + // Arithmetic operators + int sum = a + b; + int diff = a - b; + int product = a * b; + int quotient = b != 0 ? a / b : 0; + int remainder = b != 0 ? a % b : 0; + + // Comparison operators (ensure == works, not confused with ===) + boolean equal = (a == b); + boolean notEqual = (a != b); + boolean greater = (a > b); + boolean less = (a < b); + boolean greaterEqual = (a >= b); + boolean lessEqual = (a <= b); + + // Logical operators + boolean andResult = (a > 0) && (b > 0); + boolean orResult = (a > 0) || (b > 0); + boolean notResult = !(a > 0); + + // Bitwise operators + int bitwiseAnd = a & b; + int bitwiseOr = a | b; + int bitwiseXor = a ^ b; + int bitwiseNot = ~a; + int leftShift = a << 1; + int rightShift = a >> 1; + int unsignedRightShift = a >>> 1; + + // Assignment operators + int temp = a; + temp += b; + temp -= b; + temp *= 2; + temp /= 2; + temp %= 3; + temp &= 0xFF; + temp |= 0x10; + temp ^= 0x01; + temp <<= 1; + temp >>= 1; + temp >>>= 1; + + return equal && !notEqual; + } + + /** + * Tests modern Java features to ensure compatibility. + * + * @param the generic type parameter + * @param obj generic object + * @param list generic list + * @return feature test result + */ + public boolean testModernJavaFeatures(T obj, List list) { + // Generics + List strings = new ArrayList<>(); + Map map = new HashMap<>(); + + // Lambda expressions + list.stream() + .filter(Objects::nonNull) + .map(Object::toString) + .forEach(System.out::println); + + // Pattern matching instanceof (JDK 16+) + if (obj instanceof String s) { + System.out.println("String length: " + s.length()); + return true; + } + + // Text blocks (JDK 15+) + String textBlock = """ + This is a text block + with multiple lines + """; + + return !textBlock.isEmpty(); + } + + /** + * Tests record classes (JDK 14+). + * @param x the x coordinate + * @param y the y coordinate + */ + public record Point(int x, int y) { + /** + * Static method in record. + * @return new Point at origin + */ + public static Point origin() { + return new Point(0, 0); + } + } + + /** + * Tests sealed classes (JDK 17+). + */ + public sealed interface Shape permits Circle, Rectangle { + double area(); + } + + /** + * Circle implementation of sealed interface. + */ + public static final class Circle implements Shape { + private final double radius; + + public Circle(double radius) { + this.radius = radius; + } + + @Override + public double area() { + return Math.PI * radius * radius; + } + } + + /** + * Rectangle implementation of sealed interface. + */ + public static final class Rectangle implements Shape { + private final double width, height; + + public Rectangle(double width, double height) { + this.width = width; + this.height = height; + } + + @Override + public double area() { + return width * height; + } + } + + /** + * Tests pattern matching with switch (JDK 17+). + * + * @param shape the shape to analyze + * @return area description + */ + public String testPatternMatching(Shape shape) { + return switch (shape) { + case Circle c -> "Circle with area: " + c.area(); + case Rectangle r -> "Rectangle with area: " + r.area(); + }; + } + + /** + * Tests complex Java expressions and statements. + * Ensures no syntax conflicts with MaxJ additions. + * + * @param data input data + * @return processed result + */ + public Map testComplexJavaExpressions(int[] data) { + Map results = new HashMap<>(); + + // Array operations + int[] copy = Arrays.copyOf(data, data.length); + Arrays.sort(copy); + + // Stream operations + OptionalInt max = Arrays.stream(data) + .filter(x -> x > 0) + .max(); + + // Exception handling + try { + int riskyOperation = data[0] / data[1]; + results.put("division", riskyOperation); + } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) { + results.put("error", e.getMessage()); + } finally { + results.put("completed", true); + } + + // Annotations + @SuppressWarnings("unchecked") + List uncheckedList = (List) (List) new ArrayList(); + + return results; + } + + /** + * Tests that Java keywords are not affected by MaxJ additions. + * Important: tests case-sensitivity (case vs CASE). + */ + public void testJavaKeywordPreservation() { + // Ensure lowercase 'case' still works in Java switch + int value = 5; + switch (value) { + case 1: + System.out.println("case 1"); + break; + case 5: + System.out.println("case 5"); // This should work normally + break; + default: + System.out.println("default case"); + break; + } + + // Ensure lowercase 'if' and 'else' still work + if (value == 5) { + System.out.println("Standard Java if works"); + } else { + System.out.println("Standard Java else works"); + } + + // Test that Java 'switch' keyword is not affected by MaxJ 'SWITCH' + String result = switch (value) { + case 1, 2, 3 -> "low"; + case 4, 5, 6 -> "medium"; + default -> "high"; + }; + + System.out.println("Switch expression result: " + result); + } +} diff --git a/maxj/testing/test-javadoc.sh b/maxj/testing/test-javadoc.sh new file mode 100755 index 0000000000000..979de2b903d31 --- /dev/null +++ b/maxj/testing/test-javadoc.sh @@ -0,0 +1,182 @@ +#!/bin/bash + +# MaxJ Javadoc Generation Test Script +# Tests that MaxJ syntax support works correctly for JDK21 javadoc + +set -e # Exit on any error + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +TEST_DIR="$SCRIPT_DIR/test-files" +OUT_DIR="$SCRIPT_DIR/output" +JAVADOC="$PROJECT_ROOT/build/macosx-aarch64-server-release/jdk/bin/javadoc" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +echo -e "${BLUE}MaxJ Javadoc Generation Test Suite${NC}" +echo "======================================" +echo "" + +# Check if javadoc exists +if [ ! -f "$JAVADOC" ]; then + echo -e "${RED}❌ Error: javadoc not found at $JAVADOC${NC}" + echo "Please run 'make' first to build the MaxJ javadoc tool." + exit 1 +fi + +# Check if test directory exists +if [ ! -d "$TEST_DIR" ]; then + echo -e "${RED}❌ Error: Test directory not found at $TEST_DIR${NC}" + exit 1 +fi + +# Clean output directory +echo -e "${BLUE}Cleaning output directory...${NC}" +rm -rf "$OUT_DIR" +mkdir -p "$OUT_DIR" + +# Function to run a test +run_test() { + local test_name="$1" + local files="$2" + local output_dir="$OUT_DIR/$test_name" + + echo -n "Testing $test_name... " + + if $JAVADOC -Xdoclint:none -quiet -private -d "$output_dir" $files 2>/dev/null; then + echo -e "${GREEN}✅ SUCCESS${NC}" + return 0 + else + echo -e "${RED}❌ FAILED${NC}" + echo " Command: $JAVADOC -Xdoclint:none -quiet -private -d \"$output_dir\" $files" + return 1 + fi +} + +# Function to check generated docs +check_docs() { + local test_name="$1" + local output_dir="$OUT_DIR/$test_name" + + if [ -d "$output_dir" ] && [ "$(ls -A "$output_dir")" ]; then + local html_count=$(find "$output_dir" -name "*.html" | wc -l) + echo " 📄 Generated $html_count HTML files" + return 0 + else + echo -e " ${RED}❌ No documentation generated${NC}" + return 1 + fi +} + +# Test counter +TESTS_RUN=0 +TESTS_PASSED=0 + +echo -e "${BLUE}Running MaxJ Syntax Tests...${NC}" +echo "" + +# Test 1: Comprehensive MaxJ Syntax +echo -e "${YELLOW}Test 1: Comprehensive MaxJ Syntax (.maxj)${NC}" +if run_test "comprehensive-maxj" "$TEST_DIR/ComprehensiveMaxJSyntaxTest.maxj"; then + check_docs "comprehensive-maxj" + TESTS_PASSED=$((TESTS_PASSED + 1)) +fi +TESTS_RUN=$((TESTS_RUN + 1)) +echo "" + +# Test 2: Edge Cases MaxJ Syntax +echo -e "${YELLOW}Test 2: MaxJ Edge Cases (.maxj)${NC}" +if run_test "edge-cases-maxj" "$TEST_DIR/MAXJSwitchEdgeCases.maxj"; then + check_docs "edge-cases-maxj" + TESTS_PASSED=$((TESTS_PASSED + 1)) +fi +TESTS_RUN=$((TESTS_RUN + 1)) +echo "" + +# Test 3: Standard Java Syntax +echo -e "${YELLOW}Test 3: Standard Java Syntax (.java)${NC}" +if run_test "standard-java" "$TEST_DIR/StandardJavaSyntaxTest.java"; then + check_docs "standard-java" + TESTS_PASSED=$((TESTS_PASSED + 1)) +fi +TESTS_RUN=$((TESTS_RUN + 1)) +echo "" + +# Test 4: Keyword Conflict Test +echo -e "${YELLOW}Test 4: Keyword Conflict Test (.java)${NC}" +if run_test "keyword-conflicts" "$TEST_DIR/KeywordConflictTest.java"; then + check_docs "keyword-conflicts" + TESTS_PASSED=$((TESTS_PASSED + 1)) +fi +TESTS_RUN=$((TESTS_RUN + 1)) +echo "" + +# Test 5: Multiple Java Files Together +echo -e "${YELLOW}Test 5: Multiple Java Files Together${NC}" +if run_test "multiple-java" "$TEST_DIR/StandardJavaSyntaxTest.java $TEST_DIR/KeywordConflictTest.java"; then + check_docs "multiple-java" + TESTS_PASSED=$((TESTS_PASSED + 1)) +fi +TESTS_RUN=$((TESTS_RUN + 1)) +echo "" + +# Test 6: Multiple MaxJ Files Together +echo -e "${YELLOW}Test 6: Multiple MaxJ Files Together${NC}" +if run_test "multiple-maxj" "$TEST_DIR/ComprehensiveMaxJSyntaxTest.maxj $TEST_DIR/MAXJSwitchEdgeCases.maxj"; then + check_docs "multiple-maxj" + TESTS_PASSED=$((TESTS_PASSED + 1)) +fi +TESTS_RUN=$((TESTS_RUN + 1)) +echo "" + +# Test 7: Real MaxJ Project Files - Syntax Only (dependencies expected to fail) +echo -e "${YELLOW}Test 7: Real MaxJ Project Files (Syntax Test)${NC}" +REAL_MAXJ_FILE=$(find "$PROJECT_ROOT/../maxelercore" -name "*.maxj" 2>/dev/null | head -1) +if [ -n "$REAL_MAXJ_FILE" ]; then + echo -n "Testing real maxj file (syntax parsing)... " + # For real MaxJ files, we expect dependency errors but no syntax errors + # Use timeout to prevent hanging on complex files + ERROR_OUTPUT=$(timeout 30 $JAVADOC -Xdoclint:none -quiet -private -d "$OUT_DIR/real-maxj-project" "$REAL_MAXJ_FILE" 2>&1 || echo "timeout or dependency errors") + if echo "$ERROR_OUTPUT" | grep -q -E "CASE|SWITCH|OTHERWISE|.*expected.*MAXJ|illegal.*MAXJ|unexpected.*MAXJ"; then + echo -e "${RED}❌ SYNTAX ERRORS FOUND${NC}" + echo " MaxJ syntax parsing failed:" + echo "$ERROR_OUTPUT" | grep -E "CASE|SWITCH|OTHERWISE|.*expected.*MAXJ|illegal.*MAXJ|unexpected.*MAXJ" | head -3 + else + echo -e "${GREEN}✅ SYNTAX PARSING SUCCESS${NC}" + echo " 📝 No MaxJ syntax errors (dependency errors are expected)" + TESTS_PASSED=$((TESTS_PASSED + 1)) + fi + TESTS_RUN=$((TESTS_RUN + 1)) +else + echo " 📝 Skipped (no maxelercore files found)" +fi +echo "" + +# Summary +echo "======================================" +echo -e "${BLUE}Test Summary${NC}" +echo "======================================" +echo "Tests run: $TESTS_RUN" +echo -e "Tests passed: ${GREEN}$TESTS_PASSED${NC}" +if [ $TESTS_PASSED -eq $TESTS_RUN ]; then + echo -e "Result: ${GREEN}🎉 ALL TESTS PASSED!${NC}" + echo "" + echo -e "${GREEN}MaxJ Javadoc generation is fully functional!${NC}" + echo "" + echo "Generated documentation available in:" + echo " 📁 $OUT_DIR/" + for dir in "$OUT_DIR"/*; do + if [ -d "$dir" ]; then + echo " $(basename "$dir")/" + fi + done + exit 0 +else + echo -e "Result: ${RED}❌ $((TESTS_RUN - TESTS_PASSED)) TESTS FAILED${NC}" + exit 1 +fi diff --git a/maxj/testing/test-operators.sh b/maxj/testing/test-operators.sh new file mode 100755 index 0000000000000..6cdcc9b0ac23c --- /dev/null +++ b/maxj/testing/test-operators.sh @@ -0,0 +1,128 @@ +#!/bin/bash + +# Ultimate MaxJ Operator Test +# Tests every single MaxJ operator and keyword + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +JAVADOC="$PROJECT_ROOT/build/macosx-aarch64-server-release/jdk/bin/javadoc" +OUT_DIR="$SCRIPT_DIR/output/ultimate-test" + +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +YELLOW='\033[0;33m' +NC='\033[0m' + +echo -e "${BLUE}Ultimate MaxJ Operator Test${NC}" +echo "==========================" + +# Clean output +rm -rf "$OUT_DIR" +mkdir -p "$OUT_DIR" + +# Create ultimate test file +cat > "$OUT_DIR/UltimateMaxJTest.maxj" << 'EOF' +package ultimate; + +/** + * Ultimate MaxJ Syntax Test + * Tests EVERY MaxJ operator and keyword. + */ +public class UltimateMaxJTest { + + public static class HardwareSignal { + public int value; + public HardwareSignal next; + public boolean valid; + } + + /** + * Tests ALL MaxJ syntax elements. + * @param control control value + * @param data data value + * @return result + */ + public int testAllMaxJSyntax(int control, int data) { + HardwareSignal signal = new HardwareSignal(); + signal.next = new HardwareSignal(); + int result = 0; + + // TEST 1: MaxJ SWITCH/CASE/OTHERWISE + SWITCH (control) { + CASE (1) { + result = 100; + } + CASE (2) { + result = 200; + } + OTHERWISE { + result = 999; + } + } + + // TEST 2: MaxJ IF/ELSE + IF (data > 0) { + result = result + 10; + } ELSE { + result = result - 10; + } + + // TEST 3: MaxJ === operator + IF (control === 1) { + result = result + 1; + } ELSE { + result = result + 0; + } + + // TEST 4: MaxJ # operator (concatenation) + int concatenated = control # data; + result = result + concatenated; + + // TEST 5: MaxJ <== operator (connection) + signal.next.value <== data; + signal.next.valid <== true; + + // TEST 6: Complex combinations + SWITCH (control # data) { + CASE (12) { + IF (signal.next.value === 2) { + signal.next.value <== control # data # 100; + } ELSE { + signal.next.value <== 0; + } + } + OTHERWISE { + signal.next.value <== control # data; + } + } + + return result + signal.next.value; + } +} +EOF + +# Test the ultimate file +echo -n "Testing ALL MaxJ operators and keywords... " +if $JAVADOC -Xdoclint:none -quiet -private -d "$OUT_DIR/docs" "$OUT_DIR/UltimateMaxJTest.maxj" 2>/dev/null; then + echo -e "${GREEN}✅ SUCCESS${NC}" + echo "" + echo "✅ ALL MaxJ operators verified:" + echo " 🔸 SWITCH/CASE/OTHERWISE - Control flow keywords" + echo " 🔸 IF/ELSE - Conditional keywords" + echo " 🔸 === - Triple equals operator" + echo " 🔸 # - Concatenation operator" + echo " 🔸 <== - Connection operator" + echo " 🔸 Complex nested combinations" + echo "" + echo -e "${GREEN}🎉 MaxJ javadoc generation is 100% functional!${NC}" + echo "" + echo "Generated documentation:" + echo " 📁 $OUT_DIR/docs/" + ls "$OUT_DIR/docs/" | head -5 +else + echo -e "${RED}❌ FAILED${NC}" + echo "Error details:" + $JAVADOC -Xdoclint:none -quiet -private -d "$OUT_DIR/docs" "$OUT_DIR/UltimateMaxJTest.maxj" + exit 1 +fi diff --git a/maxj/testing/test-simple.sh b/maxj/testing/test-simple.sh new file mode 100755 index 0000000000000..cb6c08d4dac6e --- /dev/null +++ b/maxj/testing/test-simple.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# Simple MaxJ Javadoc Test Script +# Quick verification that MaxJ syntax support works + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +JAVADOC="$PROJECT_ROOT/build/macosx-aarch64-server-release/jdk/bin/javadoc" +TEST_DIR="$SCRIPT_DIR/test-files" +OUT_DIR="$SCRIPT_DIR/output" + +# Colors +GREEN='\033[0;32m' +RED='\033[0;31m' +BLUE='\033[0;34m' +NC='\033[0m' + +echo -e "${BLUE}MaxJ Javadoc Quick Test${NC}" +echo "======================" + +# Clean output +rm -rf "$OUT_DIR" +mkdir -p "$OUT_DIR" + +# Test MaxJ syntax +echo -n "Testing MaxJ syntax (.maxj)... " +if $JAVADOC -Xdoclint:none -quiet -private -d "$OUT_DIR/maxj" "$TEST_DIR/ComprehensiveMaxJSyntaxTest.maxj" 2>/dev/null; then + echo -e "${GREEN}✅ SUCCESS${NC}" +else + echo -e "${RED}❌ FAILED${NC}" + exit 1 +fi + +# Test MaxJ operators specifically +echo -n "Testing MaxJ operators (===, #, <==)... " +if $JAVADOC -Xdoclint:none -quiet -private -d "$OUT_DIR/operators" "$TEST_DIR/MaxJConnectionOperatorTest.maxj" "$TEST_DIR/AllMaxJOperatorsTest.maxj" 2>/dev/null; then + echo -e "${GREEN}✅ SUCCESS${NC}" +else + echo -e "${RED}❌ FAILED${NC}" + exit 1 +fi + +# Test Java syntax +echo -n "Testing Java syntax (.java)... " +if $JAVADOC -Xdoclint:none -quiet -private -d "$OUT_DIR/java" "$TEST_DIR/StandardJavaSyntaxTest.java" 2>/dev/null; then + echo -e "${GREEN}✅ SUCCESS${NC}" +else + echo -e "${RED}❌ FAILED${NC}" + exit 1 +fi + +# Test keyword conflicts +echo -n "Testing keyword conflicts... " +if $JAVADOC -Xdoclint:none -quiet -private -d "$OUT_DIR/conflicts" "$TEST_DIR/KeywordConflictTest.java" 2>/dev/null; then + echo -e "${GREEN}✅ SUCCESS${NC}" +else + echo -e "${RED}❌ FAILED${NC}" + exit 1 +fi + +echo "" +echo -e "${GREEN}🎉 All tests passed!${NC}" +echo "Generated docs in: $OUT_DIR/" +echo "" +echo "MaxJ syntax elements tested:" +echo " ✅ SWITCH/CASE/OTHERWISE" +echo " ✅ IF/ELSE" +echo " ✅ === (triple equals)" +echo " ✅ # (concatenation)" +echo " ✅ <== (connection operator)" +echo " ✅ Nested structures" +echo " ✅ Complex operator combinations" +echo " ✅ No conflicts with Java syntax" diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java index 845203c87351d..b14c2e8dc8542 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java @@ -96,7 +96,7 @@ public enum Kind { /** * Used for instances of {@link CaseTree}. */ - CASE(CaseTree.class), + _CASE(CaseTree.class), /** * Used for instances of {@link CatchTree}. @@ -161,7 +161,7 @@ public enum Kind { /** * Used for instances of {@link IfTree}. */ - IF(IfTree.class), + _IF(IfTree.class), /** * Used for instances of {@link ImportTree}. @@ -279,7 +279,7 @@ public enum Kind { /** * Used for instances of {@link SwitchTree}. */ - SWITCH(SwitchTree.class), + _SWITCH(SwitchTree.class), /** * Used for instances of {@link SwitchExpressionTree}. @@ -500,6 +500,27 @@ public enum Kind { */ CONDITIONAL_OR(BinaryTree.class), + /** + * MAXJ + * Used for instances of {@link BinaryTree} representing + * binary-concatenation {@code #}. + */ + CAT(BinaryTree.class), + + /** + * MAXJ + * Used for instances of {@link BinaryTree} representing + * value-equal-to {@code ===}. + */ + EQUAL_EQUAL_TO(BinaryTree.class), + + /** + * MAXJ + * Used for instances of {@link BinaryTree} representing + * value-not-equal-to {@code !==}. + */ + NOT_EQUAL_EQUAL_TO(BinaryTree.class), + /** * Used for instances of {@link CompoundAssignmentTree} representing * multiplication assignment {@code *=}. @@ -566,6 +587,13 @@ public enum Kind { */ OR_ASSIGNMENT(CompoundAssignmentTree.class), + /** + * MAXJ + * Used for instances of {@link CompoundAssignmentTree} representing + * connect operator {@code <==}. + */ + LE_ASSIGNMENT(CompoundAssignmentTree.class), + /** * Used for instances of {@link LiteralTree} representing * an integral literal expression of type {@code int}. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 1465ea652b1ea..5d7eca65f0e33 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1898,7 +1898,7 @@ private void handleSwitch(JCTree switchTree, chk.checkSwitchCaseStructure(cases); chk.checkSwitchCaseLabelDominated(unconditionalCaseLabel, cases); } - if (switchTree.hasTag(SWITCH)) { + if (switchTree.hasTag(_SWITCH)) { ((JCSwitch) switchTree).hasUnconditionalPattern = hasDefault || hasUnconditionalPattern || lastPatternErroneous; ((JCSwitch) switchTree).patternSwitch = patternSwitch; @@ -2461,7 +2461,7 @@ private Pair findJumpTargetNoError(JCTree.Tag tag, case FOREACHLOOP: if (label == null) return Pair.of(env1.tree, pendingError); break; - case SWITCH: + case _SWITCH: if (label == null && tag == BREAK) return Pair.of(env1.tree, null); break; case SWITCH_EXPRESSION: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java index d16bbf2a2eee0..c6e431594bd07 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java @@ -1161,8 +1161,8 @@ static class PolyScanner extends FilterScanner { static class LambdaReturnScanner extends FilterScanner { LambdaReturnScanner() { - super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP, - FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP)); + super(EnumSet.of(BLOCK, _CASE, CATCH, DOLOOP, FOREACHLOOP, + FORLOOP, _IF, RETURN, SYNCHRONIZED, _SWITCH, TRY, WHILELOOP)); } } @@ -1173,8 +1173,8 @@ static class LambdaReturnScanner extends FilterScanner { static class SwitchExpressionScanner extends FilterScanner { SwitchExpressionScanner() { - super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP, - FORLOOP, IF, SYNCHRONIZED, SWITCH, TRY, WHILELOOP, YIELD)); + super(EnumSet.of(BLOCK, _CASE, CATCH, DOLOOP, FOREACHLOOP, + FORLOOP, _IF, SYNCHRONIZED, _SWITCH, TRY, WHILELOOP, YIELD)); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java index b1c42a323be99..f12f9277a2af1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java @@ -554,7 +554,8 @@ public void visitClassDef(JCClassDecl tree) { private static boolean classNameMatchesFileName(ClassSymbol c, Env env) { return env.toplevel.sourcefile.isNameCompatible(c.name.toString(), - JavaFileObject.Kind.SOURCE); + JavaFileObject.Kind.SOURCE) + || env.toplevel.sourcefile.getName().endsWith(".maxj"); } /** Complain about a duplicate class. */ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index e74aed6a35703..e1b4eacf9cbb9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -2299,7 +2299,7 @@ private void handleSwitch(JCTree tree, JCExpression selector, if (!isExhaustive) { if (tree.hasTag(SWITCH_EXPRESSION)) { markDead(); - } else if (tree.hasTag(SWITCH) && !TreeInfo.expectedExhaustive((JCSwitch) tree)) { + } else if (tree.hasTag(_SWITCH) && !TreeInfo.expectedExhaustive((JCSwitch) tree)) { inits.assign(initsSwitch); uninits.assign(uninits.andSet(uninitsSwitch)); } @@ -2784,7 +2784,7 @@ void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) { sym.pos < getCurrentTreeStartPosition()) { switch (currentTree.getTag()) { case CLASSDEF: - case CASE: + case _CASE: case LAMBDA: if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) { reportEffectivelyFinalError(pos, sym); @@ -2811,7 +2811,7 @@ void letInit(JCTree tree) { reportEffectivelyFinalError(tree, sym); } } - case CASE -> { + case _CASE -> { if (!declaredInsideGuard.includes(sym)) { log.error(tree.pos(), Errors.CannotAssignNotDeclaredGuard(sym)); } @@ -2824,7 +2824,7 @@ void letInit(JCTree tree) { void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) { Fragment subKey = switch (currentTree.getTag()) { case LAMBDA -> Fragments.Lambda; - case CASE -> Fragments.Guard; + case _CASE -> Fragments.Guard; case CLASSDEF -> Fragments.InnerCls; default -> throw new AssertionError("Unexpected tree kind: " + currentTree.getTag()); }; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index aee7f0afe3975..b9a453ef52eea 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -3879,7 +3879,7 @@ private void handleSwitch(JCTree tree, JCExpression selector, List cases boolean boxedSwitch = !enumSwitch && !stringSwitch && !selector.type.isPrimitive(); selector = translate(selector, selector.type); cases = translateCases(cases); - if (tree.hasTag(SWITCH)) { + if (tree.hasTag(_SWITCH)) { ((JCSwitch) tree).selector = selector; ((JCSwitch) tree).cases = cases; } else if (tree.hasTag(SWITCH_EXPRESSION)) { @@ -3951,7 +3951,7 @@ public JCTree visitEnumSwitch(JCTree tree, JCExpression selector, List c } } JCTree enumSwitch; - if (tree.hasTag(SWITCH)) { + if (tree.hasTag(_SWITCH)) { enumSwitch = make.Switch(newSelector, newCases.toList()); } else if (tree.hasTag(SWITCH_EXPRESSION)) { enumSwitch = make.SwitchExpression(newSelector, newCases.toList()); @@ -4157,7 +4157,7 @@ else if (oneCase == nullCase) { oneCase.stats, null)); } - if (tree.hasTag(SWITCH)) { + if (tree.hasTag(_SWITCH)) { JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList()); // Rewire up old unlabeled break statements to the // replacement switch being created. @@ -4242,7 +4242,7 @@ private JCTree visitBoxedPrimitiveSwitch(JCTree tree, JCExpression selector, Lis newSelector = unbox(selector, syms.intType); } - if (tree.hasTag(SWITCH)) { + if (tree.hasTag(_SWITCH)) { ((JCSwitch) tree).selector = newSelector; } else { ((JCSwitchExpression) tree).selector = newSelector; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java index 0eea70195daa4..cde95bf7452a8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java @@ -797,6 +797,13 @@ private void initBinaryOperators() { .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifne) .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifne) .addBinaryOperator(INT, INT, BOOLEAN, if_icmpne), + // MAXJ operators + new BinaryNumericOperator(Tag.CONCAT) + .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dadd) + .addBinaryOperator(FLOAT, FLOAT, FLOAT, fadd) + .addBinaryOperator(LONG, LONG, LONG, ladd) + .addBinaryOperator(INT, INT, INT, iadd), + // END MAXJ operators new BinaryBooleanOperator(Tag.AND) .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_and), new BinaryBooleanOperator(Tag.OR) @@ -848,6 +855,7 @@ private void initOperatorNames() { setOperatorName(Tag.BITOR, "|"); setOperatorName(Tag.BITXOR, "^"); setOperatorName(Tag.BITAND, "&"); + setOperatorName(Tag.CONCAT, "#"); setOperatorName(Tag.SL, "<<"); setOperatorName(Tag.SR, ">>"); setOperatorName(Tag.USR, ">>>"); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 58c36a5cf7c27..52ff14ae56d38 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -657,7 +657,7 @@ private void handleSwitch(JCTree tree, c.completesNormally; } - if (tree.hasTag(Tag.SWITCH)) { + if (tree.hasTag(Tag._SWITCH)) { ((JCSwitch) tree).selector = selector; ((JCSwitch) tree).cases = cases; ((JCSwitch) tree).wasEnumSelector = enumSelector; @@ -675,7 +675,7 @@ private void handleSwitch(JCTree tree, } return ; } - if (tree.hasTag(Tag.SWITCH)) { + if (tree.hasTag(Tag._SWITCH)) { super.visitSwitch((JCSwitch) tree); } else { super.visitSwitchExpression((JCSwitchExpression) tree); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java index 5964c16c1517b..55ee8d1fe3f7e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java @@ -493,7 +493,7 @@ public static Kind getKind(Path path) { public static Kind getKind(String name) { if (name.endsWith(Kind.CLASS.extension)) return Kind.CLASS; - else if (name.endsWith(Kind.SOURCE.extension)) + else if (name.endsWith(Kind.SOURCE.extension) || name.endsWith(".maxj")) return Kind.SOURCE; else if (name.endsWith(Kind.HTML.extension)) return Kind.HTML; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index c14767a7a8c60..e478406e6041f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -784,7 +784,7 @@ public void process(OptionHelper helper, String option) { SOURCEFILE("sourcefile", null, HIDDEN, INFO) { @Override public boolean matches(String s) { - if (s.endsWith(".java")) // Java source file + if (s.endsWith(".java") || s.endsWith(".maxj")) // Java source file or MaxJ source file return true; int sep = s.indexOf('/'); if (sep != -1) { @@ -796,7 +796,7 @@ public boolean matches(String s) { } @Override public void process(OptionHelper helper, String option) throws InvalidValueException { - if (option.endsWith(".java") ) { + if (option.endsWith(".java") || option.endsWith(".maxj")) { // Java source file or MaxJ source file try { Path p = Paths.get(option); if (!Files.exists(p)) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index f40cb0fb6b7fa..284065a50b4a7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -133,6 +133,11 @@ public class JavaTokenizer extends UnicodeReader { */ protected boolean hasEscapeSequences; + /** + * true if we are parsing a .maxj file (enables MAXJ keywords). + */ + protected final boolean isMaxJFile; + /** * Construct a Java token scanner from the input character buffer. * @@ -160,6 +165,19 @@ protected JavaTokenizer(ScannerFactory fac, char[] array, int length) { this.preview = fac.preview; this.enableLineDocComments = fac.enableLineDocComments; this.sb = new StringBuilder(256); + + // Check if we're parsing a .maxj file + boolean isMaxJ = false; + try { + if (fac.log != null && fac.log.currentSourceFile() != null) { + String filename = fac.log.currentSourceFile().getName(); + isMaxJ = filename.endsWith(".maxj"); + } + } catch (Exception e) { + // If we can't determine the file type, assume it's not MAXJ + isMaxJ = false; + } + this.isMaxJFile = isMaxJ; } /** @@ -632,6 +650,29 @@ private void scanNumber(int pos, int radix) { private void checkIdent() { name = names.fromString(sb.toString()); tk = tokens.lookupKind(name); + + // Apply MAXJ keyword scoping based on file extension + if (isMaxJFile) { + // In .maxj files: recognize MAXJ keywords (CASE, ELSE, SWITCH, IF, OTHERWISE) + String nameStr = name.toString(); + if ("CASE".equals(nameStr)) { + tk = TokenKind.MAXJCASE; + } else if ("ELSE".equals(nameStr)) { + tk = TokenKind.MAXJELSE; + } else if ("SWITCH".equals(nameStr)) { + tk = TokenKind.MAXJSWITCH; + } else if ("IF".equals(nameStr)) { + tk = TokenKind.MAXJIF; + } else if ("OTHERWISE".equals(nameStr)) { + tk = TokenKind.MAXJDEFAULT; + } + } else { + // In .java files: convert MAXJ keywords back to identifiers to avoid conflicts + if (tk == TokenKind.MAXJCASE || tk == TokenKind.MAXJELSE || + tk == TokenKind.MAXJSWITCH || tk == TokenKind.MAXJIF || tk == TokenKind.MAXJDEFAULT) { + tk = TokenKind.IDENTIFIER; + } + } } /** @@ -718,6 +759,7 @@ private boolean isSpecial(char ch) { case '+': case '-': case ':': case '<': case '=': case '>': case '^': case '|': case '~': case '@': + case '#': return true; default: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index d3539b53541b3..a26bc0e2cedb8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -55,6 +55,7 @@ import static com.sun.tools.javac.parser.Tokens.TokenKind.*; import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT; import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE; +import static com.sun.tools.javac.parser.Tokens.TokenKind.MAXJCASE; import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH; import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ; import static com.sun.tools.javac.parser.Tokens.TokenKind.GT; @@ -423,18 +424,23 @@ protected void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stop return; break; case CASE: + case MAXJCASE: case DEFAULT: + case MAXJDEFAULT: case IF: + case MAXJIF: case FOR: case WHILE: case DO: case TRY: case SWITCH: + case MAXJSWITCH: case RETURN: case THROW: case BREAK: case CONTINUE: case ELSE: + case MAXJELSE: case FINALLY: case CATCH: case THIS: @@ -1154,6 +1160,7 @@ JCExpression termRest(JCExpression t) { JCExpression t1 = term(); return toP(F.at(pos).Assign(t, t1)); } + case CONNECT: case PLUSEQ: case SUBEQ: case STAREQ: @@ -1608,6 +1615,16 @@ protected JCExpression term3() { if (!annos.isEmpty()) t = illegal(annos.head.pos); t = to(F.at(pos).Indexed(t, t1)); } + // MAXJ : the following changes add the option for array slicing [:] + if (token.kind == COLON) { + accept(COLON); + if (isMode(EXPR)) { + selectExprMode(); + JCExpression t1 = term(); + if (!annos.isEmpty()) t = illegal(annos.head.pos); + t = to(F.at(pos).Indexed(t, t1)); + } + } accept(RBRACKET); } break loop; @@ -1865,6 +1882,15 @@ JCExpression term3Rest(JCExpression t, List typeArgs) { JCExpression t1 = term(); t = to(F.at(pos1).Indexed(t, t1)); } + // MAXJ : this + if (token.kind == COLON) { + accept(COLON); + if (isMode(EXPR)) { + selectExprMode(); + JCExpression t1 = term(); + t = to(F.at(pos1).Indexed(t, t1)); + } + } accept(RBRACKET); } else if (token.kind == DOT) { nextToken(); @@ -2928,11 +2954,11 @@ List blockStatement() { Comment dc; int pos = token.pos; switch (token.kind) { - case RBRACE: case CASE: case DEFAULT: case EOF: + case RBRACE: case CASE: case DEFAULT: case MAXJCASE: case MAXJDEFAULT: case EOF: return List.nil(); - case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY: - case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK: - case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH: + case LBRACE: case IF: case MAXJIF: case FOR: case WHILE: case DO: case TRY: + case SWITCH: case MAXJSWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK: + case CONTINUE: case SEMI: case ELSE: case MAXJELSE: case FINALLY: case CATCH: case ASSERT: return List.of(parseSimpleStatement()); case MONKEYS_AT: @@ -3102,6 +3128,17 @@ public JCStatement parseSimpleStatement() { } return F.at(pos).If(cond, thenpart, elsepart); } + case MAXJIF: { + nextToken(); + JCExpression cond = parExpression(); + JCStatement thenpart = parseStatementAsBlock(); + JCStatement elsepart = null; + if (token.kind == MAXJELSE) { + nextToken(); + elsepart = parseStatementAsBlock(); + } + return F.at(pos).If(cond, thenpart, elsepart); + } case FOR: { nextToken(); accept(LPAREN); @@ -3175,6 +3212,16 @@ public JCStatement parseSimpleStatement() { accept(RBRACE); return t; } + case MAXJSWITCH: { + nextToken(); + JCExpression selector = parExpression(); + accept(LBRACE); + List cases = maxjSwitchBlockStatementGroups(); + JCSwitch t = to(F.at(pos).Switch(selector, cases)); + t.bracePos = token.endPos; + accept(RBRACE); + return t; + } case SYNCHRONIZED: { nextToken(); JCExpression lock = parExpression(); @@ -3216,6 +3263,10 @@ public JCStatement parseSimpleStatement() { int elsePos = token.pos; nextToken(); return doRecover(elsePos, BasicErrorRecoveryAction.BLOCK_STMT, Errors.ElseWithoutIf); + case MAXJELSE: + int maxjElsePos = token.pos; + nextToken(); + return doRecover(maxjElsePos, BasicErrorRecoveryAction.BLOCK_STMT, Errors.ElseWithoutIf); case FINALLY: int finallyPos = token.pos; nextToken(); @@ -3375,6 +3426,52 @@ protected List switchBlockStatementGroup() { throw new AssertionError("should not reach here"); } + List maxjSwitchBlockStatementGroups() { + ListBuffer cases = new ListBuffer<>(); + while (true) { + int pos = token.pos; + switch (token.kind) { + case MAXJCASE: + case MAXJDEFAULT: + cases.append(maxjSwitchBlockStatementGroup()); + break; + case RBRACE: case EOF: + return cases.toList(); + default: + nextToken(); // to ensure progress + syntaxError(pos, Errors.Expected3(MAXJCASE, MAXJDEFAULT, RBRACE)); + } + } + } + + protected JCCase maxjSwitchBlockStatementGroup() { + int pos = token.pos; + List stats; + JCCase c; + switch (token.kind) { + case MAXJCASE: + nextToken(); + JCExpression pat = parseExpression(); + accept(LBRACE); + stats = blockStatements(); + c = F.at(pos).Case(JCCase.STATEMENT, List.of(F.at(pat.pos).ConstantCaseLabel(pat)), null, stats, null); + if (stats.isEmpty()) + storeEnd(c, S.prevToken().endPos); + accept(RBRACE); + return c; + case MAXJDEFAULT: + nextToken(); + accept(LBRACE); + stats = blockStatements(); + c = F.at(pos).Case(JCCase.STATEMENT, List.of(F.at(pos).DefaultCaseLabel()), null, stats, null); + if (stats.isEmpty()) + storeEnd(c, S.prevToken().endPos); + accept(RBRACE); + return c; + } + throw new AssertionError("should not reach here"); + } + private JCCaseLabel parseCaseLabel(boolean allowDefault) { int patternPos = token.pos; JCCaseLabel label; @@ -5517,14 +5614,20 @@ static JCTree.Tag optag(TokenKind token) { return BITAND_ASG; case EQEQ: return JCTree.Tag.EQ; + case EQEQEQ: + return JCTree.Tag.EQ_EQ; case BANGEQ: return NE; + case BANGEQEQ: + return JCTree.Tag.NE_EQ; case LT: return JCTree.Tag.LT; case GT: return JCTree.Tag.GT; case LTEQ: return LE; + case CONNECT: + return JCTree.Tag.LE_ASG; case GTEQ: return GE; case LTLT: @@ -5549,6 +5652,8 @@ static JCTree.Tag optag(TokenKind token) { return MINUS_ASG; case STAR: return MUL; + case CAT: + return JCTree.Tag.CONCAT; case STAREQ: return MUL_ASG; case SLASH: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java index 4abd9378cbe98..51343782bc619 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java @@ -102,15 +102,18 @@ public enum TokenKind implements Formattable, Predicate { BREAK("break"), BYTE("byte", Tag.NAMED), CASE("case"), + MAXJCASE("CASE"), CATCH("catch"), CHAR("char", Tag.NAMED), CLASS("class"), CONST("const"), CONTINUE("continue"), DEFAULT("default"), + MAXJDEFAULT("OTHERWISE"), DO("do"), DOUBLE("double", Tag.NAMED), ELSE("else"), + MAXJELSE("ELSE"), ENUM("enum", Tag.NAMED), EXTENDS("extends"), FINAL("final"), @@ -119,6 +122,7 @@ public enum TokenKind implements Formattable, Predicate { FOR("for"), GOTO("goto"), IF("if"), + MAXJIF("IF"), IMPLEMENTS("implements"), IMPORT("import"), INSTANCEOF("instanceof"), @@ -137,6 +141,7 @@ public enum TokenKind implements Formattable, Predicate { STRICTFP("strictfp"), SUPER("super", Tag.NAMED), SWITCH("switch"), + MAXJSWITCH("SWITCH"), SYNCHRONIZED("synchronized"), THIS("this", Tag.NAMED), THROW("throw"), @@ -177,9 +182,11 @@ public enum TokenKind implements Formattable, Predicate { QUES("?"), COLON(":"), EQEQ("=="), + EQEQEQ("==="), LTEQ("<="), GTEQ(">="), BANGEQ("!="), + BANGEQEQ("!=="), AMPAMP("&&"), BARBAR("||"), PLUSPLUS("++"), @@ -191,6 +198,7 @@ public enum TokenKind implements Formattable, Predicate { AMP("&"), BAR("|"), CARET("^"), + CAT("#"), PERCENT("%"), LTLT("<<"), GTGT(">>"), @@ -204,6 +212,7 @@ public enum TokenKind implements Formattable, Predicate { CARETEQ("^="), PERCENTEQ("%="), LTLTEQ("<<="), + CONNECT("<=="), GTGTEQ(">>="), GTGTGTEQ(">>>="), MONKEYS_AT("@"), diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index 0436f68b9e399..a8c031c0edf1f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -151,11 +151,11 @@ public enum Tag { /** Switch statements, of type Switch. */ - SWITCH, + _SWITCH, /** Case parts in switch statements/expressions, of type Case. */ - CASE, + _CASE, /** Switch expression statements, of type Switch. */ @@ -179,7 +179,7 @@ public enum Tag { /** Conditional statements, of type If. */ - IF, + _IF, /** Expression statements, of type Exec. */ @@ -347,8 +347,11 @@ public enum Tag { BITOR, // | BITXOR, // ^ BITAND, // & + CONCAT, // # EQ, // == + EQ_EQ, // === NE, // != + NE_EQ, // !== LT, // < GT, // > LE, // <= @@ -376,6 +379,7 @@ public enum Tag { MUL_ASG(MUL), // *= DIV_ASG(DIV), // /= MOD_ASG(MOD), // %= + LE_ASG(LE), // <== MODULEDEF, EXPORTS, @@ -1352,7 +1356,7 @@ protected JCSwitch(JCExpression selector, List cases) { public void accept(Visitor v) { v.visitSwitch(this); } @DefinedBy(Api.COMPILER_TREE) - public Kind getKind() { return Kind.SWITCH; } + public Kind getKind() { return Kind._SWITCH; } @DefinedBy(Api.COMPILER_TREE) public JCExpression getExpression() { return selector; } @DefinedBy(Api.COMPILER_TREE) @@ -1363,7 +1367,7 @@ public R accept(TreeVisitor v, D d) { } @Override public Tag getTag() { - return SWITCH; + return _SWITCH; } } @@ -1396,7 +1400,7 @@ protected JCCase(CaseKind caseKind, List labels, public void accept(Visitor v) { v.visitCase(this); } @Override @DefinedBy(Api.COMPILER_TREE) - public Kind getKind() { return Kind.CASE; } + public Kind getKind() { return Kind._CASE; } @Override @Deprecated @DefinedBy(Api.COMPILER_TREE) public JCExpression getExpression() { return getExpressions().head; } @@ -1428,7 +1432,7 @@ public R accept(TreeVisitor v, D d) { } @Override public Tag getTag() { - return CASE; + return _CASE; } } @@ -1625,7 +1629,7 @@ protected JCIf(JCExpression cond, public void accept(Visitor v) { v.visitIf(this); } @DefinedBy(Api.COMPILER_TREE) - public Kind getKind() { return Kind.IF; } + public Kind getKind() { return Kind._IF; } @DefinedBy(Api.COMPILER_TREE) public JCExpression getCondition() { return cond; } @DefinedBy(Api.COMPILER_TREE) @@ -1638,7 +1642,7 @@ public R accept(TreeVisitor v, D d) { } @Override public Tag getTag() { - return IF; + return _IF; } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index d953663a6d754..fd0cb64bf032b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -1310,14 +1310,18 @@ public String operatorName(JCTree.Tag tag) { case OR: return "||"; case AND: return "&&"; case EQ: return "=="; + case EQ_EQ: return "==="; case NE: return "!="; + case NE_EQ: return "!=="; case LT: return "<"; case GT: return ">"; case LE: return "<="; + case LE_ASG: return "<=="; case GE: return ">="; case BITOR: return "|"; case BITXOR: return "^"; case BITAND: return "&"; + case CONCAT: return "#"; case SL: return "<<"; case SR: return ">>"; case USR: return ">>>"; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index af823024fab50..ccc0130c060e7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -415,7 +415,7 @@ public static boolean isExpressionStatement(JCExpression tree) { case ASSIGN: case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: case SL_ASG: case SR_ASG: case USR_ASG: - case PLUS_ASG: case MINUS_ASG: + case PLUS_ASG: case MINUS_ASG: case LE_ASG: case MUL_ASG: case DIV_ASG: case MOD_ASG: case APPLY: case NEWCLASS: case ERRONEOUS: @@ -520,7 +520,7 @@ else if (tree.hasTag(TRY)) { JCTry t = (JCTry) tree; return endPos((t.finalizer != null) ? t.finalizer : (t.catchers.nonEmpty() ? t.catchers.last().body : t.body)); - } else if (tree.hasTag(SWITCH) && + } else if (tree.hasTag(_SWITCH) && ((JCSwitch) tree).bracePos != Position.NOPOS) { return ((JCSwitch) tree).bracePos; } else if (tree.hasTag(SWITCH_EXPRESSION) && @@ -558,10 +558,10 @@ public static int getStartPos(JCTree tree) { case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: case SL_ASG: case SR_ASG: case USR_ASG: case PLUS_ASG: case MINUS_ASG: case MUL_ASG: - case DIV_ASG: case MOD_ASG: + case DIV_ASG: case MOD_ASG: case LE_ASG: case OR: case AND: case BITOR: - case BITXOR: case BITAND: case EQ: - case NE: case LT: case GT: + case BITXOR: case BITAND: case EQ: case EQ_EQ: + case NE: case LT: case GT: case NE_EQ: case LE: case GE: case SL: case SR: case USR: case PLUS: case MINUS: case MUL: case DIV: @@ -659,10 +659,10 @@ public static int getEndPos(JCTree tree, EndPosTable endPosTable) { case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: case SL_ASG: case SR_ASG: case USR_ASG: case PLUS_ASG: case MINUS_ASG: case MUL_ASG: - case DIV_ASG: case MOD_ASG: + case DIV_ASG: case MOD_ASG: case LE_ASG: case OR: case AND: case BITOR: - case BITXOR: case BITAND: case EQ: - case NE: case LT: case GT: + case BITXOR: case BITAND: case EQ: case EQ_EQ: + case NE: case LT: case GT: case NE_EQ: case LE: case GE: case SL: case SR: case USR: case PLUS: case MINUS: case MUL: case DIV: @@ -674,7 +674,7 @@ public static int getEndPos(JCTree tree, EndPosTable endPosTable) { case PREINC: case PREDEC: return getEndPos(((JCOperatorExpression) tree).getOperand(RIGHT), endPosTable); - case CASE: + case _CASE: return getEndPos(((JCCase) tree).stats.last(), endPosTable); case CATCH: return getEndPos(((JCCatch) tree).body, endPosTable); @@ -684,7 +684,7 @@ public static int getEndPos(JCTree tree, EndPosTable endPosTable) { return getEndPos(((JCForLoop) tree).body, endPosTable); case FOREACHLOOP: return getEndPos(((JCEnhancedForLoop) tree).body, endPosTable); - case IF: { + case _IF: { JCIf node = (JCIf)tree; if (node.elsepart == null) { return getEndPos(node.thenpart, endPosTable); @@ -898,7 +898,7 @@ public static JCTree referencedStatement(JCLabeledStatement tree) { do t = ((JCLabeledStatement) t).body; while (t.hasTag(LABELLED)); switch (t.getTag()) { - case DOLOOP: case WHILELOOP: case FORLOOP: case FOREACHLOOP: case SWITCH: + case DOLOOP: case WHILELOOP: case FORLOOP: case FOREACHLOOP: case _SWITCH: return t; default: return tree; @@ -1169,10 +1169,13 @@ public static int opPrec(JCTree.Tag op) { case MINUS_ASG: case MUL_ASG: case DIV_ASG: + case LE_ASG: case MOD_ASG: return assignopPrec; case OR: return orPrec; case AND: return andPrec; case EQ: + case EQ_EQ: + case NE_EQ: case NE: return eqPrec; case LT: case GT: @@ -1183,6 +1186,7 @@ public static int opPrec(JCTree.Tag op) { case BITAND: return bitandPrec; case SL: case SR: + case CONCAT: case USR: return shiftPrec; case PLUS: case MINUS: return addPrec; @@ -1253,8 +1257,12 @@ static Tree.Kind tagToKind(JCTree.Tag tag) { // Equality operators case EQ: // == return Tree.Kind.EQUAL_TO; + case EQ_EQ: // === + return Tree.Kind.EQUAL_TO; case NE: // != return Tree.Kind.NOT_EQUAL_TO; + case NE_EQ: // !== + return Tree.Kind.NOT_EQUAL_TO; // Bitwise and logical operators case BITAND: // & @@ -1263,6 +1271,8 @@ static Tree.Kind tagToKind(JCTree.Tag tag) { return Tree.Kind.XOR; case BITOR: // | return Tree.Kind.OR; + case CONCAT: // # + return Tree.Kind.CAT; // Conditional operators case AND: // && @@ -1275,6 +1285,8 @@ static Tree.Kind tagToKind(JCTree.Tag tag) { return Tree.Kind.MULTIPLY_ASSIGNMENT; case DIV_ASG: // /= return Tree.Kind.DIVIDE_ASSIGNMENT; + case LE_ASG: // <= + return Tree.Kind.LE_ASSIGNMENT; case MOD_ASG: // %= return Tree.Kind.REMAINDER_ASSIGNMENT; case PLUS_ASG: // += diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/ExcludeDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/ExcludeDoclet.java new file mode 100644 index 0000000000000..a1c38ffd15eb2 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/ExcludeDoclet.java @@ -0,0 +1,166 @@ +package jdk.javadoc.doclet; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; + +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.UnknownBlockTagTree; + +import jdk.javadoc.internal.tool.DocEnvImpl; + +/** + * A Doclet that wraps the StandardDoclet to exclude elements from the + * generated documentation based on rules defined in the central Utils class. + */ +public class ExcludeDoclet extends StandardDoclet { + public ExcludeDoclet() { + } + + @Override + public String getName() { + return "ExcludeDoclet"; + } + + @Override + public boolean run(DocletEnvironment environment) { + FilteredDocletEnvironment filteredEnv = new FilteredDocletEnvironment((DocEnvImpl) environment); + return super.run(filteredEnv); + } + + private static class FilteredDocletEnvironment extends DocEnvImpl { + private static final Set msgs = Collections.synchronizedSet(new HashSet<>()); + private static final Set excludeMethods = Set.of( + "add", "addAsRHS", "and", "andAsRHS", "cat", "complement", "div", "divAsRHS", + "get", "gt", "gtAsRHS", "gte", "gteAsRHS", "lt", "ltAsRHS", "lte", "lteAsRHS", + "mul", "mulAsRHS", "neg", "or", "orAsRHS", "shiftLeft", "shiftRight", + "sub", "subAsRHS", "ternaryIf", "xor", "xorAsRHS"); + + public FilteredDocletEnvironment(DocEnvImpl delegate) { + super(delegate.toolEnv, delegate.etable); + } + + private boolean shouldBeExcluded(Element element) { + boolean isHidden = getVisibility(element) == Visibility.HIDDEN; + + boolean isUndocumentedSpecialMethod = (element.getKind() == ElementKind.METHOD && + !element.getModifiers().contains(Modifier.STATIC) && + element.getEnclosingElement().toString().contains("com.maxeler.") && + (getDocTrees().getDocCommentTree(element) == null) && + excludeMethods.contains(element.getSimpleName().toString())); + + boolean result = isHidden || isUndocumentedSpecialMethod; + + if (result && msgs.add(element.toString())) { + System.out.println("Excluding: " + element); + } + + return result; + } + + @Override + public Set getIncludedElements() { + return super.getIncludedElements().stream() + .filter(element -> !shouldBeExcluded(element)) + .collect(Collectors.toSet()); + } + + @Override + public Set getSpecifiedElements() { + return super.getSpecifiedElements().stream() + .filter(element -> !shouldBeExcluded(element)) + .collect(Collectors.toSet()); + } + + @Override + public boolean isIncluded(Element e) { + return super.isIncluded(e) && !shouldBeExcluded(e); + } + + /** + * Custom visibility levels for a Java API element. + */ + public enum Visibility { + /** Is visible externally and published. */ + PUBLISHED, + /** Is visible externally but deprecated. */ + DEPRECATED, + /** + * Is visible externally but explicitly marked not for publishing + * (e.g., @exclude or _name). + */ + HIDDEN, + /** Is not visible externally (e.g., private, package-private). */ + INTERNAL + } + + /** + * Determines the custom visibility of any program element based on modifiers, + * tags, and naming conventions. + * + * @param e The element to check. + * @return The calculated visibility of the element. + */ + private Visibility getVisibility(Element e) { + Set modifiers = e.getModifiers(); + if (!modifiers.contains(Modifier.PUBLIC) && !modifiers.contains(Modifier.PROTECTED)) { + return Visibility.INTERNAL; + } + + if (getElementUtils().isDeprecated(e)) { + return Visibility.DEPRECATED; + } + + if (hasExcludeTag(e)) { + return Visibility.HIDDEN; + } + + Element pkg = e; + while (pkg != null && pkg.getKind() != ElementKind.PACKAGE) { + pkg = pkg.getEnclosingElement(); + } + if (pkg != null && hasExcludeTag(pkg)) { + return Visibility.HIDDEN; + } + + if (e.getSimpleName().toString().startsWith("_")) { + return Visibility.HIDDEN; + } + + if (e.getKind().isClass() || e.getKind().isInterface()) { + Element current = e.getEnclosingElement(); + while (current instanceof TypeElement) { + if (current.getSimpleName().toString().startsWith("_")) { + return Visibility.HIDDEN; + } + current = current.getEnclosingElement(); + } + } + + // If no other rules apply, the element is considered published. + return Visibility.PUBLISHED; + } + + /** + * Robustly checks if an element has an @exclude tag in its Javadoc. + */ + private boolean hasExcludeTag(Element element) { + DocCommentTree docCommentTree = getDocTrees().getDocCommentTree(element); + if (docCommentTree == null) { + return false; + } + + return docCommentTree.getBlockTags().stream() + .filter(tag -> tag.getKind() == DocTree.Kind.UNKNOWN_BLOCK_TAG) + .map(UnknownBlockTagTree.class::cast) + .anyMatch(tag -> tag.getTagName().equalsIgnoreCase("exclude")); + } + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java index 2ef3ae9db2a06..0c59784ec490f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java @@ -152,6 +152,7 @@ public enum HtmlAttr { TITLE(true), TRANSLATE(true), TYPE, + USEMAP, VALIGN, VALUE, VERSION, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTag.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTag.java index c88fd867965b8..3613f02b5c44b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTag.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTag.java @@ -61,6 +61,10 @@ public enum HtmlTag { ADDRESS(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), + + AREA(BlockType.INLINE, EndKind.NONE, + attrs(AttrKind.OK, ALT, COORDS, HREF, + REL, SHAPE, TARGET, TYPE)), ARTICLE(BlockType.BLOCK, EndKind.REQUIRED, EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), @@ -204,7 +208,7 @@ public boolean accepts(HtmlTag t) { IFRAME(BlockType.OTHER, EndKind.REQUIRED), IMG(BlockType.INLINE, EndKind.NONE, - attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH, CROSSORIGIN), + attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH, CROSSORIGIN, USEMAP), attrs(AttrKind.HTML4, NAME, ALIGN, HSPACE, VSPACE, BORDER)), INPUT(BlockType.INLINE, EndKind.NONE, @@ -228,6 +232,14 @@ public boolean accepts(HtmlTag t) { attrs(AttrKind.OK, REL)), MAIN(BlockType.OTHER, EndKind.REQUIRED), + + MAP(BlockType.BLOCK, EndKind.REQUIRED, + attrs(AttrKind.OK, NAME)) { + @Override + public boolean accepts(HtmlTag t) { + return (t == AREA); + } + }, MARK(BlockType.INLINE, EndKind.REQUIRED), diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java index b4ee61fc36c76..8ac0172ec18fc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java @@ -160,11 +160,11 @@ public DocletEnvironment getEnvironment(ToolOptions toolOptions, // Normally, the args should be a series of package names or file names. // Parse the files and collect the package names. for (String arg: javaNames) { - if (fm != null && arg.endsWith(".java") && isRegularFile(arg)) { + if (fm != null && (arg.endsWith(".java") || arg.endsWith(".maxj")) && isRegularFile(arg)) { parse(fm.getJavaFileObjects(arg), compilationUnits, true); } else if (isValidPackageName(arg)) { packageNames.add(arg); - } else if (arg.endsWith(".java")) { + } else if (arg.endsWith(".java") || arg.endsWith(".maxj")) { if (fm == null) { String text = log.getText("main.assertion.error", "fm == null"); throw new ToolException(ABNORMAL, text); diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/expr/ExpressionParserConstants.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/expr/ExpressionParserConstants.java index c74d21fa75e42..a4cf7c893d2a2 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/expr/ExpressionParserConstants.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/expr/ExpressionParserConstants.java @@ -50,7 +50,7 @@ public interface ExpressionParserConstants { /** RegularExpression Id. */ int BYTE = 12; /** RegularExpression Id. */ - int CASE = 13; + int _CASE = 13; /** RegularExpression Id. */ int CATCH = 14; /** RegularExpression Id. */