Skip to main content

Grammar

Grammar represents the custom grammar for the next files.

The grammar is used to define a subset of the next files. It can limit the features of the next code according by your requirements. The grammar is a yaml file that contains rules.

Here is an example of the grammar file:

grammar.yaml
struct:
annotations:
- name: message
description: Sets the declaration as a message.
parameters:
- name: type
types: [int]
description: Sets the message type id
required: true
validators:
- name: MessageTypeMustBePositive
message: must be positive
expression: '{{gt . 0}}'
- name: req
types: [bool]
description: Sets the message as a request.

It extends built-in grammar and defines a @message annotation for struct objects. For example:

package demo;

@message(type=1, req)
struct LoginRequest {/*...*/}

@message(type=2)
struct LoginResponse {/*...*/}
tip

Run the following command to show the built-in grammar:

next grammar
# Or outputs the grammar to a file
next grammar grammar.yaml
next grammar grammar.json

Builtin

Builtin represents the built-in grammar rules. Here is an example source code for demonstration built-in grammar rules:

@next(
// available is used to set the available expression for the file.
available="cpp|java",
// deprecated is used to set the declaration as deprecated.
deprecated,
// tokens is used to set the space separated tokens for the declaration name.
tokens="DB",
// <LANG>_package is used to set the package name for target languages.
cpp_package="db",
java_package="com.example.db",
// <LANG>_imports is used to set the import declarations for target languages.
cpp_imports="<iostream>",
)
package db;

@next(
available="cpp",
deprecated,
tokens="HTTP Version",
)
const int HTTPVersion = 2;

@next(
available="cpp|java",
deprecated,
tokens="HTTP Method",
// <LANG>_alias is used to set the alias name for target languages.
java_alias="org.springframework.http.HttpMethod",
)
enum HTTPMethod {
Get = "GET",
Post = "POST",
Put = "PUT",
Delete = "DELETE",
Head = "HEAD",
Options = "OPTIONS",
Patch = "PATCH",
Trace = "TRACE",
@next(available="!java", deprecated, tokens="Connect")
Connect = "CONNECT",
}

@next(
available="cpp|java",
deprecated,
tokens="User",
cpp_alias="model::User",
)
@entity
struct User {
@id
int id;
@next(available="!java", deprecated, tokens="Name", optional, default="John Doe", cpp_alias="std::string")
string name;
}

@next(
available="cpp|java",
deprecated,
tokens="User Repository",
java_alias="org.springframework.data.repository.CrudRepository<User, Long>",
)
interface UserRepository {
@next(available="!java", deprecated, tokens="Get User", mut, error, cpp_alias="std::shared_ptr<model::User>")
findById(
@next(available="!java", deprecated, tokens="ID", mut, cpp_alias="int64_t")
int64 id
) User;
}

Common

Annotation

Annotation represents the annotation grammar rules. Only the built-in annotations are supported if no annotations are defined in the grammar.

Example:

struct:
annotations:
- name: message
description: Sets the struct as a message.
parameters:
- name: type
description: Sets the message type id.
types: [int]
required: true
validators:
- name: MessageTypeMustBePositive
expression: "{{gt . 0}}"
message: message type must be positive
package demo;

// Good
@message(type=1)
struct User {
int id;
string name;
}

@message
struct User {
int id;
string name;
}
// Error: message type is required

@message(type)
struct User {
int id;
string name;
}
// Error: message type must be an integer

@message(type=-1)
struct User {
int id;
string name;
}
// Error: message type must be positive
.Description

.Description represents the annotation description.

.Name

.Name represents the annotation name.

.Parameters

.Parameters represents the annotation parameters.

AnnotationParameter

AnnotationParameter represents the annotation parameter grammar rules. If no parameters are defined, the annotation does not have any parameters.

.Description

.Description represents the parameter description.

.Name

.Name represents the parameter name pattern. The name pattern is a regular expression that can be used to match the annotation parameter name.

Example:

  • "type": matches the annotation name type
  • "x|y": matches the annotation name x or y
  • ".+_package": matches the annotation name that ends with _package, for example, cpp_package, java_package, etc.
.Required

.Required represents the parameter is required or not.

.Types

.Types represents the parameter type. The type is a string that can be one of the following types:

  • bool: boolean type, the value can be true or false
  • int: integer type, the value can be a positive or negative integer, for example, 123
  • float: float type, the value can be a positive or negative float, for example, 1.23
  • string: string type, the value can be a string, for example, "hello"
  • type: any type name, for example, int, float, string, etc. Custom type names are supported.
