"""
parse JSON types and create a simplified and fully resolved list of type
descriptions that is convenient for Python based source-level tools
"""

import json
from sugar import *

#
# constatns 
#

# fields 
FieldKind       = 'kind'
FieldFields     = 'fields'
FieldReturn     = 'return'
FieldValue      = 'value'
FieldIdent      = 'identifier'

# kind/type class
KindNameStruct  = 'struct'
KindNameEnum    = 'enum'
KindNameFunction= 'function'

# C reserved identifiers needed
KeywordConst    = 'const'
KeywordPtr      = '*'

# extra reserved identifier names
AnonymousEnum   = '(anonymous)'


# build-in type initialier list
builtinInitList = (
    ('void',    0),   
    ('char',    1),   
    ('int8_t',  1),
    ('uint8_t', 1),
    ('int16_t', 2),
    ('uint16_t',2),
    ('int32_t', 4),
    ('uint32_t',4),
    ('int64_t', 8),
    ('uint64_t',8),
    ('size_t',  4), 
    ('float',   4),
    ('double',  8))

# construct all builtin types from the initializer list
builtins = [BuiltinDecl(ident, width)
                for (ident, width) in builtinInitList]

typeMap = None
declList = None

def reset():
    """
    reset the parser to intial state
    """
    global typeMap, declList
    typeMap = {}
    declList = builtins[:]
    for t in  builtins: typeMap[t.identifier] = t


# initialize type map with builtin types
reset()

#
# convenience functions
#

def isIdentifierCandidate(part):
    part = str(part)
    return str.isalpha(part[0]) or (part[0] == '_') or (part == AnonymousEnum)
def isConst(part): return part == KeywordConst
def isPointer(part): return part == KeywordPtr
def isAnonymous(t): return t.identifier == AnonymousEnum
def isDeclKnown(t): return typeMap.has_key(t.identifier)


def valsForKeys(h, *keys):
    """
    obtain fields for keys
    """
    return [h[k] for k in keys]


def findOrCreateDeclForIdent(ident):
    """
    looks-up the type in the type map and return it, or adds a new type
    and returns it
    """
    # FIXME handle forward references by adding an unresolved type to the
    # the list (if necessary)
    return typeMap[ident]


def  addDecl(decl):
    """
    add a new decl to the type map
    """
    # FIXME we need to handle the case where there is an existing unresolved
    # type in the map
    declList.append(decl)
    typeMap[decl.identifier] = decl
#
# parser components
#

def parseSubscripts(part):
    """
    parse out subscript values
    """
    subs = str(part)
    subs = part.split("]")[:-1]
    return [int(sub[1:]) for sub in subs]


def parseVarInfo(t):
    """
    parse type information
    """
    identifier = ""
    quals      = []
    subscripts = []
    
    for part in t.split(' '):
        if isPointer(part): quals.append(QualPtr)
        elif isConst(part): quals.append(QualConst)
        elif isIdentifierCandidate(part): identifier = part
        else: subscripts = parseSubscripts(part)
    
    return VarInfo(findOrCreateDeclForIdent(identifier), quals, subscripts)
            

def  parseVarFields(fields):
    """
    decode field set
    """
    fields = [valsForKeys(f, FieldIdent, FieldKind) for f in fields]
    return [VarDecl(identifier, parseVarInfo(kind)) for (identifier, kind) in fields]

    
def parseStruct(struct):
    """
    decode structure
    """
    identifier, fields = valsForKeys(struct, FieldIdent, FieldFields)
    t = StructDecl(identifier, parseVarFields(fields))
    addDecl(t)
    
    
def parseFunction(func):
    """
    decode function representation
    """
    identifier, fields, returnType = \
            valsForKeys(func, FieldIdent, FieldFields, FieldReturn)
    
    t = FunctionDecl(identifier,
                         parseVarFields(fields),
                         parseVarInfo(returnType))
    addDecl(t)


def parseConstant(const):
    """
    parse a constants
    """
    identifier, value = valsForKeys(const, FieldIdent, FieldValue)
    return ConstDecl(identifier, value)


