Skip to content

Latest commit

 

History

History
145 lines (99 loc) · 5.41 KB

ag-reference.md

File metadata and controls

145 lines (99 loc) · 5.41 KB

AG Reference

AG is the language to write an input to Silverchain (i.e. to write the rules of fluent APIs). The following lines are AG code that defines the rules of a fluent builder of java.time.LocalDateTime:

org.example.DateTimeBuilder {
  java.time.LocalDateTime year(int y) month(int m) day(int d);
}

AG code consists of one or more named blocks (<NAME> { }). The name of a block is the name of the entrypoint class of a fluent API. Specifically, org.example.DateTimeBuilder { … } indicates that the fluent builder allows its users to start writing a method chain by instantiating org.example.DateTimeBuilder:

import org.example.DateTimeBuilder;
new DateTimeBuilder().year(2021). … ;

The lines inside a block describe the rules on method chains. Each rule consists of

  • the type of an object that is returned by the last method in a chain,
  • a regular expression whose atomic element (or alphabet) is a method declaration,

and a semicolon. In the example AG code, the second line indicates that

  • the API allows its users to chain year(int), month(int), and day(int) in this order, and
  • the expression year(…).month(…).day(…) returns an instance of java.time.LocalDateTime.

More on chain rules

Types and methods in rule

One can write any valid Java type/method in a chain rule. One can write void, int[], String[][], etc., not only simple class/interface names; One can use ... in method parameters; One can add throws to the method.

Repeat operators

Common repeat operators such as ? are supported. The example below indicates that the invocations of month(int) and day(int) are optional.

org.example.DateTimeBuilder {
  java.time.LocalDateTime year(int y) month(int m)? day(int d)?;
}

The following lists all the operators allowed in AG code:

operator semantics
foo()? zero or one invocation of foo()
foo()* zero or more invocations of foo()
foo()+ one or more invocations of foo()
foo()[n] n invocations of foo()
foo()[n,] n or more invocations of foo()
foo()[n,m] at least n but no more than m invocations of foo()

Unordered rules

Some API would provide a group of methods that can be invoked in any order, but each of them only once. Silverchain supports a special operator {}:

import java.time.LocalDateTime;
import org.example.DateTimeBuilder;

DateTimeBuilder {
  // Invoke year, month, day in any order,
  //   but each of them only once
  LocalDateTime { year(int y), month(int m), day(int d) };
}

The above example means that the API allows all of the below:

  • year(2021).month(11).day(6)
  • year(2021).day(6).month(11)
  • month(11).year(2021).day(6)
  • month(11).day(6).year(2021)
  • day(6).year(2021).month(11)
  • day(6).month(11).year(2021).

However, the API does not allow

  • year(2021).month(11).day(6).day(6) (Invoking day twice)
  • month(11).day(6) (Missing year)

Sugars to simplify AG code

Importing types

By importing a type like in Java, one can refer to that type by its simple name:

import java.time.LocalDateTime;

org.example.DateTimeBuilder {
  LocalDateTime // = java.time.LocalDateTime
    year(int y) month(int m) day(int d);
}

One can use an import statement to use a simple name for classes to be generated by Silverchain:

import org.example.DateTimeBuilder;

DateTimeBuilder { // = org.example.DateTimeBuilder
  java.time.LocalDateTime year(int y) month(int m) day(int d);
}

Fragments

The repetition in rules can be removed by defining a fragment:

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import org.example.DateTimeBuilder;

// Fragment definition ($FRAGMENT_NAME = …);
$YMD = year(int y) month(int m) day(int d);

DateTimeBuilder {
  // $YMD is expanded into `year(int y) month(int m) day(int d)`
  LocalDateTime $YMD local();
  ZonedDateTime $YMD timezone(ZoneId z);
}

Type parameters

There are three kinds of type parameters:

  1. Ones listed in a type declaration

    1. Ones listed before ; or without ;. These type parameters are shared in a chain expression and are included in the generated type declaration. For example, if you give an input like Foo<T> { … }, Silverchain generates Foo<T>.

    2. Ones listed after ;. These type parameters are shared in a chain expression but are not included in the generated type declaration. For example, If you give an input like Foo<;T> { … }, Silverchain generates Foo (without the type parameter T). The examples mapbuilder.ag and listutil.ag are their usecases.

  2. Ones listed in a method declaration. These type parameters are not shared in a chain. They are only used in that method.

Comments

One can write comments in AG code. Everything after // in a line is treated as a comment. /* */ to write a block comment.

To add comments to generated files, use the --javadoc option (See here).