", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
3243 | try:
3244 | if len(symbols)==len("".join(symbols)):
3245 | return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
3246 | else:
3247 | return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
3248 | except:
3249 | warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
3250 | SyntaxWarning, stacklevel=2)
3251 |
3252 |
3253 | # last resort, just use MatchFirst
3254 | return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
3255 |
3256 | def dictOf( key, value ):
3257 | """Helper to easily and clearly define a dictionary by specifying the respective patterns
3258 | for the key and value. Takes care of defining the Dict, ZeroOrMore, and Group tokens
3259 | in the proper order. The key pattern can include delimiting markers or punctuation,
3260 | as long as they are suppressed, thereby leaving the significant key text. The value
3261 | pattern can include named results, so that the Dict results can include named token
3262 | fields.
3263 | """
3264 | return Dict( ZeroOrMore( Group ( key + value ) ) )
3265 |
3266 | def originalTextFor(expr, asString=True):
3267 | """Helper to return the original, untokenized text for a given expression. Useful to
3268 | restore the parsed fields of an HTML start tag into the raw tag text itself, or to
3269 | revert separate tokens with intervening whitespace back to the original matching
3270 | input text. Simpler to use than the parse action keepOriginalText, and does not
3271 | require the inspect module to chase up the call stack. By default, returns a
3272 | string containing the original parsed text.
3273 |
3274 | If the optional asString argument is passed as False, then the return value is a
3275 | ParseResults containing any results names that were originally matched, and a
3276 | single token containing the original matched text from the input string. So if
3277 | the expression passed to originalTextFor contains expressions with defined
3278 | results names, you must set asString to False if you want to preserve those
3279 | results name values."""
3280 | locMarker = Empty().setParseAction(lambda s,loc,t: loc)
3281 | matchExpr = locMarker("_original_start") + expr + locMarker("_original_end")
3282 | if asString:
3283 | extractText = lambda s,l,t: s[t._original_start:t._original_end]
3284 | else:
3285 | def extractText(s,l,t):
3286 | del t[:]
3287 | t.insert(0, s[t._original_start:t._original_end])
3288 | del t["_original_start"]
3289 | del t["_original_end"]
3290 | matchExpr.setParseAction(extractText)
3291 | return matchExpr
3292 |
3293 | # convenience constants for positional expressions
3294 | empty = Empty().setName("empty")
3295 | lineStart = LineStart().setName("lineStart")
3296 | lineEnd = LineEnd().setName("lineEnd")
3297 | stringStart = StringStart().setName("stringStart")
3298 | stringEnd = StringEnd().setName("stringEnd")
3299 |
3300 | _escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
3301 | _printables_less_backslash = "".join([ c for c in printables if c not in r"\]" ])
3302 | _escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16)))
3303 | _escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8)))
3304 | _singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
3305 | _charRange = Group(_singleChar + Suppress("-") + _singleChar)
3306 | _reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
3307 |
3308 | _expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
3309 |
3310 | def srange(s):
3311 | r"""Helper to easily define string ranges for use in Word construction. Borrows
3312 | syntax from regexp '[]' string range definitions::
3313 | srange("[0-9]") -> "0123456789"
3314 | srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz"
3315 | srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
3316 | The input string must be enclosed in []'s, and the returned string is the expanded
3317 | character set joined into a single string.
3318 | The values enclosed in the []'s may be::
3319 | a single character
3320 | an escaped character with a leading backslash (such as \- or \])
3321 | an escaped hex character with a leading '\0x' (\0x21, which is a '!' character)
3322 | an escaped octal character with a leading '\0' (\041, which is a '!' character)
3323 | a range of any of the above, separated by a dash ('a-z', etc.)
3324 | any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
3325 | """
3326 | try:
3327 | return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
3328 | except:
3329 | return ""
3330 |
3331 | def matchOnlyAtCol(n):
3332 | """Helper method for defining parse actions that require matching at a specific
3333 | column in the input text.
3334 | """
3335 | def verifyCol(strg,locn,toks):
3336 | if col(locn,strg) != n:
3337 | raise ParseException(strg,locn,"matched token not at column %d" % n)
3338 | return verifyCol
3339 |
3340 | def replaceWith(replStr):
3341 | """Helper method for common parse actions that simply return a literal value. Especially
3342 | useful when used with transformString().
3343 | """
3344 | def _replFunc(*args):
3345 | return [replStr]
3346 | return _replFunc
3347 |
3348 | def removeQuotes(s,l,t):
3349 | """Helper parse action for removing quotation marks from parsed quoted strings.
3350 | To use, add this parse action to quoted string using::
3351 | quotedString.setParseAction( removeQuotes )
3352 | """
3353 | return t[0][1:-1]
3354 |
3355 | def upcaseTokens(s,l,t):
3356 | """Helper parse action to convert tokens to upper case."""
3357 | return [ tt.upper() for tt in map(_ustr,t) ]
3358 |
3359 | def downcaseTokens(s,l,t):
3360 | """Helper parse action to convert tokens to lower case."""
3361 | return [ tt.lower() for tt in map(_ustr,t) ]
3362 |
3363 | def keepOriginalText(s,startLoc,t):
3364 | """Helper parse action to preserve original parsed text,
3365 | overriding any nested parse actions."""
3366 | try:
3367 | endloc = getTokensEndLoc()
3368 | except ParseException:
3369 | raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action")
3370 | del t[:]
3371 | t += ParseResults(s[startLoc:endloc])
3372 | return t
3373 |
3374 | def getTokensEndLoc():
3375 | """Method to be called from within a parse action to determine the end
3376 | location of the parsed tokens."""
3377 | import inspect
3378 | fstack = inspect.stack()
3379 | try:
3380 | # search up the stack (through intervening argument normalizers) for correct calling routine
3381 | for f in fstack[2:]:
3382 | if f[3] == "_parseNoCache":
3383 | endloc = f[0].f_locals["loc"]
3384 | return endloc
3385 | else:
3386 | raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action")
3387 | finally:
3388 | del fstack
3389 |
3390 | def _makeTags(tagStr, xml):
3391 | """Internal helper to construct opening and closing tag expressions, given a tag name"""
3392 | if isinstance(tagStr,basestring):
3393 | resname = tagStr
3394 | tagStr = Keyword(tagStr, caseless=not xml)
3395 | else:
3396 | resname = tagStr.name
3397 |
3398 | tagAttrName = Word(alphas,alphanums+"_-:")
3399 | if (xml):
3400 | tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
3401 | openTag = Suppress("<") + tagStr + \
3402 | Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
3403 | Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
3404 | else:
3405 | printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
3406 | tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
3407 | openTag = Suppress("<") + tagStr + \
3408 | Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
3409 | Optional( Suppress("=") + tagAttrValue ) ))) + \
3410 | Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
3411 | closeTag = Combine(_L("") + tagStr + ">")
3412 |
3413 | openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
3414 | closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("%s>" % tagStr)
3415 |
3416 | return openTag, closeTag
3417 |
3418 | def makeHTMLTags(tagStr):
3419 | """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
3420 | return _makeTags( tagStr, False )
3421 |
3422 | def makeXMLTags(tagStr):
3423 | """Helper to construct opening and closing tag expressions for XML, given a tag name"""
3424 | return _makeTags( tagStr, True )
3425 |
3426 | def withAttribute(*args,**attrDict):
3427 | """Helper to create a validating parse action to be used with start tags created
3428 | with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag
3429 | with a required attribute value, to avoid false matches on common tags such as
3430 | or .
3431 |
3432 | Call withAttribute with a series of attribute names and values. Specify the list
3433 | of filter attributes names and values as:
3434 | - keyword arguments, as in (class="Customer",align="right"), or
3435 | - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
3436 | For attribute names with a namespace prefix, you must use the second form. Attribute
3437 | names are matched insensitive to upper/lower case.
3438 |
3439 | To verify that the attribute exists, but without specifying a value, pass
3440 | withAttribute.ANY_VALUE as the value.
3441 | """
3442 | if args:
3443 | attrs = args[:]
3444 | else:
3445 | attrs = attrDict.items()
3446 | attrs = [(k,v) for k,v in attrs]
3447 | def pa(s,l,tokens):
3448 | for attrName,attrValue in attrs:
3449 | if attrName not in tokens:
3450 | raise ParseException(s,l,"no matching attribute " + attrName)
3451 | if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
3452 | raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
3453 | (attrName, tokens[attrName], attrValue))
3454 | return pa
3455 | withAttribute.ANY_VALUE = object()
3456 |
3457 | opAssoc = _Constants()
3458 | opAssoc.LEFT = object()
3459 | opAssoc.RIGHT = object()
3460 |
3461 | def operatorPrecedence( baseExpr, opList ):
3462 | """Helper method for constructing grammars of expressions made up of
3463 | operators working in a precedence hierarchy. Operators may be unary or
3464 | binary, left- or right-associative. Parse actions can also be attached
3465 | to operator expressions.
3466 |
3467 | Parameters:
3468 | - baseExpr - expression representing the most basic element for the nested
3469 | - opList - list of tuples, one for each operator precedence level in the
3470 | expression grammar; each tuple is of the form
3471 | (opExpr, numTerms, rightLeftAssoc, parseAction), where:
3472 | - opExpr is the pyparsing expression for the operator;
3473 | may also be a string, which will be converted to a Literal;
3474 | if numTerms is 3, opExpr is a tuple of two expressions, for the
3475 | two operators separating the 3 terms
3476 | - numTerms is the number of terms for this operator (must
3477 | be 1, 2, or 3)
3478 | - rightLeftAssoc is the indicator whether the operator is
3479 | right or left associative, using the pyparsing-defined
3480 | constants opAssoc.RIGHT and opAssoc.LEFT.
3481 | - parseAction is the parse action to be associated with
3482 | expressions matching this operator expression (the
3483 | parse action tuple member may be omitted)
3484 | """
3485 | ret = Forward()
3486 | lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
3487 | for i,operDef in enumerate(opList):
3488 | opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
3489 | if arity == 3:
3490 | if opExpr is None or len(opExpr) != 2:
3491 | raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
3492 | opExpr1, opExpr2 = opExpr
3493 | thisExpr = Forward()#.setName("expr%d" % i)
3494 | if rightLeftAssoc == opAssoc.LEFT:
3495 | if arity == 1:
3496 | matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
3497 | elif arity == 2:
3498 | if opExpr is not None:
3499 | matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
3500 | else:
3501 | matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
3502 | elif arity == 3:
3503 | matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
3504 | Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
3505 | else:
3506 | raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
3507 | elif rightLeftAssoc == opAssoc.RIGHT:
3508 | if arity == 1:
3509 | # try to avoid LR with this extra test
3510 | if not isinstance(opExpr, Optional):
3511 | opExpr = Optional(opExpr)
3512 | matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
3513 | elif arity == 2:
3514 | if opExpr is not None:
3515 | matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
3516 | else:
3517 | matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
3518 | elif arity == 3:
3519 | matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
3520 | Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
3521 | else:
3522 | raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
3523 | else:
3524 | raise ValueError("operator must indicate right or left associativity")
3525 | if pa:
3526 | matchExpr.setParseAction( pa )
3527 | thisExpr << ( matchExpr | lastExpr )
3528 | lastExpr = thisExpr
3529 | ret << lastExpr
3530 | return ret
3531 |
3532 | dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes")
3533 | sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes")
3534 | quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes")
3535 | unicodeString = Combine(_L('u') + quotedString.copy())
3536 |
3537 | def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString):
3538 | """Helper method for defining nested lists enclosed in opening and closing
3539 | delimiters ("(" and ")" are the default).
3540 |
3541 | Parameters:
3542 | - opener - opening character for a nested list (default="("); can also be a pyparsing expression
3543 | - closer - closing character for a nested list (default=")"); can also be a pyparsing expression
3544 | - content - expression for items within the nested lists (default=None)
3545 | - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
3546 |
3547 | If an expression is not provided for the content argument, the nested
3548 | expression will capture all whitespace-delimited content between delimiters
3549 | as a list of separate values.
3550 |
3551 | Use the ignoreExpr argument to define expressions that may contain
3552 | opening or closing characters that should not be treated as opening
3553 | or closing characters for nesting, such as quotedString or a comment
3554 | expression. Specify multiple expressions using an Or or MatchFirst.
3555 | The default is quotedString, but if no expressions are to be ignored,
3556 | then pass None for this argument.
3557 | """
3558 | if opener == closer:
3559 | raise ValueError("opening and closing strings cannot be the same")
3560 | if content is None:
3561 | if isinstance(opener,basestring) and isinstance(closer,basestring):
3562 | if len(opener) == 1 and len(closer)==1:
3563 | if ignoreExpr is not None:
3564 | content = (Combine(OneOrMore(~ignoreExpr +
3565 | CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3566 | ).setParseAction(lambda t:t[0].strip()))
3567 | else:
3568 | content = (empty+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
3569 | ).setParseAction(lambda t:t[0].strip()))
3570 | else:
3571 | if ignoreExpr is not None:
3572 | content = (Combine(OneOrMore(~ignoreExpr +
3573 | ~Literal(opener) + ~Literal(closer) +
3574 | CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3575 | ).setParseAction(lambda t:t[0].strip()))
3576 | else:
3577 | content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
3578 | CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3579 | ).setParseAction(lambda t:t[0].strip()))
3580 | else:
3581 | raise ValueError("opening and closing arguments must be strings if no content expression is given")
3582 | ret = Forward()
3583 | if ignoreExpr is not None:
3584 | ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
3585 | else:
3586 | ret << Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) )
3587 | return ret
3588 |
3589 | def indentedBlock(blockStatementExpr, indentStack, indent=True):
3590 | """Helper method for defining space-delimited indentation blocks, such as
3591 | those used to define block statements in Python source code.
3592 |
3593 | Parameters:
3594 | - blockStatementExpr - expression defining syntax of statement that
3595 | is repeated within the indented block
3596 | - indentStack - list created by caller to manage indentation stack
3597 | (multiple statementWithIndentedBlock expressions within a single grammar
3598 | should share a common indentStack)
3599 | - indent - boolean indicating whether block must be indented beyond the
3600 | the current level; set to False for block of left-most statements
3601 | (default=True)
3602 |
3603 | A valid block must contain at least one blockStatement.
3604 | """
3605 | def checkPeerIndent(s,l,t):
3606 | if l >= len(s): return
3607 | curCol = col(l,s)
3608 | if curCol != indentStack[-1]:
3609 | if curCol > indentStack[-1]:
3610 | raise ParseFatalException(s,l,"illegal nesting")
3611 | raise ParseException(s,l,"not a peer entry")
3612 |
3613 | def checkSubIndent(s,l,t):
3614 | curCol = col(l,s)
3615 | if curCol > indentStack[-1]:
3616 | indentStack.append( curCol )
3617 | else:
3618 | raise ParseException(s,l,"not a subentry")
3619 |
3620 | def checkUnindent(s,l,t):
3621 | if l >= len(s): return
3622 | curCol = col(l,s)
3623 | if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
3624 | raise ParseException(s,l,"not an unindent")
3625 | indentStack.pop()
3626 |
3627 | NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
3628 | INDENT = Empty() + Empty().setParseAction(checkSubIndent)
3629 | PEER = Empty().setParseAction(checkPeerIndent)
3630 | UNDENT = Empty().setParseAction(checkUnindent)
3631 | if indent:
3632 | smExpr = Group( Optional(NL) +
3633 | FollowedBy(blockStatementExpr) +
3634 | INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
3635 | else:
3636 | smExpr = Group( Optional(NL) +
3637 | (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
3638 | blockStatementExpr.ignore(_bslash + LineEnd())
3639 | return smExpr
3640 |
3641 | alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
3642 | punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
3643 |
3644 | anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:"))
3645 | commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline()
3646 | _htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "'))
3647 | replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
3648 |
3649 | # it's easy to get these comment structures wrong - they're very common, so may as well make them available
3650 | cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
3651 |
3652 | htmlComment = Regex(r"")
3653 | restOfLine = Regex(r".*").leaveWhitespace()
3654 | dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
3655 | cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?" + str(tokenlist))
3673 | print ("tokens = " + str(tokens))
3674 | print ("tokens.columns = " + str(tokens.columns))
3675 | print ("tokens.tables = " + str(tokens.tables))
3676 | print (tokens.asXML("SQL",True))
3677 | except ParseBaseException,err:
3678 | print (teststring + "->")
3679 | print (err.line)
3680 | print (" "*(err.column-1) + "^")
3681 | print (err)
3682 | print()
3683 |
3684 | selectToken = CaselessLiteral( "select" )
3685 | fromToken = CaselessLiteral( "from" )
3686 |
3687 | ident = Word( alphas, alphanums + "_$" )
3688 | columnName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
3689 | columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
3690 | tableName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
3691 | tableNameList = Group( delimitedList( tableName ) )#.setName("tables")
3692 | simpleSQL = ( selectToken + \
3693 | ( '*' | columnNameList ).setResultsName( "columns" ) + \
3694 | fromToken + \
3695 | tableNameList.setResultsName( "tables" ) )
3696 |
3697 | test( "SELECT * from XYZZY, ABC" )
3698 | test( "select * from SYS.XYZZY" )
3699 | test( "Select A from Sys.dual" )
3700 | test( "Select AA,BB,CC from Sys.dual" )
3701 | test( "Select A, B, C from Sys.dual" )
3702 | test( "Select A, B, C from Sys.dual" )
3703 | test( "Xelect A, B, C from Sys.dual" )
3704 | test( "Select A, B, C frox Sys.dual" )
3705 | test( "Select" )
3706 | test( "Select ^^^ frox Sys.dual" )
3707 | test( "Select A, B, C from Sys.dual, Table2 " )
3708 |
--------------------------------------------------------------------------------
/release.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """Release information"""
4 |
5 |
6 | version = "0.0.2"
7 | author = "Roland|Chima"
8 | email = "Rolandazim@gmail.com"
9 | copyright = "Copyright 2019~ Roland|Chima and contributors"
10 | license = "MIT "
11 | url = "https://github.com/ORC-1/ibolang"
12 | download_url="https://github.com/ORC-1/ibolang"
13 | description="programming language in Igbo"
14 | long_description = """
15 | .. contents::
16 | :depth: 2
17 |
18 | Introduction
19 | --------------
20 |
21 | Igbo is an indigenous language popularly spoken in Nigeria, Ibolang is a full
22 | extension of the Igbo language in Python.
23 | With Ibolang, you can write and run python like programs in Igbo
24 |
25 | Ibolang acts like python 3 and plays like python 3, it maintains all the python syntax
26 | and methods.
27 | user could use it to learn programming in their native language.
28 |
29 | Example
30 | ----------
31 | ibolang is highly user friendly, the following is a simple "HelloWorld" program
32 |
33 | deputa("Uwa Aloo")
34 |
35 |
36 | running this, will diplay
37 |
38 | Uwa Aloo
39 |
40 | to console, which translated to English is "Hello World"
41 |
42 | you can code more complex code by installing ibolang to your PC:
43 |
44 |
45 | To run programs is as simple as:
46 |
47 | $ ibolang filename.ibl
48 |
49 | from your preferred shell or command line
50 |
51 | you can go through the dictionary on:
52 | * https://github.com/ORC-1/ibolang/blob/master/dictionary.txt
53 |
54 | to get an exhaustive list of all currently available commands and there English translation
55 |
56 | Install
57 | ----------
58 |
59 | If you'd like to play Ibolang with full features included, you should install Ibolang.
60 |
61 | You could use pip or easy_install command to install Ibolang:
62 |
63 | $ pip install Ibolang
64 |
65 | or
66 |
67 | $ easy_install -U Ibolang
68 |
69 | to use easy_install command, you should install distribute module for python 3 first:
70 |
71 | http://pypi.python.org/pypi/distribute/
72 |
73 | And check your system path params if it contains python3.x/bin path.
74 |
75 | ex: edit .bashrc to include "/Library/Frameworks/Python.framework/Versions/3.x/bin" in your PATH parameter.
76 |
77 | For sytem running multiple version of python, you are better of using a virtual enviroment
78 | with Ibolang:
79 |
80 | $ conda create -n Ibolang python==3.XX
81 |
82 | or using Virtualenv
83 |
84 | $ virtualenv ibolang python==3.XX
85 |
86 | Lastly you can clone the repo using this url https://github.com/ORC-1/ibolang.git : navigate to the folder path and run python setup.py
87 | Copy the source files into your script folder, you should highly consider using
88 | a virtual enviroment if you are using this option and the previous options are better
89 | off
90 |
91 |
92 |
93 | Change Log
94 | -------------
95 |
96 | You could view the ChangeLog to see what's new in these version.
97 |
98 | * https://github.com/ORC-1/ibolang/blob/master/CHANGELOG.txt
99 |
100 |
101 | """
102 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | try:
2 | from setuptools import setup, find_packages
3 | except ImportError:
4 | from ez_setup import use_setuptools
5 | use_setuptools()
6 | from setuptools import setup, find_packages
7 |
8 | from pkg_resources import DistributionNotFound
9 |
10 | import sys
11 | import os
12 | import glob
13 | import release
14 | #execfile('release.py')
15 |
16 |
17 | # setup params
18 | required_modules = ["setuptools"]
19 | #if mac, install readline
20 | #if(sys.platform=="darwin"):
21 | # required_modules.append("readline >= 2.6.4")
22 |
23 | # nose is used for test
24 | extra_modules = {}
25 |
26 | setup(
27 | name="ibolang",
28 | version=release.version,
29 | author=release.author,
30 | author_email=release.email,
31 | download_url=release.download_url,
32 | py_modules=['core','ibolang','ig_tran','igbolang',],
33 | license=license,
34 | keywords = "traditional, simplified, Igbo, Afrocode, language, tokenize",
35 | description=release.description,
36 | long_description=release.long_description,
37 | url=release.url,
38 | zip_safe=False,
39 | install_requires = required_modules,
40 | extras_require = extra_modules,
41 | include_package_data = True,
42 | packages=find_packages(exclude=["ez_setup", 'examples', 'apidocs', "tests", "ibl"]),
43 | entry_points = """
44 | [console_scripts]
45 | ibolang = ibolang:commandline
46 |
47 | """,
48 | classifiers = [
49 | 'Development Status :: 4 - Beta',
50 | 'Environment :: Console',
51 | 'Intended Audience :: Education',
52 | 'Intended Audience :: Developers',
53 | 'Intended Audience :: System Administrators',
54 | 'License :: OSI Approved :: MIT License',
55 | 'Operating System :: OS Independent',
56 | 'Programming Language :: Python',
57 | 'Topic :: Software Development :: Libraries :: Python Modules',
58 | 'Topic :: Software Development :: Code Generators'],
59 | #test_suite = 'nose.collector',
60 | )
61 |
62 |
--------------------------------------------------------------------------------
|