0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

argument parsing, fail on parsing

This commit is contained in:
strangeqargo 2016-05-05 01:58:53 +03:00
parent 6b7bdb1e62
commit 42dfa6cddc
2 changed files with 97 additions and 48 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

View File

@ -31,40 +31,28 @@ import re
import os import os
import pprint import pprint
# error codes, we should refactor this later
ERROR_DATA_TYPE = 10
ERROR_STRANGE_PARSING = 20
from pyparsing import CaselessLiteral, Literal, SkipTo, restOfLine, oneOf, ZeroOrMore, Optional, Combine, Suppress, \ from pyparsing import CaselessLiteral, Literal, SkipTo, restOfLine, oneOf, ZeroOrMore, Optional, Combine, Suppress, \
WordStart, WordEnd, Word, alphas, alphanums, nums, QuotedString, nestedExpr, MatchFirst, OneOrMore, delimitedList, Or, Group WordStart, WordEnd, Word, alphas, alphanums, nums, QuotedString, nestedExpr, MatchFirst, OneOrMore, delimitedList, Or, Group, ParseException
def usage():
print('Usage: ddl2cpp [-no-timestamp-warning] <path to ddl> <path to target (without extension, e.g. /tmp/MyTable)> <namespace>')
if len(sys.argv) not in (4,5):
usage()
sys.exit(1)
firstPositional = 1
timestampWarning = True
if len(sys.argv) == 5:
if sys.argv[1] == '-no-timestamp-warning':
firstPositional += 1
timestampWarning = False
else:
usage()
sys.exit(1)
pathToDdl = sys.argv[firstPositional]
pathToHeader = sys.argv[firstPositional + 1] + '.h'
namespace = sys.argv[firstPositional + 2]
INCLUDE = 'sqlpp11'
NAMESPACE = 'sqlpp'
# HELPERS # HELPERS
def get_include_guard_name(namespace, inputfile): def get_include_guard_name(namespace, inputfile):
val = re.sub("[^A-Za-z]+", "_", namespace + '_' + os.path.basename(inputfile)) val = re.sub("[^A-Za-z]+", "_", namespace + '_' + os.path.basename(inputfile))
return val.upper() return val.upper()
def repl_func(m): def repl_func(m):
if (m.group(1) == '_'): if m.group(1) == '_':
return m.group(2).upper()
else:
return m.group(1) + m.group(2).upper()
def repl_func_for_args(m):
if m.group(1) == '-':
return m.group(2).upper() return m.group(2).upper()
else: else:
return m.group(1) + m.group(2).upper() return m.group(1) + m.group(2).upper()
@ -72,10 +60,61 @@ def repl_func(m):
def toClassName(s): def toClassName(s):
return re.sub("(^|\s|[_0-9])(\S)", repl_func, s) return re.sub("(^|\s|[_0-9])(\S)", repl_func, s)
def toMemberName(s): def toMemberName(s):
return re.sub("(\s|_|[0-9])(\S)", repl_func, s) return re.sub("(\s|_|[0-9])(\S)", repl_func, s)
def setArgumentBool(s, bool_value):
first_lower = lambda s: s[:1].lower() + s[1:] if s else '' # http://stackoverflow.com/a/3847369/5006740
var_name = first_lower(re.sub("(\s|-|[0-9])(\S)", repl_func_for_args, s))
globals()[var_name] = bool_value
def usage():
print('Usage: ddl2cpp [-no-timestamp-warning] <path to ddl> <path to target (without extension, e.g. /tmp/MyTable)> <namespace>')
# ARGUMENT PARSING
if len(sys.argv) < (4):
usage()
sys.exit(20)
firstPositional = 1
timestampWarning = True
failOnParse = True
optionalArgs = {
# if -some-key is present, it will set variable someKey to True
# if -no-some-key is present, it will set variable someKey to False
'timestamp-warning', # timeStampWarning = True
# '-no-time-stamp-warning' # timeStampWarning = False
'fail-on-parse' # failOnParse = True
# 'no-fail-on-parse' # failOnParse = False
}
if len(sys.argv) >= 4:
for arg in sys.argv:
noArg = arg.replace('-no-', '')
if arg in optionalArgs:
setArgumentBool(arg, True)
firstPositional += 1
elif noArg in optionalArgs:
setArgumentBool(noArg, False)
firstPositional += 1
#sys.exit(0)
pathToDdl = sys.argv[firstPositional]
pathToHeader = sys.argv[firstPositional + 1] + '.h'
namespace = sys.argv[firstPositional + 2]
INCLUDE = 'sqlpp11'
NAMESPACE = 'sqlpp'
# PARSER # PARSER
def ddlWord(string): def ddlWord(string):
return WordStart(alphanums + "_") + CaselessLiteral(string) + WordEnd(alphanums + "_") return WordStart(alphanums + "_") + CaselessLiteral(string) + WordEnd(alphanums + "_")
@ -87,8 +126,8 @@ ddlTerm = Word(alphas, alphanums + "_$")
ddlName = Or([ddlTerm, ddlString]) ddlName = Or([ddlTerm, ddlString])
ddlArguments = "(" + delimitedList(Or([ddlString, ddlTerm, ddlNum])) + ")" ddlArguments = "(" + delimitedList(Or([ddlString, ddlTerm, ddlNum])) + ")"
ddlNotNull = Group(ddlWord("NOT") + ddlWord("NULL")).setResultsName("notNull") ddlNotNull = Group(ddlWord("NOT") + ddlWord("NULL")).setResultsName("notNull")
ddlDefaultValue = ddlWord("DEFAULT").setResultsName("hasDefaultValue"); ddlDefaultValue = ddlWord("DEFAULT").setResultsName("hasDefaultValue")
ddlAutoValue = ddlWord("AUTO_INCREMENT").setResultsName("hasAutoValue"); ddlAutoValue = ddlWord("AUTO_INCREMENT").setResultsName("hasAutoValue")
ddlColumnComment = Group(ddlWord("COMMENT") + ddlString).setResultsName("comment") ddlColumnComment = Group(ddlWord("COMMENT") + ddlString).setResultsName("comment")
ddlConstraint = Or([ ddlConstraint = Or([
ddlWord("CONSTRAINT"), ddlWord("CONSTRAINT"),
@ -98,14 +137,6 @@ ddlConstraint = Or([
ddlWord("INDEX"), ddlWord("INDEX"),
ddlWord("UNIQUE"), ddlWord("UNIQUE"),
]) ])
ddlColumn = Group(Optional(ddlConstraint).setResultsName("isConstraint") + OneOrMore(MatchFirst([ddlNotNull, ddlAutoValue, ddlDefaultValue, ddlTerm, ddlNum, ddlColumnComment, ddlString, ddlArguments])))
createTable = Group(ddlWord("CREATE") + ddlWord("TABLE") + ddlName.setResultsName("tableName") + "(" + Group(delimitedList(ddlColumn)).setResultsName("columns") + ")").setResultsName("create")
ddl = ZeroOrMore(Suppress(SkipTo(createTable, False)) + createTable)
ddlComment = oneOf(["--", "#"]) + restOfLine
ddl.ignore(ddlComment)
# MAP SQL TYPES # MAP SQL TYPES
types = { types = {
@ -125,16 +156,33 @@ types = {
'boolean': 'boolean', 'boolean': 'boolean',
'double': 'floating_point', 'double': 'floating_point',
'float': 'floating_point', 'float': 'floating_point',
'date' : 'day_point', 'date': 'day_point',
'datetime' : 'time_point', 'datetime': 'time_point',
'timestamp' : 'time_point', 'timestamp': 'time_point',
'enum' : 'text', # MYSQL 'enum': 'text', # MYSQL
'set' : 'text', # MYSQL 'set': 'text', # MYSQL
} }
ddlColumn = Group(Optional(ddlConstraint).setResultsName("isConstraint") + OneOrMore(MatchFirst([ddlNotNull, ddlAutoValue, ddlDefaultValue, ddlTerm, ddlNum, ddlColumnComment, ddlString, ddlArguments])))
createTable = Group(ddlWord("CREATE") + ddlWord("TABLE") + ddlName.setResultsName("tableName") + "(" + Group(delimitedList(ddlColumn)).setResultsName("columns") + ")").setResultsName("create")
ddlComment = oneOf(["--", "#"]) + restOfLine
if failOnParse:
ddl = OneOrMore(Suppress(SkipTo(createTable, False)) + createTable)
ddl.ignore(ddlComment)
try:
tableCreations = ddl.parseFile(pathToDdl)
except ParseException as e:
print("parsing error, possible reason: can't parse default value for a field")
sys.exit()
else:
ddl = ZeroOrMore(Suppress(SkipTo(createTable, False)) + createTable)
ddl.ignore(ddlComment)
tableCreations = ddl.parseFile(pathToDdl)
# PROCESS DDL # PROCESS DDL
tableCreations = ddl.parseFile(pathToDdl)
header = open(pathToHeader, 'w') header = open(pathToHeader, 'w')
print('// generated by ' + ' '.join(sys.argv), file=header) print('// generated by ' + ' '.join(sys.argv), file=header)
@ -147,7 +195,7 @@ print('#include <' + INCLUDE + '/char_sequence.h>', file=header)
print('', file=header) print('', file=header)
print('namespace ' + namespace, file=header) print('namespace ' + namespace, file=header)
print('{', file=header) print('{', file=header)
DataTypeError = False; DataTypeError = False
for create in tableCreations: for create in tableCreations:
sqlTableName = create.tableName sqlTableName = create.tableName
tableClass = toClassName(sqlTableName) tableClass = toClassName(sqlTableName)
@ -184,22 +232,22 @@ for create in tableCreations:
print(' };', file=header) print(' };', file=header)
print(' };', file=header) print(' };', file=header)
try: try:
traitslist = [NAMESPACE + '::' + types[sqlColumnType]]; traitslist = [NAMESPACE + '::' + types[sqlColumnType]]
except KeyError as e: except KeyError as e:
print ('Error: datatype "' + sqlColumnType + '"" is not supported.') print ('Error: datatype "' + sqlColumnType + '"" is not supported.')
DataTypeError = True DataTypeError = True
requireInsert = True requireInsert = True
if column.hasAutoValue: if column.hasAutoValue:
traitslist.append(NAMESPACE + '::tag::must_not_insert'); traitslist.append(NAMESPACE + '::tag::must_not_insert')
traitslist.append(NAMESPACE + '::tag::must_not_update'); traitslist.append(NAMESPACE + '::tag::must_not_update')
requireInsert = False requireInsert = False
if not column.notNull: if not column.notNull:
traitslist.append(NAMESPACE + '::tag::can_be_null'); traitslist.append(NAMESPACE + '::tag::can_be_null')
requireInsert = False requireInsert = False
if column.hasDefaultValue: if column.hasDefaultValue:
requireInsert = False requireInsert = False
if requireInsert: if requireInsert:
traitslist.append(NAMESPACE + '::tag::require_insert'); traitslist.append(NAMESPACE + '::tag::require_insert')
print(' using _traits = ' + NAMESPACE + '::make_traits<' + ', '.join(traitslist) + '>;', file=header) print(' using _traits = ' + NAMESPACE + '::make_traits<' + ', '.join(traitslist) + '>;', file=header)
print(' };', file=header) print(' };', file=header)
print(' }', file=header) print(' }', file=header)