def test_fn_declaration():
    e = FortranEvaluator()
    e.evaluate("""\
integer function fn0()
fn0 = 5
end function
""")
    e.evaluate("""\
integer function fn1(a)
integer, intent(in) :: a
fn1 = 5
end function
""")
    e.evaluate("""\
integer function fn2(a, b)
integer, intent(in) :: a, b
fn2 = 5
end function
""")
    e.evaluate("""\
integer function fn3(a, b, c)
integer, intent(in) :: a, b, c
fn3 = 5
end function
""")
Beispiel #2
0
def test_intrinsics():
    e = FortranEvaluator()
    e.evaluate("""\
integer, parameter :: dp = kind(0.d0)
real(dp) :: a, b, c(4)
integer :: i, r
r = 0
a = 1.1_dp
b = 1.2_dp
if (b-a > 0.2_dp) r = 1
if (abs(b-a) > 0.2_dp) r = 1
if (abs(a-b) > 0.2_dp) r = 1

a = 4._dp
if (abs(sqrt(a)-2._dp) > 1e-12_dp) r = 1

a = 4._dp
if (abs(log(a)-1.3862943611198906_dp) > 1e-12_dp) r = 1

c(1) = -1._dp
c(2) = -1._dp
c(3) = -1._dp
c(4) = -1._dp
call random_number(c)
do i = 1, 4
    if (c(i) < 0._dp) r = 1
    if (c(i) > 1._dp) r = 1
end do
""")
    assert e.evaluate("r") == 0
def test_arrays3():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f(a)
integer, intent(in) :: a(3)
integer :: i
f = 0
do i = 1, 3
    f = f + a(i)
end do
end function
""")
    # TODO: Enable this after [1, 2, 3] is implemented
    #assert e.evaluate("f([1, 2, 3])") == 6

    e.evaluate("""\
integer :: x(3)
x(1) = 1
x(2) = 2
x(3) = 3
""")
    assert e.evaluate("f(x)") == 6

    e.evaluate("""\
integer function g()
integer :: x(3)
x(1) = 1
x(2) = 2
x(3) = 3
g = f(x)
end function
""")
    assert e.evaluate("g()") == 6
Beispiel #4
0
def test_plot():
    e = FortranEvaluator()
    assert e.evaluate("""\
integer :: a, b
a = 1
b = 5
plot_test(a, b)
""") == 6
def test_subroutine():
    e = FortranEvaluator()
    e.evaluate("""\
subroutine sub1(a, b)
integer, intent(in) :: a
integer, intent(out) :: b
b = a + 1
end subroutine
""")
Beispiel #6
0
def test_fn_dummy():
    e = FortranEvaluator()
    e.evaluate("""\
function f(a)
integer, intent(in) :: a
f = a + 1
end function
""")
    assert e.evaluate("f(2)") == 3
def test_f_call0():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f()
f = 5
end function
""")
    assert e.evaluate("f()+5") == 10
    assert e.evaluate("f()+6") == 11
def test_case_sensitivity():
    e = FortranEvaluator()
    e.evaluate("""\
Integer FUNCTION f(a)
INTEGER, Intent(In) :: a
f = a + 5
End Function
""")
    assert e.evaluate("f(2)") == 7
    assert e.evaluate("f(5)") == 10
def test_f_call_real_1():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f(a)
real, intent(in) :: a
f = 0
if (a > 2.7) f = 1
end function
""")
    assert e.evaluate("f(2.8)") == 1
    assert e.evaluate("f(2.6)") == 0
Beispiel #10
0
def test_fn_local():
    e = FortranEvaluator()
    e.evaluate("""\
function f3(a)
integer, intent(in) :: a
integer :: b
b = 5
f3 = a + b
end function
""")
    assert e.evaluate("f3(2)") == 7
def test_f_call_real_2():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f(a, b)
real, intent(in) :: a, b
real :: c
c = a + b
f = 0
if (c > 2.7) f = 1
end function
""")
    assert e.evaluate("f(1.8, 1.0)") == 1
    assert e.evaluate("f(1.6, 1.0)") == 0
Beispiel #12
0
def test_if_conditions():
    e = FortranEvaluator()
    e.evaluate("""\
integer :: i
i = 0
if (.false.) i = 1
if (1 == 2) i = 1
if (1 /= 1) i = 1
if (1 > 2) i = 1
if (1 >= 2) i = 1
if (2 < 1) i = 1
if (2 <= 1) i = 1
""")
    assert e.evaluate("i") == 0
