コード例 #1
0
ファイル: test_natspec.py プロジェクト: siraben/vyper
def test_params():
    code = """
@public
def foo(bar: int128, baz: uint256, potato: bytes32):
    '''
    @param bar a number
    @param baz also a number
    @dev we didn't document potato, but that's ok
    '''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    _, devdoc = parse_natspec(vyper_ast, global_ctx)

    assert devdoc == {
        "methods": {
            "foo(int128,uint256,bytes32)": {
                "details": "we didn't document potato, but that's ok",
                "params": {
                    "bar": "a number",
                    "baz": "also a number"
                },
            }
        }
    }
コード例 #2
0
ファイル: test_natspec.py プロジェクト: siraben/vyper
def test_returns():
    code = """
@public
def foo(bar: int128, baz: uint256) -> (int128, uint256):
    '''
    @return value of bar
    @return value of baz
    '''
    return bar, baz
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    _, devdoc = parse_natspec(vyper_ast, global_ctx)

    assert devdoc == {
        "methods": {
            "foo(int128,uint256)": {
                "returns": {
                    "_0": "value of bar",
                    "_1": "value of baz"
                }
            }
        }
    }
コード例 #3
0
ファイル: test_natspec.py プロジェクト: siraben/vyper
def test_documentation_example_output():
    vyper_ast = parse_to_ast(test_code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    userdoc, devdoc = parse_natspec(vyper_ast, global_ctx)

    assert userdoc == expected_userdoc
    assert devdoc == expected_devdoc
コード例 #4
0
ファイル: utils.py プロジェクト: MaxIsWell42/MakeCards
def generate_inline_function(code, variables, memory_allocator):
    ast_code = parse_to_ast(code)
    new_context = Context(
        vars=variables, global_ctx=GlobalContext(), memory_allocator=memory_allocator, origcode=code
    )
    generated_lll = parse_body(ast_code.body, new_context)
    return new_context, generated_lll
コード例 #5
0
ファイル: parser.py プロジェクト: kushagrasharma/vyper
def parse_tree_to_lll(code, origcode, runtime_only=False):
    global_ctx = GlobalContext.get_global_context(code)
    _names_def = [_def.name for _def in global_ctx._defs]
    # Checks for duplicate function names
    if len(set(_names_def)) < len(_names_def):
        raise FunctionDeclarationException("Duplicate function name: %s" % [name for name in _names_def if _names_def.count(name) > 1][0])
    _names_events = [_event.target.id for _event in global_ctx._events]
    # Checks for duplicate event names
    if len(set(_names_events)) < len(_names_events):
        raise EventDeclarationException("Duplicate event name: %s" % [name for name in _names_events if _names_events.count(name) > 1][0])
    # Initialization function
    initfunc = [_def for _def in global_ctx._defs if is_initializer(_def)]
    # Default function
    defaultfunc = [_def for _def in global_ctx._defs if is_default_func(_def)]
    # Regular functions
    otherfuncs = [_def for _def in global_ctx._defs if not is_initializer(_def) and not is_default_func(_def)]
    sigs = {}
    external_contracts = {}
    # Create the main statement
    o = ['seq']
    if global_ctx._events:
        sigs = parse_events(sigs, global_ctx)
    if global_ctx._contracts:
        external_contracts = parse_external_contracts(external_contracts, global_ctx._contracts, global_ctx._structs, global_ctx._constants)
    # If there is an init func...
    if initfunc:
        o.append(['seq', initializer_lll])
        o.append(parse_func(initfunc[0], {**{'self': sigs}, **external_contracts}, origcode, global_ctx))
    # If there are regular functions...
    if otherfuncs or defaultfunc:
        o = parse_other_functions(
            o, otherfuncs, sigs, external_contracts, origcode, global_ctx, defaultfunc, runtime_only
        )
    return LLLnode.from_list(o, typ=None)
コード例 #6
0
ファイル: test_natspec.py プロジェクト: siraben/vyper
def test_no_tags_implies_notice():
    code = """
'''
Because there is no tag, this docstring is handled as a notice.
'''
@public
def foo():
    '''
    This one too!
    '''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    userdoc, devdoc = parse_natspec(vyper_ast, global_ctx)

    assert userdoc == {
        "methods": {
            "foo()": {
                "notice": "This one too!"
            }
        },
        "notice":
        "Because there is no tag, this docstring is handled as a notice.",
    }
    assert not devdoc
コード例 #7
0
def mk_full_signature(code, sig_formatter=None, interface_codes=None):

    if sig_formatter is None:
        # Use default JSON style output.
        sig_formatter = _default_sig_formatter

    o = []
    global_ctx = GlobalContext.get_global_context(
        code, interface_codes=interface_codes)

    # Produce event signatues.
    for code in global_ctx._events:
        sig = EventSignature.from_declaration(code, global_ctx)
        o.append(sig_formatter(sig, global_ctx._custom_units_descriptions))

    # Produce function signatures.
    for code in global_ctx._defs:
        sig = FunctionSignature.from_definition(
            code,
            sigs=global_ctx._contracts,
            custom_units=global_ctx._custom_units,
            custom_structs=global_ctx._structs,
            constants=global_ctx._constants)
        if not sig.private:
            default_sigs = generate_default_arg_sigs(code,
                                                     global_ctx._contracts,
                                                     global_ctx)
            for s in default_sigs:
                o.append(
                    sig_formatter(s, global_ctx._custom_units_descriptions))
    return o
コード例 #8
0
ファイル: test_natspec.py プロジェクト: siraben/vyper
def test_whitespace():
    code = """
'''
        @dev

  Whitespace    gets  cleaned
    up,
            people can use


         awful formatting.


We don't mind!

@author Mr No-linter
                '''
"""
    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    _, devdoc = parse_natspec(vyper_ast, global_ctx)

    assert devdoc == {
        "author":
        "Mr No-linter",
        "details":
        "Whitespace gets cleaned up, people can use awful formatting. We don't mind!",
    }
コード例 #9
0
def parse_natspec(
    vyper_ast: vy_ast.Module,
    interface_codes: Union[InterfaceDict, InterfaceImports, None] = None,
) -> Tuple[dict, dict]:
    """
    Parses NatSpec documentation from a contract.

    Arguments
    ---------
    vyper_ast : Module
        Module-level vyper ast node.
    interface_codes: Dict, optional
        Dict containing relevant data for any import statements related to
        this contract.

    Returns
    -------
    dict
        NatSpec user documentation
    dict
        NatSpec developer documentation
    """
    userdoc, devdoc = {}, {}
    source: str = vyper_ast.full_source_code

    global_ctx = GlobalContext.get_global_context(vyper_ast, interface_codes)

    docstring = vyper_ast.get("doc_string.value")
    if docstring:
        devdoc.update(_parse_docstring(source, docstring, ("param", "return")))
        if "notice" in devdoc:
            userdoc["notice"] = devdoc.pop("notice")

    for node in [i for i in vyper_ast.body if i.get("doc_string.value")]:
        docstring = node.doc_string.value
        sigs = sig_utils.mk_single_method_identifier(node, global_ctx)

        if isinstance(node.returns, vy_ast.Tuple):
            ret_len = len(node.returns.elts)
        elif node.returns:
            ret_len = 1
        else:
            ret_len = 0

        if sigs:
            args = tuple(i.arg for i in node.args.args)
            fn_natspec = _parse_docstring(source, docstring, ("title",), args, ret_len)
            for s in sigs:
                if "notice" in fn_natspec:
                    userdoc.setdefault("methods", {})[s] = {
                        "notice": fn_natspec.pop("notice")
                    }
                if fn_natspec:
                    devdoc.setdefault("methods", {})[s] = fn_natspec

    return userdoc, devdoc
コード例 #10
0
def mk_method_identifiers(source_str, interface_codes=None):
    identifiers = {}
    global_ctx = GlobalContext.get_global_context(
        parse_to_ast(source_str),
        interface_codes=interface_codes,
    )

    for code in global_ctx._defs:
        identifiers.update(mk_single_method_identifier(code, global_ctx))

    return identifiers
コード例 #11
0
def parse_to_lll(
    source_code: str, runtime_only: bool = False, interface_codes: Optional[InterfaceImports] = None
) -> LLLnode:
    vyper_module = vy_ast.parse_to_ast(source_code)
    global_ctx = GlobalContext.get_global_context(vyper_module, interface_codes=interface_codes)
    lll_nodes, lll_runtime = parse_tree_to_lll(source_code, global_ctx)

    if runtime_only:
        return lll_runtime
    else:
        return lll_nodes
コード例 #12
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_empty_param(bad_docstring):
    code = f"""
@external
def foo(a: int128):
    '''{bad_docstring}'''
    pass
    """
    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match="No description given for parameter 'a'"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #13
0
ファイル: test_natspec.py プロジェクト: siraben/vyper
def test_empty_field(bad_docstring):
    code = f"""
@public
def foo():
    '''{bad_docstring}'''
    pass
    """
    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="No description given for tag '@notice'"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #14
0
ファイル: parser.py プロジェクト: kushagrasharma/vyper
def mk_method_identifiers(code):
    o = {}
    global_ctx = GlobalContext.get_global_context(parse(code))

    for code in global_ctx._defs:
        sig = FunctionSignature.from_definition(code, sigs=global_ctx._contracts, custom_units=global_ctx._custom_units, constants=global_ctx._constants)
        if not sig.private:
            default_sigs = generate_default_arg_sigs(code, global_ctx._contracts, global_ctx)
            for s in default_sigs:
                o[s.sig] = hex(s.method_id)

    return o
コード例 #15
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_invalid_field(field):
    code = f"""
@external
def foo():
    '''@{field} function level docstrings cannot have titles'''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match=f"'@{field}' is not a valid field"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #16
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_unknown_param():
    code = """
@external
def foo(bar: int128, baz: uint256):
    '''@param hotdog not a number'''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match="Method has no parameter 'hotdog'"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #17
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_too_many_returns_no_return_type():
    code = """
@external
def foo():
    '''@return should fail, the function does not include a return value'''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match="Method does not return any values"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #18
0
ファイル: parser.py プロジェクト: zhengger/vyper
def mk_full_signature(code):
    o = []
    global_ctx = GlobalContext.get_global_context(code)

    for code in global_ctx._events:
        sig = EventSignature.from_declaration(code, custom_units=global_ctx._custom_units)
        o.append(sig.to_abi_dict())
    for code in global_ctx._defs:
        sig = FunctionSignature.from_definition(code, sigs=global_ctx._contracts, custom_units=global_ctx._custom_units)
        if not sig.private:
            default_sigs = generate_default_arg_sigs(code, global_ctx._contracts, global_ctx._custom_units)
            for s in default_sigs:
                o.append(s.to_abi_dict())
    return o
コード例 #19
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_empty_fields(field):
    code = f"""
'''
@{field}
'''
@external
def foo():
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match=f"No description given for tag '@{field}'"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #20
0
def produce_source_map(code, interface_codes=None):
    global_ctx = GlobalContext.get_global_context(
        parser.parse_to_ast(code), interface_codes=interface_codes)
    asm_list = compile_lll.compile_to_assembly(
        optimizer.optimize(
            parse_to_lll(code,
                         runtime_only=True,
                         interface_codes=interface_codes)))
    c, line_number_map = compile_lll.assembly_to_evm(asm_list)
    source_map = {
        "globals": {},
        "locals": {},
        "line_number_map": line_number_map
    }
    source_map["globals"] = {
        name: serialise_var_rec(var_record)
        for name, var_record in global_ctx._globals.items()
    }
    # Fetch context for each function.
    lll = parser.parse_tree_to_lll(
        parser.parse_to_ast(code),
        code,
        interface_codes=interface_codes,
        runtime_only=True,
    )
    contexts = {
        f.func_name: f.context
        for f in lll.args[1:] if hasattr(f, "context")
    }

    prev_func_name = None
    for _def in global_ctx._defs:
        if _def.name != "__init__":
            func_info = {"from_lineno": _def.lineno, "variables": {}}
            # set local variables for specific function.
            context = contexts[_def.name]
            func_info["variables"] = {
                var_name: serialise_var_rec(var_rec)
                for var_name, var_rec in context.vars.items()
            }

            source_map["locals"][_def.name] = func_info
            # set to_lineno
            if prev_func_name:
                source_map["locals"][prev_func_name]["to_lineno"] = _def.lineno
            prev_func_name = _def.name

    source_map["locals"][_def.name]["to_lineno"] = len(code.splitlines())

    return source_map
コード例 #21
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_duplicate_fields():
    code = """
@external
def foo():
    '''
    @notice It's fine to have one notice, but....
    @notice a second one, not so much
    '''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match="Duplicate NatSpec field '@notice'"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #22
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_unknown_field():
    code = """
@external
def foo():
    '''
    @notice this is ok
    @thing this is bad
    '''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match="Unknown NatSpec field '@thing'"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #23
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_duplicate_param():
    code = """
@external
def foo(bar: int128, baz: uint256):
    '''
    @param bar a number
    @param bar also a number
    '''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException, match="Parameter 'bar' documented more than once"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #24
0
ファイル: test_natspec.py プロジェクト: siraben/vyper
def test_partial_natspec():
    code = """
@public
def foo():
    '''
    Regular comments preceeding natspec is not allowed
    @notice this is natspec
    '''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(NatSpecSyntaxException,
                       match="NatSpec docstring opens with untagged comment"):
        parse_natspec(vyper_ast, global_ctx)
コード例 #25
0
ファイル: interface.py プロジェクト: siraben/vyper
def extract_sigs(sig_code):
    if sig_code['type'] == 'vyper':
        interface_ast = [
            i for i in vy_ast.parse_to_ast(sig_code['code'])
            if isinstance(i, vy_ast.FunctionDef) or
            (isinstance(i, vy_ast.AnnAssign) and i.target.id != "implements")
        ]
        global_ctx = GlobalContext.get_global_context(interface_ast)
        return sig_utils.mk_full_signature(global_ctx,
                                           sig_formatter=lambda x: x)
    elif sig_code['type'] == 'json':
        return mk_full_signature_from_json(sig_code['code'])
    else:
        raise Exception((
            f"Unknown interface signature type '{sig_code['type']}' supplied. "
            "'vyper' & 'json' are supported"))
コード例 #26
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_license(license):
    code = f"""
'''
@license {license}
'''
@external
def foo():
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    _, devdoc = parse_natspec(vyper_ast, global_ctx)

    assert devdoc == {
        "license": license,
    }
コード例 #27
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_too_many_returns_single_return_type():
    code = """
@external
def foo() -> int128:
    '''
    @return int128
    @return this should fail
    '''
    return 1
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    with pytest.raises(
        NatSpecSyntaxException, match="Number of documented return values exceeds actual number",
    ):
        parse_natspec(vyper_ast, global_ctx)
コード例 #28
0
ファイル: test_natspec.py プロジェクト: z0rk1i/vyper
def test_ignore_private_methods():
    code = """
@external
def foo(bar: int128, baz: uint256):
    '''@dev I will be parsed.'''
    pass

@internal
def notfoo(bar: int128, baz: uint256):
    '''@dev I will not be parsed.'''
    pass
    """

    vyper_ast = parse_to_ast(code)
    global_ctx = GlobalContext.get_global_context(vyper_ast)
    _, devdoc = parse_natspec(vyper_ast, global_ctx)

    assert devdoc["methods"] == {"foo(int128,uint256)": {"details": "I will be parsed."}}
コード例 #29
0
ファイル: phases.py プロジェクト: sambacha/vyper-xcode
def generate_global_context(
    vyper_module: vy_ast.Module, interface_codes: Optional[InterfaceImports],
) -> GlobalContext:
    """
    Generate a contextualized AST from the Vyper AST.

    Arguments
    ---------
    vyper_module : vy_ast.Module
        Top-level Vyper AST node
    interface_codes: Dict, optional
        Interfaces that may be imported by the contracts.

    Returns
    -------
    GlobalContext
        Sorted, contextualized representation of the Vyper AST
    """
    return GlobalContext.get_global_context(vyper_module, interface_codes=interface_codes)
コード例 #30
0
ファイル: source_map.py プロジェクト: akinama3/vyper-debug
def produce_source_map(code):
    global_ctx = GlobalContext.get_global_context(parser.parse_to_ast(code))
    asm_list = compile_lll.compile_to_assembly(
        optimizer.optimize(parse_to_lll(code, runtime_only=True)))
    c, line_number_map = compile_lll.assembly_to_evm(asm_list)
    source_map = {
        'globals': {},
        'locals': {},
        'line_number_map': line_number_map
    }
    source_map['globals'] = {
        name: serialise_var_rec(var_record)
        for name, var_record in global_ctx._globals.items()
    }
    # Fetch context for each function.
    lll = parser.parse_tree_to_lll(parser.parse_to_ast(code),
                                   code,
                                   runtime_only=True)
    contexts = {
        f.func_name: f.context
        for f in lll.args[1:] if hasattr(f, 'context')
    }

    prev_func_name = None
    for _def in global_ctx._defs:
        if _def.name != '__init__':
            func_info = {'from_lineno': _def.lineno, 'variables': {}}
            # set local variables for specific function.
            context = contexts[_def.name]
            func_info['variables'] = {
                var_name: serialise_var_rec(var_rec)
                for var_name, var_rec in context.vars.items()
            }

            source_map['locals'][_def.name] = func_info
            # set to_lineno
            if prev_func_name:
                source_map['locals'][prev_func_name]['to_lineno'] = _def.lineno
            prev_func_name = _def.name

    source_map['locals'][_def.name]['to_lineno'] = len(code.splitlines())

    return source_map