def parseEnum(enum):
    """
    parse an enumerated type
    """
    identifier, fields = valsForKeys(enum, FieldIdent, FieldFields)
    t = EnumDecl(identifier, [parseConstant(c) for c in fields])
    if isAnonymous(t) and isDeclKnown(t):
        # handle adding fields to anonymously specified enumerated type
        enum = typeMap[identifier]
        enum.fields += t.fields
    else:
        # add ordinary enum decl
        addDecl(t)
 
    
#
# do the parsing
#
    
parser = {
    KindNameStruct   : parseStruct,
    KindNameFunction : parseFunction,
    KindNameEnum     : parseEnum
}

def parse(inf):
    """
    parse json input file
    """
    for rec in json.load(inf):
        parser[rec[FieldKind]](rec)
    return declList
        
    
def getResults():
    """
    get the parser result
    """
    return declList
f6ef92f3be7f08505c9c697e5c221ef4a5e6e61e
<mask token>


def reset():
    """
    reset the parser to intial state
    """
    global typeMap, declList
    typeMap = {}
    declList = builtins[:]
    for t in builtins:
        typeMap[t.identifier] = t


<mask token>


def isPointer(part):
    return part == KeywordPtr


def isAnonymous(t):
    return t.identifier == AnonymousEnum


def isDeclKnown(t):
    return typeMap.has_key(t.identifier)


<mask token>


def addDecl(decl):
    """
    add a new decl to the type map
    """
    declList.append(decl)
    typeMap[decl.identifier] = decl


def parseSubscripts(part):
    """
    parse out subscript values
    """
    subs = str(part)
    subs = part.split(']')[:-1]
    return [int(sub[1:]) for sub in subs]


def parseVarInfo(t):
    """
    parse type information
    """
    identifier = ''
    quals = []
    subscripts = []
    for part in t.split(' '):
        if isPointer(part):
            quals.append(QualPtr)
        elif isConst(part):
            quals.append(QualConst)
        elif isIdentifierCandidate(part):
            identifier = part
        else:
            subscripts = parseSubscripts(part)
    return VarInfo(findOrCreateDeclForIdent(identifier), quals, subscripts)


def parseVarFields(fields):
    """
    decode field set
    """
    fields = [valsForKeys(f, FieldIdent, FieldKind) for f in fields]
    return [VarDecl(identifier, parseVarInfo(kind)) for identifier, kind in
        fields]


def parseStruct(struct):
    """
    decode structure
    """
    identifier, fields = valsForKeys(struct, FieldIdent, FieldFields)
    t = StructDecl(identifier, parseVarFields(fields))
    addDecl(t)


def parseFunction(func):
    """
    decode function representation
    """
    identifier, fields, returnType = valsForKeys(func, FieldIdent,
        FieldFields, FieldReturn)
    t = FunctionDecl(identifier, parseVarFields(fields), parseVarInfo(
        returnType))
    addDecl(t)


<mask token>


def parseEnum(enum):
    """
    parse an enumerated type
    """
    identifier, fields = valsForKeys(enum, FieldIdent, FieldFields)
    t = EnumDecl(identifier, [parseConstant(c) for c in fields])
    if isAnonymous(t) and isDeclKnown(t):
        enum = typeMap[identifier]
        enum.fields += t.fields
    else:
        addDecl(t)


<mask token>


def parse(inf):
    """
    parse json input file
    """
    for rec in json.load(inf):
        parser[rec[FieldKind]](rec)
    return declList


def getResults():
    """
    get the parser result
    """
    return declList

<mask token>


def reset():
    """
    reset the parser to intial state
    """
    global typeMap, declList
    typeMap = {}
    declList = builtins[:]
    for t in builtins:
        typeMap[t.identifier] = t


<mask token>


def isPointer(part):
    return part == KeywordPtr


def isAnonymous(t):
    return t.identifier == AnonymousEnum


def isDeclKnown(t):
    return typeMap.has_key(t.identifier)


<mask token>


def findOrCreateDeclForIdent(ident):
    """
    looks-up the type in the type map and return it, or adds a new type
    and returns it
    """
    return typeMap[ident]


def addDecl(decl):
    """
    add a new decl to the type map
    """
    declList.append(decl)
    typeMap[decl.identifier] = decl


def parseSubscripts(part):
    """
    parse out subscript values
    """
    subs = str(part)
    subs = part.split(']')[:-1]
    return [int(sub[1:]) for sub in subs]


