手拉手教你实现一门编程语言 Enkel, 系列 17

本文系 Creating JVM language 翻译的第 17 篇。 原文中的代码和原文有不一致的地方均在新的代码仓库中更正过,建议参考新的代码仓库。

源码

Github

字节码 - JVM 语言的通用描述

所有基于 JVM 的编程语言最终被编译到字节码,然后被虚拟机加载解释执行,这意味着虚拟机并不知道是什么语言生成了字节码。只要类在 classpath 上。

这为 Enkel 调用 Java 库以及其他框架提供了具体可能性。

查找类方法和构造器

为了能够引用到其他类,有如下两种选择:

  • 运行时 相信程序员并且不检验生成的字节码,这可能会导致如果 classpath 不存在,JVM 会抛出异常
  • 编译时 在生成字节码之前验证。如果验证失败,会终止编译过程。

在 Enkel 中,我决定使用第二种方式,主要是出于安全考量。我们可以使用反射 API 来实现:

public class ClassPathScope {

 public Optional<FunctionSignature> getMethodSignature(Type owner, String methodName, List<Type> arguments) {
     try {
         Class<?> methodOwnerClass = owner.getTypeClass();
         Class<?>[] params = arguments.stream()
                 .map(Type::getTypeClass).toArray(Class<?>[]::new);
         Method method = methodOwnerClass.getMethod(methodName,params);
         return Optional.of(ReflectionObjectToSignatureMapper.fromMethod(method));
     } catch (Exception e) {
         return Optional.empty();
     }
 }

 public Optional<FunctionSignature> getConstructorSignature(String className, List<Type> arguments) {
     try {
         Class<?> methodOwnerClass = Class.forName(className);
         Class<?>[] params = arguments.stream()
                 .map(Type::getTypeClass).toArray(Class<?>[]::new);
         Constructor<?> constructor = methodOwnerClass.getConstructor(params);
         return Optional.of(ReflectionObjectToSignatureMapper.fromConstructor(constructor));
     } catch (Exception e) {
         return Optional.empty();
     }
 }
}
复制代码

如果方法或者构造器不存在,会抛异常并且终止编译:

    //Scope.java
    return new ClassPathScope().getMethodSignature(owner.get(), methodName, argumentsTypes)
                    .orElseThrow(() -> new MethodSignatureNotFoundException(this,methodName,arguments));
复制代码

这种方式看起来更加安全,但是同时也会慢一点。所有的依赖需要在编译的时候通过反射的方式来解决依赖。

示例

调用其他 Enkel 类

下面我们从 Client 类中调用 Library 的方法:

 Client {
 
     start {
         print "Client: Calling my own 'Library' class:"
         var myLibrary = new Library()
         var addition = myLibrary.add(5,2)
         print "Client: Result returned from 'Library.add' = " + addition
     }
 
 }
复制代码
Library {

    int add(int x,int y) {
        print "Library: add() method called"
        return x+y
    }

}
复制代码

这里我们需要先编译 Library(我们目前不支持多文件同时编译),否则 Client 没办法编译通过。

kuba@kuba-laptop:~/repos/Enkel-JVM-language$ java -classpath compiler/target/compiler-1.0-SNAPSHOT-jar-with-dependencies.jar:. com.kubadziworski.compiler.Compiler EnkelExamples/ClassPathCalls/Library.enk 
kuba@kuba-laptop:~/repos/Enkel-JVM-language$ java -classpath compiler/target/compiler-1.0-SNAPSHOT-jar-with-dependencies.jar:. com.kubadziworski.compiler.Compiler EnkelExamples/ClassPathCalls/Client.enk 
kuba@kuba-laptop:~/repos/Enkel-JVM-language$ java Client 
Client: Calling my own 'Library' class:
Library: add() method called
Client: Result returned from 'Library.add' = 7
复制代码

调用 Java 的 API


    start {
        var someString = "someString"
        print someString + " to upper case : " +  someString.toUpperCase()
    }

}
复制代码
$ java Client 
cos to upper case = COS
复制代码

转载于:https://juejin.im/post/5b914c6bf265da0ac25648b5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值