Elena编程语言简介

2020-06-06 23:03:15

Elena是一种具有后期绑定的通用语言。它是多范例的,结合了函数式和面向对象编程的特点。它同时支持强类型和弱类型、运行时转换、装箱和取消装箱基元类型、直接使用外部库。提供了一组丰富的工具来处理消息分派:多方法、消息限定、通用消息处理程序。

开发和学习编程语言是一项艰巨的任务。因此,遇到一种新语言时,您可能会问:为什么要使用另一种编程语言?简短的答案是尝试一下不同的方式。为什么不把消息当作可以进行不同操作的普通语言元素来处理:加载、传递、修改、分派?我们可以在不使用反射的情况下做到这一点吗?这就是我的动机。Elena的设计目的是方便编写动态、多态的代码,将动态和静态语言的元素结合起来。

Elena是一种具有后期绑定的通用语言。它是多范例的,结合了函数式和面向对象编程的特点。它同时支持强类型和弱类型、运行时转换、装箱和取消装箱基元类型、直接使用外部库。提供了一组丰富的工具来处理消息分派:多方法、消息限定、通用消息处理程序。多重继承可以使用混合和类型接口来模拟。内置脚本引擎允许将自定义脚本合并到您的应用程序中。同时支持独立应用程序和虚拟机客户端。

Elena编译器是用C++完全实现的。编译时,编译器不需要外部依赖项,如Flex、Bison.。您只需要Visual Studio 2017版或更高版本。

要构建编译器,您可以打开CMD,转到根Elena文件夹并键入:

在开始100%面向对象语言的程序之前,了解真正面向对象语言的基本概念是极其重要的。

在OOP中,类定义了此类型的所有对象通用的一组属性和方法。它可能包含用于创建其实例的特殊方法,称为-构造函数。

对象是类的实例。通常,对象存储在动态内存中。对象有一种特殊情况-Singleton,它只作为单个实例存在。请注意,在Elena中,类本身就是一个对象,可以像使用任何其他对象一样使用它。

字段,也称为实例变量,是在类中声明的变量。只有使用赋值或读取字段内容的方法才能读取这些变量。还支持静态字段。

在C++中,我们谈论的是指向对象的指针,而在C#中,我们谈论的是指向对象的引用。这两个概念基本上是相同的,引用是由直接指针实现的,而直接指针只是内存地址。在Elena中,我们使用引用。

方法类似于函数,不同之处在于它应用于特定对象。我们还可以说,该方法是在对象上调用的,或者是发送给";对象的。所讨论的对象被称为接收者。在接收对象上调用每个方法。在C++或C#中,接收器在Elena-";self";中称为";this";。

Elena中的方法类似于C#和C++中的方法,在C#和C++中,它们被调用";成员函数";。方法可以接受参数并始终返回结果(如果没有提供结果,则返回自己的引用)。方法体是一系列可执行语句。方法从表达式中调用,就像在其他语言中一样。

";方法&34;和";消息";之间有一个重要的区别。方法是代码体,而消息是发送的内容。方法类似于函数。在此类比中,发送消息类似于调用函数。调用方法的表达式称为消息发送表达式。

Elena术语明确区分了";消息";和";方法";。消息发送表达式将向对象发送消息。对象如何响应消息取决于对象的类。不同类的对象将以不同的方式响应同一消息,因为它们将调用不同的方法。泛型方法可以接受具有指定签名(参数类型)的任何消息。

当我们学习或仅仅是了解任何一种新的编程语言时,一个很好的开始总是著名的程序Hello world!";。

为了创建我们的第一个程序,我们必须获得Elena编译器,为此,您只需在此链接中下载编译器。

由于bin文件夹位于PATH系统中,这对于能够生成可执行文件以访问所使用的Elena运行时是必要的,例如,当异常抛出以显示异常发生在哪个类&;方法中时。

让我们开始吧,首先,我们需要打开Elena IDE,为此,您可以键入cmd&34;elide&34;或者,只需打开名为#34;elide&34;的可执行文件。

