Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
梦境迷离
Scala Macro Tools
提交
ed92a6f1
S
Scala Macro Tools
项目概览
梦境迷离
/
Scala Macro Tools
上一次同步 大约 1 年
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
Scala Macro Tools
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
ed92a6f1
编写于
11月 25, 2021
作者:
梦境迷离
提交者:
GitHub
11月 25, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add `@JavaCompatible` (#119)
* add JavaCompatible * ready to 0.3.2
上级
02c349ce
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
272 addition
and
4 deletion
+272
-4
README.md
README.md
+3
-2
README_CN.md
README_CN.md
+3
-2
src/main/scala/io/github/dreamylost/JavaCompatible.scala
src/main/scala/io/github/dreamylost/JavaCompatible.scala
+42
-0
src/main/scala/io/github/dreamylost/macros/javaCompatibleMacro.scala
...ala/io/github/dreamylost/macros/javaCompatibleMacro.scala
+112
-0
src/test/scala/io/github/dreamylost/JavaCompatibleTest.scala
src/test/scala/io/github/dreamylost/JavaCompatibleTest.scala
+112
-0
未找到文件。
README.md
浏览文件 @
ed92a6f1
...
...
@@ -18,8 +18,8 @@ Learn Scala macro and abstract syntax tree.
# Environment
-
It is compiled in Java 8,
11
-
It is compiled in Scala 2.11.x ~ 2.13.x
-
Compile passed in Java 8、
11
-
Compile passed in Scala 2.11.12、2.12.14、2.13.6
# Features
...
...
@@ -33,6 +33,7 @@ Learn Scala macro and abstract syntax tree.
-
`@equalsAndHashCode`
-
`@jacksonEnum`
-
`@elapsed`
-
`@JavaCompatible`
> The intellij plugin named `Scala-Macro-Tools` in marketplace.
...
...
README_CN.md
浏览文件 @
ed92a6f1
...
...
@@ -18,8 +18,8 @@
# 环境
-
使用 Java 8,
11 编译通过
-
使用 Scala 2.11.x ~ 2.13.x
编译通过
-
Java 8、
11 编译通过
-
Scala 2.11.12、2.12.14、2.13.6
编译通过
# 功能
...
...
@@ -33,6 +33,7 @@
-
`@equalsAndHashCode`
-
`@jacksonEnum`
-
`@elapsed`
-
`@JavaCompatible`
> Intellij插件 `Scala-Macro-Tools`。
...
...
src/main/scala/io/github/dreamylost/JavaCompatible.scala
0 → 100644
浏览文件 @
ed92a6f1
/*
* Copyright (c) 2021 jxnu-liguobin && contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package
io.github.dreamylost
import
scala.annotation.
{
compileTimeOnly
,
StaticAnnotation
}
import
io.github.dreamylost.macros.javaCompatibleMacro
/**
* annotation to generate non-parameter constructor and get/set method for case classes.
* Fields marked `private[this]` in curry are not supported !
*
* @author 梦境迷离
* @param verbose Whether to enable detailed log.
* @since 2021/11/23
* @version 1.0
*/
@compileTimeOnly
(
"enable macro to expand macro annotations"
)
final
class
JavaCompatible
(
verbose
:
Boolean
=
false
)
extends
StaticAnnotation
{
def
macroTransform
(
annottees
:
Any*
)
:
Any
=
macro
javaCompatibleMacro
.
JavaCompatibleProcessor
.
impl
}
src/main/scala/io/github/dreamylost/macros/javaCompatibleMacro.scala
0 → 100644
浏览文件 @
ed92a6f1
/*
* Copyright (c) 2021 jxnu-liguobin && contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package
io.github.dreamylost.macros
import
scala.reflect.macros.whitebox
/**
*
* @author 梦境迷离
* @since 2021/11/23
* @version 1.0
*/
object
javaCompatibleMacro
{
class
JavaCompatibleProcessor
(
override
val
c
:
whitebox.Context
)
extends
AbstractMacroProcessor
(
c
)
{
import
c.universe._
/**
* We generate this method with currying, and we have to deal with the first layer of currying alone.
*/
private
def
getNoArgsContrWithCurrying
(
annotteeClassParams
:
List
[
List
[
Tree
]],
annotteeClassDefinitions
:
Seq
[
Tree
])
:
Tree
=
{
if
(
annotteeClassDefinitions
.
exists
(
f
=>
!
isNotLocalClassMember
(
f
)))
{
c
.
info
(
c
.
enclosingPosition
,
s
"The params of 'private[this]' exists in class constructor"
,
verbose
)
}
annotteeClassDefinitions
.
foreach
{
case
defDef
:
DefDef
if
defDef.name.decodedName.toString
=
=
"this"
&&
defDef
.
vparamss
.
isEmpty
=>
c
.
abort
(
defDef
.
pos
,
"Non-parameter constructor method has already defined, please remove it or not use'@JavaCompatible'"
)
case
_
=>
}
val
defaultParameters
=
annotteeClassParams
.
map
(
valDefAccessors
).
map
(
params
=>
params
.
map
(
param
=>
{
param
.
paramType
match
{
case
t
if
t
<:<
typeOf
[
Int
]
=>
q
"0"
case
t
if
t
<:<
typeOf
[
Byte
]
=>
q
"0"
case
t
if
t
<:<
typeOf
[
Double
]
=>
q
"0D"
case
t
if
t
<:<
typeOf
[
Float
]
=>
q
"0F"
case
t
if
t
<:<
typeOf
[
Short
]
=>
q
"0"
case
t
if
t
<:<
typeOf
[
Long
]
=>
q
"0L"
case
t
if
t
<:<
typeOf
[
Char
]
=>
q
"63.toChar"
// default char is ?
case
t
if
t
<:<
typeOf
[
Boolean
]
=>
q
"false"
case
_
=>
q
"null"
}
}))
if
(
annotteeClassParams
.
isEmpty
||
annotteeClassParams
.
size
==
1
)
{
q
"""
def this() = {
this(..${defaultParameters.flatten})
}
"""
}
else
{
q
"""
def this() = {
this(..${defaultParameters.head})(...${defaultParameters.tail})
}
"""
}
}
private
def
replaceAnnotation
(
valDefTree
:
Tree
)
:
Tree
=
{
val
safeValDef
=
valDefAccessors
(
Seq
(
valDefTree
)).
head
val
mods
=
safeValDef
.
mods
.
mapAnnotations
(
f
=>
{
if
(!
f
.
toString
().
contains
(
"BeanProperty"
))
f
++
List
(
q
"new _root_.scala.beans.BeanProperty"
)
else
f
})
ValDef
(
mods
,
safeValDef
.
name
,
safeValDef
.
tpt
,
safeValDef
.
rhs
)
}
private
def
getClassWithBeanProperty
(
classDecl
:
ClassDef
)
:
Tree
=
{
val
q
"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends ..$bases { ..$body }"
=
classDecl
val
newFieldss
=
paramss
.
asInstanceOf
[
List
[
List
[
Tree
]]].
map
(
_
.
map
(
replaceAnnotation
))
q
"$mods class $tpname[..$tparams] $ctorMods(...$newFieldss) extends ..$bases { ..$body }"
}
override
def
createCustomExpr
(
classDecl
:
ClassDef
,
compDeclOpt
:
Option
[
ModuleDef
]
=
None
)
:
Any
=
{
val
tmpClassDefTree
=
appendClassBody
(
classDecl
,
classInfo
=>
List
(
getNoArgsContrWithCurrying
(
classInfo
.
classParamss
,
classInfo
.
body
)))
val
rest
=
getClassWithBeanProperty
(
tmpClassDefTree
)
c
.
Expr
(
q
"""
${compDeclOpt.fold(EmptyTree)(x => x)}
$rest
"""
)
}
override
def
checkAnnottees
(
annottees
:
Seq
[
c.universe.Expr
[
Any
]])
:
Unit
=
{
super
.
checkAnnottees
(
annottees
)
val
annotateeClass
:
ClassDef
=
checkGetClassDef
(
annottees
)
if
(!
isCaseClass
(
annotateeClass
))
{
c
.
abort
(
c
.
enclosingPosition
,
ErrorMessage
.
ONLY_CASE_CLASS
)
}
}
}
}
src/test/scala/io/github/dreamylost/JavaCompatibleTest.scala
0 → 100644
浏览文件 @
ed92a6f1
/*
* Copyright (c) 2021 jxnu-liguobin && contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package
io.github.dreamylost
import
org.scalatest.flatspec.AnyFlatSpec
import
org.scalatest.matchers.should.Matchers
/**
*
* @author 梦境迷离
* @since 2021/11/23
* @version 1.0
*/
class
JavaCompatibleTest
extends
AnyFlatSpec
with
Matchers
{
"JavaCompatible1"
should
"ok"
in
{
"""
| @JavaCompatible
| case class A(a: Int, b: Short, c: Byte, d: Double, e: Float, f: Long, g: Char, h: Boolean)
| val t = new A()
| assert(t.a == 0 && t.g == '?')
|"""
.
stripMargin
should
compile
}
"JavaCompatible2"
should
"ok"
in
{
"""
| @JavaCompatible
| case class A(a: Int, b: Short, c: Byte, d: Double)(val e: Float, val f: Long)(val g: Char, val h: Boolean)
| val t = new A()
| assert(t.a == 0 && t.g == '?')
|"""
.
stripMargin
should
compile
}
"JavaCompatible3"
should
"failed"
in
{
"""
| @JavaCompatible
| case class A(a: Int, b: Short, c: Byte, d: Double)(val e: Float, val f: Long)(g: Char, h: Boolean)
| val t = new A()
| assert(t.a == 0 && t.g == '?')
|"""
.
stripMargin
shouldNot
compile
"""
| @JavaCompatible
| class A(val a: Int, val b: Short)
| val t = new A()
| assert(t.a == 0)
|"""
.
stripMargin
shouldNot
compile
}
"JavaCompatible4"
should
"ok"
in
{
@JavaCompatible
case
class
A
(
a
:
Int
,
b
:
Short
,
c
:
Byte
,
d
:
Double
,
e
:
Float
,
f
:
Long
,
g
:
Char
,
h
:
Boolean
,
i
:
String
)
val
t
=
new
A
()
assert
(
t
.
a
==
0
&&
t
.
g
==
'?'
)
}
"JavaCompatible5"
should
"ok"
in
{
import
scala.beans.BeanProperty
@JavaCompatible
case
class
A
(
@BeanProperty
a
:
Int
,
b
:
Short
,
c
:
Byte
,
d
:
Double
,
e
:
Float
,
f
:
Long
,
g
:
Char
,
h
:
Boolean
,
i
:
String
)
val
t
=
new
A
()
assert
(
t
.
a
==
0
&&
t
.
g
==
'?'
)
}
"JavaCompatible6"
should
"ok when exists @BeanProperty"
in
{
import
scala.beans.BeanProperty
@JavaCompatible
case
class
A
(
@BeanProperty
a
:
Int
,
b
:
Short
,
c
:
Byte
,
d
:
Double
,
e
:
Float
,
f
:
Long
,
g
:
Char
,
h
:
Boolean
,
i
:
String
)
val
t
=
new
A
()
assert
(
t
.
getA
==
0
)
assert
(
t
.
getB
==
0
)
}
"JavaCompatible7"
should
"ok when exists super"
in
{
import
scala.beans.BeanProperty
class
B
(
@BeanProperty
val
name
:
String
,
@BeanProperty
val
id
:
Int
)
@JavaCompatible
case
class
A
(
a
:
Int
,
b
:
Short
,
override
val
name
:
String
,
override
val
id
:
Int
)
extends
B
(
name
,
id
)
val
t
=
new
A
()
assert
(
t
.
getA
==
0
)
assert
(
t
.
getB
==
0
)
}
// Why this code compile failed but test in """ """.stripMargin will pass?
"JavaCompatible8"
should
"fail when exists super but not use @BeanProperty"
in
{
"""
| class B(val name: String, val id: Int)
| @JavaCompatible
| case class A(a: Int, b: Short, override val name: String, override val id: Int) extends B(name, id)
| val t = new A()
|"""
.
stripMargin
should
compile
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录