def test_whitespace4():
    e = FortranEvaluator()
    e.evaluate("""\

""")
    e.evaluate(" ")
    e.evaluate("")
Beispiel #14
0
def test_do_loops_fn():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f()
integer :: i, j
j = 0
do i = 1, 10
    j = j + i
end do
f = j
end function
""")
    assert e.evaluate("f()") == 55
    e.evaluate("""\
integer function f2(n)
integer, intent(in) :: n
integer :: i, j
j = 0
do i = 1, n
    j = j + i
end do
f2 = j
end function
""")
    assert e.evaluate("f2(10)") == 55
    assert e.evaluate("f2(20)") == 210
def test_if_then_else_1():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f(a)
real, intent(in) :: a
f = 3
if (a > 2.7) then
    f = 1
else
    f = 0
end if
end function
""")
    assert e.evaluate("f(2.8)") == 1
    assert e.evaluate("f(2.6)") == 0
def test_program():
    e = FortranEvaluator()
    e.evaluate("""\
program test
implicit none
contains

    subroutine sub1(a, b)
    integer, intent(in) :: a
    integer, intent(out) :: b
    b = a + 1
    end subroutine

end program
""")
Beispiel #17
0
def test_expr():
    e = FortranEvaluator()
    e.evaluate("""\
integer :: x, i
i = 0
x = (2+3)*5
if (x /= 25) i = 1

x = (2+3)*4
if (x /= 20) i = 1

x = (2+3)*(2+3)
if (x /= 25) i = 1

x = (2+3)*(2+3)*4*2*(1+2)
if (x /= 600) i = 1

x = x / 60
if (x /= 10) i = 1

x = x + 1
if (x /= 11) i = 1

x = x - 1
if (x /= 10) i = 1

x = -2
if (x /= -2) i = 1

x = -2*3
if (x /= -6) i = 1

x = -2*(-3)
if (x /= 6) i = 1

x = 3 - 1
if (x /= 2) i = 1

x = 1 - 3
if (x /= -2) i = 1
if (x /= (-2)) i = 1

x = 1 - (-3)
if (x /= 4) i = 1
if (x /= +4) i = 1
if (x /= (+4)) i = 1
""")
    assert e.evaluate("i") == 0
Beispiel #18
0
def test_arrays2():
    e = FortranEvaluator()
    e.evaluate("""\
integer, parameter :: dp = kind(0.d0)
real(dp) :: a(3), b, c
integer :: i
a(1) = 3._dp
a(2) = 2._dp
a(3) = 1._dp
b = sum(a)
if (abs(b-6._dp) < 1e-12_dp) then
    i = 1
else
    i = 2
end if
""")
    assert e.evaluate("i") == 1
def test_variables1():
    e = FortranEvaluator()
    assert not e._global_scope.resolve("a", False)
    e.evaluate("integer :: a")
    assert e._global_scope.resolve("a", False)
    e.evaluate("a = 5")
    assert e._global_scope.resolve("a", False)
    assert e.evaluate("a") == 5
    assert e._global_scope.resolve("a", False)
    assert e.evaluate("a+3") == 8
def test_multiline1():
    e = FortranEvaluator()
    e.evaluate("""\
integer :: a
a = 5""")
    assert e.evaluate("a") == 5
    e.evaluate("""\
a = 6
a = a + 1""")
    assert e.evaluate("a") == 7
    assert e.evaluate("""\
a = 6
a = a + 2
a""") == 8
def test_f_call_outarg():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f(a, b)
integer, intent(in) :: a
integer, intent(out) :: b
b = a + 5
f = 0
end function
""")
    e.evaluate("integer :: i")
    assert e.evaluate("f(2, i)") == 0
    assert e.evaluate("i") == 7
def test_multiline2():
    e = FortranEvaluator()
    e.evaluate("""\
integer :: b
b = 5
function f2(a)
integer, intent(in) :: a
f2 = a + b
end function
""")
    assert e.evaluate("f2(2)") == 7
    e.evaluate("b = 6")
    assert e.evaluate("f2(2)") == 8
def test_whitespace2():
    e = FortranEvaluator()
    e.evaluate("""\
integer :: a
""")
    e.evaluate("""\
a = 5
""")
    assert e.evaluate("""\
a
""") == 5
def test_f_call_real_int_2():
    e = FortranEvaluator()
    e.evaluate("""\