打开elide IDE后,我们将新建一个项目,为此,我们只需要进入菜单";File->;New->;Project";,当您在项目菜单中单击时,会打开如下对话框:

类型:是您将创建的应用程序的类型,如GUI、控制台、在虚拟机上运行的控制台应用程序.。

单击";确定&34;后,我们需要创建一个新的源文件,为此,只需转到菜单";文件-&>源文件";或使用快捷方式";Ctrl+N";。

编写完这段代码后,您需要将项目和源代码保存在某个目录中,您只需要构建它。

这里,我们声明一个公共函数(包含函数和消息的静态类)。默认情况下,程序是程序的入口点,但是可以更改这一点。

";system";:它是一个命名空间,命名空间本身可以包含用撇号分隔的子元素

这对我们意味着什么?这意味着我们使用参数";Hello World!";向命名空间System中的类Console的方法writeLine发送一条消息。

就像在C#、C++、Python等其他语言中一样,我们可以向导入某些命名空间添加特殊关键字,使用此关键字,我们可以减少代码。

这个程序唯一的问题是我们不能读取输出……所以,要解决这个问题,我们只需要再使用一个方法,我们可以通过两种方式使用这个方法。

最后一个分号可以省略。编写相同程序的第二种方法效果很好,因为在Elena中,每个方法都返回一个对象。

就像在Smalltalk中一样,在Elena中,所有东西都是对象,因此,要创建变量,我们只需要使用属性var。

因此,举个例子,让我们编写一个简单的程序来从键盘上读取一些东西。

导入扩展;public program(){var number:=console.print(";键入编号:";).readLine().toInt();*console.printLine(";您键入";,number);*console.readChar()}。

很简单,对吧?因此,在本例中,我们需要再导入一个名称空间,名称空间扩展包含扩展方法#";loadLineTo[2]";的定义。

var x:=new IntNumber();var y:=0;var k:=new system';Calendar';date();var n:=k.Year;var s:=";Hello World";;var u:=0fffffh;var l:=3.1415r;var m:=new RealNumber(3.14r);var j:=true;var h:=false;

导入扩展;Singleton Tester{printMe(S){console.printLine(S)}}公共程序(){var a;var b:=a:=2;Tester.printMe(A);Tester.printMe(B);Tester.printMe(b:=3);}。

导入扩展;单例测试器{printMe(S){console.printLine(S)}assignMe(ref retVal,val){retVal:=val}}public program(){Tester.assignMe(ref var I,2);Tester.printMe(I);}。

可以使用代码模板-if声明Elena中的分支语句。让我们来看看:

导入扩展;public program(){console.writeLine:";Hi!!:)";;var you name:=console.writeLine(";您的名字?";).readLine();console.writeLine:";;var your Age:=console.loadLineTo(new Integer());var number of fChildrens:=0;if(your Age&Get。你还很年轻!!&34;}否则(your Age>;=11&;&;your Age<;=20){console.writeLine:";青春期,会有很多人生气吗?";}如果(your Age&>;=21&;&;your Age<;=30){console.writeLine:&34;您已经有孩子了吗?(是/否)&34;;String有孩子吗?如果(haveChildren.lowerCase()==";yes";){number OfChildrens:=console.writeLine(";Cool!!您有几个孩子?";).loadLineTo(new Integer())}}如果(your Age>;=31&;&;your Age<;=40){console.writeLine:";童年的前40年是最困难的!&34;}如果(your Age&>;=41&;&;your Age<;=50){console.writeLine:";Life。=51&;&;您的年龄<;=60){console.writeLine:";享受您的生活!";}如果(your Age>;=61){console.writeLine:";您到了享受和放松的年龄!!";};console.readChar()}。

像在其他编程语言中一样,Elena支持循环,让我们来看看While循环,这个循环是使用WHILE和FOR模板实现的。

导入扩展;public program(){var array:=Array.Allocation:200;var i:=0;While(i<;array.Length){array[i]:=i*10;i+=1};for(int i:=0,i<;array.Length,i+=1){console.printLine(";at index";,i,";具有值:";,array[i]);

Elena支持以下模板运算符:doIfNotNil(.?,类似于C#)和tryOrReturn(.\)。

tryOrReturn尝试向左操作数发送消息并返回操作结果。如果对象不处理它,则返回空。

导入系统;导入扩展;B{test(String Command){console.printLine(Command);}}C;public program(){var a:=nil;var b:=new B();var c:=new C();a.?test(";fired a.?test&34;);b.?test(";fired b.?test&34;);a.\test(";fired a.\test&34;);已解雇b.\test";);c.\test(";fired c.\test";);console.readLine();}。

public program(){1//声明嵌套函数Func f1:={console.writeLine(";fired';f1';";)};Func f2:=nil;f1.?();f2.?();console.readLine();}。

Elena是一种面向对象的语言。要创建程序,我们必须声明新类。

类用代码(方法)封装数据(字段)以访问它。在大多数情况下,无法直接访问课程内容。通常,该字段引用另一个类,依此类推,直到我们到达内容被视为原始数据(例如,数字值或文字值)的原始类。

类形成继承树。有一个常见的超级类系统对象。尽管可以使用分派处理程序(混合/组对象)或接口继承代码,但Elena不支持多重继承。当没有提供父类时,该类直接继承系统对象(超类)。

类实例可以在特殊方法-构造函数的帮助下创建。构造函数主要用于初始化类字段。有一些特殊类型的类没有构造函数,可以直接使用(嵌套类、扩展、闭包)。类本身被视为无状态对象。

为了理解这些信息,我们将编写一些类,以使其实现和使用更加清晰。

导入系统;导入扩展;类MyFirstClass{构造函数(){console.printLine(";MyFirstClass实例化!ehhhhhh!!";)}}public program(){var myFirstClass:=new MyFirstClass();console.readChar()}。

面向对象编程的基本原则之一是类之间的继承,所以让我们实现两个类,一个基类和一个派生类。

导入系统;导入扩展;类MyFirstBaseClass{string theField1;string theField2;构造函数new(){theField1:=";";;theField2:=";";}构造函数new(String Field1){console.printLine(";fieldBaseClass1=";,field1);theField1:=field1;console.printLine(";fieldBaseClass2=";,field2);theField1:=field1;theField2:=field2}printFields(){console.printLine(self.Field1);console.printLine(self.Field2)}Field1=theField1;//property Field1 Field2=theField2;--从DerivedClass";){console.printLine(";使用1个参数调用MyFirstDerivedClass的构造函数";);console.printLine(";field1=";,field1)}构造函数(String field1,string field2)<;=new(field1+&34;;--从DerivedClass";,field2调用。console.printLine(";field1=";,field1);console.printLine(";field2=";,field2)}}public Program(){var myFirstDerivedClassInstance:=nil;var number OfArgsToInitInstance:=0;var ContinueLoop:=true;而(ContineLoop){number OfArgsToInitInstance。&;number OfArgsToInitInstance<;=2){ContineLoop:=false}};//这是';开关';.。number OfArgsToInitInstance=>;0{myFirstDerivedClassInstance:=new MyFirstDerivedClass()}1{myFirstDerivedClassInstance:=new MyFirstDerivedClass(";来自程序";)}}2{myFirstDerivedClassInstance:=new MyFirstDerivedClass(";Argument1。

可以声明不能在类外部调用的私有方法。

导入扩展;class MyClass{private printPrivate(){console.printLine(";private prin.";)}printPublic(){console.print(";call from public print-";);//self是对当前对象self.printPrivate()}}public program(){//注意,如果构造函数未显式声明//系统对象1(没有输入参数)将继承var myClass:=new MyClass:=new MyClass:=new MyMyClass:=new MyClass:=new MyClass。myClass.printPrivate()}。

在正常情况下,类字段不能在类之外访问。这就是为什么我们可以声明一种特殊的方法来访问它:

导入扩展;类MyClass{int_x;get int x()=_x;//获取访问器集x(Int O)//设置访问器{_x:=o}}public program(){var myClass:=new MyClass();myClass.x:=2;console.printLine(";MyClass.x=";,myClass.x)}。

导入扩展;类MyClass{prop int x;}public program(){var myClass:=new MyClass();myClass.x:=2;console.printLine(";MyClass.x=";,myClass.x)}

让我们学习如何在基本数据类型(int、long、real、string)之间进行转换。我们将使用扩展模块中声明的扩展方法。

导入扩展;public program(){int n:=20;real r:=3.4r;long l:=5000000000000l;console.writeLine(";n=";+n.toString());console.writeLine(";r=";+r.toString());console.writeLine(";l=";+l.toString();}。

导入扩展;public program(){int n:=20;long l:=50000000000l;console.writeLine(";n=0o";+n.toString(8));console.writeLine(";l=0x";+l.toString(16));}。

导入扩展;公共程序(){int n:=";20";.toInt();//=20 long l:=";5000000000000";.toLong();//=50000000000l实际r:=";2.3";.toReal();//=2.3r}。

导入扩展;公共程序(){int n:=";24";.toInt(8);//=20 long l:=";48C27395000";.toLong(16);//=50000000000001}。

导入扩展;public program(){int n:=200;long l:=n.toLong();//=200l real r1:=n.toReal();//=200.0r real R2:=l.toReal();//=200.0r}。

导入扩展;:public program(){int n:=200;long l:=n;//=200l real r1:=n;//=200.0r real r2:=l;//=200.0r}。

如果实数没有小数部分,则可以将实数转换为整数:

导入扩展;public program(){real r:=200.0r;long l:=r.toLong();//=200l int n:=r.toInt();//=200}。

导入扩展;public program(){real r:=200.2r;real r2:=r.Integer;//=200.0r long l:=r.Integer.toLong();//=200l int n:=r.Integer.toInt();//=200}。

导入扩展;PUBLIC PROGRAM(){try{new object().nonExistingMethod();}catch::{函数(MethodNotFoundException E)*{}:console.console.printLine(";方法未找到";)*}**函数(异常e)*{}*console.printLine(";未知错误";)(";UNKNOWN ERROR";)(";未知错误";)(";UNKNOWN ERROR";)(";未知错误";)(";未知错误";)。

导入扩展;public program(){console.printLine(";try";);try{var o:=new object();o.ail();}Finally{console.printLine(";Finally";);}catch(Exception E){console.printLine(";error!";);}}。

如果我们想要保证对象始终正确关闭,可以使用Using Pattern:

导入扩展;类A{构造函数(){console.printLine(";打开";);}do(){console.printLine(";做";);}关闭(){console.printLine(";关闭";);}}公共程序(){正在使用(var a:=new A(){a.do();}}。

import system';io;import tensions;public program(){//从命令行参数var filename:=program_arguments[1]中获取文件名;//使用(auto read:=File.Assign(Filename).textreader())打开文本文件读取器{//重复直到读取完所有行,同时(reader.Available){//读取行字符串line:=reader.readLine();//打印行console.printLine(line。

import system';io;import tensions;public program(){//从命令行参数var filename:=program_arguments[1]中获取文件名;//使用(auto Writer:=File.Assign(Filename).textwriter()){//重复操作,直到输入空行为止(string line:=console.readLine(),line!=emptyString,line:=console.readLine()){//保存到文件写入器

如果要追加到现有文件,则应使用logger()方法,例如:

import system&39;io;import Extensions;import system';Collection;public program(){//从命令行参数var filename:=PROGRAM_ARGUMENTS[1];//创建列表以保存读取的数据列表<;byte>;dump:=new list<;byte>;();//使用(AUTO READER:=BinaryFileReader)打开二进制文件读取器。new(Filename)){//重复直到读取完所有文件,同时(reader.Available){//将当前字节读入变量b//注意变量声明为Just-in-place reader.read(Ref Byte B);//将读取的字节添加到转储文件。append(B);};};//将文件内容打印为字节列表console.printLine(dump.asEnumerable());}。

导入系统;导入扩展;公共程序(){//指定。

..