def parseVarInfo(t):
    """
    parse type information
    """
    identifier = ''
    quals = []
    subscripts = []
    for part in t.split(' '):
        if isPointer(part):
            quals.append(QualPtr)
        elif isConst(part):
            quals.append(QualConst)
        elif isIdentifierCandidate(part):
            identifier = part
        else:
            subscripts = parseSubscripts(part)
    return VarInfo(findOrCreateDeclForIdent(identifier), quals, subscripts)


def parseVarFields(fields):
    """
    decode field set
    """
    fields = [valsForKeys(f, FieldIdent, FieldKind) for f in fields]
    return [VarDecl(identifier, parseVarInfo(kind)) for identifier, kind in
        fields]


def parseStruct(struct):
    """
    decode structure
    """
    identifier, fields = valsForKeys(struct, FieldIdent, FieldFields)
    t = StructDecl(identifier, parseVarFields(fields))
    addDecl(t)


def parseFunction(func):
    """
    decode function representation
    """
    identifier, fields, returnType = valsForKeys(func, FieldIdent,
        FieldFields, FieldReturn)
    t = FunctionDecl(identifier, parseVarFields(fields), parseVarInfo(
        returnType))
    addDecl(t)


<mask token>


def parseEnum(enum):
    """
    parse an enumerated type
    """
    identifier, fields = valsForKeys(enum, FieldIdent, FieldFields)
    t = EnumDecl(identifier, [parseConstant(c) for c in fields])
    if isAnonymous(t) and isDeclKnown(t):
        enum = typeMap[identifier]
        enum.fields += t.fields
    else:
        addDecl(t)


<mask token>


def parse(inf):
    """
    parse json input file
    """
    for rec in json.load(inf):
        parser[rec[FieldKind]](rec)
    return declList


def getResults():
    """
    get the parser result
    """
    return declList

<mask token>


def reset():
    """
    reset the parser to intial state
    """
    global typeMap, declList
    typeMap = {}
    declList = builtins[:]
    for t in builtins:
        typeMap[t.identifier] = t


<mask token>


def isConst(part):
    return part == KeywordConst


def isPointer(part):
    return part == KeywordPtr


def isAnonymous(t):
    return t.identifier == AnonymousEnum


def isDeclKnown(t):
    return typeMap.has_key(t.identifier)


<mask token>


def findOrCreateDeclForIdent(ident):
    """
    looks-up the type in the type map and return it, or adds a new type
    and returns it
    """
    return typeMap[ident]


def addDecl(decl):
    """
    add a new decl to the type map
    """
    declList.append(decl)
    typeMap[decl.identifier] = decl


def parseSubscripts(part):
    """
    parse out subscript values
    """
    subs = str(part)
    subs = part.split(']')[:-1]
    return [int(sub[1:]) for sub in subs]


def parseVarInfo(t):
    """
    parse type information
    """
    identifier = ''
    quals = []
    subscripts = []
    for part in t.split(' '):
        if isPointer(part):
            quals.append(QualPtr)
        elif isConst(part):
            quals.append(QualConst)
        elif isIdentifierCandidate(part):
            identifier = part
        else:
            subscripts = parseSubscripts(part)
    return VarInfo(findOrCreateDeclForIdent(identifier), quals, subscripts)


def parseVarFields(fields):
    """
    decode field set
    """
    fields = [valsForKeys(f, FieldIdent, FieldKind) for f in fields]
    return [VarDecl(identifier, parseVarInfo(kind)) for identifier, kind in
        fields]


def parseStruct(struct):
    """
    decode structure
    """
    identifier, fields = valsForKeys(struct, FieldIdent, FieldFields)
    t = StructDecl(identifier, parseVarFields(fields))
    addDecl(t)


def parseFunction(func):
    """
    decode function representation
    """
    identifier, fields, returnType = valsForKeys(func, FieldIdent,
        FieldFields, FieldReturn)
    t = FunctionDecl(identifier, parseVarFields(fields), parseVarInfo(
        returnType))
    addDecl(t)


<mask token>


def parseEnum(enum):
    """
    parse an enumerated type
    """
    identifier, fields = valsForKeys(enum, FieldIdent, FieldFields)
    t = EnumDecl(identifier, [parseConstant(c) for c in fields])
    if isAnonymous(t) and isDeclKnown(t):
        enum = typeMap[identifier]
        enum.fields += t.fields
    else:
        addDecl(t)


<mask token>


def parse(inf):
    """
    parse json input file
    """
    for rec in json.load(inf):
        parser[rec[FieldKind]](rec)
    return declList


def getResults():
    """
    get the parser result
    """
    return declList

<mask token>


def reset():
    """
    reset the parser to intial state
    """
    global typeMap, declList
    typeMap = {}
    declList = builtins[:]
    for t in builtins:
        typeMap[t.identifier] = t


<mask token>


def isIdentifierCandidate(part):
    part = str(part)
    return str.isalpha(part[0]) or part[0] == '_' or part == AnonymousEnum


def isConst(part):
    return part == KeywordConst


def isPointer(part):
    return part == KeywordPtr


def isAnonymous(t):
    return t.identifier == AnonymousEnum


def isDeclKnown(t):
    return typeMap.has_key(t.identifier)


def valsForKeys(h, *keys):
    """
    obtain fields for keys
    """
    return [h[k] for k in keys]


def findOrCreateDeclForIdent(ident):
    """
    looks-up the type in the type map and return it, or adds a new type
    and returns it
    """
    return typeMap[ident]


def addDecl(decl):
    """
    add a new decl to the type map
    """
    declList.append(decl)
    typeMap[decl.identifier] = decl


def parseSubscripts(part):
    """
    parse out subscript values
    """
    subs = str(part)
    subs = part.split(']')[:-1]
    return [int(sub[1:]) for sub in subs]


def parseVarInfo(t):
    """
    parse type information
    """
    identifier = ''
    quals = []
    subscripts = []
    for part in t.split(' '):
        if isPointer(part):
            quals.append(QualPtr)
        elif isConst(part):
            quals.append(QualConst)
        elif isIdentifierCandidate(part):
            identifier = part
        else:
            subscripts = parseSubscripts(part)
    return VarInfo(findOrCreateDeclForIdent(identifier), quals, subscripts)


def parseVarFields(fields):
    """
    decode field set
    """
    fields = [valsForKeys(f, FieldIdent, FieldKind) for f in fields]
    return [VarDecl(identifier, parseVarInfo(kind)) for identifier, kind in
        fields]


def parseStruct(struct):
    """
    decode structure
    """
    identifier, fields = valsForKeys(struct, FieldIdent, FieldFields)
    t = StructDecl(identifier, parseVarFields(fields))
    addDecl(t)


def parseFunction(func):
    """
    decode function representation
    """
    identifier, fields, returnType = valsForKeys(func, FieldIdent,
        FieldFields, FieldReturn)
    t = FunctionDecl(identifier, parseVarFields(fields), parseVarInfo(
        returnType))
    addDecl(t)


def parseConstant(const):
    """
    parse a constants
    """
    identifier, value = valsForKeys(const, FieldIdent, FieldValue)
    return ConstDecl(identifier, value)


def parseEnum(enum):
    """
    parse an enumerated type
    """
    identifier, fields = valsForKeys(enum, FieldIdent, FieldFields)
    t = EnumDecl(identifier, [parseConstant(c) for c in fields])
    if isAnonymous(t) and isDeclKnown(t):
        enum = typeMap[identifier]
        enum.fields += t.fields
    else:
        addDecl(t)


<mask token>


def parse(inf):
    """
    parse json input file
    """
    for rec in json.load(inf):
        parser[rec[FieldKind]](rec)
    return declList


def getResults():
    """
    get the parser result
    """
    return declList

"""
parse JSON types and create a simplified and fully resolved list of type
descriptions that is convenient for Python based source-level tools
"""

import json
from sugar import *

#
# constatns 
#

# fields 
FieldKind       = 'kind'
FieldFields     = 'fields'
FieldReturn     = 'return'
FieldValue      = 'value'
FieldIdent      = 'identifier'

# kind/type class
KindNameStruct  = 'struct'
KindNameEnum    = 'enum'
KindNameFunction= 'function'

# C reserved identifiers needed
KeywordConst    = 'const'
KeywordPtr      = '*'

# extra reserved identifier names
AnonymousEnum   = '(anonymous)'


