Use enums for sym, fail if no toast

This commit is contained in:
Ganesh Viswanathan 2018-11-21 17:24:13 -06:00
commit c0481ac41c
4 changed files with 105 additions and 80 deletions

View file

@ -20,30 +20,30 @@ proc addHeader*(fullpath: string) =
# Preprocessor # Preprocessor
# #
proc preprocDef(node: ref Ast) = proc pPreprocDef(node: ref Ast) =
if node.children.len() == 2: if node.children.len() == 2:
let let
name = getNodeValIf(node.children[0], "identifier") name = getNodeValIf(node.children[0], identifier)
val = getNodeValIf(node.children[1], "preproc_arg") val = getNodeValIf(node.children[1], preproc_arg)
if name.nBl and val.nBl and name notin gConsts: if name.nBl and val.nBl and name notin gConsts:
gConsts.add(name) gConsts.add(name)
if val.getLit().nBl: if val.getLit().nBl:
# #define NAME VALUE # #define NAME VALUE
gConstStr &= &" {name.getIdentifier()}* = {val} # preprocDef()\n" gConstStr &= &" {name.getIdentifier()}* = {val} # pPreprocDef()\n"
# #
# Types # Types
# #
proc typeScan(node: ref Ast, sym, identifier, offset: string): string = proc typeScan(node: ref Ast, sym, id: Sym, offset: string): string =
if node.sym != sym or node.children.len() != 2: if node.sym != sym or node.children.len() != 2:
return return
let let
pname = getNodeValIf(node.children[1], identifier) pname = getNodeValIf(node.children[1], id)
ptyp = getNodeValIf(node.children[0], "primitive_type") ptyp = getNodeValIf(node.children[0], primitive_type)
ttyp = getNodeValIf(node.children[0], "type_identifier") ttyp = getNodeValIf(node.children[0], type_identifier)
if pname.len() == 0: if pname.len() == 0:
return return
@ -51,48 +51,51 @@ proc typeScan(node: ref Ast, sym, identifier, offset: string): string =
result = &"{offset}{pname.getIdentifier()}: {ptyp.getType()}" result = &"{offset}{pname.getIdentifier()}: {ptyp.getType()}"
elif ttyp.nBl: elif ttyp.nBl:
result = &"{offset}{pname.getIdentifier()}: {ttyp}" result = &"{offset}{pname.getIdentifier()}: {ttyp}"
elif node.children[0].sym in ["struct_specifier", "enum_specifier"] and node.children[0].children.len() == 1: elif node.children[0].sym in [struct_specifier, enum_specifier] and node.children[0].children.len() == 1:
let styp = getNodeValIf(node.children[0].children[0], "type_identifier") let styp = getNodeValIf(node.children[0].children[0], type_identifier)
if styp.nBl: if styp.nBl:
result = &"{offset}{pname.getIdentifier()}: {styp}" result = &"{offset}{pname.getIdentifier()}: {styp}"
else: else:
return return
proc structSpecifier(node: ref Ast, name = "") = proc pStructSpecifier(node: ref Ast, name = "") =
var stmt: string var stmt: string
if node.children.len() == 1 and name notin gTypes: if node.children.len() == 1 and name notin gTypes:
case node.children[0].sym: case node.children[0].sym:
of "type_identifier": of type_identifier:
let typ = getNodeValIf(node.children[0], "type_identifier") let typ = getNodeValIf(node.children[0], type_identifier)
if typ.nBl: if typ.nBl:
gTypes.add(name) gTypes.add(name)
if name != typ: if name != typ:
# typedef struct X Y # typedef struct X Y
gTypeStr &= &" {name}* = {typ} #1 structSpecifier()\n" gTypeStr &= &" {name}* = {typ} #1 pStructSpecifier()\n"
else: else:
# typedef struct X X # typedef struct X X
gTypeStr &= &" {name}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #2 structSpecifier()\n" gTypeStr &= &" {name}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #2 pStructSpecifier()\n"
of "field_declaration_list": of field_declaration_list:
# typedef struct { fields } X # typedef struct { fields } X
stmt = &" {name}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #3 structSpecifier()\n" stmt = &" {name}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #3 pStructSpecifier()\n"
for field in node.children[0].children: for field in node.children[0].children:
let ts = typeScan(field, "field_declaration", "field_identifier", " ") let ts = typeScan(field, field_declaration, field_identifier, " ")
if ts.len() == 0: if ts.len() == 0:
return return
stmt &= ts & "\n" stmt &= ts & "\n"
gTypes.add(name) gTypes.add(name)
gTypeStr &= stmt gTypeStr &= stmt
elif name.len() == 0 and node.children.len() == 2 and node.children[1].sym == "field_declaration_list": else:
let ename = getNodeValIf(node.children[0], "type_identifier") discard
elif name.len() == 0 and node.children.len() == 2 and node.children[1].sym == field_declaration_list:
let ename = getNodeValIf(node.children[0], type_identifier)
if ename.nBl and ename notin gTypes: if ename.nBl and ename notin gTypes:
# struct X { fields } # struct X { fields }
stmt &= &" {ename}* {{.importc: \"struct {ename}\", header: {gCurrentHeader}, bycopy.}} = object #4 structSpecifier()\n" stmt &= &" {ename}* {{.importc: \"struct {ename}\", header: {gCurrentHeader}, bycopy.}} = object #4 pStructSpecifier()\n"
for field in node.children[1].children: for field in node.children[1].children:
let ts = typeScan(field, "field_declaration", "field_identifier", " ") let ts = typeScan(field, field_declaration, field_identifier, " ")
if ts.len() == 0: if ts.len() == 0:
return return
stmt &= ts & "\n" stmt &= ts & "\n"
@ -100,33 +103,33 @@ proc structSpecifier(node: ref Ast, name = "") =
gTypes.add(name) gTypes.add(name)
gTypeStr &= stmt gTypeStr &= stmt
proc enumSpecifier(node: ref Ast, name = "") = proc pEnumSpecifier(node: ref Ast, name = "") =
var var
ename: string ename: string
elid: int elid: int
stmt: string stmt: string
if node.children.len() == 1 and node.children[0].sym == "enumerator_list": if node.children.len() == 1 and node.children[0].sym == enumerator_list:
# typedef enum { fields } X # typedef enum { fields } X
ename = name ename = name
elid = 0 elid = 0
stmt = &" {name}* = enum #1 enumSpecifier()\n" stmt = &" {name}* = enum #1 pEnumSpecifier()\n"
elif name.len() == 0 and node.children.len() == 2 and node.children[1].sym == "enumerator_list": elif name.len() == 0 and node.children.len() == 2 and node.children[1].sym == enumerator_list:
ename = getNodeValIf(node.children[0], "type_identifier") ename = getNodeValIf(node.children[0], type_identifier)
elid = 1 elid = 1
if ename.nBl: if ename.nBl:
# enum X { fields } # enum X { fields }
stmt = &" {ename}* = enum #2 enumSpecifier()\n" stmt = &" {ename}* = enum #2 pEnumSpecifier()\n"
else: else:
return return
for field in node.children[elid].children: for field in node.children[elid].children:
if field.sym == "enumerator": if field.sym == enumerator:
let fname = getNodeValIf(field.children[0], "identifier") let fname = getNodeValIf(field.children[0], identifier)
if field.children.len() == 1: if field.children.len() == 1:
stmt &= &" {fname}\n" stmt &= &" {fname}\n"
elif field.children.len() == 2 and field.children[1].sym == "number_literal": elif field.children.len() == 2 and field.children[1].sym == number_literal:
let num = getNodeValIf(field.children[1], "number_literal") let num = getNodeValIf(field.children[1], number_literal)
stmt &= &" {fname} = {num}\n" stmt &= &" {fname} = {num}\n"
else: else:
return return
@ -135,44 +138,46 @@ proc enumSpecifier(node: ref Ast, name = "") =
gTypes.add(name) gTypes.add(name)
gTypeStr &= stmt gTypeStr &= stmt
proc typeDefinition(node: ref Ast) = proc pTypeDefinition(node: ref Ast) =
if node.children.len() == 2: if node.children.len() == 2:
var var
name = getNodeValIf(node.children[1], "type_identifier") name = getNodeValIf(node.children[1], type_identifier)
pname = getNodeValIf(node.children[1], "pointer_declarator") pname = getNodeValIf(node.children[1], pointer_declarator)
ptyp = getNodeValIf(node.children[0], "primitive_type") ptyp = getNodeValIf(node.children[0], primitive_type)
ttyp = getNodeValIf(node.children[0], "type_identifier") ttyp = getNodeValIf(node.children[0], type_identifier)
if name.len() == 0 and node.children[1].sym == "pointer_declarator" and node.children[1].children.len() == 1: if name.len() == 0 and node.children[1].sym == pointer_declarator and node.children[1].children.len() == 1:
name = getNodeValIf(node.children[1].children[0], "type_identifier") name = getNodeValIf(node.children[1].children[0], type_identifier)
if name.nBl and name notin gTypes: if name.nBl and name notin gTypes:
if ptyp.nBl: if ptyp.nBl:
# typedef int X # typedef int X
gTypes.add(name) gTypes.add(name)
gTypeStr &= &" {name}* = {ptyp.getType()} #1 typeDefinition()\n" gTypeStr &= &" {name}* = {ptyp.getType()} #1 pTypeDefinition()\n"
elif ttyp.nBl: elif ttyp.nBl:
# typedef X Y # typedef X Y
gTypes.add(name) gTypes.add(name)
gTypeStr &= &" {name}* = {ttyp} #2 typeDefinition()\n" gTypeStr &= &" {name}* = {ttyp} #2 pTypeDefinition()\n"
else: else:
case node.children[0].sym: case node.children[0].sym:
of "struct_specifier": of struct_specifier:
structSpecifier(node.children[0], name) pStructSpecifier(node.children[0], name)
of "enum_specifier": of enum_specifier:
enumSpecifier(node.children[0], name) pEnumSpecifier(node.children[0], name)
else:
discard
proc functionDeclarator(node: ref Ast, typ: string) = proc pFunctionDeclarator(node: ref Ast, typ: string) =
if node.children.len() == 2: if node.children.len() == 2:
let let
name = getNodeValIf(node.children[0], "identifier") name = getNodeValIf(node.children[0], identifier)
if name.nBl and name notin gProcs and node.children[1].sym == "parameter_list": if name.nBl and name notin gProcs and node.children[1].sym == parameter_list:
# typ function(typ param1, ...) # typ function(typ param1, ...)
var stmt = &"# functionDeclarator()\nproc {name}*(" var stmt = &"# pFunctionDeclarator()\nproc {name}*("
for i in 0 .. node.children[1].children.len()-1: for i in 0 .. node.children[1].children.len()-1:
let ts = typeScan(node.children[1].children[i], "parameter_declaration", "identifier", "") let ts = typeScan(node.children[1].children[i], parameter_declaration, identifier, "")
if ts.len() == 0: if ts.len() == 0:
return return
stmt &= ts stmt &= ts
@ -189,38 +194,40 @@ proc functionDeclarator(node: ref Ast, typ: string) =
gProcs.add(name) gProcs.add(name)
gProcStr &= stmt gProcStr &= stmt
proc declaration*(node: ref Ast) = proc pDeclaration*(node: ref Ast) =
if node.children.len() == 2 and node.children[1].sym == "function_declarator": if node.children.len() == 2 and node.children[1].sym == function_declarator:
let let
ptyp = getNodeValIf(node.children[0], "primitive_type") ptyp = getNodeValIf(node.children[0], primitive_type)
ttyp = getNodeValIf(node.children[0], "type_identifier") ttyp = getNodeValIf(node.children[0], type_identifier)
if ptyp.nBl: if ptyp.nBl:
functionDeclarator(node.children[1], ptyp.getType()) pFunctionDeclarator(node.children[1], ptyp.getType())
elif ttyp.nBl: elif ttyp.nBl:
functionDeclarator(node.children[1], ttyp) pFunctionDeclarator(node.children[1], ttyp)
elif node.children[0].sym == "struct_specifier" and node.children[0].children.len() == 1: elif node.children[0].sym == struct_specifier and node.children[0].children.len() == 1:
let styp = getNodeValIf(node.children[0].children[0], "type_identifier") let styp = getNodeValIf(node.children[0].children[0], type_identifier)
if styp.nBl: if styp.nBl:
functionDeclarator(node.children[1], styp) pFunctionDeclarator(node.children[1], styp)
proc genNimAst*(node: ref Ast) = proc genNimAst*(node: ref Ast) =
case node.sym: case node.sym:
of "ERROR": of ERROR:
let (line, col) = getLineCol(node) let (line, col) = getLineCol(node)
echo &"Potentially invalid syntax at line {line} column {col}" echo &"Potentially invalid syntax at line {line} column {col}"
of "preproc_def": of preproc_def:
preprocDef(node) pPreprocDef(node)
of "type_definition": of type_definition:
typeDefinition(node) pTypeDefinition(node)
of "declaration": of declaration:
declaration(node) pDeclaration(node)
of "struct_specifier": of struct_specifier:
if node.parent.sym notin ["type_definition", "declaration"]: if node.parent.sym notin [type_definition, declaration]:
structSpecifier(node) pStructSpecifier(node)
of "enum_specifier": of enum_specifier:
if node.parent.sym notin ["type_definition", "declaration"]: if node.parent.sym notin [type_definition, declaration]:
enumSpecifier(node) pEnumSpecifier(node)
else:
discard
for child in node.children: for child in node.children:
genNimAst(child) genNimAst(child)

