Added support for Julia code duplication.

This commit is contained in:
wener
2023-02-21 19:30:28 +01:00
parent a74bf9665f
commit 636cf15009
15 changed files with 535 additions and 2 deletions

View File

@ -406,6 +406,9 @@ entries:
- title: Gherkin
url: /pmd_languages_gherkin.html
output: web, pdf
- title: Julia
url: /pmd_languages_julia.html
output: web, pdf
- title: Developer Documentation
output: web, pdf
folderitems:

View File

@ -0,0 +1,15 @@
---
title: Julia
permalink: pmd_languages_julia.html
---
The [Julia](https://julialang.org/) is dynamically typed, like a scripting language,
and has good support for interactive use.
Julia was designed from the beginning for high performance.
Julia programs compile to efficient native code for multiple platforms via LLVM.
## Support in PMD
Starting from version 6.55.0, Gherkin support was added to CPD.
### Limitations
- Support for Julia only extends to CPD to detect code duplication in Julia source files.

View File

@ -179,6 +179,11 @@
<artifactId>pmd-jsp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-julia</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-kotlin</artifactId>

View File

@ -28,10 +28,10 @@ public class BinaryDistributionIT extends AbstractBinaryDistributionTest {
static {
// note: apex, javascript, visualforce, and scala require java8
if (PMDExecutor.isJava7Test()) {
SUPPORTED_LANGUAGES_CPD = "Supported languages: [cpp, cs, dart, fortran, gherkin, go, groovy, java, jsp, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, swift, tsql, xml]";
SUPPORTED_LANGUAGES_CPD = "Supported languages: [cpp, cs, dart, fortran, gherkin, go, groovy, java, jsp, julia, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, swift, tsql, xml]";
SUPPORTED_LANGUAGES_PMD = "java, jsp, modelica, plsql, pom, vm, wsdl, xml, xsl";
} else {
SUPPORTED_LANGUAGES_CPD = "Supported languages: [apex, cpp, cs, dart, ecmascript, fortran, gherkin, go, groovy, html, java, jsp, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, scala, swift, tsql, vf, xml]";
SUPPORTED_LANGUAGES_CPD = "Supported languages: [apex, cpp, cs, dart, ecmascript, fortran, gherkin, go, groovy, html, java, jsp, julia, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, scala, swift, tsql, vf, xml]";
SUPPORTED_LANGUAGES_PMD = "apex, ecmascript, html, java, jsp, modelica, plsql, pom, scala, vf, vm, wsdl, xml, xsl";
}
}

59
pmd-julia/pom.xml Normal file
View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>pmd-julia</artifactId>
<name>PMD Julia</name>
<parent>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
<version>6.55.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<useDefaultDelimiters>false</useDefaultDelimiters>
<delimiters>
<delimiter>${*}</delimiter>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-lang-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,163 @@
grammar Julia;
// Parser
// TODO
// Calculate cyclomatic complexity
// Create tokenizer for CPD
// Publish first version 0.1 in Github and remain public for all increments
main
: functionBody (functionDefinition functionBody)* END? EOF
;
functionDefinition
: functionDefinition1
| functionDefinition2
;
functionDefinition1
: FUNCTION IDENTIFIER? anyToken*? ('(' anyToken*? ')' whereClause*? functionBody)? END
;
functionDefinition2
: functionIdentifier '(' anyToken*? ')' whereClause*? '=' functionBody
;
functionIdentifier
: IDENTIFIER
| '(' anyToken*? ')' // Operator
;
whereClause
: WHERE anyToken*?
;
functionBody
: anyToken*? (statement anyToken*?)*?
;
statement
: beginStatement
| doStatement
| forStatement
| functionDefinition1
| ifStatement
| letStatement
| macroStatement
| structStatement
| tryCatchStatement
| typeStatement
| whileStatement
;
beginStatement
: BEGIN functionBody END
;
doStatement
: DO functionBody END
;
forStatement
: FOR functionBody END
;
ifStatement
: IF functionBody (ELSIF functionBody)* (ELSE functionBody)? END
;
letStatement
: LET functionBody END
;
macroStatement
: MACRO functionBody END
;
structStatement
: STRUCT functionBody END
;
tryCatchStatement
: TRY functionBody (CATCH functionBody)? (FINALLY functionBody)? END
;
typeStatement
: TYPE functionBody END
;
whileStatement
: WHILE functionBody END
;
anyToken
: ANY
| BEGIN
| CATCH
| CHAR
| DO
| ELSE
| ELSIF
| END
| EXTERNALCOMMAND
| FINALLY
| FOR
| FUNCTION
| IDENTIFIER
| IF
| LET
| MACRO
| STRING
| STRUCT
| TRY
| TYPE
| WHERE
| WHILE
| '(' anyToken*? ')'
| '[' anyToken*? ']'
| '{' anyToken*? '}'
| '='
| '&&' // short-circuit
| '||' // short-circuit
| '==' // to disambiguate from "="
;
// Lexer
COMMENTS : '#' (~[=\r\n]~[\r\n]*)? -> skip; // skip #= because otherwise multiline comments are not recognized, see next line
MULTILINECOMMENTS1 : '#=' .*? '=#' -> skip;
MULTILINECOMMENTS2 : '```' .*? '```' -> skip;
MULTILINESTRING : '"""' ('\\"'|.)*? '"""' -> skip;
NL : '\r'? '\n' -> skip ;
WHITESPACE : [ \t]+ -> skip ;
BEGIN : 'begin' ;
CATCH : 'catch' ;
CHAR : '\'' '\\'? .? '\'' ;
DO : 'do' ;
ELSE : 'else' ;
ELSIF : 'elsif' ;
END : 'end' ;
EXTERNALCOMMAND : '`' .*? '`' ;
FINALLY : 'finally' ;
FOR : 'for' ;
FUNCTION : 'function' ;
IF : 'if' ;
LET : 'let' ;
MACRO : 'macro' ;
STRING : '"' ('\\\\'|'\\"'|'$(' ('$(' .*? ')'|'"' .*? '"'|.)*? ')'|.)*? '"';
STRUCT : 'struct' ;
TRY : 'try' ;
TYPE : 'type' ;
WHERE : 'where' ;
WHILE : 'while' ;
IDENTIFIER : [$a-zA-Z_] [a-zA-Z_0-9]* ;
ANY : . ;

View File

@ -0,0 +1,8 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* Contains the Antlr grammar for Julia.
*/
package net.sourceforge.pmd.lang.julia.ast;

View File

@ -0,0 +1,20 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.julia.cpd;
import net.sourceforge.pmd.cpd.AbstractLanguage;
/**
* Language implementation for Julia.
*/
public class JuliaLanguage extends AbstractLanguage {
/**
* Creates a new Julia Language instance.
*/
public JuliaLanguage() {
super("Julia", "julia", new JuliaTokenizer(), ".jl");
}
}

View File

@ -0,0 +1,30 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.julia.cpd;
import org.antlr.v4.runtime.CharStream;
import net.sourceforge.pmd.cpd.AntlrTokenizer;
import net.sourceforge.pmd.cpd.SourceCode;
import net.sourceforge.pmd.cpd.token.AntlrTokenFilter;
import net.sourceforge.pmd.lang.antlr.AntlrTokenManager;
import net.sourceforge.pmd.lang.julia.ast.JuliaLexer;
/**
* The Julia Tokenizer.
*/
public class JuliaTokenizer extends AntlrTokenizer {
@Override
protected AntlrTokenManager getLexerForSource(SourceCode sourceCode) {
CharStream charStream = AntlrTokenizer.getCharStreamFromSourceCode(sourceCode);
return new AntlrTokenManager(new JuliaLexer(charStream), sourceCode.getFileName());
}
@Override
protected AntlrTokenFilter getTokenFilter(final AntlrTokenManager tokenManager) {
return new AntlrTokenFilter(tokenManager);
}
}

View File

@ -0,0 +1,8 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/**
* Contains Julia tokenizer and language classes.
*/
package net.sourceforge.pmd.lang.julia.cpd;

View File

@ -0,0 +1 @@
net.sourceforge.pmd.lang.julia.cpd.JuliaLanguage

View File

@ -0,0 +1,34 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.util.Properties;
import org.junit.Test;
import net.sourceforge.pmd.cpd.test.CpdTextComparisonTest;
import net.sourceforge.pmd.lang.julia.cpd.JuliaTokenizer;
public class JuliaTokenizerTest extends CpdTextComparisonTest {
public JuliaTokenizerTest() {
super(".jl");
}
@Override
protected String getResourcePrefix() {
return "../lang/julia/cpd/testdata";
}
@Override
public Tokenizer newTokenizer(Properties properties) {
JuliaTokenizer tok = new JuliaTokenizer();
return tok;
}
@Test
public void testMathExample() {
doTest("mathExample");
}
}

View File

@ -0,0 +1,33 @@
# function to calculate the volume of a sphere
function sphere_vol(r)
# julia allows Unicode names (in UTF-8 encoding)
# so either "pi" or the symbol π can be used
return 4/3*pi*r^3
end
# functions can also be defined more succinctly
quadratic(a, sqr_term, b) = (-b + sqr_term) / 2a
# calculates x for 0 = a*x^2+b*x+c, arguments types can be defined in function definitions
function quadratic2(a::Float64, b::Float64, c::Float64)
# unlike other languages 2a is equivalent to 2*a
# a^2 is used instead of a**2 or pow(a,2)
sqr_term = sqrt(b^2-4a*c)
r1 = quadratic(a, sqr_term, b)
r2 = quadratic(a, -sqr_term, b)
# multiple values can be returned from a function using tuples
# if the return keyword is omitted, the last term is returned
r1, r2
end
vol = sphere_vol(3)
# @printf allows number formatting but does not automatically append the \n to statements, see below
using Printf
@printf "volume = %0.3f\n" vol
#> volume = 113.097
quad1, quad2 = quadratic2(2.0, -2.0, -12.0)
println("result 1: ", quad1)
#> result 1: 3.0
println("result 2: ", quad2)
#> result 2: -2.0

View File

@ -0,0 +1,153 @@
[Image] or [Truncated image[ Bcol Ecol
L2
[function] 1 8
[sphere_vol] 10 19
[(] 20 20
[r] 21 21
[)] 22 22
L5
[return] 3 8
[4] 10 10
[/] 11 11
[3] 12 12
[*] 13 13
[pi] 14 15
[*] 16 16
[r] 17 17
[^] 18 18
[3] 19 19
L6
[end] 1 3
L9
[quadratic] 1 9
[(] 10 10
[a] 11 11
[,] 12 12
[sqr_term] 14 21
[,] 22 22
[b] 24 24
[)] 25 25
[=] 27 27
[(] 29 29
[-] 30 30
[b] 31 31
[+] 33 33
[sqr_term] 35 42
[)] 43 43
[/] 45 45
[2] 47 47
[a] 48 48
L12
[function] 1 8
[quadratic2] 10 19
[(] 20 20
[a] 21 21
[:] 22 22
[:] 23 23
[Float64] 24 30
[,] 31 31
[b] 33 33
[:] 34 34
[:] 35 35
[Float64] 36 42
[,] 43 43
[c] 45 45
[:] 46 46
[:] 47 47
[Float64] 48 54
[)] 55 55
L15
[sqr_term] 3 10
[=] 12 12
[sqrt] 14 17
[(] 18 18
[b] 19 19
[^] 20 20
[2] 21 21
[-] 22 22
[4] 23 23
[a] 24 24
[*] 25 25
[c] 26 26
[)] 27 27
L16
[r1] 3 4
[=] 6 6
[quadratic] 8 16
[(] 17 17
[a] 18 18
[,] 19 19
[sqr_term] 21 28
[,] 29 29
[b] 31 31
[)] 32 32
L17
[r2] 3 4
[=] 6 6
[quadratic] 8 16
[(] 17 17
[a] 18 18
[,] 19 19
[-] 21 21
[sqr_term] 22 29
[,] 30 30
[b] 32 32
[)] 33 33
L20
[r1] 3 4
[,] 5 5
[r2] 7 8
L21
[end] 1 3
L23
[vol] 1 3
[=] 5 5
[sphere_vol] 7 16
[(] 17 17
[3] 18 18
[)] 19 19
L25
[using] 1 5
[Printf] 7 12
L26
[@] 1 1
[printf] 2 7
["volume = %0.3f\\n"] 9 26
[vol] 28 30
L29
[quad1] 1 5
[,] 6 6
[quad2] 8 12
[=] 14 14
[quadratic2] 16 25
[(] 26 26
[2] 27 27
[.] 28 28
[0] 29 29
[,] 30 30
[-] 32 32
[2] 33 33
[.] 34 34
[0] 35 35
[,] 36 36
[-] 38 38
[1] 39 39
[2] 40 40
[.] 41 41
[0] 42 42
[)] 43 43
L30
[println] 1 7
[(] 8 8
["result 1: "] 9 20
[,] 21 21
[quad1] 23 27
[)] 28 28
L32
[println] 1 7
[(] 8 8
["result 2: "] 9 20
[,] 21 21
[quad2] 23 27
[)] 28 28
EOF

View File

@ -1085,6 +1085,7 @@
<module>pmd-lua</module>
<module>pmd-java</module>
<module>pmd-jsp</module>
<module>pmd-julia</module>
<module>pmd-kotlin</module>
<module>pmd-matlab</module>
<module>pmd-modelica</module>