Skip to content

Commit

Permalink
cmd/gentypes: generate request, response, event ctor (#63)
Browse files Browse the repository at this point in the history
The mapping from event request and response id to event and response types
can be done in generating. This makes sure that the maps stay up
to date with the spec.
  • Loading branch information
suzmue committed Sep 16, 2021
1 parent 9372df2 commit b502379
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 118 deletions.
64 changes: 64 additions & 0 deletions cmd/gentypes/gentypes.go
Expand Up @@ -31,6 +31,7 @@ import (
"net/http"
"os"
"strings"
"unicode"
)

var (
Expand Down Expand Up @@ -424,6 +425,55 @@ func emitMethodsForType(sb *strings.Builder, typeName string) {
}
}

func emitCtor(sb *strings.Builder, reqs, resps, events []string) {
fmt.Fprint(sb, `
// Mapping of request commands and corresponding struct constructors that
// can be passed to json.Unmarshal.
var requestCtor = map[string]messageCtor{`)
for _, r := range reqs {
req := strings.TrimSuffix(firstToLower(r), "Request")
var msg string
if req == "initialize" {
msg = `
Arguments: InitializeRequestArguments{
// Set the default values specified here: https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Initialize.
LinesStartAt1: true,
ColumnsStartAt1: true,
PathFormat: "path",
},
`
}
fmt.Fprintf(sb, "\n\t\"%s\":\tfunc() Message { return &%s{%s} },", req, r, msg)
}
fmt.Fprint(sb, "\n}")

fmt.Fprint(sb, `
// Mapping of response commands and corresponding struct constructors that
// can be passed to json.Unmarshal.
var responseCtor = map[string]messageCtor{`)
for _, r := range resps {
resp := strings.TrimSuffix(firstToLower(r), "Response")

fmt.Fprintf(sb, "\n\t\"%s\":\tfunc() Message { return &%s{} },", resp, r)
}
fmt.Fprint(sb, "\n}")

fmt.Fprint(sb, `
// Mapping of event ids and corresponding struct constructors that
// can be passed to json.Unmarshal.
var eventCtor = map[string]messageCtor{`)
for _, e := range events {
ev := strings.TrimSuffix(firstToLower(e), "Event")
fmt.Fprintf(sb, "\n\t\"%s\":\tfunc() Message { return &%s{} },", ev, e)
}
fmt.Fprint(sb, "\n}\n")
}

func firstToLower(s string) string {
r := []rune(s)
return string(unicode.ToLower(r[0])) + string(r[1:])
}

const preamble = `// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -537,15 +587,29 @@ func main() {
log.Fatal(err)
}

var requests, responses, events []string
for _, typeName := range typeNames {
if _, ok := typesExcludeList[typeName]; !ok {
b.WriteString(emitToplevelType(replaceGoTypename(typeName), typeMap[typeName]))
b.WriteString("\n")
}

emitMethodsForType(&b, replaceGoTypename(typeName))
// Add the typename to the appropriate list.
if strings.HasSuffix(typeName, "Request") && typeName != "Request" {
requests = append(requests, typeName)
}
if strings.HasSuffix(typeName, "Response") && typeName != "Response" && typeName != "ErrorResponse" {
responses = append(responses, typeName)
}
if strings.HasSuffix(typeName, "Event") && typeName != "Event" {
events = append(events, typeName)
}
}

// Emit the maps from id to response and event types.
emitCtor(&b, requests, responses, events)

wholeFile := []byte(b.String())
formatted, err := format.Source(wholeFile)
if err != nil {
Expand Down
118 changes: 0 additions & 118 deletions codec.go
Expand Up @@ -73,61 +73,6 @@ func decodeRequest(data []byte) (Message, error) {
return nil, &DecodeProtocolMessageFieldError{r.GetSeq(), "Request", "command", r.Command}
}

// Mapping of request commands and corresponding struct constructors that
// can be passed to json.Unmarshal.
var requestCtor = map[string]messageCtor{
"cancel": func() Message { return &CancelRequest{} },
"runInTerminal": func() Message { return &RunInTerminalRequest{} },
"initialize": func() Message {
return &InitializeRequest{
Arguments: InitializeRequestArguments{
// Set the default values specified here: https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Initialize.
LinesStartAt1: true,
ColumnsStartAt1: true,
PathFormat: "path",
},
}
},
"configurationDone": func() Message { return &ConfigurationDoneRequest{} },
"launch": func() Message { return &LaunchRequest{} },
"attach": func() Message { return &AttachRequest{} },
"restart": func() Message { return &RestartRequest{} },
"disconnect": func() Message { return &DisconnectRequest{} },
"terminate": func() Message { return &TerminateRequest{} },
"breakpointLocations": func() Message { return &BreakpointLocationsRequest{} },
"setBreakpoints": func() Message { return &SetBreakpointsRequest{} },
"setFunctionBreakpoints": func() Message { return &SetFunctionBreakpointsRequest{} },
"setExceptionBreakpoints": func() Message { return &SetExceptionBreakpointsRequest{} },
"dataBreakpointInfo": func() Message { return &DataBreakpointInfoRequest{} },
"setDataBreakpoints": func() Message { return &SetDataBreakpointsRequest{} },
"continue": func() Message { return &ContinueRequest{} },
"next": func() Message { return &NextRequest{} },
"stepIn": func() Message { return &StepInRequest{} },
"stepOut": func() Message { return &StepOutRequest{} },
"stepBack": func() Message { return &StepBackRequest{} },
"reverseContinue": func() Message { return &ReverseContinueRequest{} },
"restartFrame": func() Message { return &RestartFrameRequest{} },
"goto": func() Message { return &GotoRequest{} },
"pause": func() Message { return &PauseRequest{} },
"stackTrace": func() Message { return &StackTraceRequest{} },
"scopes": func() Message { return &ScopesRequest{} },
"variables": func() Message { return &VariablesRequest{} },
"setVariable": func() Message { return &SetVariableRequest{} },
"source": func() Message { return &SourceRequest{} },
"threads": func() Message { return &ThreadsRequest{} },
"terminateThreads": func() Message { return &TerminateThreadsRequest{} },
"modules": func() Message { return &ModulesRequest{} },
"loadedSources": func() Message { return &LoadedSourcesRequest{} },
"evaluate": func() Message { return &EvaluateRequest{} },
"setExpression": func() Message { return &SetExpressionRequest{} },
"stepInTargets": func() Message { return &StepInTargetsRequest{} },
"gotoTargets": func() Message { return &GotoTargetsRequest{} },
"completions": func() Message { return &CompletionsRequest{} },
"exceptionInfo": func() Message { return &ExceptionInfoRequest{} },
"readMemory": func() Message { return &ReadMemoryRequest{} },
"disassemble": func() Message { return &DisassembleRequest{} },
}

// decodeResponse determines what response type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
Expand All @@ -149,52 +94,6 @@ func decodeResponse(data []byte) (Message, error) {
return nil, &DecodeProtocolMessageFieldError{r.GetSeq(), "Response", "command", r.Command}
}

// Mapping of response commands and corresponding struct constructors that
// can be passed to json.Unmarshal.
var responseCtor = map[string]messageCtor{
"cancel": func() Message { return &CancelResponse{} },
"runInTerminal": func() Message { return &RunInTerminalResponse{} },
"initialize": func() Message { return &InitializeResponse{} },
"configurationDone": func() Message { return &ConfigurationDoneResponse{} },
"launch": func() Message { return &LaunchResponse{} },
"attach": func() Message { return &AttachResponse{} },
"restart": func() Message { return &RestartResponse{} },
"disconnect": func() Message { return &DisconnectResponse{} },
"terminate": func() Message { return &TerminateResponse{} },
"breakpointLocations": func() Message { return &BreakpointLocationsResponse{} },
"setBreakpoints": func() Message { return &SetBreakpointsResponse{} },
"setFunctionBreakpoints": func() Message { return &SetFunctionBreakpointsResponse{} },
"setExceptionBreakpoints": func() Message { return &SetExceptionBreakpointsResponse{} },
"dataBreakpointInfo": func() Message { return &DataBreakpointInfoResponse{} },
"setDataBreakpoints": func() Message { return &SetDataBreakpointsResponse{} },
"continue": func() Message { return &ContinueResponse{} },
"next": func() Message { return &NextResponse{} },
"stepIn": func() Message { return &StepInResponse{} },
"stepOut": func() Message { return &StepOutResponse{} },
"stepBack": func() Message { return &StepBackResponse{} },
"reverseContinue": func() Message { return &ReverseContinueResponse{} },
"restartFrame": func() Message { return &RestartFrameResponse{} },
"goto": func() Message { return &GotoResponse{} },
"pause": func() Message { return &PauseResponse{} },
"stackTrace": func() Message { return &StackTraceResponse{} },
"scopes": func() Message { return &ScopesResponse{} },
"variables": func() Message { return &VariablesResponse{} },
"setVariable": func() Message { return &SetVariableResponse{} },
"source": func() Message { return &SourceResponse{} },
"threads": func() Message { return &ThreadsResponse{} },
"terminateThreads": func() Message { return &TerminateThreadsResponse{} },
"modules": func() Message { return &ModulesResponse{} },
"loadedSources": func() Message { return &LoadedSourcesResponse{} },
"evaluate": func() Message { return &EvaluateResponse{} },
"setExpression": func() Message { return &SetExpressionResponse{} },
"stepInTargets": func() Message { return &StepInTargetsResponse{} },
"gotoTargets": func() Message { return &GotoTargetsResponse{} },
"completions": func() Message { return &CompletionsResponse{} },
"exceptionInfo": func() Message { return &ExceptionInfoResponse{} },
"readMemory": func() Message { return &ReadMemoryResponse{} },
"disassemble": func() Message { return &DisassembleResponse{} },
}

// decodeEvent determines what event type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
Expand All @@ -210,20 +109,3 @@ func decodeEvent(data []byte) (Message, error) {
}
return nil, &DecodeProtocolMessageFieldError{e.GetSeq(), "Event", "event", e.Event}
}

// Mapping of event ids and corresponding struct constructors that
// can be passed to json.Unmarshal.
var eventCtor = map[string]messageCtor{
"initialized": func() Message { return &InitializedEvent{} },
"stopped": func() Message { return &StoppedEvent{} },
"continued": func() Message { return &ContinuedEvent{} },
"exited": func() Message { return &ExitedEvent{} },
"terminated": func() Message { return &TerminatedEvent{} },
"thread": func() Message { return &ThreadEvent{} },
"output": func() Message { return &OutputEvent{} },
"breakpoint": func() Message { return &BreakpointEvent{} },
"module": func() Message { return &ModuleEvent{} },
"loadedSource": func() Message { return &LoadedSourceEvent{} },
"process": func() Message { return &ProcessEvent{} },
"capabilities": func() Message { return &CapabilitiesEvent{} },
}

0 comments on commit b502379

Please sign in to comment.