Example #1
0
def check_BinaryOperator(node, env):
    check(node.left, env)
    check(node.right, env)
    node.type = check_binop(node.left.type, node.operator, node.right.type)
    if node.type is None and (node.left.type and node.right.type):
        # if left and right have types then we are *not* in a cascading case
        error(f'Invalid binop: {node.left.type} {node.operator} {node.right.type}')
Example #2
0
def check_NamedLocation(node, env):
    declaration = env.get(node.name)
    if declaration is None:
        error(f'Location {node} was not declared')
        return  # cannot do further checking

    node.type = declaration.type
    node.mutable = not isinstance(declaration, (Constant, Function))
Example #3
0
def check_Function(node, env):
    if node.name in env.maps[0]:
        error(f'Duplicate definition of {node.name}.')
        # and do NOT overwrite it ... originally defined function stays
    else:
        env[node.name] = node

    local_env = env.new_child()
    check(node.parameters, local_env)
    check(node.statements, local_env)
Example #4
0
def check_Assignment(node, env):
    check(node.location, env)
    check(node.expression, env)

    # What I expect
    if node.location.type != node.expression.type:
        error(f'Type error on assignment: {node.location.type} != {node.expression.type}')

    # Mutability: let's make assignment responsible for this
    if not node.location.mutable:  # Wishful Thinking Programming!
        error(f"Cannot assign to immutable location: {node.location}")
Example #5
0
def _checkVariableOrConst(node, env):
    if node.value is not None:
        check(node.value, env)

        if node.type_specified_when_declared:
            if node.value.type != node.type:
                error(f'Variable defined as type {node.type} does not match {node.value.type}')
        else:
            # infer type from value
            node.type = node.value.type

    if node.name in env:
        error(f'Duplicate definition of {node.name}')
    env[node.name] = node
Example #6
0
def check_FunctionCall(node, env):
    # Check function arguments
    check(node.args, env)

    # Check that the function is defined
    func = env.get(node.function_name)
    if func is None:
        error(f'Function {node.function_name} is not defined.')

    # Check that the function is a function
    if not isinstance(func, Function):
        error(f'Cannot call {node.name} as a function')
        return  # ... and no further checking is possible

    # Check that the function has all of the arguments that it needs
    if len(func.parameters) != len(node.args):
        error(f'Function is missing required arguments. Needs {func.parameters} got {node.args}')

    # Check that the function parameter types match the supplied argument types
    for n, (arg, param) in enumerate(zip(node.args, func.parameters), 1):
        if param.type != arg.type:
            error(f'Type error in argument {n}: {param.type} != {arg.type}')

    node.type = func.return_type
Example #7
0
def check_UnaryOperator(node, env):
    check(node.operand, env)
    node.type = check_unop(node.operator, node.operand.type)
    if node.type is None:
        error(f'Invalid unary operation: {node.operator}{node.operand}')
Example #8
0
def check_While(node, env):
    check(node.test, env)
    if node.test.type != Bool.type:
        error('If test did not evaluate to a Boolean!')
    check(node.consequence, env.new_child())
Example #9
0
def check_If(node, env):
    check(node.test, env)
    if node.test.type != Bool.type:
        error('If test did not evaluate to a Boolean!')
    check(node.consequence, env.new_child())  # Make a new scope (from ChainMap)
    check(node.alternative, env.new_child())
Example #10
0
def check_FunctionParameter(node, env):
    if node.name in env.maps[0]:
        error(f'Duplicate definition of {node.name}')
    env[node.name] = node