diff options
Diffstat (limited to 'cmd/opdoc/opdoc.go')
-rw-r--r-- | cmd/opdoc/opdoc.go | 226 |
1 files changed, 124 insertions, 102 deletions
diff --git a/cmd/opdoc/opdoc.go b/cmd/opdoc/opdoc.go index be9b69956..c98a1a0f7 100644 --- a/cmd/opdoc/opdoc.go +++ b/cmd/opdoc/opdoc.go @@ -29,8 +29,8 @@ import ( ) func opGroupMarkdownTable(names []string, out io.Writer) { - fmt.Fprint(out, `| Op | Description | -| --- | --- | + fmt.Fprint(out, `| Opcode | Description | +| - | -- | `) opSpecs := logic.OpsByName[logic.LogicVersion] // TODO: sort by logic.OpSpecs[].Opcode @@ -58,69 +58,98 @@ func typeEnumTableMarkdown(out io.Writer) { func integerConstantsTableMarkdown(out io.Writer) { fmt.Fprintf(out, "#### OnComplete\n\n") fmt.Fprintf(out, "%s\n\n", logic.OnCompletionPreamble) - fmt.Fprintf(out, "| Value | Constant name | Description |\n") - fmt.Fprintf(out, "| --- | --- | --- |\n") + fmt.Fprintf(out, "| Value | Name | Description |\n") + fmt.Fprintf(out, "| - | ---- | -------- |\n") for i, name := range logic.OnCompletionNames { value := uint64(i) fmt.Fprintf(out, "| %d | %s | %s |\n", value, markdownTableEscape(name), logic.OnCompletionDescription(value)) } fmt.Fprintf(out, "\n") - fmt.Fprintf(out, "#### TypeEnum constants\n") - fmt.Fprintf(out, "| Value | Constant name | Description |\n") - fmt.Fprintf(out, "| --- | --- | --- |\n") + fmt.Fprintf(out, "#### TypeEnum constants\n\n") + fmt.Fprintf(out, "| Value | Name | Description |\n") + fmt.Fprintf(out, "| - | --- | ------ |\n") for i, name := range logic.TxnTypeNames { fmt.Fprintf(out, "| %d | %s | %s |\n", i, markdownTableEscape(name), logic.TypeNameDescriptions[name]) } out.Write([]byte("\n")) } -func fieldTableMarkdown(out io.Writer, names []string, types []logic.StackType, extra map[string]string) { - if types != nil { - fmt.Fprintf(out, "| Index | Name | Type | Notes |\n") - fmt.Fprintf(out, "| --- | --- | --- | --- |\n") - } else { - fmt.Fprintf(out, "| Index | Name | Notes |\n") - fmt.Fprintf(out, "| --- | --- | --- |\n") +type speccer interface { + SpecByName(name string) logic.FieldSpec +} + +func fieldSpecsMarkdown(out io.Writer, names []string, specs speccer) { + showTypes := false + showVers := false + spec0 := specs.SpecByName(names[0]) + opVer := spec0.OpVersion() + for _, name := range names { + if specs.SpecByName(name).Type() != logic.StackNone { + showTypes = true + } + if specs.SpecByName(name).Version() != opVer { + showVers = true + } + } + headers := "| Index | Name |" + widths := "| - | ------ |" + if showTypes { + headers += " Type |" + widths += " -- |" + } + if showVers { + headers += " In |" + widths += " - |" } + headers += " Notes |\n" + widths += " --------- |\n" + fmt.Fprint(out, headers, widths) for i, name := range names { + spec := specs.SpecByName(name) str := fmt.Sprintf("| %d | %s", i, markdownTableEscape(name)) - if types != nil { - gfType := types[i] - str = fmt.Sprintf("%s | %s", str, markdownTableEscape(gfType.String())) + if showTypes { + str = fmt.Sprintf("%s | %s", str, markdownTableEscape(spec.Type().String())) + } + if showVers { + if spec.Version() == spec.OpVersion() { + str = fmt.Sprintf("%s | ", str) + } else { + str = fmt.Sprintf("%s | v%d ", str, spec.Version()) + } } - fmt.Fprintf(out, "%s | %s |\n", str, extra[name]) + fmt.Fprintf(out, "%s | %s |\n", str, spec.Note()) } - out.Write([]byte("\n")) + fmt.Fprint(out, "\n") } func transactionFieldsMarkdown(out io.Writer) { fmt.Fprintf(out, "\n`txn` Fields (see [transaction reference](https://developer.algorand.org/docs/reference/transactions/)):\n\n") - fieldTableMarkdown(out, logic.TxnFieldNames, logic.TxnFieldTypes, logic.TxnFieldDocs()) + fieldSpecsMarkdown(out, logic.TxnFieldNames, logic.TxnFieldSpecByName) } func globalFieldsMarkdown(out io.Writer) { fmt.Fprintf(out, "\n`global` Fields:\n\n") - fieldTableMarkdown(out, logic.GlobalFieldNames, logic.GlobalFieldTypes, logic.GlobalFieldDocs()) + fieldSpecsMarkdown(out, logic.GlobalFieldNames, logic.GlobalFieldSpecByName) } func assetHoldingFieldsMarkdown(out io.Writer) { fmt.Fprintf(out, "\n`asset_holding_get` Fields:\n\n") - fieldTableMarkdown(out, logic.AssetHoldingFieldNames, logic.AssetHoldingFieldTypes, logic.AssetHoldingFieldDocs) + fieldSpecsMarkdown(out, logic.AssetHoldingFieldNames, logic.AssetHoldingFieldSpecByName) } func assetParamsFieldsMarkdown(out io.Writer) { fmt.Fprintf(out, "\n`asset_params_get` Fields:\n\n") - fieldTableMarkdown(out, logic.AssetParamsFieldNames, logic.AssetParamsFieldTypes, logic.AssetParamsFieldDocs()) + fieldSpecsMarkdown(out, logic.AssetParamsFieldNames, logic.AssetParamsFieldSpecByName) } func appParamsFieldsMarkdown(out io.Writer) { fmt.Fprintf(out, "\n`app_params_get` Fields:\n\n") - fieldTableMarkdown(out, logic.AppParamsFieldNames, logic.AppParamsFieldTypes, logic.AppParamsFieldDocs()) + fieldSpecsMarkdown(out, logic.AppParamsFieldNames, logic.AppParamsFieldSpecByName) } func ecDsaCurvesMarkdown(out io.Writer) { fmt.Fprintf(out, "\n`ECDSA` Curves:\n\n") - fieldTableMarkdown(out, logic.EcdsaCurveNames, nil, logic.EcdsaCurveDocs) + fieldSpecsMarkdown(out, logic.EcdsaCurveNames, logic.EcdsaCurveSpecByName) } func immediateMarkdown(op *logic.OpSpec) string { @@ -131,38 +160,45 @@ func immediateMarkdown(op *logic.OpSpec) string { return markdown } -func opToMarkdown(out io.Writer, op *logic.OpSpec) (err error) { - ws := "" - opextra := logic.OpImmediateNote(op.Name) - if opextra != "" { - ws = " " +func stackMarkdown(op *logic.OpSpec) string { + out := "- Stack: " + special := logic.OpStackEffects(op.Name) + if special != "" { + return out + special + "\n" } - fmt.Fprintf(out, "\n## %s%s\n\n- Opcode: 0x%02x%s%s\n", op.Name, immediateMarkdown(op), op.Opcode, ws, opextra) - if op.Args == nil { - fmt.Fprintf(out, "- Pops: _None_\n") - } else if len(op.Args) == 1 { - fmt.Fprintf(out, "- Pops: *... stack*, %s\n", op.Args[0].String()) - } else { - fmt.Fprintf(out, "- Pops: *... stack*, {%s A}", op.Args[0].String()) - for i, v := range op.Args[1:] { - fmt.Fprintf(out, ", {%s %c}", v.String(), rune(int('B')+i)) + + out += "..." + for i, v := range op.Args { + out += fmt.Sprintf(", %c", rune(int('A')+i)) + if v.Typed() { + out += fmt.Sprintf(": %s", v) } - out.Write([]byte("\n")) } + out += " → ..." - if op.Returns == nil { - fmt.Fprintf(out, "- Pushes: _None_\n") - } else { - if len(op.Returns) == 1 { - fmt.Fprintf(out, "- Pushes: %s", op.Returns[0].String()) - } else { - fmt.Fprintf(out, "- Pushes: *... stack*, %s", op.Returns[0].String()) - for _, rt := range op.Returns[1:] { - fmt.Fprintf(out, ", %s", rt.String()) + for i, rt := range op.Returns { + out += ", " + if len(op.Returns) > 1 { + start := int('X') + if len(op.Returns) > 3 { + start = int('Z') + 1 - len(op.Returns) } + out += fmt.Sprintf("%c: ", rune(start+i)) } - fmt.Fprintf(out, "\n") + out += rt.String() } + return out + "\n" +} + +func opToMarkdown(out io.Writer, op *logic.OpSpec) (err error) { + ws := "" + opextra := logic.OpImmediateNote(op.Name) + if opextra != "" { + ws = " " + } + stackEffects := stackMarkdown(op) + fmt.Fprintf(out, "\n## %s%s\n\n- Opcode: 0x%02x%s%s\n%s", + op.Name, immediateMarkdown(op), op.Opcode, ws, opextra, stackEffects) fmt.Fprintf(out, "- %s\n", logic.OpDoc(op.Name)) // if cost changed with versions print all of them costs := logic.OpAllCosts(op.Name) @@ -170,12 +206,12 @@ func opToMarkdown(out io.Writer, op *logic.OpSpec) (err error) { fmt.Fprintf(out, "- **Cost**:\n") for _, cost := range costs { if cost.From == cost.To { - fmt.Fprintf(out, " - %d (LogicSigVersion = %d)\n", cost.Cost, cost.To) + fmt.Fprintf(out, " - %d (v%d)\n", cost.Cost, cost.To) } else { if cost.To < logic.LogicVersion { - fmt.Fprintf(out, " - %d (%d <= LogicSigVersion <= %d)\n", cost.Cost, cost.From, cost.To) + fmt.Fprintf(out, " - %d (v%d - v%d)\n", cost.Cost, cost.From, cost.To) } else { - fmt.Fprintf(out, " - %d (LogicSigVersion >= %d)\n", cost.Cost, cost.From) + fmt.Fprintf(out, " - %d (since v%d)\n", cost.Cost, cost.From) } } } @@ -186,7 +222,7 @@ func opToMarkdown(out io.Writer, op *logic.OpSpec) (err error) { } } if op.Version > 1 { - fmt.Fprintf(out, "- LogicSigVersion >= %d\n", op.Version) + fmt.Fprintf(out, "- Availability: v%d\n", op.Version) } if !op.Modes.Any() { fmt.Fprintf(out, "- Mode: %s\n", op.Modes.String()) @@ -250,28 +286,6 @@ type LanguageSpec struct { Ops []OpRecord } -func argEnum(name string) []string { - if name == "txn" || name == "gtxn" || name == "gtxns" { - return logic.TxnFieldNames - } - if name == "global" { - return logic.GlobalFieldNames - } - if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" || name == "gtxnsas" { - return logic.TxnaFieldNames - } - if name == "asset_holding_get" { - return logic.AssetHoldingFieldNames - } - if name == "asset_params_get" { - return logic.AssetParamsFieldNames - } - if name == "app_params_get" { - return logic.AppParamsFieldNames - } - return nil -} - func typeString(types []logic.StackType) string { out := make([]byte, len(types)) for i, t := range types { @@ -294,27 +308,32 @@ func typeString(types []logic.StackType) string { return string(out) } -func argEnumTypes(name string) string { - if name == "txn" || name == "gtxn" || name == "gtxns" { - return typeString(logic.TxnFieldTypes) - } - if name == "global" { - return typeString(logic.GlobalFieldTypes) - } - if name == "txna" || name == "gtxna" || name == "gtxnsa" || name == "txnas" || name == "gtxnas" || name == "gtxnsas" { - return typeString(logic.TxnaFieldTypes) - } - if name == "asset_holding_get" { - return typeString(logic.AssetHoldingFieldTypes) - } - if name == "asset_params_get" { - return typeString(logic.AssetParamsFieldTypes) - } - if name == "app_params_get" { - return typeString(logic.AppParamsFieldTypes) +func fieldsAndTypes(names []string, specs speccer) ([]string, string) { + types := make([]logic.StackType, len(names)) + for i, name := range names { + types[i] = specs.SpecByName(name).Type() } + return names, typeString(types) +} - return "" +func argEnums(name string) (names []string, types string) { + switch name { + case "txn", "gtxn", "gtxns", "itxn", "gitxn", "itxn_field": + return fieldsAndTypes(logic.TxnFieldNames, logic.TxnFieldSpecByName) + case "global": + return + case "txna", "gtxna", "gtxnsa", "txnas", "gtxnas", "gtxnsas", "itxna", "gitxna": + // Map is the whole txn field spec map. That's fine, we only lookup the given names. + return fieldsAndTypes(logic.TxnaFieldNames(), logic.TxnFieldSpecByName) + case "asset_holding_get": + return fieldsAndTypes(logic.AssetHoldingFieldNames, logic.AssetHoldingFieldSpecByName) + case "asset_params_get": + return fieldsAndTypes(logic.AssetParamsFieldNames, logic.AssetParamsFieldSpecByName) + case "app_params_get": + return fieldsAndTypes(logic.AppParamsFieldNames, logic.AppParamsFieldSpecByName) + default: + return nil, "" + } } func buildLanguageSpec(opGroups map[string][]string) *LanguageSpec { @@ -327,8 +346,7 @@ func buildLanguageSpec(opGroups map[string][]string) *LanguageSpec { records[i].Returns = typeString(spec.Returns) records[i].Cost = spec.Details.Cost records[i].Size = spec.Details.Size - records[i].ArgEnum = argEnum(spec.Name) - records[i].ArgEnumTypes = argEnumTypes(spec.Name) + records[i].ArgEnum, records[i].ArgEnumTypes = argEnums(spec.Name) records[i].Doc = logic.OpDoc(spec.Name) records[i].DocExtra = logic.OpDocExtra(spec.Name) records[i].ImmediateNote = logic.OpImmediateNote(spec.Name) @@ -361,25 +379,29 @@ func main() { constants.Close() txnfields, _ := os.Create("txn_fields.md") - fieldTableMarkdown(txnfields, logic.TxnFieldNames, logic.TxnFieldTypes, logic.TxnFieldDocs()) + fieldSpecsMarkdown(txnfields, logic.TxnFieldNames, logic.TxnFieldSpecByName) txnfields.Close() globalfields, _ := os.Create("global_fields.md") - fieldTableMarkdown(globalfields, logic.GlobalFieldNames, logic.GlobalFieldTypes, logic.GlobalFieldDocs()) + fieldSpecsMarkdown(globalfields, logic.GlobalFieldNames, logic.GlobalFieldSpecByName) globalfields.Close() assetholding, _ := os.Create("asset_holding_fields.md") - fieldTableMarkdown(assetholding, logic.AssetHoldingFieldNames, logic.AssetHoldingFieldTypes, logic.AssetHoldingFieldDocs) + fieldSpecsMarkdown(assetholding, logic.AssetHoldingFieldNames, logic.AssetHoldingFieldSpecByName) assetholding.Close() assetparams, _ := os.Create("asset_params_fields.md") - fieldTableMarkdown(assetparams, logic.AssetParamsFieldNames, logic.AssetParamsFieldTypes, logic.AssetParamsFieldDocs()) + fieldSpecsMarkdown(assetparams, logic.AssetParamsFieldNames, logic.AssetParamsFieldSpecByName) assetparams.Close() appparams, _ := os.Create("app_params_fields.md") - fieldTableMarkdown(appparams, logic.AppParamsFieldNames, logic.AppParamsFieldTypes, logic.AppParamsFieldDocs()) + fieldSpecsMarkdown(appparams, logic.AppParamsFieldNames, logic.AppParamsFieldSpecByName) appparams.Close() + acctparams, _ := os.Create("acct_params_fields.md") + fieldSpecsMarkdown(acctparams, logic.AcctParamsFieldNames, logic.AcctParamsFieldSpecByName) + acctparams.Close() + langspecjs, _ := os.Create("langspec.json") enc := json.NewEncoder(langspecjs) enc.Encode(buildLanguageSpec(opGroups)) |