integer function f(a, b)
real, intent(in) :: a
integer, intent(in) :: b
f = 0
if (a > 1.7) f = 1
f = f + b
end function
""")
    assert e.evaluate("f(1.8, 0)") == 1
    assert e.evaluate("f(1.6, 0)") == 0
    assert e.evaluate("f(1.8, 1)") == 2
    assert e.evaluate("f(1.6, 1)") == 1
def test_print(capfd):
    e = FortranEvaluator()
    e.evaluate("""\
integer :: x
x = (2+3)*5
print *, x, 1, 3, x, (2+3)*5+x
""")
    out = capfd.readouterr().out
    assert out.replace("\r", "") == "25 1 3 25 50 \n"

    e.evaluate("""\
print *, "Hello world!"
""")
    out = capfd.readouterr().out
    assert out.replace("\r", "") == "Hello world! \n"
Beispiel #26
0
def main(verbose=True):
    llvm.initialize()
    llvm.initialize_native_asmprinter()
    llvm.initialize_native_target()

    target = llvm.Target.from_triple(llvm.get_default_triple())
    target_machine = target.create_target_machine()
    target_machine.set_asm_verbosity(True)

    # Empty backing module
    backing_mod = llvm.parse_assembly("")
    backing_mod.verify()
    engine = llvm.create_mcjit_compiler(backing_mod, target_machine)

    print("Interactive Fortran.")
    print("  * Use Ctrl-D to exit.")
    print("  * Use Enter to submit.")
    print("  * Features:")
    print("    - Multi-line editing (use Alt-Enter)")
    print("    - History")
    print("    - Syntax highlighting")
    print()

    fortran_evaluator = FortranEvaluator()

    session = PromptSession('> ',
                            lexer=PygmentsLexer(FortranLexer),
                            multiline=True,
                            key_bindings=kb)
    try:
        while True:
            text = session.prompt()
            if verbose:
                print()
            handle_input(engine, fortran_evaluator, text, verbose)
            if verbose:
                print()
    except EOFError:
        print("Exiting.")
Beispiel #27
0
def test_print(capfd):
    import ctypes
    libc = ctypes.CDLL(None)
    c_stdout = ctypes.c_void_p.in_dll(libc, 'stdout')

    e = FortranEvaluator()
    e.evaluate("""\
integer :: x
x = (2+3)*5
print *, x, 1, 3, x, (2+3)*5+x
""")
    libc.fflush(c_stdout)  # The C stdout buffer must be flushed out
    out = capfd.readouterr().out
    assert out == "25 1 3 25 50 \n"

    e.evaluate("""\
print *, "Hello world!"
""")
    libc.fflush(c_stdout)
    out = capfd.readouterr().out
    assert out == "Hello world! \n"
Beispiel #28
0
def test_do_loops_interactive():
    e = FortranEvaluator()
    e.evaluate("""\
integer :: i, j
j = 0
do i = 1, 10
    j = j + i
end do
""")
    assert e.evaluate("j") == 55

    e.evaluate("""\
j = 0
do i = 10, 1, -1
    j = j + i
end do
""")
    assert e.evaluate("j") == 55

    e.evaluate("""\
j = 0
do i = 1, 9, 2
    j = j + i
end do
""")
    assert e.evaluate("j") == 25

    e.evaluate("""\
j = 0
do i = 9, 1, -2
    j = j + i
end do
""")
    assert e.evaluate("j") == 25

    e.evaluate("""\
j = 0
do i = 1, 10, 2
    j = j + i
end do
""")
    assert e.evaluate("j") == 25

    e.evaluate("""\
j = 0
do i = 1, 10, 3
    j = j + i
end do
""")
    assert e.evaluate("j") == 22

    e.evaluate("""\
j = 0
do i = 10, 1, -3
    j = j + i
end do
""")
    assert e.evaluate("j") == 22

    e.evaluate("""\
j = 0
do i = 1, 1
    j = j + i
end do
""")
    assert e.evaluate("j") == 1

    e.evaluate("""\
j = 0
do i = 1, 1, -1
    j = j + i
end do
""")
    assert e.evaluate("j") == 1

    e.evaluate("""\
j = 0
do i = 1, 0
    j = j + i
end do
""")
    assert e.evaluate("j") == 0

    e.evaluate("""\
j = 0
do i = 0, 1, -1
    j = j + i
end do
""")
    assert e.evaluate("j") == 0

    e.evaluate("""\
j = 0
do i = 1, 10
    j = j + i
    if (i == 2) exit
