Produce valid Cocopacks
As of this change -- just a few minor fixes -- CocoPy produces real Cocopacks! $ cocopy index.py | coco pack info -a - // Basic example of an AWS web server accessible over HTTP. package "webserver" { dependencies [ aws: "*" ] module "index.py" { imports [ "coconut/aws" ] exports [ ".init" -> ".init" ".main" -> ".main" "_Name" -> "__name__" "main" -> "main" ] method ".init": () method ".main": () property "_Name": dynamic method "main": (): dynamic } } The contents of various tokens aren't quite right yet (they must be fully qualified), meaning the pack still won't verify and load. But we're getting close...
This commit is contained in:
parent
f1c1684d6f
commit
b2f2c4adb1
4 changed files with 34 additions and 28 deletions
|
@ -216,7 +216,7 @@ class Function(Definition):
|
|||
def __init__(self, kind, name, parameters=None, return_type=None, body=None, loc=None):
|
||||
assert isinstance(kind, basestring)
|
||||
assert isinstance(name, Identifier)
|
||||
assert (parameters is none or
|
||||
assert (parameters is None or
|
||||
(isinstance(parameters, list) and all(isinstance(node, LocalVariable) for node in parameters)))
|
||||
assert return_type is None or isinstance(return_type, TypeToken)
|
||||
assert body is None or isinstance(body, Block)
|
||||
|
@ -229,7 +229,7 @@ class ModuleMethod(Function, ModuleMember):
|
|||
"""A module method is just a function defined at the module scope."""
|
||||
def __init__(self, name, parameters=None, return_type=None, body=None, loc=None):
|
||||
assert isinstance(name, Identifier)
|
||||
assert (parameters is none or
|
||||
assert (parameters is None or
|
||||
(isinstance(parameters, list) and all(isinstance(node, LocalVariable) for node in parameters)))
|
||||
assert return_type is None or isinstance(return_type, TypeToken)
|
||||
assert body is None or isinstance(body, Block)
|
||||
|
@ -240,7 +240,7 @@ class ClassMethod(Function, ClassMember):
|
|||
def __init__(self, name, parameters=None, return_type=None, body=None,
|
||||
access=None, static=None, sealed=None, abstract=None, loc=None):
|
||||
assert isinstance(name, Identifier)
|
||||
assert (parameters is none or
|
||||
assert (parameters is None or
|
||||
(isinstance(parameters, list) and all(isinstance(node, LocalVariable) for node in parameters)))
|
||||
assert return_type is None or isinstance(return_type, TypeToken)
|
||||
assert body is None or isinstance(body, Block)
|
||||
|
@ -438,21 +438,21 @@ class BoolLiteral(Literal):
|
|||
"""A `bool`-typed literal (`true` or `false`)."""
|
||||
def __init__(self, value, loc=None):
|
||||
assert isinstance(value, bool)
|
||||
super(BoolLiteral, self).__init__("BoolLiteral", loc)
|
||||
super(BoolLiteral, self).__init__("BoolLiteral", loc=loc)
|
||||
self.value = value
|
||||
|
||||
class NumberLiteral(Literal):
|
||||
"""A `number`-typed literal (floating point IEEE 754)."""
|
||||
def __init__(self, value, loc=None):
|
||||
assert isinstance(value, int) or isinstance(value, long) or isinstance(value, float)
|
||||
super(NumberLiteral, self).__init__("NumberLiteral", loc)
|
||||
super(NumberLiteral, self).__init__("NumberLiteral", loc=loc)
|
||||
self.value = value
|
||||
|
||||
class StringLiteral(Literal):
|
||||
"""A `string`-typed literal."""
|
||||
def __init__(self, value, loc=None):
|
||||
assert isinstance(value, basestring)
|
||||
super(StringLiteral, self).__init__("StringLiteral", loc)
|
||||
super(StringLiteral, self).__init__("StringLiteral", loc=loc)
|
||||
self.value = value
|
||||
|
||||
class ArrayLiteral(Literal):
|
||||
|
|
|
@ -104,9 +104,11 @@ class Transformer:
|
|||
var_modname = "__name__"
|
||||
members[var_modname] = ast.ModuleProperty(
|
||||
self.ident(var_modname), self.type_token(tokens.type_dynamic))
|
||||
modname_init_expr = ast.BinaryOperatorExpression(
|
||||
ast.LoadLocationExpression(var_modname), ast.binop_assign, ast.StringLiteral("__main__"))
|
||||
initstmts.append(ast.ExpressionStatement(modname_init_expr))
|
||||
modname_init = ast.BinaryOperatorExpression(
|
||||
ast.LoadLocationExpression(ast.Token(var_modname)),
|
||||
ast.binop_assign,
|
||||
ast.StringLiteral("__main__"))
|
||||
initstmts.append(ast.ExpressionStatement(modname_init))
|
||||
|
||||
# Enumerate the top-level statements and put them in the right place. This transformation is subtle because
|
||||
# loose code (arbitrary statements) aren't supported in CocoIL. Instead, we must elevate top-level definitions
|
||||
|
@ -125,7 +127,7 @@ class Transformer:
|
|||
else:
|
||||
# For all other statement nodes, simply accumulate them for the module initializer.
|
||||
initstmt = self.transform_stmt(stmt)
|
||||
assert initstmt.is_statement()
|
||||
assert isinstance(initstmt, ast.Statement)
|
||||
initstmts.append(initstmt)
|
||||
|
||||
# If any top-level statements spilled over, add them to the initializer.
|
||||
|
@ -148,7 +150,8 @@ class Transformer:
|
|||
# By default, Python exports everything, so add all declarations to the list.
|
||||
exports = dict()
|
||||
for name in members:
|
||||
exports[name] = name # TODO: this needs to be a full qualified token.
|
||||
# TODO: this needs to be a full qualified token.
|
||||
exports[name] = ast.Export(self.ident(name), ast.Token(name))
|
||||
|
||||
return ast.Module(self.ident(name), list(imports), exports, members)
|
||||
|
||||
|
@ -206,7 +209,7 @@ class Transformer:
|
|||
assert False, "Unrecognized statement node: {}".format(type(node).__name__)
|
||||
|
||||
# Check that the return is good and then return it.
|
||||
assert isinstance(stmt, ast.Node) and stmt.is_statement(), \
|
||||
assert isinstance(stmt, ast.Statement), \
|
||||
"Expected PyAST node {} to produce a statement; got {}".format(
|
||||
type(node).__name__, type(stmt).__name__)
|
||||
return stmt
|
||||
|
@ -218,19 +221,21 @@ class Transformer:
|
|||
stmts.append(self.transform_stmt(node))
|
||||
|
||||
# Propagate location information based on the inner statements.
|
||||
loc = None
|
||||
if len(stmts) > 0:
|
||||
file = None
|
||||
start = None
|
||||
end = None
|
||||
if stmts[0].loc:
|
||||
file = stmts[0].loc.file
|
||||
start = stmts[0].loc.start
|
||||
if stmts[len(stmts)-1].loc:
|
||||
if not start:
|
||||
file = stmts[len(stmts)-1].file
|
||||
start = stmts[len(stmts)-1].loc.start
|
||||
end = stmts[len(stmts)-1].loc.end
|
||||
loc = ast.Location(file, start, end)
|
||||
firstloc = stmts[0].loc
|
||||
lastloc = stmts[len(stmts)-1].loc
|
||||
file, start, end = None, None, None
|
||||
if firstloc:
|
||||
file = firstloc.file
|
||||
start = firstloc.start
|
||||
if lastloc:
|
||||
if not firstloc:
|
||||
file = lastloc.file
|
||||
start = loastloc.start
|
||||
end = lastloc.end
|
||||
if file and start:
|
||||
loc = ast.Location(file, start, end)
|
||||
|
||||
return ast.Block(stmts, loc)
|
||||
|
||||
|
@ -411,7 +416,7 @@ class Transformer:
|
|||
assert False, "Unrecognized statement node: {}".format(type(node).__name__)
|
||||
|
||||
# Check that the return is good and then return it.
|
||||
assert isinstance(expr, ast.Node) and expr.is_expression(), \
|
||||
assert isinstance(expr, ast.Expression), \
|
||||
"Expected PyAST node {} to produce an expression; got {}".format(
|
||||
type(node).__name__, type(expr).__name__)
|
||||
return expr
|
||||
|
@ -419,7 +424,7 @@ class Transformer:
|
|||
def transform_Attribute(self, node):
|
||||
assert not node.ctx
|
||||
obj = self.transform_expr(node.value)
|
||||
return ast.LoadDynamicExpression(node.attr, obj, loc=self.loc_from(node))
|
||||
return ast.LoadDynamicExpression(ast.StringLiteral(node.attr), obj, loc=self.loc_from(node))
|
||||
|
||||
def transform_BinOp(self, node):
|
||||
self.not_yet_implemented(node) # left, op, right
|
||||
|
@ -487,7 +492,7 @@ class Transformer:
|
|||
|
||||
def transform_Name(self, node):
|
||||
assert not node.ctx
|
||||
return ast.LoadLocationExpression(node.id, loc=self.loc_from(node))
|
||||
return ast.LoadLocationExpression(ast.Token(node.id), loc=self.loc_from(node))
|
||||
|
||||
def transform_NameID(self, node):
|
||||
assert not node.ctx
|
||||
|
|
|
@ -51,7 +51,7 @@ def to_serializable_dict(m, opts=None):
|
|||
|
||||
def to_serializable_value(v, opts=None):
|
||||
"""This routine converts a singular value into its JSON-serializable equivalent."""
|
||||
if (isinstance(v, str) or isinstance(v, unicode) or
|
||||
if (isinstance(v, basestring) or
|
||||
isinstance(v, int) or isinstance(v, long) or isinstance(v, float) or
|
||||
isinstance(v, bool) or v is None):
|
||||
# Simple serializable values can be stored without any translation.
|
||||
|
|
|
@ -34,4 +34,5 @@ typemod_func_sep = ")" # the separator between parameters and return of
|
|||
acc_public = "public"
|
||||
acc_private = "private"
|
||||
acc_protected = "protected"
|
||||
accs = set([ acc_public, acc_private, acc_protected ])
|
||||
|
||||
|
|
Loading…
Reference in a new issue