View file

@ -16,7 +16,7 @@ proc getLit*(str: string): string =
str.contains(re"^0x[\d]+$"): str.contains(re"^0x[\d]+$"):
return str return str
proc getNodeValIf*(node: ref Ast, esym: string): string = proc getNodeValIf*(node: ref Ast, esym: Sym): string =
if esym != node.sym: if esym != node.sym:
return return

View file

@ -1,9 +1,20 @@
import macros import macros
type type
Sym* = enum
ERROR, IGNORED,
enumerator, enumerator_list, enum_specifier,
declaration,
field_declaration, field_declaration_list, field_identifier, function_declarator,
identifier,
number_literal,
parameter_declaration, parameter_list, pointer_declarator, preproc_arg, preproc_def, primitive_type,
struct_specifier,
type_definition, type_identifier
Ast* = object Ast* = object
sym*: string sym*: Sym
start*, stop*: int start*, stop*: uint32
parent*: ref Ast parent*: ref Ast
children*: seq[ref Ast] children*: seq[ref Ast]

View file

@ -24,6 +24,10 @@ proc tokenize(fullpath: string) =
else: else:
collect &= $i collect &= $i
if gTokens.len() == 0:
echo "toast binary not installed - nimble install nimterop to force build"
quit(1)
proc readFromTokens(): ref Ast = proc readFromTokens(): ref Ast =
if idx == gTokens.len(): if idx == gTokens.len():
echo "Bad AST" echo "Bad AST"
@ -35,14 +39,17 @@ proc readFromTokens(): ref Ast =
quit(1) quit(1)
if gTokens[idx+1] != "comment": if gTokens[idx+1] != "comment":
result = new(Ast) result = new(Ast)
result.sym = gTokens[idx+1] try:
result.start = gTokens[idx+2].parseInt() result.sym = parseEnum[Sym](gTokens[idx+1])
result.stop = gTokens[idx+3].parseInt() except:
result.sym = IGNORED
result.start = gTokens[idx+2].parseInt().uint32
result.stop = gTokens[idx+3].parseInt().uint32
result.children = @[] result.children = @[]
idx += 4 idx += 4
while gTokens[idx] != ")": while gTokens[idx] != ")":
var res = readFromTokens() var res = readFromTokens()
if not res.isNil() and res.sym.nBl: if not res.isNil():
res.parent = result res.parent = result
result.children.add(res) result.children.add(res)
elif gTokens[idx] == ")": elif gTokens[idx] == ")":
@ -52,7 +59,7 @@ proc readFromTokens(): ref Ast =
idx += 1 idx += 1
proc printAst*(node: ref Ast, offset=""): string = proc printAst*(node: ref Ast, offset=""): string =
result = offset & "(" & node.sym & " " & $node.start & " " & $node.stop result = offset & "(" & $node.sym & " " & $node.start & " " & $node.stop
if node.children.len() != 0: if node.children.len() != 0:
result &= "\n" result &= "\n"
for child in node.children: for child in node.children: