コード例 #1
0
    def resolve_mutation(self, t, tree):
        """
        Resolve a mutation on t with the MutationTable, instantiate it and
        check the caller arguments.
        """
        # a mutation on 'object' returns 'any' (for now)
        if t == ObjectType.instance():
            return AnyType.instance()

        name = tree.mutation_fragment.child(0).value
        args = self.build_arguments(tree.mutation_fragment, name,
                                    fn_type='Mutation')

        # a mutation on 'any' returns 'any'
        overloads = self.mutation_table.resolve(t, name)
        tree.expect(overloads is not None, 'mutation_invalid_name', name=name)
        ms = overloads.match(args.keys())
        if ms is None:
            # if there's only one overload, use this for a better error
            # message
            single = overloads.single()
            if single is None:
                self.show_available_mutation_overloads(tree, overloads)
            else:
                ms = [single]

        if len(ms) > 1:
            # a mutation on any might have matched multiple overloads
            return AnyType.instance()
        else:
            assert len(ms) == 1
            m = ms[0]
            m = m.instantiate(t)
            m.check_call(tree.mutation_fragment, args)
            return m.output()
コード例 #2
0
ファイル: Casting.py プロジェクト: ramlaxman/storyscript
def implicit_type_cast(tree, source_type, target_type, fn_type, fn_name,
                       arg_name, arg_node):
    """
    Checks whether an implicit cast from source_type to
    target type is allowed. If it is possible the implicit cast
    is performed on AST subtree.

    Args:
        tree: AST subtree which holds the args
            source_type: instance of one of the suitable type class
            for argument
        target_type: instance of one of the suitable type class
            for parameter
        fn_type: string specifying if the args are for a function,
            mutation or a service
        fn_name: string specifying name of the function,
            or a service
        arg_name: string specifying name of the argument
        arg_node: Tree node pointing to the actual argument node
            inside the tree in question
    """
    type_cast_result = target_type.can_be_assigned(source_type)
    tree.expect(type_cast_result or source_type == AnyType.instance(),
                'param_arg_type_mismatch',
                fn_type=fn_type,
                name=fn_name,
                arg_name=arg_name,
                target=target_type,
                source=source_type)
    if target_type != AnyType.instance() and type_cast_result != source_type:
        # We don't emit a type cast if:
        # * Target type is AnyType (AnyType can represent anything)
        # * Target and Source type are the same.
        arg_node.children[1] = SymbolExpressionVisitor.\
            type_cast_expression(arg_node.children[1], target_type)
コード例 #3
0
 def base_type(self, tree):
     """
     Resolves a base type expression to a type
     """
     assert tree.data == 'base_type'
     tok = tree.first_child()
     if tok.type == 'BOOLEAN_TYPE':
         return base_symbol(BooleanType.instance())
     elif tok.type == 'INT_TYPE':
         return base_symbol(IntType.instance())
     elif tok.type == 'FLOAT_TYPE':
         return base_symbol(FloatType.instance())
     elif tok.type == 'STRING_TYPE':
         return base_symbol(StringType.instance())
     elif tok.type == 'ANY_TYPE':
         return base_symbol(AnyType.instance())
     elif tok.type == 'OBJECT_TYPE':
         return base_symbol(ObjectType.instance())
     elif tok.type == 'FUNCTION_TYPE':
         return base_symbol(AnyType.instance())
     elif tok.type == 'TIME_TYPE':
         return base_symbol(TimeType.instance())
     else:
         assert tok.type == 'REGEXP_TYPE'
         return base_symbol(RegExpType.instance())
コード例 #4
0
ファイル: FunctionTable.py プロジェクト: wilzbach/storyscript
def test_function_insert():
    fn = FunctionTable()
    fn.insert("foo", {}, AnyType.instance())

    fn_b = FunctionTable()
    fn_b.insert("bar", {}, AnyType.instance())
    fn_b.insert_fn_table(fn)

    assert list(fn_b.functions.keys()) == ["bar", "foo"]
