Browse Source

generate-wire.py: create structures for optional fields.

If a structure foo has a optional fields opt1 and opt2, this creates
towire_foo, towire_foo_opt1 and towire_foo_opt2 (since opt2 implies opt1),
similarly for fromwire_*.

This requires the callers to be updated to call the correct routines (eg.
try fromwire_foo_opt2, then fromwire_foo_opt1, then finally fromwire_foo),
but this is a minimal change to the generation code.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
5320cab2de
  1. 63
      tools/generate-wire.py

63
tools/generate-wire.py

@ -2,6 +2,7 @@
# Read from stdin, spit out C header or body.
import argparse
import copy
from collections import namedtuple
import fileinput
import re
@ -387,6 +388,28 @@ class Message(object):
subcalls='\n'.join(subcalls),
)
def find_message(messages, name):
for m in messages:
if m.name == name:
return m
return None
def find_message_with_option(messages, optional_messages, name, option):
fullname = name + "_" + option;
base = find_message(messages, name)
if not base:
raise ValueError('Unknown message {}'.format(name))
m = find_message(optional_messages, name)
if not m:
# Add a new option.
m = copy.deepcopy(base)
m.name = fullname
optional_messages.append(m)
return m
parser = argparse.ArgumentParser(description='Generate C from from CSV')
parser.add_argument('--header', action='store_true', help="Create wire header")
parser.add_argument('--bolt', action='store_true', help="Generate wire-format for BOLT")
@ -397,6 +420,7 @@ options = parser.parse_args()
# Maps message names to messages
messages = []
messages_with_option = []
comments = []
includes = []
prevfield = None
@ -423,22 +447,27 @@ for line in fileinput.input(options.files):
messages.append(Message(parts[0],Enumtype("WIRE_" + parts[0].upper(), parts[1]), comments))
comments=[]
prevfield = None
elif len(parts) == 4:
# eg commit_sig,0,channel-id,8 OR
# commit_sig,0,channel-id,u64
for m in messages:
if m.name == parts[0]:
f = Field(parts[0], parts[2], parts[3], comments, prevfield)
m.addField(f)
# If it used prevfield as lenvar, keep that for next
# time (multiple fields can use the same lenvar).
if not f.lenvar:
prevfield = parts[2]
break
comments=[]
else:
raise ValueError('Line {} malformed'.format(line.rstrip()))
if len(parts) == 4:
# eg commit_sig,0,channel-id,8 OR
# commit_sig,0,channel-id,u64
m = find_message(messages, parts[0])
if m is None:
raise ValueError('Unknown message {}'.format(name))
elif len(parts) == 5:
# eg.
# channel_reestablish,48,your_last_per_commitment_secret,32,option209
m = find_message_with_option(messages, messages_with_option, parts[0], parts[4])
else:
raise ValueError('Line {} malformed'.format(line.rstrip()))
f = Field(m.name, parts[2], parts[3], comments, prevfield)
m.addField(f)
# If it used prevfield as lenvar, keep that for next
# time (multiple fields can use the same lenvar).
if not f.lenvar:
prevfield = parts[2]
comments=[]
header_template = """#ifndef LIGHTNING_{idem}
#define LIGHTNING_{idem}
@ -485,8 +514,8 @@ for m in messages:
includes = '\n'.join(includes)
cases = ['case {enum.name}: return "{enum.name}";'.format(enum=m.enum) for m in messages]
fromwire_decls = [m.print_fromwire(options.header) for m in messages]
towire_decls = [m.print_towire(options.header) for m in messages]
fromwire_decls = [m.print_fromwire(options.header) for m in messages + messages_with_option]
towire_decls = [m.print_towire(options.header) for m in messages + messages_with_option]
print(template.format(
headerfilename=options.headerfilename,

Loading…
Cancel
Save