G # programming language

xiaoxiao2021-03-05  28

G # programming language Version1.0

Original: Ernest Alexander Booth

Original: http://erniebooth.name/articles/169.aspx

Translation: lover_p (http://blog.9cbs.net/loverp)

[content]

l about g #

l aop

l foundation

N generator inheritance

N capture

n tap

N Keyword EMIT

N target

N adaptive generation

N CAS and Injection Characteristics

l summarize

[text]

About G #

G # is a new programming language that I have conceived in the past few months. Its purpose is to generate a type of secure code that can be injected into a code base when compiling or runtime is compiled (INJECT). Its syntax is a supercoming of C # 2.0. Unlike other code generation technology and tools (such as Codesmith, a great tool / language), G # does not intend to generate code for starting points or consumption. Instead, G # uses the aspective programming (AOP) technology to inject code to the customer code. We will introduce AOP quickly because it is still new for many developers.

AOP

AOP or aspective software development (AOSD) was created in Xerox Parc in 1997, which is a relatively advanced software model (PARADIGM). Its ideas are simple, and the developers can reduce the complexity of software development every time only one problem domain. In other words, people are trying to solve a business problem (such as selling products on the Internet), there is no need to consider problems in security, threads, logins, data access, and other fields. This is called the separation of interest (Separation of Concerns). By separating these areas or aspects, a special expert can develop the best solutions that solve the problem, so developers don't need to master all the industries. This is expected to generate strong and fully functional software because developers only need to be an expert in software issues.

AOP begins by defining aspects (that is, a set of behavior) and then injects the code into the appropriate method. Each code injection point is called a join point. Let us take safety as an example. "All inputs are evil" is a safe community, Mantra, spells. One way to fight this problem is that all developers are required to check if there is malicious input before using the data. Developers are likely to develop a helper method to solve this problem, and all developers will simply call this auxiliary method in their code. AOP can solve this problem, it extracts these same auxiliary methods and creates an aspect, and then injects it into where the user input is required. This process is called a weaving. We did not simply define a list of positions that will receive "evil input", but define a set of criteria that will be used (Criteria). Since this is the case, we hope to inject all public properties, methods, and constructors with parameters other than aspects. The benefits of creating a list are the benefits of developers without having to add their memory to check the input to check the input.

Compared to the AOP language you are familiar with aspect, G # does not have a separate arranging file: Orchestration is integrated into the syntax. For most programmers, others can inject code into their code base, which is undoubtedly a suggestion that is easy to cause panic. In order to solve this problem, G # contains a security model for handling this problem, and allows programmers to control which people can inject code and what code that can be injected, which will be discussed later. Let's see some basic elements before we go deeply: foundation

Public Class Client

{

Public client ()

{

Messenger ("Hello World");

}

Private void Messenger (String Message)

{

Console.writeline (Message);

}

}

Public Generator Rename

{

Static Generation Changeit: Target Client.Messenger (String Message)

{

Preserver

{

String OldMessage = Message;

Message = "Hello G #";

}

POST

{

Message = OldMessage;

}

}

}

Although this example does not use any use, it demonstrates a lot of characteristics of G #. First, the Client class uses a standard C # syntax - this is valid in G #, which simply outputs the message "Hello World" to the console. This class definitions below is a new language structure in G #, called generator. Now only need to think that the generator is a container for defining the code that "how to generate code", this is similar to the class. Rename is the name of this generator, as if the client is the name of the class. Next define a generation called Changeit. Similar to the generation and method, each time you call it, you will perform some actions, and the difference is usually generated when the call is generated. Note that changeit has a target (Target), here is a Messenger method from the Client class. The target can be any (language) configuration, and can also include wildcards and regular expressions to specify a set of items as a target. This means that all code from the generated (emit) will be injected into the Messenger method. Keyword prelines All code defined in the posterior parentheses will be injected into the code defined in the Messenger method. Keyword POST specifies that all code defined in the rear parentheses will be injected into the code defined in the Messenger method. Because this generation is marked with keyword static, the actual injection of code is part of the compilation process, which is important to understand this. The programmer will not see the Messenger method, unless ILDASM or REFLEctor checks the Messenger method. There is also a feature that is currently only a dream, is capable of generating dynamic Region, which can open it in Visual Studio .NET to check which code generated in the customer environment. We will discuss other types of buildings later.

Private void Messenger (String Message)

{

// from changeit preload.

String OldMessage = Message;

// from changeit preload.

Message = "Hello G #";

// from the messenger method body.

Console.writeline (Message);

// from changit post block.Message = OldMessage;

}

This method will then print "Hello G #" to the console, then change the Message string back to the original incoming message. Note that the string in .NET is not variable, it is actually not changed by one string. Therefore, by changing the Message in the POSSAGE back to the initial message to protect the "Hello World" message outside the Messenger method, it is not necessary, but for any code executed in the Messenger method, the rear injection code is very important. A logic problem that appears here is that when the code in the Messenger method is executed after the post condition? This issue is perfectly led by the next section.

Inheritance of the generator

The example above shows that the generator is the generated package container, but it can also contain all members that can be included (such as methods, attributes, domains, events, etc.). In addition, visibility and other modifiers such as Virtual can also be generated. Therefore, the generator is an object-oriented and can inherit each other. The reasons and classes are similar: This allows the base chrildren to define a basic injection behavior and define more special behaviors by sub-generators.

Public Class Client

{

Protected string message;

Public client ()

{

THIS.MESSAGE = "Hello WORLD";

Messenger (this.Message);

}

Private void Messenger (String Message)

{

Console.writeline (Message);

}

}

Public Generator Base

{

Protected Virtual Generation Changeit: Target Client.Messenger (*)

{

Preserver

{

String message = "Hello G #";

}

POST

{

THIS.MESSAGE = Message;

}

}

}

Public Generator Sub: Base

{

Protected Override Generation Changeit: Target Client.Messenger (String Message)

{

Preserver

{

Base.pre ();

Message = Capture.Message;

}

POST

{

Capture.Message = Message;

Base.post ();

}

}

}

The Messenger method is given below. Let's break these code. The SUB generator is derived from the Base generator and rewrites "Method" Changeit in the "Base Class". The "base class" uses an asterisk (*) to define a goal, which can be replaced by any parameters, which means that its goal can be all overloaded forms of Messenger in the Client class. We will introduce the details of the target. With yourself, you can know that a basic rule is that more features must be specified for the target in rewriting generation. In another part of the code, we use the keyword base to access the PRE and POST of the base generator, so we can decide whether to issue a SUB generator before or after the Base generator issues code.

Private void Messenger (String Message)

{

// base

String Capture.Message = "Hello G #";

// SUB

Message = Capture.Message;

Console.writeline (Message);

// subcapture.Message = Message;

// base

THIS.MESSAGE = Capture.Message;

}

capture

Keyword Capture is used to reference variables defined in the same generated scope, even if this variable is defined in the baseive. The reason for accessing these variables is that all generated code will be in the same scope. When accessing the capture variable, the keyword Capture is not required, but the Messenger method here uses the same name, in which case the keyword Capture needs to solve the problem of confusion. Variable Message Defines in the ChangeIt generation of the Base generator, and its target Messenger method is also possible to define parameters of the same name because we use an asterisk (*) wildcard. This situation is likely to occur because local variables can be defined in the generation, and the local variables of the same name can be defined in the overload of its target method later. If G # does not take action, when the target method is defined and the variables of the local variable in the generated, a compilation error will be triggered.

Segmentation

In order to point out how to make a code, G # provides a code that can replace the code by executing code. This is implemented by "§" symbol, which is called section Sign. This symbol is like this in the Times New Roman font: §, and in the Courier New font (the original is a Courier font, this is here for the same code format, both very similar): §. When is placed in the code, the subsequent code will be executed, not the issued:

Preserver

{

§ for (int i = 0; i <10; i )

§ {

Console.writeLine (i);

§}

}

The green highlighted code will be executed during compilation instead of being issued. The code issued from this pre-block is like this:

Console.writeline (0);

Console.writeline (1);

Console.writeline (2);

Console.writeLine (3);

Console.writeline (4);

Console.writeline (5);

Console.writeline (6);

Console.writeline (7);

Console.writeline (8);

Console.writeline (9);

Console.writeLine (10);

Note "i" is replaced by its integer value when these lines of code are issued. G # knows how to inject basic types such as INT and FLOAT, but he cannot issue class or other custom complex types. If § follows a method, the return value type of the method must be basic type, void, or emit. If it is other type, the compilation process will destroy everything returned. We will explain the keyword EMIT in the next section. I have never seen which keyboard has § symbols, but you can generate this symbol by defining a combination shortcut, I chose "Ctrl L" (lower-written L) to output this symbol in Word and in Visual Studio .NET A macro is written in combination with this shortcut to output this symbol.

Keyword EMIT

We have discussed how to use keyword pre and post to issue code, but G # has a richer way to specify how and where to issue code. One method is to use keyword emit like using pre and posts:

Emit

{

Console.writeline ("Hello G #");

}

Code "Console.WriteLine (" Hello G # ");" Where is it? It will be issued in EMIT blocks generated by its base. [(That REMINDS BE OF THE DEFINITION OF A Normal] OK, then pre and post actually also EMIT blocks, only they define the position of the code (behind the front and method of the method). For the above code segment, we need to provide a context environment to indicate where these code is sent.

...

Preserver

{

§ counter ();

}

...

Void counter ()

{

Emit

{

Console.writeline ("The Emit Keyword In Action);

}

}

When a generation with the pre-block is compiled, it calls the Counter method because there is § symbol in front of Counter (). In the Counter method, the keyword EMIT is used to inject call to console.writeline. The EMIT block will replace the call to Counter () with the code in the block. There is no limit to the number of EMIT blocks in a method, and § can be used in the EMIT block.

In addition, EMIT is just a mapping of the EMIT type defined in the G # framework, so we can create an instance of EMIT.

Preserver

{

§ displayparts ();

}

...

Public Emit DisplayParts ()

{

Emit Partone, Parttwo;

Partone

{

§ INJECTOR (PartTwo);

Console.writeline ("part one");

§ Parttwo.emit ();

}

Return Partone.emit ();

}

Private void injector (Emit Target)

{

Target

{

Console.writeline ("Injection ...");

}

}

In the above code snippet, we created two EMIT objects Partone and PartTwo in the definition of DisplayParts. Then we define an EMIT block using Partone plus parentheses. All the code between the brackets will be issued to the local storage of Partone, which will return this local storage when we call the EMIT method on the Partone object. Finally, note that the return value type EMT is called in the pre-block of the code segment. [Since the Emitted Code Is Not Caught It Is Emitted Into The pre block.]

aims

We have explored how to use keyword pre and post when a method is target, but in addition, G # also defines some keywords to use other language configuration as a target. The following table gives other keywords that can issue code and their description. You can also use wildcards when specifying the target configuration for these keywords, see the following example:

Keyword Description Class Injection Target Namespace All Class Namespace Injects All Namespace Set | GET Injection Target All SET and GET Area Generator Injects All Builder The Generation Injecting Target Defined All methods defined by all attributes defined by generating a Property injection target

Public Generator Base

{

Protected Virtual Generation ChangeClient: TARGET CLIENT

{

Property Public String *

{

get

{

POST

{

Console.writeLine (Value);

}

}

set

{

Preserver

{

Console.writeLine (Value);

}

}

}

Method (public | protected) * cl * (*)

{

Console.writeline ("Cl * Method Targeted");

}

}

}

Here we infuse all types of attributes with name String. We also use keyword value in the GET accessor, which represents the value returned by the GET Accessor of the target code in G #. The use of Pre and POST here is not different from the usage in the method. The next keyword Method defines all public and protected methods we will inject. Two asterisks (*) indicate that the return value type is arbitrary and the name of the method is started with "CL", followed by any more Any character. (Translation: In fact, it is 3 star, and the rear parentheses indicates that the method can take any parameters.) You can also use the "Pound ($)" symbol as a wildcard in the name, indicating any character. Note that this is important: all members who meet constraints in the Client class will be injected.

Adaptive generation

The second type of generated is adaptive generation, just simply replacing a keyword STATIC that generates the front key to Adaptive. Adaptive generation is generated at runtime and injects code, so it can check the status of the object to guide generation.

Adaptive generation advantages than static generation, the advantage of third parties can also provide generating frameworks and components. Third-party developers can use the code base they do not know as their goals by creating a phantom target (Phantom Target). The illusion target does not exist in the generated frame or target framework. When developers want to use a third-party generator, they can join the namespace, class, method of the illusion, class, method, and relocate the generated code to the appropriate location in their code base.

Public Class Client

{

Protected string message;

Public client ()

{

THIS.MESSAGE = "Hello WORLD";

Messenger (this.Message);

}

Public String Message

{

get

{

Return this.Message;

}

}

Private void Messenger (String Message)

{

Console.writeline (Message);

}

}

// PHANTOM TARGET

Namespace thirdparty.security

{

Public Adaptive Generator INPUT: Target Client

{

}

}

A set of asseses:

// third party generator

Public Generator Security

{

Protected Adaptive Generation CheckInput

: Target thirdParty.security.input

{

Property Public String *

{

get

{

Preserver

{

Value = validateInput (value);

}

}

}

Method public * * (all string * (input))

{

Preserver

{

INPUT = ValidateInput (INPUT);

}

}

}

}

In the above code, we defined a Client class, a third-party generator Security and a phantom target namespace THIRDPARTY.Security. Class and phantom targets are defined in a program set, while third-party generators are available in another program. A third party defines all types of public properties to call to call the ValidateInput method before returning. It also defines all returned value types to call ValidateInput before performing any code before performing any code. The keyword all in G # indicates that this matter is done for all the standard parameters in the scope. The asterisk (*) indicates that the name of the parameter can be arbitrary. We must put the name of the arguments you want to reference in parentheses to tell the compiler that we are using this name, but we don't want to use it as a standard Part. The current CLR can be dynamically injecting the IL code at runtime, which occurs when the assembly is loaded, and is completed by the Profiler API. However, this approach has a series of security issues because it disables CAS, so in-depth research can also be found to find a practical solution. We will describe how this is done below.

CAS and Injection Features

It is now expected to resolve the security problem caused by injecting code. The G # security model ensures that only those you want him to inject the code can inject the code, and these code can only limit the code access security (CAS, CASSS SACURITY) licenses you allow. By using metadata, you can declare that you grant the permissions of the injected code. This still needs to define a syntax and join the recommendation [STILL NEED TO Define this syntax and open to suggestions.]. All assemblies containing generators and generated must be given a strong key, then add an InjECTOR feature with the public keyword to the target assembly. Only the assembly of the strong key is pointed out in the Injector to run and inject the code.

to sum up

The code generation provides us with a variety of possibilities, we hope that G # can develop into a generic, type-safe code generation language. According to your opinions and suggestions, the G #'s grammar will also change and further refine, so thank you very much for reading the G # 's related documentation, if you have any opinions, questions or ideas, please send Ernie Boot to email: gsharp@erniebooth.name .

转载请注明原文地址:https://www.9cbs.com/read-37266.html

New Post(0)