.Validators

.Validators represents the Validator for the annotation parameter.

Annotations

Annotations represents a list of annotations.

Validator

Validator represents the validator for the grammar rules.

.Expression

.Expression represents the validator expression. The expression is a template string that can access the data by the . operator. The expression must return a boolean value.

The data is the current context object. For example, package object for the package validator.

.Message

.Message represents the error message when the validator is failed.

.Name

.Name represents the validator name.

Const

Const represents the grammar rules for the const declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the const declaration.

.Disabled

.Disabled represents the const declaration is off or not. If the const declaration is off, the const declaration is not allowed in the next files.

Example:

const:
disabled: true
package demo;

const x = 1;
// Error: const declaration is not allowed
.Types

.Types represents a list of type names that are supported in the const declaration. If no types are defined, the const declaration supports all types. Otherwise, the const declaration only supports the specified types.

Currently, each type name can be one of the following types:

  • bool: boolean type, the value can be true or false
  • int: integer type, the value can be a positive or negative integer, for example, 123
  • float: float type, the value can be a positive or negative float, for example, 1.23
  • string: string type, the value can be a string, for example, "hello"

Example:

const:
types:
- int
- float
package demo;

const x = 1; // Good
const y = 1.23; // Good

const z = "hello";
// Error: string type is not allowed in the const declaration
.Validators

.Validators represents the Validator for the const declaration. It's used to validate the const name. You can access the const name by .Name.

Example:

const:
validators:
- name: ConstNameMustBeCapitalized
expression: "{{eq .Name (.Name | capitalize)}}"
message: const name must be capitalized
package demo;

const Hello = 1; // Good

const world = 1;
// Error: const name must be capitalized, expected: World

Enum

Enum represents the grammar rules for the enum declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the enum declaration.

.Disabled

.Disabled represents the enum declaration is off or not. If the enum declaration is off, the enum declaration is not allowed in the next files.

Example:

enum:
disabled: true
package demo;

enum Color {
Red;
Green;
Blue;
}
// Error: enum declaration is not allowed
.Member

.Member represents the EnumMember grammar rules for the enum declaration.

.Validators

.Validators represents the Validator for the enum declaration. It's used to validate the enum name. You can access the enum name by .Name.

Example:

enum:
validators:
- name: EnumNameMustBeCapitalized
expression: "{{eq .Name (.Name | capitalize)}}"
message: enum name must be capitalized
package demo;

// Good
enum Color {
Red;
Green;
Blue;
}

enum size {
Small;
Medium;
Large;
}
// Error: enum name must be capitalized, expected: Size

EnumMember

EnumMember represents the grammar rules for the enum member declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the enum member declaration.

.Types

.Types represents a list of type names that are supported in the enum declaration.

If no types are defined, the enum declaration supports all types. Otherwise, the enum declaration only supports the specified types.

Currently, each type name can be one of the following types:

  • int: integer type, the value can be a positive or negative integer, for example, 123
  • float: float type, the value can be a positive or negative float, for example, 1.23
  • string: string type, the value can be a string, for example, "hello"

Example:

enum:
member:
types:
- int
package demo;

// Good
enum Color {
Red = 1,
Green = 2,
Blue = 3
}

enum Size {
Small = "small",
Medium = "medium",
Large = "large"
}
// Error: string type is not allowed in the enum declaration
.Validators

.Validators represents the Validator for the enum member declaration.

It's used to validate the enum member name. You can access the enum member name by .Name.

Example:

enum:
member:
validators:
- name: EnumMemberNameMustBeCapitalized
expression: "{{eq .Name (.Name | capitalize)}}"
message: enum member name must be capitalized
package demo;

enum Size {
Small = 1,
Medium = 2,
large = 3;
// Error: enum member name must be capitalized, expected: Large
}
.ValueRequired

.ValueRequired represents the enum member value is required or not. If the enum member value is required, the enum member value must be specified in the next files.

Example:

enum:
member:
value_required: true
package demo;

enum Size {
Small = 1,
Medium = 2;
Large;
// Error: enum member value is required
}
.ZeroRequired

.ZeroRequired represents the enum member zero value for integer types is required or not.

If the enum member zero value is required, the enum member zero value must be specified in the next files.