# build-in type initialier list
builtinInitList = (
    ('void',    0),   
    ('char',    1),   
    ('int8_t',  1),
    ('uint8_t', 1),
    ('int16_t', 2),
    ('uint16_t',2),
    ('int32_t', 4),
    ('uint32_t',4),
    ('int64_t', 8),
    ('uint64_t',8),
    ('size_t',  4), 
    ('float',   4),
    ('double',  8))

# construct all builtin types from the initializer list
builtins = [BuiltinDecl(ident, width)
                for (ident, width) in builtinInitList]

typeMap = None
declList = None

def reset():
    """
    reset the parser to intial state
    """
    global typeMap, declList
    typeMap = {}
    declList = builtins[:]
    for t in  builtins: typeMap[t.identifier] = t


# initialize type map with builtin types
reset()

#
# convenience functions
#

def isIdentifierCandidate(part):
    part = str(part)
    return str.isalpha(part[0]) or (part[0] == '_') or (part == AnonymousEnum)
def isConst(part): return part == KeywordConst
def isPointer(part): return part == KeywordPtr
def isAnonymous(t): return t.identifier == AnonymousEnum
def isDeclKnown(t): return typeMap.has_key(t.identifier)


def valsForKeys(h, *keys):
    """
    obtain fields for keys
    """
    return [h[k] for k in keys]


def findOrCreateDeclForIdent(ident):
    """
    looks-up the type in the type map and return it, or adds a new type
    and returns it
    """
    # FIXME handle forward references by adding an unresolved type to the
    # the list (if necessary)
    return typeMap[ident]


def  addDecl(decl):
    """
    add a new decl to the type map
    """
    # FIXME we need to handle the case where there is an existing unresolved
    # type in the map
    declList.append(decl)
    typeMap[decl.identifier] = decl
#
# parser components
#

def parseSubscripts(part):
    """
    parse out subscript values
    """
    subs = str(part)
    subs = part.split("]")[:-1]
    return [int(sub[1:]) for sub in subs]


def parseVarInfo(t):
    """
    parse type information
    """
    identifier = ""
    quals      = []
    subscripts = []
    
    for part in t.split(' '):
        if isPointer(part): quals.append(QualPtr)
        elif isConst(part): quals.append(QualConst)
        elif isIdentifierCandidate(part): identifier = part
        else: subscripts = parseSubscripts(part)
    
    return VarInfo(findOrCreateDeclForIdent(identifier), quals, subscripts)
            

def  parseVarFields(fields):
    """
    decode field set
    """
    fields = [valsForKeys(f, FieldIdent, FieldKind) for f in fields]
    return [VarDecl(identifier, parseVarInfo(kind)) for (identifier, kind) in fields]

    
def parseStruct(struct):
    """
    decode structure
    """
    identifier, fields = valsForKeys(struct, FieldIdent, FieldFields)
    t = StructDecl(identifier, parseVarFields(fields))
    addDecl(t)
    
    
def parseFunction(func):
    """
    decode function representation
    """
    identifier, fields, returnType = \
            valsForKeys(func, FieldIdent, FieldFields, FieldReturn)
    
    t = FunctionDecl(identifier,
                         parseVarFields(fields),
                         parseVarInfo(returnType))
    addDecl(t)


def parseConstant(const):
    """
    parse a constants
    """
    identifier, value = valsForKeys(const, FieldIdent, FieldValue)
    return ConstDecl(identifier, value)


def parseEnum(enum):
    """
    parse an enumerated type
    """
    identifier, fields = valsForKeys(enum, FieldIdent, FieldFields)
    t = EnumDecl(identifier, [parseConstant(c) for c in fields])
    if isAnonymous(t) and isDeclKnown(t):
        # handle adding fields to anonymously specified enumerated type
        enum = typeMap[identifier]
        enum.fields += t.fields
    else:
        # add ordinary enum decl
        addDecl(t)
 
    
#
# do the parsing
#
    
parser = {
    KindNameStruct   : parseStruct,
    KindNameFunction : parseFunction,
    KindNameEnum     : parseEnum
}

def parse(inf):
    """
    parse json input file
    """
    for rec in json.load(inf):
        parser[rec[FieldKind]](rec)
    return declList
        
    
def getResults():
    """
    get the parser result
    """
    return declList