end do
""")
    assert e.evaluate("j") == 3

    e.evaluate("""\
j = 0
do i = 1, 10
    if (i == 2) exit
    j = j + i
end do
""")
    assert e.evaluate("j") == 1

    e.evaluate("""\
j = 0
do i = 1, 10
    if (i == 2) cycle
    j = j + i
end do
""")
    assert e.evaluate("j") == 53

    e.evaluate("""
integer :: a, b
j = 0
a = 1
b = 10
do i = a, b
    j = j + i
end do
""")
    assert e.evaluate("j") == 55

    e.evaluate("""\
a = 0
do i = 1, 10
    do j = 1, 10
        a = a + (i-1)*10+j
    end do
end do
""")
    assert e.evaluate("a") == 50 * 101

    e.evaluate("""\
a = 0
do i = 1, 10
    do j = 1, i
        a = a + j
    end do
end do
""")
    assert e.evaluate("a") == 220
Beispiel #29
0
def main():
    parser = argparse.ArgumentParser(description="Fortran compiler.")
    # Standard options compatible with gfortran or clang
    # We follow the established conventions
    std = parser.add_argument_group('standard arguments',
                                    'compatible with other compilers')
    std.add_argument('file', help="source file", nargs="?")
    std.add_argument('-emit-llvm',
                     action="store_true",
                     help="emit LLVM IR source code, do not assemble or link")
    std.add_argument('-S',
                     action="store_true",
                     help="emit assembly, do not assemble or link")
    std.add_argument('-c',
                     action="store_true",
                     help="compile and assemble, do not link")
    std.add_argument('-o', metavar="FILE", help="place the output into FILE")
    std.add_argument('-v', action="store_true", help="be more verbose")
    std.add_argument('-O3',
                     action="store_true",
                     help="turn LLVM optimizations on")
    std.add_argument('-E',
                     action="store_true",
                     help="not used (present for compatibility with cmake)")
    # LFortran specific options, we follow the Python conventions:
    # short option (-k), long option (--long-option)
    lf = parser.add_argument_group('LFortran arguments',
                                   'specific to LFortran')
    lf.add_argument('--ld-musl',
                    action="store_true",
                    help="invoke ld directly and link with musl")
    lf.add_argument('--show-ast',
                    action="store_true",
                    help="show AST for the given file and exit")
    lf.add_argument('--show-asr',
                    action="store_true",
                    help="show ASR for the given file and exit")
    lf.add_argument(
        '--show-ast-typed',
        action="store_true",
        help=
        "show type annotated AST (parsing and semantics) for the given file and exit (deprecated)"
    )
    args = parser.parse_args()

    if args.E:
        # CMake calls `lfort` with -E, and if we silently return a non-zero
        # exit code, CMake does not produce an error to the user.
        sys.exit(1)

    filename = args.file
    verbose = args.v
    optimize = args.O3

    if not filename:
        from lfortran.prompt import main
        main(verbose=verbose)
        return

    basename, ext = os.path.splitext(os.path.basename(filename))
    link_only = (open(filename, mode="rb").read(4)[1:] == b"ELF")

    if args.o:
        outfile = args.o
    elif args.S:
        outfile = "%s.s" % basename
    elif args.emit_llvm:
        outfile = "%s.ll" % basename
    elif args.c:
        outfile = "%s.o" % basename
    else:
        outfile = "a.out"

    if args.c:
        objfile = outfile
    elif link_only:
        objfile = filename
    else:
        objfile = "tmp_object_file.o"

    if not link_only:
        # Fortran -> LLVM IR source
        if verbose: print("Reading...")
        source = open(filename).read()
        if verbose: print("    Done.")
        if len(sys.argv) == 2 and filename:
            # Run as a script:
            if verbose: print("Importing evaluator...")
            from lfortran.codegen.evaluator import FortranEvaluator
            if verbose: print("    Done.")
            e = FortranEvaluator()
            e.evaluate(source)
            return
        if verbose: print("Importing parser...")
        from .ast import (src_to_ast, SyntaxErrorException, print_tree,
                          print_tree_typed)
        if verbose: print("    Done.")
        try:
            if verbose: print("Parsing...")
            if args.show_ast or args.show_ast_typed or args.show_asr:
                ast_tree = src_to_ast(source, translation_unit=False)
            else:
                ast_tree = src_to_ast(source)
            if verbose: print("    Done.")
        except SyntaxErrorException as err:
            print(str(err))
            sys.exit(1)
        if args.show_ast:
            print_tree(ast_tree)
            return
        if args.show_asr:
            from lfortran import ast_to_asr
            from lfortran.asr.pprint import pprint_asr
            asr_repr = ast_to_asr(ast_tree)
            pprint_asr(asr_repr)
            return
        if verbose: print("Importing semantic analyzer...")
        from .semantic.analyze import create_symbol_table, annotate_tree
        if verbose: print("    Done.")
        if verbose: print("Symbol table...")
        symbol_table = create_symbol_table(ast_tree)
        if verbose: print("    Done.")
        if verbose: print("Type annotation...")
        annotate_tree(ast_tree, symbol_table)
        if verbose: print("    Done.")
        if args.show_ast_typed:
            print_tree_typed(ast_tree)
            return
        if verbose: print("Importing codegen...")
        from .codegen.gen import codegen
        if verbose: print("    Done.")
        if verbose: print("LLMV IR generation...")
        module = codegen(ast_tree, symbol_table)
        if verbose: print("    Done.")
        if verbose: print("LLMV IR -> string...")
        source_ll = str(module)
        if verbose: print("    Done.")

        # LLVM IR source -> assembly / machine object code
        if verbose: print("Initializing LLVM...")
        llvm.initialize()
        llvm.initialize_native_asmprinter()
        llvm.initialize_native_target()
        target = llvm.Target.from_triple(module.triple)
        target_machine = target.create_target_machine()
        target_machine.set_asm_verbosity(True)
        if verbose: print("    Done.")
        if verbose: print("Loading LLMV IR string...")
        mod = llvm.parse_assembly(source_ll)
        if verbose: print("    Done.")
        if verbose: print("Verifying LLMV IR...")
        mod.verify()
        if verbose: print("    Done.")
        if optimize:
            if verbose: print("Optimizing...")
            pmb = llvm.create_pass_manager_builder()
            pmb.opt_level = 3
            pmb.loop_vectorize = True
            pmb.slp_vectorize = True
            pm = llvm.create_module_pass_manager()
            pmb.populate(pm)
            pm.run(mod)
            if verbose: print("    Done.")

        if args.emit_llvm:
            with open(outfile, "w") as ll:
                ll.write(str(mod))
            return
        if args.S:
            with open(outfile, "w") as o:
                o.write(target_machine.emit_assembly(mod))
            return
        if verbose: print("Machine code...")
        with open(objfile, "wb") as o:
            o.write(target_machine.emit_object(mod))
        if verbose: print("    Done.")
        if args.c:
            return

    # Link object code
    base_dir = get_lib_path()
    if args.ld_musl:
        # Invoke `ld` directly and link with musl. This is system dependent.
        musl_dir = "/usr/lib/x86_64-linux-musl"
        LDFLAGS = "{1}/liblfortran_runtime_static.a {0}/crt1.o {0}/libc.a".format(
            musl_dir, base_dir)
        os.system("ld -o %s %s %s" % (outfile, objfile, LDFLAGS))
    else:
        # Invoke a C compiler to do the linking
        os.system("cc -o %s %s -L%s -Wl,-rpath=%s -llfortran_runtime -lm" %
                  (outfile, objfile, base_dir, base_dir))
    if objfile == "tmp_object_file.o":
        os.system("rm %s" % objfile)
Beispiel #30
0
def test_arrays1():
    e = FortranEvaluator()
    e.evaluate("""\
integer :: i, a(3)
do i = 1, 3
    a(i) = i+10
end do
""")
    assert e.evaluate("a(1)") == 11
    assert e.evaluate("a(2)") == 12
    assert e.evaluate("a(3)") == 13

    e.evaluate("""\
integer :: b(4)
do i = 11, 14
    b(i-10) = i
end do
""")
    assert e.evaluate("b(1)") == 11
    assert e.evaluate("b(2)") == 12
    assert e.evaluate("b(3)") == 13
    assert e.evaluate("b(4)") == 14

    e.evaluate("""\
do i = 1, 3
    b(i) = a(i)-10
end do
""")
    assert e.evaluate("b(1)") == 1
    assert e.evaluate("b(2)") == 2
    assert e.evaluate("b(3)") == 3

    e.evaluate("b(4) = b(1)+b(2)+b(3)+a(1)")
    assert e.evaluate("b(4)") == 17

    e.evaluate("b(4) = a(1)")
    assert e.evaluate("b(4)") == 11