コード例 #5
0
    def map(self, tree):
        assert tree.data == 'map'
        keys = []
        values = []
        for i, item in enumerate(tree.children):
            assert isinstance(item, Tree)
            key_child = item.child(0)
            if key_child.data == 'string':
                new_key = self.string(key_child).type()
            elif key_child.data == 'number':
                new_key = self.number(key_child).type()
            elif key_child.data == 'boolean':
                new_key = self.boolean(key_child).type()
            else:
                assert key_child.data == 'path'
                new_key = self.path(key_child).type()
            keys.append(new_key)
            values.append(self.base_expression(item.child(1)).type())

            # check all keys - even if they don't match
            key_child.expect(new_key.hashable(),
                             'type_key_not_hashable',
                             key=new_key)

        key = None
        value = None
        for i, p in enumerate(zip(keys, values)):
            new_key, new_value = p
            if i >= 1:
                # type mismatch in the list
                if key != new_key:
                    key = AnyType.instance()
                    break
                if value != new_value:
                    value = AnyType.instance()
                    break
            else:
                key = new_key
                value = new_value

        if not self.with_as:
            tree.expect(key is not None, 'map_type_no_any')
            tree.expect(value is not None, 'map_type_no_any')
        if key is None:
            key = AnyType.instance()
        if value is None:
            value = AnyType.instance()
        return base_symbol(MapType(key, value))
コード例 #6
0
ファイル: TypeResolver.py プロジェクト: rashmi43/storyscript
 def function_statement(self, tree, scope):
     """
     Create a new scope _without_ a parent scope for this function.
     Prepopulate the scope with symbols from the function arguments.
     """
     scope = Scope.root()
     return_type = AnyType.instance()
     args = {}
     for c in tree.children[2:]:
         if isinstance(c, Tree) and c.data == 'typed_argument':
             name = c.child(0)
             e_sym = self.resolver.types(c.types)
             sym = Symbol.from_path(name, e_sym.type())
             scope.insert(sym)
             args[sym.name()] = sym
     # add function to the function table
     function_name = tree.child(1).value
     tree.expect(self.function_table.resolve(function_name) is None,
                 'function_redeclaration',
                 name=function_name)
     output = tree.function_output
     if output is not None:
         output = self.resolver.types(output.types).type()
     self.function_table.insert(function_name, args, output)
     if tree.function_output:
         return_type = self.resolver.types(
             tree.function_output.types).type()
     return scope, return_type
コード例 #7
0
    def get_type_instance(cls, ty):
        """
        Maps a type class from the hub SDK to its corresponding TypeClass
        in the compiler.
        """
        assert isinstance(ty, OutputBase), ty
        if isinstance(ty, OutputBoolean):
            return BooleanType.instance()
        if isinstance(ty, OutputInt):
            return IntType.instance()
        if isinstance(ty, OutputFloat):
            return FloatType.instance()
        if isinstance(ty, OutputString):
            return StringType.instance()
        if isinstance(ty, OutputAny):
            return AnyType.instance()
        if isinstance(ty, OutputObject):
            return ObjectType({
                k: cls.get_type_instance(v)
                for k, v in ty.properties().items()
            })
        if isinstance(ty, OutputList):
            return ListType(cls.get_type_instance(ty.elements()), )
        if isinstance(ty, OutputNone):
            return NoneType.instance()
        if isinstance(ty, OutputRegex):
            return RegExpType.instance()
        if isinstance(ty, OutputEnum):
            return StringType.instance()

        assert isinstance(ty, OutputMap), f"Unknown Hub Type: {ty!r}"
        return MapType(
            cls.get_type_instance(ty.keys()),
            cls.get_type_instance(ty.values()),
        )
コード例 #8
0
def test_mutation_pretty_b():
    args = {
        "a": Symbol("a", IntType.instance()),
        "b": Symbol("b", StringType.instance()),
    }
    fn = MutationFunction("foo", args, AnyType.instance(), desc="")
    assert fn.pretty() == "foo(a:`int` b:`string`)"
コード例 #9
0
def test_none_op():
    none = NoneType.instance()
    assert none.binary_op(none, Token('MINUS', '-')) is None
    assert none.binary_op(IntType.instance(), Token('MINUS', '-')) is None
    assert none.binary_op(IntType.instance(), Token('PLUS', '+')) is None
    assert none.binary_op(StringType.instance(), Token('PLUS', '+')) is None
    assert none.binary_op(AnyType.instance(), None) is None
