Beispiel #1
0
 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 = NoneType.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)
             c.expect(
                 e_sym.type() != ObjectType.instance(),
                 "arg_type_no_object",
                 arg=name,
                 type=e_sym.type(),
             )
             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.module.function_table.resolve(function_name) is None,
         "function_redeclaration",
         name=function_name,
     )
     output = tree.function_output
     if output is not None:
         return_type = self.resolver.types(output.types).type()
         tree.expect(return_type != ObjectType.instance(),
                     "return_type_no_object")
     self.module.function_table.insert(function_name, args, return_type)
     return scope, return_type
Beispiel #2
0
    def service_block(self, tree, scope):
        service_name = tree.service.path.child(0).value
        name = scope.resolve(service_name)
        if name is not None and name.type() != ObjectType.instance():
            tree.expect(tree.service.service_fragment.output is None,
                        'mutation_nested')
            tree.expect(tree.nested_block is None, 'mutation_nested')
            # resolve to perform checks
            self.resolver.service(tree.service)
            return

        tree.scope = Scope(parent=scope)
        self.update_scope(tree.scope)

        self.implicit_output(tree)

        output = tree.service.service_fragment.output
        if output is not None:
            output.expect(len(output.children) == 1, 'output_type_only_one',
                          target='service')

            name = output.children[0]
            resolved = tree.scope.resolve(name)
            output.expect(resolved is None, 'output_unique',
                          name=resolved.name() if resolved else None)
            sym = Symbol(name, ObjectType.instance())
            tree.scope.insert(sym)

        if tree.nested_block:
            tree.expect(not self.in_service_block, 'nested_service_block')
            self.in_service_block = True
            for c in tree.nested_block.children:
                self.visit_children(c, scope=tree.scope)
            self.in_service_block = False
Beispiel #3
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')

        command = tree.service_fragment.command
        tree.expect(command is not None, 'service_without_command')

        self.check_service_fragment_arguments(tree.service_fragment)

        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(self.resolve_service(tree))

        # variable exists -> event-based service
        if t.type() == ObjectType.instance():
            # In case of event-based service resolve using output_sym.
            return base_symbol(self.resolve_service(tree, t))

        var_name = tree.path.child(0).value
        tree.path.expect(0, 'service_name_not_var', var=var_name)
Beispiel #4
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())
Beispiel #5
0
    def service_block(self, tree, scope):
        service_name = tree.service.path.child(0).value
        name = scope.resolve(service_name)
        if name is not None and name.type() != ObjectType.instance():
            tree.expect(tree.service.service_fragment.output is None,
                        'mutation_nested')
            tree.expect(tree.nested_block is None, 'mutation_nested')
            # resolve to perform checks
            self.resolver.service(tree.service)
            return

        tree.scope = Scope(parent=scope)
        with self.create_scope(tree.scope):

            self.implicit_output(tree)

            output = tree.service.service_fragment.output
            if output is not None:
                self.check_output(tree, output, target='service')

            if tree.nested_block:
                tree.expect(not self.in_service_block, 'nested_service_block')
                self.in_service_block = True
                for c in tree.nested_block.children:
                    self.visit_children(c, scope=tree.scope)
                self.in_service_block = False
Beispiel #6
0
    def service_block(self, tree, scope):
        service_name = tree.service.path.child(0).value
        name = scope.resolve(service_name)
        if name is not None and name.type() != ObjectType.instance():
            tree.expect(tree.service.service_fragment.output is None,
                        'mutation_nested')
            tree.expect(tree.nested_block is None, 'mutation_nested')
            # resolve to perform checks
            self.resolver.service(tree.service)
            return

        tree.scope = Scope(parent=scope)

        self.implicit_output(tree)
        output = tree.service.service_fragment.output
        if output is not None:
            self.check_output(tree, output, target='service')

        args = tree.service.service_fragment.arguments
        if args is not None:
            # only look at value nodes (argname, (2) expr, argname, (4) expr)
            for arg in args.children[1::2]:
                self.resolver.expression(arg)

        if tree.nested_block:
            with self.create_scope(tree.scope):
                tree.expect(not self.in_service_block, 'nested_service_block')
                self.in_service_block = True
                for c in tree.nested_block.children:
                    self.visit_children(c, scope=tree.scope)
                self.in_service_block = False
        else:
            tree.service.service_fragment.expect(output is None,
                                                 'service_no_inline_output')
    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()
Beispiel #8
0
    def when_block(self, tree, scope):
        tree.scope = Scope(parent=scope)
        with self.create_scope(tree.scope):
            self.implicit_output(tree)

            output = tree.service.service_fragment.output
            output.expect(len(output.children) == 1,
                          'output_type_only_one',
                          target='when')

            name = output.children[0]
            resolved = tree.scope.resolve(name)
            output.expect(resolved is None,
                          'output_unique',
                          name=resolved.name() if resolved else None)
            sym = Symbol.from_path(name,
                                   ObjectType.instance(),
                                   storage_class=StorageClass.read)
            tree.scope.insert(sym)

            tree.expect(not self.in_when_block, 'nested_when_block')
            self.in_when_block = True
            for c in tree.nested_block.children:
                self.visit_children(c, scope=tree.scope)
            self.in_when_block = False
Beispiel #9
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()),
        )
Beispiel #10
0
 def as_expression(self, tree, expr):
     assert tree.child(1).data == 'as_operator'
     # check for compatibility
     t = self.visitor.types(tree.child(1).types)
     tree.expect(t.type() != ObjectType.instance(), 'object_no_as')
     tree.expect(explicit_cast(expr.type(), t.type()),
                 'type_operation_cast_incompatible',
                 left=expr.type(), right=t.type())
     return t
Beispiel #11
0
 def root(cls):
     """
     Creates a root scope.
     """
     scope = cls(parent=None)
     # insert global symbols
     app = Symbol(name='app', type_=ObjectType.instance())
     scope.insert(app)
     return scope
Beispiel #12
0
    def check_output(self, tree, output, target):
        output.expect(len(output.children) == 1, 'output_type_only_one',
                      target=target)

        name = output.children[0]
        resolved = tree.scope.resolve(name)
        output.expect(resolved is None, 'output_unique',
                      name=resolved.name() if resolved else None)
        sym = Symbol.from_path(name, ObjectType.instance(),
                               storage_class=StorageClass.rebindable())
        tree.scope.insert(sym)
Beispiel #13
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
Beispiel #14
0
# -*- coding: utf-8 -*-

from storyscript.compiler.semantics.types.Types import (
    MapType,
    ObjectType,
    StringType,
)

from .Symbols import StorageClass, Symbol, Symbols

app_props = {
    "secrets":
    Symbol(
        name="secrets",
        type_=ObjectType(
            obj=MapType(StringType.instance(), StringType.instance())),
        storage_class=StorageClass.read(),
        desc="Secret variables of this application",
    ),
    "hostname":
    Symbol(
        name="hostname",
        type_=StringType.instance(),
        storage_class=StorageClass.read(),
        desc="Server hostname of this application",
    ),
    "version":
    Symbol(
        name="version",
        type_=StringType.instance(),
        storage_class=StorageClass.read(),
Beispiel #15
0
# -*- coding: utf-8 -*-

from storyscript.compiler.semantics.types.Types import MapType, ObjectType, \
    StringType

from .Symbols import StorageClass, Symbol, Symbols


app_props = {
    'secrets': Symbol(name='secrets',
                      type_=ObjectType(obj=MapType(StringType.instance(),
                                       StringType.instance())),
                      storage_class=StorageClass.read()),
    'hostname': Symbol(name='hostname', type_=StringType.instance(),
                       storage_class=StorageClass.read()),
    'version': Symbol(name='version', type_=StringType.instance(),
                      storage_class=StorageClass.read()),
}
app_keyword = Symbol(name='app', type_=ObjectType(obj=app_props),
                     storage_class=StorageClass.read())


class Scope:
    """
    Manages an individual scope
    """

    def __init__(self, parent=None):
        self._parent = parent
        self._symbols = Symbols()
Beispiel #16
0
        (StringType.instance(), OutputEnum(data={})),
        (
            ListType(AnyType.instance()),
            OutputList(OutputAny.create(), data={}),
        ),
        (
            ListType(IntType.instance()),
            OutputList(OutputInt(data={}), data={}),
        ),
        (
            MapType(IntType.instance(), StringType.instance()),
            OutputMap(OutputInt(data={}), OutputString(data={}), data={}),
        ),
        (
            ObjectType({
                "i": IntType.instance(),
                "s": StringType.instance()
            }),
            OutputObject({
                "i": OutputInt(data={}),
                "s": OutputString(data={})
            },
                         data={}),
        ),
        (
            ObjectType({"p": IntType.instance()}),
            OutputObject({"p": OutputInt(data={})}, data={}),
        ),
        (ObjectType({}), OutputObject({}, data={})),
    ],
)
def test_types(hub, expected):