예제 #1
0
def parse(tokens, pos=0):
    assert (isinstance(tokens, list))
    assert (all(map(lambda x: isinstance(x, Tokenizer.TkAtom), tokens)))
    assert (isinstance(pos, int))
    assert (pos < len(tokens))

    full_geometry = tokens[pos].geometry
    values = []

    while True:
        if isinstance(tokens[pos], Tokenizer.CallBeg):
            init_geometry = tokens[pos].geometry
            (pos, action) = parse(tokens, pos + 1)
            order_args = []
            named_args = []

            while not isinstance(tokens[pos], Tokenizer.CallEnd):
                (pos, new_arg) = parse(tokens, pos)

                if isinstance(tokens[pos], Tokenizer.CommonEqual):
                    (pos, value) = parse(tokens, pos + 1)
                    named_args.append(CallNamedArg(new_arg, value))
                else:
                    order_args.append(new_arg)

            geometry = init_geometry.expandTo(tokens[pos].geometry)
            values.append(Call(action, order_args, named_args, geometry))
        elif isinstance(tokens[pos], Tokenizer.CallEnd):
            raise Exception('Invalid ")" character!')
        elif isinstance(tokens[pos], Tokenizer.Boolean):
            values.append(Boolean(tokens[pos].text, tokens[pos].geometry))
        elif isinstance(tokens[pos], Tokenizer.Number):
            values.append(Number(tokens[pos].text, tokens[pos].geometry))
        elif isinstance(tokens[pos], Tokenizer.Symbol):
            values.append(Symbol(tokens[pos].text, tokens[pos].geometry))
        elif isinstance(tokens[pos], Tokenizer.String):
            values.append(String(tokens[pos].text, tokens[pos].geometry))
        elif isinstance(tokens[pos], Tokenizer.StringEval):
            values.append(StringEval(tokens[pos].text, tokens[pos].geometry))
        elif isinstance(tokens[pos], Tokenizer.FuncBeg):

            def testSyntax(token):
                if isinstance(token,Tokenizer.CommonEqual) or \
                   isinstance(token,Tokenizer.FuncName) or \
                   isinstance(token,Tokenizer.FuncStar) or \
                   isinstance(token,Tokenizer.FuncPlus):
                    raise Exception('Invalid syntax for function call!')

            FUNC_ORDER = 0
            FUNC_ORDER_DEFS = 1
            FUNC_ORDER_VAR = 2
            FUNC_NAMED = 3
            FUNC_NAMED_DEFS = 4
            FUNC_NAMED_VAR = 5
            FUNC_STOP = 6

            init_geometry = tokens[pos].geometry
            pos = pos + 1
            cpos = 0
            order = []
            order_defs = []
            order_var = None
            named = []
            named_defs = []
            named_var = None
            body = None
            contents = []
            state = FUNC_ORDER

            while not isinstance(tokens[pos], Tokenizer.FuncEnd):
                if isinstance(tokens[pos], Tokenizer.CommonEqual):
                    contents.append(tokens[pos])
                    pos = pos + 1
                elif isinstance(tokens[pos], Tokenizer.FuncName):
                    contents.append(tokens[pos])
                    pos = pos + 1
                elif isinstance(tokens[pos], Tokenizer.FuncStar):
                    contents.append(tokens[pos])
                    pos = pos + 1
                elif isinstance(tokens[pos], Tokenizer.FuncPlus):
                    contents.append(tokens[pos])
                    pos = pos + 1
                else:
                    (pos, new_item) = parse(tokens, pos)
                    contents.append(new_item)

            if len(contents) < 1:
                raise Exception('Invalid empty function!')

            testSyntax(contents[-1])

            body = contents[-1]
            del contents[-1]

            while cpos < len(contents) and state != FUNC_STOP:
                if state == FUNC_ORDER:
                    if cpos + 3 < len(contents) and \
                       isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \
                       isinstance(contents[cpos+3],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        testSyntax(contents[cpos + 2])
                        state = FUNC_NAMED_DEFS
                        named_defs.append(
                            FuncArg(contents[cpos], contents[cpos + 2]))
                        cpos = cpos + 4
                    elif cpos + 2 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.CommonEqual):
                        testSyntax(contents[cpos])
                        testSyntax(contents[cpos + 2])
                        state = FUNC_ORDER_DEFS
                        order_defs.append(
                            FuncArg(contents[cpos], contents[cpos + 2]))
                        cpos = cpos + 3
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED
                        named.append(FuncArg(contents[cpos], None))
                        cpos = cpos + 2
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncStar):
                        testSyntax(contents[cpos])
                        state = FUNC_ORDER_VAR
                        order_var = contents[cpos]
                        cpos = cpos + 2
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncPlus):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED_VAR
                        named_var = contents[cpos]
                        cpos = cpos + 2
                    elif cpos < len(contents):
                        testSyntax(contents[cpos])
                        state = FUNC_ORDER
                        order.append(FuncArg(contents[cpos], None))
                        cpos = cpos + 1
                    else:
                        state = FUNC_STOP
                elif state == FUNC_ORDER_DEFS:
                    if cpos + 3 < len(contents) and \
                       isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \
                       isinstance(contents[cpos+3],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        testSyntax(contents[cpos + 2])
                        state = FUNC_NAMED_DEFS
                        named_defs.append(
                            FuncArg(contents[cpos], contents[cpos + 2]))
                        cpos = cpos + 4
                    elif cpos + 2 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.CommonEqual):
                        testSyntax(contents[cpos])
                        testSyntax(contents[cpos + 2])
                        state = FUNC_ORDER_DEFS
                        order_defs.append(
                            FuncArg(contents[cpos], contents[cpos + 2]))
                        cpos = cpos + 3
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED
                        named.append(FuncArg(contents[cpos], None))
                        cpos = cpos + 2
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncStar):
                        testSyntax(contents[cpos])
                        state = FUNC_ORDER_VAR
                        order_var = contents[cpos]
                        cpos = cpos + 2
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncPlus):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED_VAR
                        named_var = contents[cpos]
                        cpos = cpos + 2
                    elif cpos < len(contents):
                        raise Exception(
                            'Cannot use order arguments after default ones!')
                    else:
                        state = FUNC_STOP
                elif state == FUNC_ORDER_VAR:
                    if cpos + 3 < len(contents) and \
                       isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \
                       isinstance(contents[cpos+3],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        testSyntax(contents[cpos + 2])
                        state = FUNC_NAMED_DEFS
                        named_defs.append(
                            FuncArg(contents[cpos], contents[cpos + 2]))
                        cpos = cpos + 4
                    elif cpos + 2 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.CommonEqual):
                        raise Exception(
                            'Cannot use order arguments (with default) after variable one!'
                        )
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED
                        named.append(FuncArg(contents[cpos], None))
                        cpos = cpos + 2
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncStar):
                        raise Exception(
                            'Only one variable order argument allowed!')
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncPlus):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED_VAR
                        named_var = contents[cpos]
                        cpos = cpos + 2
                    elif cpos < len(contents):
                        raise Exception(
                            'Cannot use order arguments after variable one!')
                    else:
                        state = FUNC_STOP
                elif state == FUNC_NAMED:
                    if cpos + 3 < len(contents) and \
                       isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \
                       isinstance(contents[cpos+3],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        testSyntax(contents[cpos + 2])
                        state = FUNC_NAMED_DEFS
                        named_defs.append(
                            FuncArg(contents[cpos], contents[cpos + 2]))
                        cpos = cpos + 4
                    elif cpos + 2 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.CommonEqual):
                        raise Exception(
                            'Cannot use order arguments (with default) after named ones!'
                        )
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED
                        named.append(FuncArg(contents[cpos], None))
                        cpos = cpos + 2
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncStar):
                        raise Exception(
                            'Cannot use variable order argument after named ones!'
                        )
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncPlus):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED_VAR
                        named_var = contents[cpos]
                        cpos = cpos + 2
                    elif cpos < len(contents):
                        raise Exception(
                            'Cannot use order arguments after named ones!')
                    else:
                        state = FUNC_STOP
                elif state == FUNC_NAMED_DEFS:
                    if cpos + 3 < len(contents) and \
                       isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \
                       isinstance(contents[cpos+3],Tokenizer.FuncName):
                        testSyntax(contents[cpos])
                        testSyntax(contents[cpos + 2])
                        state = FUNC_NAMED_DEFS
                        named_defs.append(
                            FuncArg(contents[cpos], contents[cpos + 2]))
                        cpos = cpos + 4
                    elif cpos + 2 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.CommonEqual):
                        raise Exception(
                            'Cannot use order arguments (with default) after named ones!'
                        )
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncName):
                        raise Exception(
                            'Cannot use named arguments after default named arguments!'
                        )
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncStar):
                        raise Exception(
                            'Cannot use variable order argument after named ones!'
                        )
                    elif cpos + 1 < len(contents) and \
                         isinstance(contents[cpos+1],Tokenizer.FuncPlus):
                        testSyntax(contents[cpos])
                        state = FUNC_NAMED_VAR
                        named_var = contents[cpos]
                        cpos = cpos + 2
                    elif cpos < len(contents):
                        raise Exception(
                            'Cannot use order arguments after default ones!')
                    else:
                        state = FUNC_STOP
                elif state == FUNC_NAMED_VAR:
                    if cpos < len(contents):
                        raise Exception(
                            'Invalid argument after named variable one!')
                    else:
                        state = FUNC_STOP
                else:
                    raise Exception('Critical Error: Invalid Func FSM Path!')

            if cpos != len(contents):
                raise Exception('Invalid syntax for function call!')

            geometry = init_geometry.expandTo(tokens[pos].geometry)
            values.append(
                Func(order, order_defs, order_var, named, named_defs,
                     named_var, body, geometry))
        elif isinstance(tokens[pos], Tokenizer.FuncEnd):
            raise Exception('Invalid "]" character!')
        elif isinstance(tokens[pos], Tokenizer.FuncName):
            raise Exception('Invalid "!" character!')
        elif isinstance(tokens[pos], Tokenizer.FuncStar):
            raise Exception('Invalid "*" character!')
        elif isinstance(tokens[pos], Tokenizer.FuncPlus):
            raise Exception('Invalid "+" character!')
        elif isinstance(tokens[pos], Tokenizer.BlockBeg):
            init_geometry = tokens[pos].geometry
            (pos, action) = parse(tokens, pos + 1)
            order_args = []
            named_args = []

            while not isinstance(tokens[pos], Tokenizer.BlockEnd):
                (pos, new_arg) = parse(tokens, pos)

                if isinstance(tokens[pos], Tokenizer.CommonEqual):
                    (pos, value) = parse(tokens, pos + 1)
                    named_args.append(CallNamedArg(new_arg, value))
                else:
                    order_args.append(new_arg)

            geometry = init_geometry.expandTo(tokens[pos].geometry)
            body = Call(action, order_args, named_args, geometry)
            values.append(Func([], [], None, [], [], None, body, geometry))
        elif isinstance(tokens[pos], Tokenizer.BlockEnd):
            raise Exception('Invalid "}" character!')
        elif isinstance(tokens[pos], Tokenizer.DictBeg):
            init_geometry = tokens[pos].geometry
            pos = pos + 1
            keyvalues = []

            while not isinstance(tokens[pos], Tokenizer.DictEnd):
                (pos, key) = parse(tokens, pos)
                (pos, value) = parse(tokens, pos)

                keyvalues.append((key, value))

            geometry = init_geometry.expandTo(tokens[pos].geometry)
            values.append(Dict(keyvalues, geometry))
        elif isinstance(tokens[pos], Tokenizer.DictEnd):
            raise Exception('Invalid ">" character!')
        elif isinstance(tokens[pos], Tokenizer.DictBar):
            raise Exception('Invalid "|" character!')
        elif isinstance(tokens[pos], Tokenizer.CommonEqual):
            raise Exception('Invalid "=" character!')
        else:
            raise Exception('Invalid syntax!')

        pos = pos + 1

        if pos < len(tokens) and isinstance(tokens[pos], Tokenizer.DictBar):
            pos = pos + 1
        else:
            break

    if len(values) == 1:
        return (pos, values[0])
    else:
        no_geom = Stream.Geometry(0, Stream.RelPos(0, 0), 0,
                                  Stream.RelPos(0, 0))
        build_kvs = [(Symbol('Length',
                             no_geom), Number(str(len(values)), no_geom))]

        for i in range(0, len(values)):
            build_kvs.append((Number(str(i), no_geom), values[i]))

        geometry = full_geometry.expandTo(tokens[pos - 1].geometry)
        return (pos, Dict(build_kvs, geometry))