コード例 #10
0
    def type_to_tree(tree, t):
        """
        Converts a type to its respective AST Tree representation.
        """
        if isinstance(t, ListType):
            inner = SymbolExpressionVisitor.type_to_tree(tree, t.inner)
            return Tree('list_type', [
                Tree('types', [inner])
            ])
        if isinstance(t, MapType):
            key = SymbolExpressionVisitor.type_to_tree(tree, t.key)
            value = SymbolExpressionVisitor.type_to_tree(tree, t.value)
            return Tree('map_type', [
                key,
                Tree('types', [value]),
            ])
        if t == BooleanType.instance():
            base_type = tree.create_token('BOOLEAN_TYPE', 'boolean')
        elif t == IntType.instance():
            base_type = tree.create_token('INTEGER_TYPE', 'int')
        elif t == FloatType.instance():
            base_type = tree.create_token('FLOAT_TYPE', 'float')
        elif t == StringType.instance():
            base_type = tree.create_token('STRING_TYPE', 'string')
        elif t == TimeType.instance():
            base_type = tree.create_token('TIME_TYPE', 'time')
        elif t == RegExpType.instance():
            base_type = tree.create_token('REGEXP_TYPE', 'regex')
        else:
            assert t == AnyType.instance()
            base_type = tree.create_token('ANY_TYPE', 'any')

        return Tree('base_type', [base_type])
コード例 #11
0
def test_mutation_pretty_b():
    args = {
        'a': Symbol('a', IntType.instance()),
        'b': Symbol('b', StringType.instance())
    }
    fn = MutationFunction('foo', args, AnyType.instance())
    assert fn.pretty() == 'foo a:`int` b:`string`'
コード例 #12
0
    def type_to_tree(tree, t):
        """
        Converts a type to its respective AST Tree representation.
        """
        if isinstance(t, ListType):
            inner = SymbolExpressionVisitor.type_to_tree(tree, t.inner)
            return Tree("list_type", [Tree("types", [inner])])
        if isinstance(t, MapType):
            key = SymbolExpressionVisitor.type_to_tree(tree, t.key)
            value = SymbolExpressionVisitor.type_to_tree(tree, t.value)
            return Tree("map_type", [key, Tree("types", [value]),])
        if t == BooleanType.instance():
            base_type = tree.create_token("BOOLEAN_TYPE", "boolean")
        elif t == IntType.instance():
            base_type = tree.create_token("INTEGER_TYPE", "int")
        elif t == FloatType.instance():
            base_type = tree.create_token("FLOAT_TYPE", "float")
        elif t == StringType.instance():
            base_type = tree.create_token("STRING_TYPE", "string")
        elif t == TimeType.instance():
            base_type = tree.create_token("TIME_TYPE", "time")
        elif t == RegExpType.instance():
            base_type = tree.create_token("REGEXP_TYPE", "regex")
        else:
            assert t == AnyType.instance()
            base_type = tree.create_token("ANY_TYPE", "any")

        return Tree("base_type", [base_type])
コード例 #13
0
def test_none_op():
    none = NoneType.instance()
    assert none.binary_op(none, Token("MINUS", "-")) is None
    assert none.binary_op(IntType.instance(), Token("MINUS", "-")) is None
    assert none.binary_op(IntType.instance(), Token("PLUS", "+")) is None
    assert none.binary_op(StringType.instance(), Token("PLUS", "+")) is None
    assert none.binary_op(AnyType.instance(), None) is None
コード例 #14
0
    def values(self, tree):
        """
        Parses a values subtree
        """
        subtree = tree.child(0)
        if hasattr(subtree, 'data'):
            if subtree.data == 'string':
                return self.string(subtree)
            elif subtree.data == 'boolean':
                return self.boolean(subtree)
            elif subtree.data == 'list':
                return self.list(subtree)
            elif subtree.data == 'number':
                return self.number(subtree)
            elif subtree.data == 'time':
                return self.time(subtree)
            elif subtree.data == 'map':
                return self.map(subtree)
            elif subtree.data == 'regular_expression':
                return self.regular_expression(subtree)
            else:
                assert subtree.data == 'void'
                return base_symbol(AnyType.instance())

        assert subtree.type == 'NAME'
        return self.path(tree)
コード例 #15
0
 def implicit_cast(self, tree, val, values):
     """
     Creates an AST with the cast.
     This boils down to
     - finding the right level to insert the new pow_expression with
       its respective as_operator
     - building a correct tree cascade in pow_expression to the old value
     """
     if val == AnyType.instance():
         return
     for i, v in enumerate(values):
         if i > 0:
             # ignore the arith_operator tree child
             i += 1
         # check whether a tree child needs casting
         if v != val:
             element = tree.children[i]
             casted_type = self.type_to_tree(element, val)
             element = Tree('expression', [
                 element,
                 Tree('as_operator', [
                     Tree('types', [
                         casted_type
                     ])
                 ])
             ])
             element.kind = 'as_expression'
             tree.children[i] = element