Example:

enum:
member:
zero_required: true
package demo;

enum Size {
Small = 1,
Medium = 2,
Large = 3;
}
// Error: enum member zero value is required, for example:
// enum Size {
// Small = 0,
// Medium = 1,
// Large = 2
// }

Import

Import represents the grammar rules for the import declaration.

.Disabled

.Disabled represents the import declaration is off or not. If the import declaration is off, the import declaration is not allowed in the next files.

Example:

import:
disabled: true
package demo;

import "other.next";
// Error: import declaration is not allowed

Interface

Interface represents the grammar rules for the interface declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the interface declaration.

.Disabled

.Disabled represents the interface declaration is off or not. If the interface declaration is off, the interface declaration is not allowed in the next files.

Example:

interface:
disabled: true
package demo;

interface User {
GetID() int;
}
// Error: interface declaration is not allowed
.Method

.Method represents the InterfaceMethod grammar rules for the interface declaration.

.Validators

.Validators represents the Validator for the interface declaration. It's used to validate the interface name. You can access the interface name by .Name.

Example:

interface:
validators:
- name: InterfaceNameMustBeCapitalized
expression: "{{eq .Name (.Name | capitalize)}}"
message: interface name must be capitalized
package demo;

// Good
interface User {
GetID() int;
}

interface user {
GetName() string;
}
// Error: interface name must be capitalized, expected: User

InterfaceMethod

InterfaceMethod represents the grammar rules for the interface method declaration.

Example:

interface:
method:
annotations:
- name: http
description: Sets the method as an HTTP handler.
parameters:
- name: method
description: Sets the HTTP method.
types: [string]
required: true
validators:
- name: HTTPMethodMustBeValid
expression: "{{includes (list `GET` `POST` `PUT` `DELETE` `PATCH` `HEAD` `OPTIONS` `TRACE` `CONNECT`) .}}"
message: http method must be valid
validators:
- name: MethodNameMustBeCapitalized
expression: "{{eq .Name (.Name | capitalize)}}"
message: method name must be capitalized
.Annotations

.Annotations represents the Annotation grammar rules for the interface method declaration.

.Parameter

.Parameter represents the InterfaceMethodParameter grammar rules for the interface method declaration.

.Validators

.Validators represents the Validator for the interface method declaration.

InterfaceMethodParameter

InterfaceMethodParameter represents the grammar rules for the interface method parameter declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the interface method parameter declaration.

.Validators

.Validators represents the Validator for the interface method parameter declaration.

Package

Package represents the grammar rules for the package declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the package declaration.

.Validators

.Validators represents the Validator for the package declaration. It's used to validate the package name. For example, You can limit the package name must be not start with a "_" character. The validator expression is a template string that can access package name by .Name.

Example:

package:
validators:
- name: PackageNameNotStartWithUnderscore
expression: "{{not (hasPrefix `_` .Name)}}"
message: package name must not start with an underscore
package _test;
// Error: package name must not start with an underscore

Struct

Struct represents the grammar rules for the struct declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the struct declaration.

.Disabled

.Disabled represents the struct declaration is off or not. If the struct declaration is off, the struct declaration is not allowed in the next files.

Example:

struct:
disabled: true
package demo;

struct User {
int id;
string name;
}
// Error: struct declaration is not allowed
.Field

.Field represents the StructField grammar rules for the struct declaration.

.Validators

.Validators represents the Validator for the struct declaration. It's used to validate the struct name. You can access the struct name by .Name.

Example:

struct:
validators:
- name: StructNameMustBeCapitalized
expression: "{{eq .Name (.Name | capitalize)}}"
message: struct name must be capitalized
package demo;

// Good
struct User {
int id;
string name;
}

struct point {
int x;
int y;
}
// Error: struct name must be capitalized, expected: Point

StructField

StructField represents the grammar rules for the struct field declaration.

.Annotations

.Annotations represents the Annotation grammar rules for the struct field declaration.

.Validators

.Validators represents the Validator for the struct field declaration. It's used to validate the struct field name. You can access the struct field name by .Name.

Example:

struct:
field:
validators:
- name: StructFieldNameMustNotBeCapitalized
expression: "{{ne .Name (capitalize .Name)}}"
message: struct field name must not be capitalized
package demo;

struct User {
int id;
string Name;
// Error: struct field name must not be capitalized, expected: name
}