Skip to main content

Language Guide

Language Syntax​

Lexical Elements​

Next uses several common lexical elements:

  • Comments:
    • Line comments: // This is a line comment
    • Block comments: /* This is a block comment */
  • Identifiers: Names must start with a letter and can contain letters and numbers.
  • Keywords: Reserved words that have special meaning in Next.

Keywords​

Next reserves the following keywords:

package   import    const     enum      struct    interface
map vector array bool int int8
int16 int32 int64 float32 float64 string
byte bytes any true false
caution

Avoid using these keywords as identifiers in your Next definitions.

Operators​

Next supports various operators for different operations:

CategoryOperators
Arithmetic+, -, *, /, %
Logical&&, ||, !
Comparison==, !=, <, >, <=, >=
Bitwise&, |, ^, <<, >>, &^

Data Types​

Next offers a rich set of data types to model various kinds of information effectively.

Primitive Types​

TypeDescriptionExample
boolBoolean valuetrue, false
int, int8, int16, int32, int64Signed integers42, -7
float32, float64Floating-point numbers3.14, -0.01
stringUTF-8 encoded string"Hello, World!"
byte, bytesByte and byte arrays0x0A, []byte{0x0A, 0x0B}
anyAny type-

Composite Types​

Next also provides several composite types for more complex data structures:

  1. Array: Fixed-size arrays

    array<int, 5> scores;
  2. Vector: Dynamic-size arrays

    vector<string> names;
  3. Map: Key-value pairs

    map<string, int> ages;
  4. Enum: Named constants

    enum Color {
    Red = 1;
    Green = 2;
    Blue = 3;
    }
  5. Struct: User-defined types

    struct Person {
    string name;
    int age;
    }
  6. Interface: Method signatures

    interface Reader {
    read(bytes buffer) int;
    }

Enumerations​

Enums in Next allow you to define a set of named constants. They can be particularly useful for representing a fixed set of values, such as status codes or configuration options.

Basic Enum Definition​

enum Status {
Pending = 1;
Approved = 2;
Rejected = 3;
}

Using iota​

Next supports the iota keyword for auto-incrementing enum values:

enum Color {
Red = iota; // 0
Green; // 1
Blue; // 2
}

You can also use iota with expressions:

enum FilePermission {
Read = 1 << iota; // 1
Write; // 2
Execute; // 4
}

Non-Integer Enums​

Next also supports floating-point and string enums:

enum MathConstants {
Pi = 3.14159265358979323846;
E = 2.71828182845904523536;
}

enum OperatingSystem {
Windows = "windows";
Linux = "linux";
MacOS = "macos";
}
NOTE

When using non-integer enums, be aware that not all target languages may support them natively. Ensure your templates handle these cases appropriately.

Structs​

Structs in Next allow you to define complex data types by grouping related fields together.

Basic Struct Definition​

struct User {
int64 id;
string username;
string email;
}

Nested Structs​

You can nest structs within each other:

struct Address {
string street;
string city;
string country;
}

struct Employee {
User user;
Address address;
float64 salary;
}

Using Annotations with Structs​

Annotations can be used to provide additional metadata for structs and their fields:

@message(type=101)
struct LoginRequest {
string username;
@sensitive string password;
@next(optional) string twoFactorToken;
}

Interfaces​

Interfaces in Next define a set of method signatures that can be implemented by structs.

Basic Interface Definition​

interface Shape {
area() float64;
perimeter() float64;
}

Interface with Error Handling​

You can use annotations to indicate error handling in interfaces:

interface FileSystem {
@next(error)
read(string path) bytes;

@next(error)
write(string path, bytes data);
}

Annotations​

Annotations in Next provide a powerful way to add metadata to your definitions. This metadata can be used to control code generation, add validation rules, or provide additional information for documentation.

Built-in Annotations​

Next includes @next as a built-in annotation, which is used to provide language-specific information:

@next(
go_package="github.com/example/project",
cpp_package="example::project",
java_package="com.example.project"
)
package myproject;

Custom Annotations​

You can define custom annotations for various purposes:

@api(version="v1")
@authorize(roles="admin,user")
struct UserProfile {
@validate(min=3, max=50)
string username;

@validate(pattern="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")
string email;
}
tip

Custom annotations are processed by annotation solvers or within templates. Ensure you have the necessary logic to handle these annotations in your code generation process.

Template System​

Next uses a powerful template system based on Go's text/template package. This system allows for complex logic and text manipulation during code generation.

Basic Template Structure​

{{- define "go/struct" -}}
type {{next .Type}} struct {
{{- next .Fields}}
}
{{- end}}

Template Inheritance​

Next supports template inheritance, allowing you to extend or override base templates:

{{- define "cpp/struct" -}}
class {{next .Type}} {
public:
{{next .Fields}}
};
{{- end}}

Using super for Template Extension​

The super keyword allows you to call the parent template within an overridden template:

{{- define "go/struct" -}}
{{super .}}
{{- with .Annotations.message.type}}

func ({{next $.Type}}) MessageType() int { return {{.}} }
{{- end}}
{{- end}}

Command Line Interface​

The Next command-line interface provides various options to control the code generation process.

Basic Usage​

next [options] [source_files...]

Common Options​

  • -O LANG=DIR: Set output directory for a specific language
  • -M LANG.KEY=VALUE: Define type mappings
  • -T LANG=PATH: Specify custom templates
  • -X ANNOTATION=PROGRAM: Define custom annotation solvers
  • -v LEVEL: Set verbosity level (0=error, 1=info, 2=debug, 3=trace)

Example​

next \
-O go=./output/go \
-M cpp.map="std::map<%K%,%V%>" \
-O go=./gen/go -T go=./templates/go/custom.go.npl \
-O cpp=./gen/cpp -T cpp=./templates/cpp/custom.cpp.npl \
-X validate="./validate_solver" \
-v 2

Best Practices​

To make the most of Next, consider the following best practices:

  1. Organize Your Next Files: Group related definitions together and use meaningful file names.

  2. Use Annotations Effectively: Leverage annotations to provide language-specific information and customize code generation.

  3. Create Modular Templates: Break down your templates into reusable components for better maintainability.

  4. Leverage Type Mappings: Use type mappings to ensure your generated code follows language-specific conventions.

  5. Implement Custom Annotation Solvers: For complex annotations, create custom solvers to handle the logic separately from your templates.

  6. Version Control Your Templates: Keep your templates and Next definitions under version control to track changes over time.

  7. Test Generated Code: Regularly test the generated code across all target languages to ensure consistency and correctness.

  8. Document Your Annotations: Provide clear documentation for any custom annotations you create, including their purpose and expected usage.

  9. Use Consistent Naming Conventions: Adopt a consistent naming style across your Next definitions to improve readability and maintain consistency in generated code.

  10. Optimize for Performance: When dealing with large projects, optimize your templates and annotation solvers for performance to reduce code generation time.

Conclusion​

Next provides a powerful and flexible way to generate code across multiple programming languages. By mastering its syntax, template system, and advanced features, you can significantly streamline your development process and ensure consistency across different parts of your project.

Remember that while Next offers many capabilities, the key to successful usage lies in understanding your project's specific needs and leveraging Next's features accordingly. Happy coding!