コード例 #16
0
 def list(self, tree):
     assert tree.data == 'list'
     value = None
     for i, c in enumerate(tree.children[1:]):
         if not isinstance(c, Tree):
             continue
         val = self.base_expression(c).type()
         if i >= 1:
             # type mismatch in the list
             if val != value:
                 value = AnyType.instance()
                 break
         else:
             value = val
     if value is None:
         value = AnyType.instance()
     return base_symbol(ListType(value))
コード例 #17
0
ファイル: MutationTable.py プロジェクト: shaz13/storyscript
 def _resolve_any(self, muts, name):
     """
     Searches for all potential type overloads on mutation.
     """
     mo = MutationOverloads(name, AnyType.instance())
     for overloads in muts.values():
         mo.add_overloads(overloads)
     return mo
コード例 #18
0
 def get_type_instance(var, obj=None):
     """
     Returns the correctly mapped type class instance of the given type.
     Params:
         var: A Symbol from which type could be retrieved.
         object: In case the Symbol is of type Object, the object that
             should be wrapped inside the ObjectType instance.
     """
     type_class = TypeMappings.type_class_mapping(var.type())
     if type_class == ObjectType:
         output_type = ObjectType(obj=obj)
     elif type_class == ListType:
         output_type = ListType(AnyType.instance())
     elif type_class == MapType:
         output_type = MapType(AnyType.instance(), AnyType.instance())
     else:
         assert type_class in (AnyType, BooleanType, FloatType, IntType,
                               StringType)
         output_type = type_class.instance()
     return output_type
コード例 #19
0
ファイル: Function.py プロジェクト: shaz13/storyscript
 def _check_arg_types(self, tree, args):
     """
     Checks that for each argument its type can be implicitly converted to
     the respective function argument.
     """
     for k, argument in zip(args.keys(), tree.children[1:]):
         target = self._args[k].type()
         t = args[k].type()
         type_cast_result = target.can_be_assigned(t)
         tree.expect(type_cast_result or t == AnyType.instance(),
                     'function_arg_type_mismatch',
                     fn_type=self.fn_type,
                     name=self._name,
                     arg_name=k,
                     target=target,
                     source=t)
         if target != AnyType.instance() and type_cast_result != t:
             # We don't emit a type cast if:
             # * Target type is AnyType (AnyType can represent anything)
             # * Target and Source type are the same.
             argument.children[1] = SymbolExpressionVisitor.\
                 type_cast_expression(argument.children[1], target)
コード例 #20
0
 def nary_args_implicit_cast(self, tree, target_type, source_types):
     """
     Cast nary_expression arguments implicitly.
     """
     if target_type == AnyType.instance():
         return
     for i, t in enumerate(source_types):
         if i > 0:
             # ignore the arith_operator tree child
             i += 1
         # check whether a tree child needs casting
         if t != target_type:
             tree.children[i] = self.type_cast_expression(
                 tree.children[i], target_type)
コード例 #21
0
 def service(self, tree):
     # unknown for now
     if tree.service_fragment.output is not None:
         tree.service_fragment.output.expect(
             0, 'service_no_inline_output')
     try:
         # check whether variable exists
         t = self.path(tree.path)
         service_to_mutation(tree)
         return self.resolve_mutation(t, tree)
     except CompilerError as e:
         # ignore only invalid variables (must be services)
         if e.error == 'var_not_defined':
             return AnyType.instance()
         raise e
コード例 #22
0
 def _check_arg_types(self, tree, args):
     """
     Checks that for each argument its type can be implicitly converted to
     the respective function argument.
     """
     for k in args.keys():
         target = self._args[k].type()
         t = args[k].type()
         tree.expect(target.can_be_assigned(t) or t == AnyType.instance(),
                     'function_arg_type_mismatch',
                     fn_type=self.fn_type,
                     name=self._name,
                     arg_name=k,
                     target=target,
                     source=t)
コード例 #23
0
    def service(self, tree):
        # unknown for now
        if tree.service_fragment.output is not None:
            tree.service_fragment.output.expect(0, 'service_no_inline_output')
        t = None
        try:
            # check whether variable exists
            t = self.path(tree.path)
        except CompilerError:
            # ignore invalid variables (not existent or invalid)
            # -> must be a service
            return base_symbol(AnyType.instance())

        # variable exists -> mutation
        service_to_mutation(tree)
        return self.resolve_mutation(t, tree)
