Documentation
¶
Overview ¶
Package emit is what every code generator in backend/ shares: which declarations are the model's own, reading directives for one target, reporting what cannot be generated, and resolving a type reference to the shapes the prelude spells.
It knows nothing about any target language. A backend owns its type mapping, its naming, and its output; this package owns the parts that would otherwise be written once per backend and drift.
It is internal to backend/ and free to change.
Index ¶
- func Camel(name string) string
- func Deprecated(m *ir.Meta) (string, bool)
- func Doc(m *ir.Meta) []string
- func Fielded(e *ir.Enum) bool
- func IsOwn(d *ir.Decl) bool
- func LastSegment(name string) string
- func Pascal(name string) string
- func ScreamingSnake(name string) string
- func Snake(name string) string
- func Unsupported(pos *ir.Position, format string, args ...any) error
- func Words(name string) []string
- type Form
- type Member
- type NumberRule
- type Ref
- type Session
- func (s *Session) Block(name string) (*ir.Directive, bool)
- func (s *Session) Cascade(decls []*ir.Decl, skipped map[*ir.Decl]bool)
- func (s *Session) DeclName(d *ir.Decl, style func(string) string) string
- func (s *Session) Error(pos *ir.Position, format string, args ...any)
- func (s *Session) Expand(r *Ref) (*Ref, error)
- func (s *Session) FieldName(f *ir.Field, style func(string) string) string
- func (s *Session) Find(all []*ir.Directive, name string) (*ir.Directive, bool)
- func (s *Session) Numbers(owner string, members []Member, rule NumberRule) ([]int64, error)
- func (s *Session) Own() []*ir.Decl
- func (s *Session) References(d *ir.Decl) []*ir.Decl
- func (s *Session) Resolve(id *ir.ID) (*Ref, error)
- func (s *Session) Response(files []*plugin.File) *plugin.Response
- func (s *Session) Text(all []*ir.Directive, name string) (string, bool)
- func (s *Session) TypeReferences(ids ...*ir.ID) []*ir.Decl
- func (s *Session) Warn(err error)
- func (s *Session) WarnConstraints(d *ir.Decl)
- func (s *Session) WarnWhere(d *ir.Decl)
- type UnsupportedError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Deprecated ¶
Deprecated returns the reason a node is deprecated, which may be empty, and whether it is.
func Fielded ¶
Fielded reports whether any variant of an enum carries fields, which is what separates a plain enum from a sum type in every target.
func IsOwn ¶ added in v0.2.3
IsOwn reports whether a declaration is the model's rather than the prelude's; Session.Own says how the two are told apart.
It is the predicate rather than the list, for a backend walking the declaration table by index because something it emits is keyed on one.
func LastSegment ¶
LastSegment is the part of a dotted name after its last dot. A declaration's name may arrive qualified, and every target writes the bare name.
func Pascal ¶
Pascal joins words with each one's first letter upper case and the rest as written: `user_id` is UserId and `userID` is UserID.
func ScreamingSnake ¶
ScreamingSnake joins upper-case words with underscores.
func Unsupported ¶
Unsupported returns an UnsupportedError at a position.
func Words ¶
Words splits a name into the words a case convention joins.
A boundary falls before an upper-case letter that follows a lower-case letter or a digit, and before the last letter of an upper-case run that a lower-case letter follows, so `userID` is user and ID and `HTTPServer` is HTTP and Server. Anything that is not a letter or a digit separates words and is dropped. A digit stays with the word it follows: `last4` is one word.
Types ¶
type Form ¶
type Form int
Form is which of the prelude's shapes a type reference resolved to.
const ( // Prim is a primitive that is not a collection: `string`, `int`, and so // on. [Ref.Name] says which. Prim Form = iota + 1 List Set Map // Option is `T?`. Option // Nullable is `T | null`. Nullable // Named is a struct, an enum, or a newtype. [Ref.Decl] is it. Named // Extern is a declaration another package owns. [Ref.Extern] is it, // and [Ref.Name] is its qualified name. Only a [Session] with Externs // set resolves one. Extern )
type Member ¶
Member is something a wire format numbers: a field or a variant.
func FieldMembers ¶
FieldMembers is the members of a field list.
func VariantMembers ¶
VariantMembers is the members of a variant list.
type NumberRule ¶
type NumberRule struct {
Max int64
// Reserved is inclusive ranges that are an error to pin and skipped when allocating.
Reserved [][2]int64
// Skip is numbers allocation passes over; refusing a pin on one is the caller's job.
Skip map[int64]bool
}
NumberRule is what a target allows a member's number to be.
type Ref ¶
type Ref struct {
Form Form
// Name is the primitive's name when Form is [Prim].
Name string
// Elem is the element of a List or a Set, the value of a Map, and what
// an Option or a Nullable wraps.
Elem *Ref
// Key is the key of a Map.
Key *Ref
// Decl is the declaration when Form is [Named].
Decl *ir.Decl
// Extern is the extern when Form is [Extern].
Extern *ir.Extern
// ID is the type table entry this was resolved from, after alias
// expansion.
ID *ir.ID
Pos *ir.Position
}
Ref is a type reference with its aliases expanded and its prelude spellings recognized.
type Session ¶
type Session struct {
Model *ir.Model
Target string
// Lang is the target language as a message names it: "Go",
// "Protobuf", and so on.
Lang string
// Externs makes [Session.Resolve] return a reference to an extern as
// an [Extern] ref rather than refusing it, for a backend that maps
// externs itself.
Externs bool
Diags []*plugin.Diagnostic
}
Session is one request's state. A backend makes a fresh one per Generate call, so a reused connection shares nothing between requests.
func NewSession ¶
NewSession starts a session for one request.
func (*Session) Block ¶
Block reads a directive written on the target block itself rather than against a node in the model.
It returns the directive rather than its argument, because a diagnostic about the value wants the position it was written at.
func (*Session) Cascade ¶
Cascade extends skipped with every declaration in decls that names a skipped one, until nothing more is added, and warns about each one it adds.
A backend renders what it can and marks what it cannot. Emitting a declaration whose field names a skipped one produces output that refers to something it does not declare, which no target accepts, so the referrer is skipped too and the warning says which declaration caused it.
func (*Session) DeclName ¶
DeclName is a declaration's name in the target language: a `name` directive's argument when there is one, and otherwise the last segment of the TDL name passed through style.
func (*Session) Error ¶
Error reports a problem that makes the output unusable. The host writes nothing when a response carries one.
func (*Session) Expand ¶
Expand follows a newtype to what it wraps, for a target with no distinct type to give it. Any other reference is returned as it is.
func (*Session) FieldName ¶
FieldName is a field's name in the target language, by the same rule as Session.DeclName.
func (*Session) Find ¶
Find returns a directive carrying at least one argument.
A model carries directives for every target block in it, tagged with the block they came from, so this filters rather than assuming what it is handed is its own.
func (*Session) Numbers ¶
Numbers assigns each member its wire number. A `number` directive pins a member's number; each unpinned member, in declaration order, takes the lowest number from 1 that no pin or earlier member holds and the rule does not reserve or skip. A number the rule refuses, or two pins sharing one, is an UnsupportedError.
Pins keep a wire format stable while the source moves: inserting an unpinned member anywhere but the end renumbers every unpinned member after it.
func (*Session) Own ¶
Own returns the declarations the model's own file declared.
The prelude is merged into the declaration table untagged, so a model whose source declares two things arrives with twenty-one declarations. A backend that emits per declaration has to decide what is the user's, and which file a declaration came from is what says so.
The embedded prelude is named prelude.Name and nothing else is: it is parsed under that name rather than read from a path, so the comparison is against the whole name and not its ending. A user's `my-std.tdl`, or a `std.tdl` of their own in any directory, is theirs and is generated.
A replacement prelude passed to `sema.WithPrelude` is named by whoever passed it and is not recognized here. Marking the prelude on the wire is the fix, and `plugins.md` argues the opposite, that a backend should see prelude declarations as declarations like any other; until that is settled, a project replacing the prelude generates it too.
func (*Session) References ¶
References returns the declarations d names: through its fields, its variants' fields, a newtype's base, and the type arguments of each, with aliases followed to what they expand to. A declaration naming itself is included.
func (*Session) Resolve ¶
Resolve walks a type reference into a Ref, or says why this phase cannot generate it.
The prelude is replaceable, so this reads the spellings lowering itself knows (List, Set, Map, Option, Nullable) rather than anything about what the declarations mean. A model that redeclares `primitive string` in its own file reaches the same entry, because what matters is that the constructor is a primitive named `string`.
A primitive of any name resolves; whether the target has a type for it is the backend's decision.
func (*Session) TypeReferences ¶ added in v0.2.11
TypeReferences returns the declarations the type references ids name, walked as Session.References walks a declaration's.
func (*Session) Warn ¶
Warn reports something the backend cannot handle, with a position when the failure carried one.
A backend says what it cannot do here rather than returning an error, because this reaches the user with a position attached and does not stop the run.
func (*Session) WarnConstraints ¶
WarnConstraints says out loud that a declaration's constraints are not enforced: a newtype's `where` block, and each field's, in a struct or in an enum's variants. The declaration is still emitted.
type UnsupportedError ¶
UnsupportedError reports a shape the backend cannot express. It reaches the user as a warning rather than stopping the run, so a model that is mostly generatable generates.
func (*UnsupportedError) Error ¶
func (e *UnsupportedError) Error() string