Skip to content

Commit

Permalink
Defaulting None for optional fields
Browse files Browse the repository at this point in the history
  • Loading branch information
earlbread committed Aug 14, 2017
1 parent fc16709 commit fd477bc
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 25 deletions.
90 changes: 70 additions & 20 deletions src/Nirum/Targets/Python.hs
Original file line number Diff line number Diff line change
Expand Up @@ -320,16 +320,20 @@ toIndentedCodes f traversable concatenator =
T.intercalate concatenator $ map f traversable

compileParameters :: (ParameterName -> ParameterType -> Code)
-> [(T.Text, Code)]
-> [(T.Text, Code, Bool)]
-> Code
compileParameters gen nameTypePairs =
toIndentedCodes (uncurry gen) nameTypePairs ", "
compileParameters gen nameTypeTriples =
toIndentedCodes
(\(n, t, o) -> gen n t `T.append` if o then "=None" else "")
nameTypeTriples ", "

compileFieldInitializers :: DS.DeclarationSet Field -> CodeGen Code
compileFieldInitializers fields = do
compileFieldInitializers :: DS.DeclarationSet Field -> Int -> CodeGen Code
compileFieldInitializers fields depth = do
initializers <- forM (toList fields) compileFieldInitializer
return $ T.intercalate "\n " initializers
return $ T.intercalate indentSpaces initializers
where
indentSpaces :: T.Text
indentSpaces = "\n" `T.append` T.replicate depth " "
compileFieldInitializer :: Field -> CodeGen Code
compileFieldInitializer (Field fieldName' fieldType' _) =
case fieldType' of
Expand Down Expand Up @@ -432,11 +436,16 @@ compileUnionTag :: Source -> Name -> Tag -> CodeGen Code
compileUnionTag source parentname d@(Tag typename' fields _) = do
typeExprCodes <- mapM (compileTypeExpression source)
[typeExpr | (Field _ typeExpr _) <- toList fields]
let className = toClassName' typename'
let optionFlags = [ case typeExpr of
OptionModifier _ -> True
_ -> False
| (Field _ typeExpr _) <- toList fields
]
className = toClassName' typename'
tagNames = map (toAttributeName' . fieldName) (toList fields)
nameNTypes = zip tagNames typeExprCodes
nameTypeTriples = zip3 tagNames typeExprCodes optionFlags
slotTypes = toIndentedCodes
(\ (n, t) -> [qq|('{n}', {t})|]) nameNTypes ",\n "
(\ (n, t, _) -> [qq|('{n}', {t})|]) nameTypeTriples ",\n "
slots = if length tagNames == 1
then [qq|'{head tagNames}'|] `T.snoc` ','
else toIndentedCodes (\ n -> [qq|'{n}'|]) tagNames ",\n "
Expand All @@ -458,7 +467,27 @@ compileUnionTag source parentname d@(Tag typename' fields _) = do
typeRepr <- typeReprCompiler
arg <- parameterCompiler
ret <- returnCompiler
initializers <- compileFieldInitializers fields
pyVer <- getPythonVersion
initializers <- compileFieldInitializers fields $ case pyVer of
Python3 -> 2
Python2 -> 3
let initParams = compileParameters arg nameTypeTriples
inits = case pyVer of
Python2 -> [qq|
def __init__(self, **kwargs):
def __init__($initParams):
$initializers
pass
__init__(**kwargs)
validate_record_type(self)
|]
Python3 -> [qq|
def __init__(self{ if null nameTypeTriples
then T.empty
else ", *, " `T.append` initParams }) -> None:
$initializers
validate_union_type(self)
|]
return [qq|
class $className($parentClass):
{compileDocstringWithFields " " d fields}
Expand All @@ -474,9 +503,7 @@ class $className($parentClass):
def __nirum_tag_types__():
return [$slotTypes]

def __init__(self, {compileParameters arg nameNTypes}){ ret "None" }:
$initializers
validate_union_type(self)
{ inits :: T.Text }

def __repr__(self){ ret "str" }:
return '\{0\}(\{1\})'.format(
Expand Down Expand Up @@ -669,12 +696,17 @@ compileTypeDeclaration src d@TypeDeclaration { typename = typename'
fieldList = toList fields
typeExprCodes <- mapM (compileTypeExpression src)
[typeExpr | (Field _ typeExpr _) <- fieldList]
let fieldNames = map toAttributeName' [ name'
let optionFlags = [ case typeExpr of
OptionModifier _ -> True
_ -> False
| (Field _ typeExpr _) <- fieldList
]
fieldNames = map toAttributeName' [ name'
| (Field name' _ _) <- fieldList
]
nameTypePairs = zip fieldNames typeExprCodes
nameTypeTriples = zip3 fieldNames typeExprCodes optionFlags
slotTypes = toIndentedCodes
(\ (n, t) -> [qq|'{n}': {t}|]) nameTypePairs ",\n "
(\ (n, t, _) -> [qq|'{n}': {t}|]) nameTypeTriples",\n "
slots = toIndentedCodes (\ n -> [qq|'{n}'|]) fieldNames ",\n "
nameMaps = toIndentedCodes
toNamePair
Expand All @@ -693,7 +725,27 @@ compileTypeDeclaration src d@TypeDeclaration { typename = typename'
arg <- parameterCompiler
ret <- returnCompiler
typeRepr <- typeReprCompiler
initializers <- compileFieldInitializers fields
pyVer <- getPythonVersion
initializers <- compileFieldInitializers fields $ case pyVer of
Python3 -> 2
Python2 -> 3
let initParams = compileParameters arg nameTypeTriples
inits = case pyVer of
Python2 -> [qq|
def __init__(self, **kwargs):
def __init__($initParams):
$initializers
pass
__init__(**kwargs)
validate_record_type(self)
|]
Python3 -> [qq|
def __init__(self{ if null nameTypeTriples
then T.empty
else ", *, " `T.append` initParams }) -> None:
$initializers
validate_record_type(self)
|]
let clsType = arg "cls" "type"
return [qq|
class $className(object):
Expand All @@ -710,9 +762,7 @@ class $className(object):
def __nirum_field_types__():
return \{$slotTypes\}

def __init__(self, {compileParameters arg nameTypePairs}){ret "None"}:
$initializers
validate_record_type(self)
{inits :: T.Text}

def __repr__(self){ret "bool"}:
return '\{0\}(\{1\})'.format(
Expand Down
13 changes: 10 additions & 3 deletions test/nirum_fixture/fixture/foo.nrm
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,17 @@ service ping-service (
);

record person (
irum first-name,
irum last-name,
irum first-name,
irum last-name,
);

record people (
{person} people
{person} people
);

record product (
text name,
int64? price,
bool sale,
uri? url,
);
10 changes: 8 additions & 2 deletions test/python/primitive_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from fixture.foo import (CultureAgnosticName, EastAsianName,
EvaChar, FloatUnbox, Gender, ImportedTypeUnbox, Irum,
Line, MixedName, NullService,
Point1, Point2, Point3d, Pop, PingService, Rnb,
Run, Stop, Way, WesternName)
Point1, Point2, Point3d, Pop, PingService, Product,
Rnb, Run, Stop, Way, WesternName)
from fixture.foo.bar import PathUnbox, IntUnbox, Point
from fixture.qux import Path, Name

Expand Down Expand Up @@ -249,3 +249,9 @@ def test_service():
PingService().ping(nonce=u'nonce')
with raises(TypeError):
PingService().ping(wrongkwd=u'a')


def test_optional_initializer_test():
product = Product(name='coffee', sale=False)
assert product.price is None
assert product.url is None

0 comments on commit fd477bc

Please sign in to comment.