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 */
- Line comments:
- 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
Avoid using these keywords as identifiers in your Next definitions.
Operators
Next supports various operators for different operations:
Category | Operators |
---|---|
Arithmetic | + , - , * , / , % |
Logical | && , || , ! |
Comparison | == , != , < , > , <= , >= |
Bitwise | & , | , ^ , << , >> , &^ |
Data Types
Next offers a rich set of data types to model various kinds of information effectively.
Primitive Types
Type | Description | Example |
---|---|---|
bool | Boolean value | true , false |
int , int8 , int16 , int32 , int64 | Signed integers | 42 , -7 |
float32 , float64 | Floating-point numbers | 3.14 , -0.01 |
string | UTF-8 encoded string | "Hello, World!" |
byte , bytes | Byte and byte arrays | 0x0A , []byte{0x0A, 0x0B} |
any | Any type | - |
Composite Types
Next also provides several composite types for more complex data structures:
-
Array: Fixed-size arrays
array<int, 5> scores;
-
Vector: Dynamic-size arrays
vector<string> names;
-
Map: Key-value pairs
map<string, int> ages;
-
Enum: Named constants
enum Color {
Red = 1;
Green = 2;
Blue = 3;
} -
Struct: User-defined types
struct Person {
string name;
int age;
} -
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";
}
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;
}
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:
-
Organize Your Next Files: Group related definitions together and use meaningful file names.
-
Use Annotations Effectively: Leverage annotations to provide language-specific information and customize code generation.
-
Create Modular Templates: Break down your templates into reusable components for better maintainability.
-
Leverage Type Mappings: Use type mappings to ensure your generated code follows language-specific conventions.
-
Implement Custom Annotation Solvers: For complex annotations, create custom solvers to handle the logic separately from your templates.
-
Version Control Your Templates: Keep your templates and Next definitions under version control to track changes over time.
-
Test Generated Code: Regularly test the generated code across all target languages to ensure consistency and correctness.
-
Document Your Annotations: Provide clear documentation for any custom annotations you create, including their purpose and expected usage.
-
Use Consistent Naming Conventions: Adopt a consistent naming style across your Next definitions to improve readability and maintain consistency in generated code.
-
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!