コード例 #24
0
ファイル: MutationTable.py プロジェクト: shaz13/storyscript
    def resolve(self, type_, name):
        """
        Returns the mutation `name` or `None`.
        """
        muts = self.mutations.get(name, None)
        if muts is None:
            return None

        if type_ == AnyType.instance():
            return self._resolve_any(muts, name)

        t = self.type_key(type(type_))
        overloads = muts.get(t, None)
        if overloads is None:
            return None

        mo = MutationOverloads(name, type_)
        mo.add_overloads(overloads)
        return mo
コード例 #25
0
 def implicit_cast(self, tree, val, values):
     """
     Creates an AST with the cast.
     This boils down to
     - finding the right level to insert the new pow_expression with
       its respective as_operator
     - building a correct tree cascade in pow_expression to the old value
     """
     if val == AnyType.instance():
         return
     insert_tree_name = tree.data
     for i, v in enumerate(values):
         if i > 0:
             # ignore the arith_operator tree child
             i += 1
         # check whether a tree child needs casting
         if v != val:
             element = tree.children[i]
             casted_type = self.type_to_tree(element, val)
             if i != 0:
                 element = Tree(insert_tree_name, [element])
             if element.data == 'mul_expression':
                 element = Tree('arith_expression', [element])
             if element.data == 'arith_expression':
                 element = Tree('cmp_expression', [element])
             tree.children[i] = Tree('unary_expression', [
                 Tree('pow_expression', [
                     Tree('primary_expression', [
                         Tree('or_expression', [
                             Tree('and_expression', [element]),
                         ]),
                     ]),
                     Tree('as_operator', [Tree('types', [casted_type])])
                 ])
             ])
             for e in ['mul_expression', 'arith_expression']:
                 if e == insert_tree_name:
                     break
                 else:
                     tree.children[i] = Tree(e, [tree.children[i]])
             if i == 0:
                 tree.children[0] = Tree(insert_tree_name,
                                         [tree.children[0]])
コード例 #26
0
def parse_type(type_):
    """
    Parses a type string and returns its parsed type which can be a:
        - BaseType (e.g. `IntType`)
        - TypeSymbol (e.g. `TypeSymbol(A)`)
        - GenericType (e.g. `ListGenericType(TypeSymbol(A))`)
    """
    assert len(type_) > 0
    type_ = type_.strip()
    if type_ == "boolean":
        return BooleanType.instance()
    if type_ == "int":
        return IntType.instance()
    if type_ == "float":
        return FloatType.instance()
    if type_ == "string":
        return StringType.instance()
    if type_ == "time":
        return TimeType.instance()
    if type_ == "none":
        return NoneType.instance()
    if type_ == "regexp":
        return RegExpType.instance()
    if type_ == "any":
        return AnyType.instance()

    if "[" in type_:
        types = []
        for t in parse_type_inner(type_).split(","):
            t2 = parse_type(t)
            types.append(t2)
        if type_.startswith("List["):
            return ListGenericType(types)
        else:
            assert type_.startswith("Map[")
            return MapGenericType(types)

    assert "]" not in type_
    return TypeSymbol(type_)
コード例 #27
0
        nonlocal c
        c = c + 1
        return c

    single_fn = singleton(test_fn)
    assert single_fn() == 1
    assert single_fn() == 1
    assert c == 1


@mark.parametrize('type_,expected', [
    (BooleanType.instance(), 'boolean'),
    (IntType.instance(), 'int'),
    (FloatType.instance(), 'float'),
    (NoneType.instance(), 'none'),
    (AnyType.instance(), 'any'),
    (RegExpType.instance(), 'regexp'),
    (ListType(AnyType.instance()), 'List[any]'),
    (MapType(IntType.instance(), StringType.instance()), 'Map[int,string]'),
])
def test_boolean_str(type_, expected):
    assert str(type_) == expected


def test_none_eq():
    assert NoneType.instance() == NoneType.instance()
    assert NoneType.instance() != IntType.instance()
    assert NoneType.instance() != AnyType.instance()


def test_none_assign():
コード例 #28
0
def test_none_eq():
    assert NoneType.instance() == NoneType.instance()
    assert NoneType.instance() != IntType.instance()
    assert NoneType.instance() != AnyType.instance()
コード例 #29
0
def test_none_assign():
    assert not NoneType.instance().can_be_assigned(IntType.instance())
    assert not NoneType.instance().can_be_assigned(AnyType.instance())
コード例 #30
0
def test_none_explicit_from():
    assert NoneType.instance().explicit_from(IntType.instance()) is None
    assert NoneType.instance().explicit_from(AnyType.instance()) is None