From 4ea1f063d3ffc792eead170e1aa289840416f741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Fri, 7 Aug 2020 12:18:52 -0600 Subject: [PATCH] Remove all prototype Python code and tests This code and tests have been moved to lfortran.py. --- .gitlab-ci.yml | 106 +-- CMakeLists.txt | 12 - build.bat | 2 - build0.bat | 11 - build0.sh | 11 +- build1.bat | 7 - build_java.sh | 17 - grammar/README.md | 9 - grammar/asdl_py.py | 424 ---------- grammar/fortran.g4 | 553 ------------- lfort | 6 - lfortran/__init__.py | 4 - lfortran/adapters/__init__.py | 0 lfortran/adapters/gfortran/__init__.py | 0 lfortran/adapters/gfortran/mod.py | 519 ------------- lfortran/asr/__init__.py | 0 lfortran/asr/asr_check.py | 97 --- lfortran/asr/asr_to_ast.py | 189 ----- lfortran/asr/builder.py | 125 --- lfortran/asr/pprint.py | 44 -- lfortran/asr/tests/__init__.py | 0 lfortran/asr/tests/test_builder.py | 43 -- lfortran/asr/tests/test_pprint.py | 12 - lfortran/ast/__init__.py | 16 - lfortran/ast/ast_to_src.py | 182 ----- lfortran/ast/tests/__init__.py | 0 .../ast/tests/case_sensitivity_results.py | 13 - lfortran/ast/tests/controlflow_results.py | 22 - lfortran/ast/tests/decl_results.py | 18 - lfortran/ast/tests/expr_results.py | 57 -- lfortran/ast/tests/interactive_results.py | 11 - lfortran/ast/tests/module_results.py | 17 - lfortran/ast/tests/program_results.py | 6 - lfortran/ast/tests/statements_results.py | 49 -- lfortran/ast/tests/subroutine_results.py | 11 - lfortran/ast/tests/test_ast.py | 47 -- lfortran/ast/tests/test_cparser.py | 22 - lfortran/ast/tests/test_dump.py | 39 - lfortran/ast/tests/test_files.py | 420 ---------- lfortran/ast/tests/test_parser.py | 724 ------------------ lfortran/ast/tests/test_utils.py | 79 -- lfortran/ast/tests/test_visitor.py | 128 ---- lfortran/ast/tests/use_results.py | 5 - lfortran/ast/utils.py | 337 -------- lfortran/cli.py | 233 ------ lfortran/codegen/__init__.py | 0 lfortran/codegen/asr_to_llvm.py | 130 ---- lfortran/codegen/evaluator.py | 195 ----- lfortran/codegen/gen.py | 679 ---------------- lfortran/codegen/tests/__init__.py | 0 lfortran/codegen/tests/test_arrays.py | 96 --- lfortran/codegen/tests/test_asr_to_llvm.py | 43 -- lfortran/codegen/tests/test_do_loops.py | 249 ------ lfortran/codegen/tests/test_expr.py | 65 -- lfortran/codegen/tests/test_fortran_eval.py | 332 -------- lfortran/codegen/tests/test_intrinsics.py | 44 -- lfortran/codegen/tests/test_llvm_eval.py | 401 ---------- lfortran/codegen/tests/test_symbol_scope.py | 73 -- lfortran/parser/CMakeLists.txt | 7 - lfortran/parser/__init__.py | 0 lfortran/parser/cparser.pyx | 49 -- lfortran/parser/cwrapper.pxd | 20 - lfortran/parser/parser.py | 595 -------------- lfortran/prompt.py | 126 --- lfortran/semantic/__init__.py | 0 lfortran/semantic/analyze.py | 456 ----------- lfortran/semantic/ast_to_asr.py | 210 ----- lfortran/semantic/kinds.py | 50 -- lfortran/semantic/tests/__init__.py | 0 lfortran/semantic/tests/test_ast_to_asr.py | 95 --- lfortran/semantic/tests/test_variables.py | 441 ----------- lfortran/tests/__init__.py | 0 lfortran/tests/test_lld.py | 120 --- lfortran/tests/utils.py | 5 - 74 files changed, 29 insertions(+), 9079 deletions(-) delete mode 100644 build.bat delete mode 100644 build0.bat delete mode 100644 build1.bat delete mode 100755 build_java.sh delete mode 100644 grammar/README.md delete mode 100644 grammar/asdl_py.py delete mode 100644 grammar/fortran.g4 delete mode 100755 lfort delete mode 100644 lfortran/__init__.py delete mode 100644 lfortran/adapters/__init__.py delete mode 100644 lfortran/adapters/gfortran/__init__.py delete mode 100644 lfortran/adapters/gfortran/mod.py delete mode 100644 lfortran/asr/__init__.py delete mode 100644 lfortran/asr/asr_check.py delete mode 100644 lfortran/asr/asr_to_ast.py delete mode 100644 lfortran/asr/builder.py delete mode 100644 lfortran/asr/pprint.py delete mode 100644 lfortran/asr/tests/__init__.py delete mode 100644 lfortran/asr/tests/test_builder.py delete mode 100644 lfortran/asr/tests/test_pprint.py delete mode 100644 lfortran/ast/__init__.py delete mode 100644 lfortran/ast/ast_to_src.py delete mode 100644 lfortran/ast/tests/__init__.py delete mode 100644 lfortran/ast/tests/case_sensitivity_results.py delete mode 100644 lfortran/ast/tests/controlflow_results.py delete mode 100644 lfortran/ast/tests/decl_results.py delete mode 100644 lfortran/ast/tests/expr_results.py delete mode 100644 lfortran/ast/tests/interactive_results.py delete mode 100644 lfortran/ast/tests/module_results.py delete mode 100644 lfortran/ast/tests/program_results.py delete mode 100644 lfortran/ast/tests/statements_results.py delete mode 100644 lfortran/ast/tests/subroutine_results.py delete mode 100644 lfortran/ast/tests/test_ast.py delete mode 100644 lfortran/ast/tests/test_cparser.py delete mode 100644 lfortran/ast/tests/test_dump.py delete mode 100644 lfortran/ast/tests/test_files.py delete mode 100644 lfortran/ast/tests/test_parser.py delete mode 100644 lfortran/ast/tests/test_utils.py delete mode 100644 lfortran/ast/tests/test_visitor.py delete mode 100644 lfortran/ast/tests/use_results.py delete mode 100644 lfortran/ast/utils.py delete mode 100644 lfortran/cli.py delete mode 100644 lfortran/codegen/__init__.py delete mode 100644 lfortran/codegen/asr_to_llvm.py delete mode 100644 lfortran/codegen/evaluator.py delete mode 100644 lfortran/codegen/gen.py delete mode 100644 lfortran/codegen/tests/__init__.py delete mode 100644 lfortran/codegen/tests/test_arrays.py delete mode 100644 lfortran/codegen/tests/test_asr_to_llvm.py delete mode 100644 lfortran/codegen/tests/test_do_loops.py delete mode 100644 lfortran/codegen/tests/test_expr.py delete mode 100644 lfortran/codegen/tests/test_fortran_eval.py delete mode 100644 lfortran/codegen/tests/test_intrinsics.py delete mode 100644 lfortran/codegen/tests/test_llvm_eval.py delete mode 100644 lfortran/codegen/tests/test_symbol_scope.py delete mode 100644 lfortran/parser/CMakeLists.txt delete mode 100644 lfortran/parser/__init__.py delete mode 100644 lfortran/parser/cparser.pyx delete mode 100644 lfortran/parser/cwrapper.pxd delete mode 100644 lfortran/parser/parser.py delete mode 100644 lfortran/prompt.py delete mode 100644 lfortran/semantic/__init__.py delete mode 100644 lfortran/semantic/analyze.py delete mode 100644 lfortran/semantic/ast_to_asr.py delete mode 100644 lfortran/semantic/kinds.py delete mode 100644 lfortran/semantic/tests/__init__.py delete mode 100644 lfortran/semantic/tests/test_ast_to_asr.py delete mode 100644 lfortran/semantic/tests/test_variables.py delete mode 100644 lfortran/tests/__init__.py delete mode 100644 lfortran/tests/test_lld.py delete mode 100644 lfortran/tests/utils.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 12dbccc0ca..17801df26a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,6 @@ prepare tarball: stage: tarball image: registry.gitlab.com/lfortran/ci-images:prepare-1.7.0 script: - - export CLASSPATH="$HOME/antlr-4.7-complete.jar:$CLASSPATH" - ./build0.sh - python setup.py sdist - ci/upload_tarball.sh @@ -42,31 +41,6 @@ azure: variables: - $SSH_PRIVATE_KEY_AZURE - -# Test full dependencies when a C compiler is available and used for linking -full: - stage: build - image: registry.gitlab.com/lfortran/ci-images:full-1.7.0 - script: - - export PATH="$HOME/conda_root/bin:$PATH" - - conda install -c conda-forge python-clang - - tar xzf dist/lfortran-${lfortran_version}.tar.gz - - cd lfortran-${lfortran_version} - - pip install --no-index -v . - - cd .. - - rm -r lfortran lfortran-${lfortran_version} - - rm lfort - - py.test --pyargs lfortran - - python show_ast.py - - lfort examples/expr2.f90 -o a.out - - ./a.out - - ./test_lfort_cmdline gfortran - - ./test_lfort_cmdline lfort - - ./test_lfort gfortran - - ./test_lfort lfort - - cd integration_tests/interop - - ./run.sh - # Test the C++ version cxx: stage: build @@ -185,27 +159,27 @@ build.xsh: - xonsh ci/build.xsh # Build and upload documentation -documentation: - stage: build - image: registry.gitlab.com/lfortran/ci-images:jupyter-1.7.0 - script: - - sudo apt-get update - - sudo apt-get install -yq --no-install-recommends openssh-client - - export PATH="$HOME/conda_root/bin:$PATH" - - pip install nbconvert mkdocs - - tar xzf dist/lfortran-${lfortran_version}.tar.gz - - cd lfortran-${lfortran_version} - - pip install --no-index -v . - - cd .. - - rm -r lfortran lfortran-${lfortran_version} - - cd doc - - python convert_nb.py - - mkdocs build -s - - ../ci/upload_docs.sh - artifacts: - paths: - - doc/site - when: always +#documentation: +# stage: build +# image: registry.gitlab.com/lfortran/ci-images:jupyter-1.7.0 +# script: +# - sudo apt-get update +# - sudo apt-get install -yq --no-install-recommends openssh-client +# - export PATH="$HOME/conda_root/bin:$PATH" +# - pip install nbconvert mkdocs +# - tar xzf dist/lfortran-${lfortran_version}.tar.gz +# - cd lfortran-${lfortran_version} +# - pip install --no-index -v . +# - cd .. +# - rm -r lfortran lfortran-${lfortran_version} +# - cd doc +# - python convert_nb.py +# - mkdocs build -s +# - ../ci/upload_docs.sh +# artifacts: +# paths: +# - doc/site +# when: always # Update the downloads page downloads_update: @@ -226,39 +200,15 @@ minimal: - tar xzf dist/lfortran-${lfortran_version}.tar.gz - cd lfortran-${lfortran_version} - export CFLAGS="-I/usr/include/x86_64-linux-musl/" - - pip install --no-index -v . - - cd .. - - rm -r lfortran lfortran-${lfortran_version} - - rm lfort + #- pip install --no-index -v . + #- cd .. + #- rm -r lfortran lfortran-${lfortran_version} + #- rm lfort - sudo apt-get remove -yq gcc g++ libc6-dev - sudo apt-get autoremove -yq - - py.test --pyargs lfortran - - lfort --ld-musl examples/expr2.f90 -o a.out - - ./a.out - -# Test Jupyter notebooks -jupyter: - stage: build - image: registry.gitlab.com/lfortran/ci-images:jupyter-1.7.0 - script: - - export PATH="$HOME/conda_root/bin:$PATH" - - tar xzf dist/lfortran-${lfortran_version}.tar.gz - - cd lfortran-${lfortran_version} - - pip install --no-index -v . - - cd .. - - rm -r lfortran lfortran-${lfortran_version} - - (git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/lfortran/fortran_kernel && cd fortran_kernel && git checkout v0.1.4 && pip install --no-index . && cd .. && rm -r fortran_kernel) - - python -m fortran_kernel.install --sys-prefix - - jupyter kernelspec list --json - - cd share/lfortran/nb - - py.test --pyargs lfortran - - jupyter nbconvert --to notebook --execute --ExecutePreprocessor.timeout=60 --output Demo_out.ipynb Demo.ipynb - - ls -l output1.png - artifacts: - paths: - - share/lfortran/nb/Demo_out.ipynb - - share/lfortran/nb/output1.png - when: always + #- py.test --pyargs lfortran + #- lfort --ld-musl examples/expr2.f90 -o a.out + #- ./a.out # Test Bison grammar grammar: diff --git a/CMakeLists.txt b/CMakeLists.txt index 21ed20fe7c..7f364b79bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,14 +119,6 @@ if (WITH_STACKTRACE) set(HAVE_LFORTRAN_STACKTRACE yes) endif() - -# Python -set(WITH_PYTHON no CACHE BOOL "Build with Python wrappers") -if (WITH_PYTHON) - cmake_minimum_required(VERSION 3.12.4 FATAL_ERROR) - find_package(Python REQUIRED COMPONENTS Interpreter Development) -endif() - enable_testing() message("\n") @@ -151,10 +143,6 @@ message("WITH_STACKTRACE: ${WITH_STACKTRACE}") message("HAVE_LFORTRAN_DEMANGLE: ${HAVE_LFORTRAN_DEMANGLE}") message("WITH_LLVM: ${WITH_LLVM}") message("WITH_JSON: ${WITH_JSON}") -message("WITH_PYTHON: ${WITH_PYTHON}") add_subdirectory(src) -if (WITH_PYTHON) - add_subdirectory(lfortran/parser) -endif() diff --git a/build.bat b/build.bat deleted file mode 100644 index 4af0bd6a36..0000000000 --- a/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -call build0.bat -call build1.bat diff --git a/build0.bat b/build0.bat deleted file mode 100644 index fab0feff6e..0000000000 --- a/build0.bat +++ /dev/null @@ -1,11 +0,0 @@ -python grammar\asdl_py.py -python grammar\asdl_cpp.py -python grammar\asdl_py.py grammar\ASR.asdl lfortran\asr\asr.py ..ast.utils -cd grammar -call antlr4 -Dlanguage=Python3 -no-listener -visitor fortran.g4 -o ..\lfortran\parser -cd .. - -cd src\lfortran\parser -re2c -W -b tokenizer.re -o tokenizer.cpp -bison -Wall -d parser.yy -cd ..\..\.. diff --git a/build0.sh b/build0.sh index d31a7d4a6d..9ee7b57992 100755 --- a/build0.sh +++ b/build0.sh @@ -3,12 +3,8 @@ set -e set -x -# Generate a Fortran AST from AST.asdl (Python) -python grammar/asdl_py.py # Generate a Fortran AST from AST.asdl (C++) python grammar/asdl_cpp.py -# Generate a Fortran ASR from ASR.asdl -python grammar/asdl_py.py grammar/ASR.asdl lfortran/asr/asr.py ..ast.utils # Generate a Fortran ASR from ASR.asdl (C++) python grammar/asdl_cpp.py grammar/ASR.asdl src/lfortran/asr.h @@ -17,9 +13,4 @@ python grammar/asdl_cpp.py grammar/ASR.asdl src/lfortran/asr.h (cd src/lfortran/parser && bison -Wall -d -r all parser.yy) grep -n "'" src/lfortran/parser/parser.yy && echo "Single quote not allowed" && exit 1 - -(cd lfortran/parser && cython -3 -I. cparser.pyx) - -# Generate a parse tree from fortran.g4 -antlr4="java org.antlr.v4.Tool" -(cd grammar && $antlr4 -Dlanguage=Python3 -no-listener -visitor fortran.g4 -o ../lfortran/parser) +echo "OK" diff --git a/build1.bat b/build1.bat deleted file mode 100644 index f688f3c403..0000000000 --- a/build1.bat +++ /dev/null @@ -1,7 +0,0 @@ -cmake ^ - -DCMAKE_INSTALL_PREFIX=%cd% ^ - -DCMAKE_GENERATOR_PLATFORM=x64 ^ - -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE ^ - . - -cmake --build . --target install diff --git a/build_java.sh b/build_java.sh deleted file mode 100755 index bbfd875bc2..0000000000 --- a/build_java.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e -set -x - -antlr4="java org.antlr.v4.Tool" -grun="java org.antlr.v4.gui.TestRig" - -$antlr4 grammar/fortran.g4 -javac grammar/fortran*.java - -# Test: -cd grammar -$grun fortran root -tree ../examples/expr2.f90 - -# Visualize -#$grun fortran root -gui ../examples/expr2.f90 diff --git a/grammar/README.md b/grammar/README.md deleted file mode 100644 index b692ff2fe7..0000000000 --- a/grammar/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Fortran Grammar Tools - -This directory contains the Fortran parse tree grammar (fortran.g4) and the -Fortran AST description (Fortran.asdl). The first is used by ANTLR4 to generate -a Python parser, the second is used by `asdl_py.py` to generate Python AST -classes and visitors. All generates files are written into the `lfortran` -module as Python files and once they are generated, this `grammar` directory is -not needed anymore and `lfortran` becomes just a regular Python library that -has all the Python files it needs. diff --git a/grammar/asdl_py.py b/grammar/asdl_py.py deleted file mode 100644 index 7005e47992..0000000000 --- a/grammar/asdl_py.py +++ /dev/null @@ -1,424 +0,0 @@ -""" -Generate AST node definitions from an ASDL description. -""" - -import sys -import os -import asdl - - -class ASDLVisitor(asdl.VisitorBase): - - def __init__(self, stream, data): - super(ASDLVisitor, self).__init__() - self.stream = stream - self.data = data - - def visitModule(self, mod, *args): - for df in mod.dfns: - self.visit(df, *args) - - def visitSum(self, sum, *args): - for tp in sum.types: - self.visit(tp, *args) - - def visitType(self, tp, *args): - self.visit(tp.value, *args) - - def visitProduct(self, prod, *args): - for field in prod.fields: - self.visit(field, *args) - - def visitConstructor(self, cons, *args): - for field in cons.fields: - self.visit(field, *args) - - def visitField(self, field, *args): - pass - - def emit(self, line, level=0): - indent = " "*level - self.stream.write(indent + line + "\n") - - -def is_simple_sum(sum): - """ - Returns true if `sum` is a simple sum. - - Example of a simple sum: - - boolop = And | Or - - Example of not a simple sum: - - type - = Integer(int kind) - | Real(int kind) - - """ - assert isinstance(sum, asdl.Sum) - for constructor in sum.types: - if constructor.fields: - return False - return True - -def attr_to_args(attrs): - args = [] - for attr in attrs: - kw = "" - if attr.type == "int": - if attr.name in ["lineno", "col_offset"]: - kw = "=1" - else: - kw = "=0" - elif attr.type in ["string", "identifier"]: - kw = '=None' - elif attr.seq: - kw = "=[]" - else: - kw = "=None" - args.append(attr.name + kw) - return ", ".join(args) - - -class ASTNodeVisitor(ASDLVisitor): - - def visitType(self, tp): - self.visit(tp.value, tp.name) - - def visitSum(self, sum, base): - if is_simple_sum(sum): - self.emit("class %s(AST): # Sum" % (base,)) - self.emit( "pass", 1) - self.emit("") - self.emit("") - for i, cons in enumerate(sum.types): - self.emit("class %s(%s): # Type" % (cons.name, base)) - self.emit( "pass", 1) - self.emit("") - self.emit("") - else: - self.emit("class %s(AST): # Sum" % (base,)) - if sum.attributes: - self.emit("") - self.emit("def __init__(self, %s):" \ - % attr_to_args(sum.attributes), 1) - for attr in sum.attributes: - self.visit(attr) - self.emit( "self._type = None", 2) - else: - self.emit("pass", 1) - self.emit("") - self.emit("") - for cons in sum.types: - self.visit(cons, base, sum.attributes) - self.emit("") - - def visitProduct(self, product, name): - self.emit("class %s(AST): # Product" % (name,)) - self.emit("") - self._fields = [] - self.make_constructor(product.fields, product) - s = ", ".join(self._fields) - if len(self._fields) == 1: s = s + "," - self.emit("self._fields = (%s)" % s, 2) - self.emit("self._type = None", 2) - self.emit("") - self.emit("def walkabout(self, visitor):", 1) - self.emit("return visitor.visit_%s(self)" % (name,), 2) - self.emit("") - self.emit("") - - def make_constructor(self, fields, node, extras=None, base=None): - if fields or extras: - arg_fields = fields + extras if extras else fields - args = attr_to_args(arg_fields) - self.emit("def __init__(self, %s):" % args, 1) - for field in fields: - self.visit(field) - if extras: - base_args = ", ".join(str(field.name) for field in extras) - self.emit("%s.__init__(self, %s)" % (base, base_args), 2) - else: - self.emit("def __init__(self):", 1) - - def visitConstructor(self, cons, base, extra_attributes): - self.emit("class %s(%s): # Constructor" % (cons.name, base)) - self.emit("") - self._fields = [] - self.make_constructor(cons.fields, cons, extra_attributes, base) - s = ", ".join(self._fields) - if len(self._fields) == 1: s = s + "," - self.emit("self._fields = (%s)" % s, 2) - self.emit("self._type = None", 2) - self.emit("") - self.emit("def walkabout(self, visitor):", 1) - self.emit("return visitor.visit_%s(self)" % (cons.name,), 2) - self.emit("") - self.emit("") - - def visitField(self, field): - self.emit("self.%s = %s" % (field.name, field.name), 2) - if field.seq: - self.emit('assert isinstance(%s, list)' % field.name, 2) - self.emit('for x in %s:' % field.name, 2) - type_ = field.type - if type_ == "string": - type_ = "str" - elif type_ == "identifier": - type_ = "str" - elif type_ == "constant": - type_ = "bool" - elif type_ == "node": - type_ = "AST" - self.emit('checkinstance(x, %s, %r)' % (type_, field.opt), 3) - else: - type_ = field.type - if type_ == "string": - type_ = "str" - elif type_ == "identifier": - type_ = "str" - elif type_ == "constant": - type_ = "bool" - elif type_ == "node": - type_ = "AST" - elif type_ == "symbol_table": - type_ = "object" - self.emit('checkinstance(%s, %s, %r)' % \ - (field.name, type_, field.opt), 2) - self._fields.append("'" + field.name + "'") - - -class ASTVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("class ASTVisitor(object):") - self.emit("") - self.emit( "def visit_sequence(self, seq):", 1) - self.emit( "if seq is not None:", 2) - self.emit( "for node in seq:", 3) - self.emit( "self.visit(node)", 4) - self.emit("") - self.emit( "def visit(self, node):", 1) - self.emit( "return node.walkabout(self)", 2) - self.emit("") - self.emit( "def default_visitor(self, node):", 1) - self.emit( "raise NodeVisitorNotImplemented", 2) - self.emit("") - super(ASTVisitorVisitor, self).visitModule(mod) - self.emit("") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(ASTVisitorVisitor, self).visitType(tp, tp.name) - - def visitProduct(self, prod, name): - self.emit( "def visit_%s(self, node):" % (name,), 1) - self.emit( "return self.default_visitor(node)", 2) - - def visitConstructor(self, cons, _): - self.emit( "def visit_%s(self, node):" % (cons.name,), 1) - self.emit( "return self.default_visitor(node)", 2) - - -class GenericASTVisitorVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("class GenericASTVisitor(ASTVisitor):") - self.emit("") - super(GenericASTVisitorVisitor, self).visitModule(mod) - self.emit("") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(GenericASTVisitorVisitor, self).visitType(tp, tp.name) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - self.emit("def visit_%s(self, node):" % (name,), 1) - have_body = False - for field in fields: - if self.visitField(field): - have_body = True - if not have_body: - self.emit("pass", 2) - self.emit("") - - def visitField(self, field): - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - level = 2 - template = "self.visit(node.%s)" - if field.seq: - template = "self.visit_sequence(node.%s)" - elif field.opt: - self.emit("if node.%s:" % (field.name,), 2) - level = 3 - self.emit(template % (field.name,), level) - return True - return False - - -class NodeTransformerVisitor(ASDLVisitor): - - def visitModule(self, mod): - self.emit("class NodeTransformerBase(ASTVisitor):") - self.emit("") - super(NodeTransformerVisitor, self).visitModule(mod) - self.emit("") - - def visitType(self, tp): - if not (isinstance(tp.value, asdl.Sum) and - is_simple_sum(tp.value)): - super(NodeTransformerVisitor, self).visitType(tp, tp.name) - - def visitProduct(self, prod, name): - self.make_visitor(name, prod.fields) - - def visitConstructor(self, cons, _): - self.make_visitor(cons.name, cons.fields) - - def make_visitor(self, name, fields): - self.emit("def visit_%s(self, node):" % (name,), 1) - parts = [] - for field in fields: - self.visitField(field) - parts.append("%s=%s" % (field.name, field.name)) - self.emit("return %s(%s)" % (name, ", ".join(parts)), 2) - self.emit("") - - def visitField(self, field): - if (field.type not in asdl.builtin_types and - field.type not in self.data.simple_types): - level = 2 - template = "%s = self.visit(node.%s)" - if field.seq: - template = "%s = self.visit_sequence(node.%s)" - elif field.opt: - self.emit("if node.%s:" % (field.name,), 2) - level = 3 - self.emit(template % (field.name, field.name), level) - if field.opt: - self.emit("else:", 2) - self.emit( "%s = None" % field.name, 3) - else: - self.emit( "%s = self.visit_object(node.%s)" % \ - (field.name, field.name), 2) - - -class ASDLData(object): - - def __init__(self, tree): - simple_types = set() - prod_simple = set() - field_masks = {} - required_masks = {} - optional_masks = {} - cons_attributes = {} - def add_masks(fields, node): - required_mask = 0 - optional_mask = 0 - for i, field in enumerate(fields): - flag = 1 << i - if field not in field_masks: - field_masks[field] = flag - else: - assert field_masks[field] == flag - if field.opt: - optional_mask |= flag - else: - required_mask |= flag - required_masks[node] = required_mask - optional_masks[node] = optional_mask - for tp in tree.dfns: - if isinstance(tp.value, asdl.Sum): - sum = tp.value - if is_simple_sum(sum): - simple_types.add(tp.name) - else: - attrs = [field for field in sum.attributes] - for cons in sum.types: - add_masks(attrs + cons.fields, cons) - cons_attributes[cons] = attrs - else: - prod = tp.value - prod_simple.add(tp.name) - add_masks(prod.fields, prod) - prod_simple.update(simple_types) - self.cons_attributes = cons_attributes - self.simple_types = simple_types - self.prod_simple = prod_simple - self.field_masks = field_masks - self.required_masks = required_masks - self.optional_masks = optional_masks - - -HEAD = r"""# Generated by utils/asdl_py.py - -class AST(object): - _attrs_ = ['lineno', 'col_offset'] - - def __init__(self): - self._fields = () - self._type = None - - def walkabout(self, visitor): - raise AssertionError("walkabout() implementation not provided") - - def mutate_over(self, visitor): - raise AssertionError("mutate_over() implementation not provided") - - -class NodeVisitorNotImplemented(Exception): - pass - -def checkinstance(a, b, opt=False): - if opt and a is None: - return - from {} import dump - if not isinstance(a, b): - if isinstance(a, AST): - a_dump = dump(a) - else: - a_dump = a - print("Wrong instance: %s, types: a=%s; b=%s" % (a_dump, type(a), b)) - assert isinstance(a, b) - -""" - -visitors = [ASTNodeVisitor, ASTVisitorVisitor, GenericASTVisitorVisitor, - NodeTransformerVisitor] - - -def main(argv): - if len(argv) == 4: - def_file, out_file, util_import_part = argv[1:] - elif len(argv) == 1: - print("Assuming default values of AST.asdl and ast.py") - here = os.path.dirname(__file__) - def_file = os.path.join(here, "AST.asdl") - out_file = os.path.join(here, "..", "lfortran", "ast", "ast.py") - util_import_part = ".utils" - else: - print("invalid arguments") - return 2 - mod = asdl.parse(def_file) - data = ASDLData(mod) - fp = open(out_file, "w") - try: - fp.write(HEAD.format(util_import_part)) - for visitor in visitors: - visitor(fp, data).visit(mod) - finally: - fp.close() - - -if __name__ == "__main__": - sys.exit(main(sys.argv)) diff --git a/grammar/fortran.g4 b/grammar/fortran.g4 deleted file mode 100644 index f8becd54b0..0000000000 --- a/grammar/fortran.g4 +++ /dev/null @@ -1,553 +0,0 @@ -/* -This is a grammar for a subset of modern Fortran. - -The file is organized in several sections, rules in each section only depend on -the same or further sections, never on the previous sections. As such any -section together with all the subsequent sections form a self-contained -grammar. -*/ - -grammar fortran; - -// ---------------------------------------------------------------------------- -// Top level rules to be used for parsing. -// -// * For compiling files use the 'root' rule: -// * For interactive usage use the 'unit' rule, which allows to parse shorter -// pieces of code, much like Python -// - -root - : (module | program) EOF - ; - -units - : ( NEWLINE* script_unit NEWLINE* (EOF | NEWLINE+ | ';' NEWLINE*))+ EOF - ; - -script_unit - : module - | program - | subroutine - | function - | use_statement - | var_decl - | statement - | expr - ; - -// ---------------------------------------------------------------------------- -// Module definitions -// -// * private/public blocks -// * interface blocks -// - -module - : NEWLINE* KW_MODULE ident NEWLINE+ (use_statement NEWLINE+)* implicit_statement - NEWLINE+ module_decl* contains_block? KW_END KW_MODULE ident? - (EOF | NEWLINE+) - ; - -module_decl - : private_decl - | public_decl - | var_decl - | interface_decl - ; - -private_decl - : KW_PRIVATE '::'? id_list? NEWLINE+ - ; - -public_decl - : KW_PUBLIC '::'? id_list? NEWLINE+ - ; - -interface_decl - : KW_INTERFACE ident NEWLINE+ (KW_MODULE KW_PROCEDURE id_list NEWLINE+)* KW_END KW_INTERFACE ident? NEWLINE+ - ; - -// ---------------------------------------------------------------------------- -// Subroutine/functions/program definitions -// -// * argument lists -// * use statement -// * variable (and arrays) declarations -// -// It turns out that all subroutines, functions and programs have a very similar -// structure. -// - -program - : NEWLINE* KW_PROGRAM ident NEWLINE+ sub_block - KW_PROGRAM? ident? (EOF | NEWLINE+) - ; - -subroutine - : KW_SUBROUTINE ident ('(' id_list? ')')? NEWLINE+ sub_block KW_SUBROUTINE ident? - (EOF | NEWLINE+) - ; - -function - : (var_type ('(' ident ')')?)? KW_PURE? KW_RECURSIVE? - KW_FUNCTION ident ('(' id_list? ')')? (KW_RESULT '(' ident ')')? NEWLINE+ - sub_block KW_FUNCTION ident? (EOF | NEWLINE+) - ; - -sub_block - : (use_statement NEWLINE+)* (implicit_statement NEWLINE+)? var_decl* statements contains_block? KW_END - ; - -contains_block - : KW_CONTAINS NEWLINE+ sub_or_func+ - ; - -sub_or_func - : subroutine | function - ; - -implicit_statement - : KW_IMPLICIT KW_NONE - ; - -use_statement - : KW_USE ident (',' KW_ONLY ':' use_symbol_list)? - ; - -use_symbol_list : use_symbol (',' use_symbol)* ; -use_symbol : ident | ident '=>' ident ; - -id_list : ident (',' ident)* ; - -var_decl - : var_type ('(' (ident '=')? ('*' | ident) ')')? (',' var_modifier)* '::'? var_sym_decl (',' var_sym_decl)* ';'* NEWLINE* - ; - -var_type - : KW_INTEGER | KW_CHAR | KW_REAL | KW_COMPLEX | KW_LOGICAL | KW_TYPE - | KW_CHARACTER - ; - -var_modifier - : KW_PARAMETER | KW_INTENT | KW_DIMENSION array_decl? | KW_ALLOCATABLE | KW_POINTER - | KW_PROTECTED | KW_SAVE | KW_CONTIGUOUS - | KW_INTENT '(' (KW_IN | KW_OUT | KW_INOUT ) ')' - ; - -var_sym_decl - : ident array_decl? ('=' expr)? - ; - -array_decl - : '(' array_comp_decl (',' array_comp_decl)* ')' - ; - -array_comp_decl - : expr - | expr? ':' expr? - ; - - -// ---------------------------------------------------------------------------- -// Control flow: -// -// * statements -// * assignment -// * if/do/where/print/exit statements -// * subroutine calls -// - -statements - : ';'* ( statement (NEWLINE+ | ';' NEWLINE*))* - ; - -statement - : assignment_statement - | exit_statement - | cycle_statement - | return_statement - | subroutine_call - | builtin_statement - | if_statement - | do_statement - | while_statement - | select_statement - | where_statement - | print_statement - | write_statement - | stop_statement - | error_stop_statement - | ';' - ; - -assignment_statement - : expr op=('='|'=>') expr - ; - -exit_statement - : KW_EXIT - ; - -cycle_statement - : KW_CYCLE - ; - -return_statement - : KW_RETURN - ; - -subroutine_call - : KW_CALL struct_member* ident '(' arg_list? ')' - ; - -builtin_statement - : name=(KW_ALLOCATE | KW_OPEN | KW_CLOSE) '(' arg_list? ')' - ; - - -if_statement - : if_cond statement # if_single_line - | if_block KW_END KW_IF # if_multi_line - ; - -if_cond: KW_IF '(' expr ')' ; - -if_block - : if_cond KW_THEN NEWLINE+ statements if_else_block? - ; - -if_else_block - : KW_ELSE (if_block | (NEWLINE+ statements)) - ; - -where_statement - : where_cond statement # where_single_line - | where_block KW_END KW_WHERE # where_multi_line - ; - -where_cond: KW_WHERE '(' expr ')' ; - -where_block - : where_cond NEWLINE+ statements where_else_block? - ; - -where_else_block - : KW_ELSE KW_WHERE? (where_block | (NEWLINE+ statements)) - ; - -do_statement - : KW_DO (ident '=' expr ',' expr (',' expr)?)? NEWLINE+ statements KW_END KW_DO - ; - -while_statement - : KW_DO KW_WHILE '(' expr ')' NEWLINE* statements KW_END KW_DO - ; - -select_statement - : KW_SELECT KW_CASE '(' expr ')' NEWLINE+ case_statement* select_default_statement? KW_END KW_SELECT - ; - -case_statement - : KW_CASE '(' expr ')' NEWLINE+ statements - ; - -select_default_statement - : KW_CASE KW_DEFAULT NEWLINE+ statements - ; - -print_statement - : KW_PRINT ('*' | STRING) ',' expr_list? - ; - -write_statement - : KW_WRITE '(' ('*' | expr) ',' ('*' | STRING) ')' expr_list? - ; - -stop_statement - : KW_STOP STRING? NUMBER? - ; - -error_stop_statement - : KW_ERROR KW_STOP STRING? NUMBER? - ; - - -// ---------------------------------------------------------------------------- -// Fortran expression -// -// * function calls -// * array operations -// * arithmetics -// * numbers/variables/strings/etc. -// * derived types access (e.g. x%a(3)) -// -// Expressions are used in previous sections in the following situations: -// -// * assignments, possibly during declaration (x=1+2) -// * subroutine/function calls (f(1+2, 2*a)) -// * in array dimension declarations (integer :: a(2*n)) -// * in if statement conditions (if (x == y+1) then) -// -// An expression can have any type (e.g. logical, integer, real, string), so -// the allowed usage depends on the actual type (e.g. a dimension of an array -// must be an integer, an if statement condition must be a logical, etc.). -// - -expr_list - : expr (',' expr)* - ; - -/* -expr_fn_call: func call like f(), f(x), f(1,2), but it can also be an array - access -expr_array_call: array index like a(i), a(i, :, 3:) -expr_array_const: arrays like [1, 2, 3, x] -*/ -expr -// ### primary - : struct_member* ident '(' arg_list? ')' # expr_fn_call - | struct_member* ident '(' array_index_list ')' # expr_array_call - | '[' expr_list ']' # expr_array_const - | struct_member* ident # expr_id - | number # expr_number - | op=('.true.' | '.false.') # expr_truefalse - | STRING # expr_string - | '(' expr ')' # expr_nest // E.g. (1+2)*3 - -// ### level-1 - -// ### level-2 - | expr '**' expr # expr_pow - | expr op=('*'|'/') expr # expr_muldiv - | op=('+'|'-') expr # expr_unary - | expr op=('+'|'-') expr # expr_addsub - -// ### level-3 - | expr '//' expr # expr_string_conc - -// ### level-4 - | expr op=('<'|'<='|'=='|'/='|'>='|'>' | '.lt.'|'.le.'|'.eq.'|'.neq.'|'.ge.'|'.gt.') expr # expr_rel - -// ### level-5 - | '.not.' expr # expr_not - | expr '.and.' expr # expr_and - | expr '.or.' expr # expr_or - | expr op=('.eqv.'|'.neqv') expr # expr_eqv - ; - -arg_list - : arg (',' arg)* - ; - -arg - : expr - | ident '=' expr - ; - -array_index_list - : array_index (',' array_index)* - ; - -array_index - : expr # array_index_simple - | expr? ':' expr? # array_index_slice - ; - -struct_member: ident '%' ; - -number - : NUMBER # number_real // Real number - | '(' NUMBER ',' NUMBER ')' # number_complex // Complex number - ; - -ident - : ID - | KW_ALLOCATABLE - | KW_ALLOCATE - | KW_CALL - | KW_CASE - | KW_CHAR - | KW_CHARACTER - | KW_CLOSE - | KW_COMPLEX - | KW_CONTAINS - | KW_CONTIGUOUS - | KW_CYCLE - | KW_DEFAULT - | KW_DIMENSION - | KW_DO - | KW_ELSE - | KW_END - | KW_ERROR - | KW_EXIT - | KW_FUNCTION - | KW_IF - | KW_IMPLICIT - | KW_IN - | KW_INOUT - | KW_INTEGER - | KW_INTERFACE - | KW_INTENT - | KW_LOGICAL - | KW_MODULE - | KW_NONE - | KW_ONLY - | KW_OPEN - | KW_OUT - | KW_PARAMETER - | KW_POINTER - | KW_PRINT - | KW_PRIVATE - | KW_PROCEDURE - | KW_PROGRAM - | KW_PROTECTED - | KW_PUBLIC - | KW_PURE - | KW_REAL - | KW_RECURSIVE - | KW_RESULT - | KW_RETURN - | KW_SAVE - | KW_SELECT - | KW_STOP - | KW_SUBROUTINE - | KW_THEN - | KW_TYPE - | KW_USE - | KW_WHERE - | KW_WHILE - | KW_WRITE - ; - -// ---------------------------------------------------------------------------- -// Lexer -// -// * numbers -// * identifiers (variables/arguments/function calls) -// * strings -// * comments -// * white space / end of lines -// -// Besides the explicit tokens below (in uppercase), there are implicit tokens -// above in quotes, such as '.true.', 'exit', '*', '(', etc. Those all together -// form the tokens and are saved into `fortranLexer.tokens`. -// - -// Keywords - -fragment A : [aA] ; -fragment B : [bB] ; -fragment C : [cC] ; -fragment D : [dD] ; -fragment E : [eE] ; -fragment F : [fF] ; -fragment G : [gG] ; -fragment H : [hH] ; -fragment I : [iI] ; -fragment J : [jJ] ; -fragment K : [kK] ; -fragment L : [lL] ; -fragment M : [mM] ; -fragment N : [nN] ; -fragment O : [oO] ; -fragment P : [pP] ; -fragment Q : [qQ] ; -fragment R : [rR] ; -fragment S : [sS] ; -fragment T : [tT] ; -fragment U : [uU] ; -fragment V : [vV] ; -fragment W : [wW] ; -fragment X : [xX] ; -fragment Y : [yY] ; -fragment Z : [zZ] ; - -KW_ALLOCATABLE: A L L O C A T A B L E; -KW_ALLOCATE: A L L O C A T E; -KW_CALL: C A L L; -KW_CASE: C A S E; -KW_CHAR: C H A R; -KW_CHARACTER: C H A R A C T E R; -KW_CLOSE: C L O S E; -KW_COMPLEX: C O M P L E X; -KW_CONTAINS: C O N T A I N S; -KW_CONTIGUOUS: C O N T I G U O U S; -KW_CYCLE: C Y C L E; -KW_DEFAULT: D E F A U L T; -KW_DIMENSION: D I M E N S I O N; -KW_DO: D O; -KW_ELSE: E L S E; -KW_END: E N D; -KW_ERROR: E R R O R; -KW_EXIT: E X I T; -KW_FUNCTION: F U N C T I O N; -KW_IF: I F; -KW_IMPLICIT: I M P L I C I T; -KW_IN: I N; -KW_INOUT: I N O U T; -KW_INTEGER: I N T E G E R; -KW_INTERFACE: I N T E R F A C E; -KW_INTENT: I N T E N T; -KW_LOGICAL: L O G I C A L; -KW_MODULE: M O D U L E; -KW_NONE: N O N E; -KW_ONLY: O N L Y; -KW_OPEN: O P E N; -KW_OUT: O U T; -KW_PARAMETER: P A R A M E T E R; -KW_POINTER: P O I N T E R; -KW_PRINT: P R I N T; -KW_PRIVATE: P R I V A T E; -KW_PROCEDURE: P R O C E D U R E; -KW_PROGRAM: P R O G R A M ; -KW_PROTECTED: P R O T E C T E D; -KW_PUBLIC: P U B L I C; -KW_PURE: P U R E; -KW_REAL: R E A L; -KW_RECURSIVE: R E C U R S I V E; -KW_RESULT: R E S U L T; -KW_RETURN: R E T U R N; -KW_SAVE: S A V E; -KW_SELECT: S E L E C T; -KW_STOP: S T O P; -KW_SUBROUTINE: S U B R O U T I N E; -KW_THEN: T H E N; -KW_TYPE: T Y P E; -KW_USE: U S E; -KW_WHERE: W H E R E; -KW_WHILE: W H I L E; -KW_WRITE: W R I T E; - - -NUMBER - : ([0-9]+ '.' [0-9]* | '.' [0-9]+) EXP? NTYP? - | [0-9]+ EXP? NTYP? - ; - -fragment EXP : [eEdD] [+-]? [0-9]+ ; -fragment NTYP : '_' ID ; - -ID - : ('a' .. 'z' | 'A' .. 'Z') ('a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_')* - ; - -STRING - : '"' ('""'|~'"')* '"' - | '\'' ('\'\''|~'\'')* '\'' - ; - -COMMENT - : '!' ~[\r\n]* -> skip; - -LINE_CONTINUATION - : '&' WS* COMMENT? NEWLINE -> skip - ; - -NEWLINE - : '\r'? '\n' - ; - -WS - : [ \t] -> skip - ; \ No newline at end of file diff --git a/lfort b/lfort deleted file mode 100755 index 6809a750f3..0000000000 --- a/lfort +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python - -from lfortran.cli import main - -if __name__ == "__main__": - main() diff --git a/lfortran/__init__.py b/lfortran/__init__.py deleted file mode 100644 index 525264b8a6..0000000000 --- a/lfortran/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .ast.utils import src_to_ast -from .ast.ast_to_src import ast_to_src -from .semantic.ast_to_asr import ast_to_asr -from .asr.asr_to_ast import asr_to_ast diff --git a/lfortran/adapters/__init__.py b/lfortran/adapters/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/adapters/gfortran/__init__.py b/lfortran/adapters/gfortran/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/adapters/gfortran/mod.py b/lfortran/adapters/gfortran/mod.py deleted file mode 100644 index 893bfc604f..0000000000 --- a/lfortran/adapters/gfortran/mod.py +++ /dev/null @@ -1,519 +0,0 @@ -""" -# Module for parsing GFortran module files. - -## Usage: - -Load the module file using: - ->>> version, orig_filename, symtab, public_symbols = load_module("filename.mod") - -The `symtab` will contain the symbol table, `public_symbols` contains the list -of module symbols that are public, `orig_filename` is the name of the original -Fortran module source code (e.g., "filename.f90") and `version` is the GFortran -module version (e.g., 14). - -## Design Motivation - -This module is self-contained, it does not depend on the rest of LFortran. It -parses the GFortran module file into a representation with the following -properties: - -* It contains all the information from the original GFortran module file - (nothing got lost), so that in principle the original file can be - reconstructed (the only thing lost would be white space and the order of the - symbols). - -* It is as simple as possible: it does not contain any additional - information that could be inferred. - -* Implemented using natural Python datastructures/syntax: it uses a Python - dicitonary, lists and namedtuples to store the data. - -In this sense it an abstract representation of the module file that is suitable -as the basis for any tools that need to work with the GFortran module file. - -## Details - -The symbol table `symtab` is a dictionary, with keys being the symbol index -(number). The following symbol types are permitted: Procedure, Variable, Module. -Each is represented by a namedtuple. Procedure and Variable have some common -fields: - -* name: name of the symbol -* mod: which module it belongs to -* type: type of the symbol - -Procedure has `args` and `return_sym` fields, which contain VarIdx namedtuples. -Each variable is uniquely indentified by its symbol index, which can be used to -look it up in the `symtab` dictionary. The VarIdx namedtuple represents this -symbol index. - -If the variable is an array, then the `bounds` field is not None and it -contains the lower and upper bound for each dimension (as lists of lists). If -the upper bound is None, it is an assumed-shape array, otherwise it is an -explicit-shape array. The array bound can be an integer (represented by the -Integer namedtuple), or it can be a variable (represented by VarIdx) or an -expression (represented by Expr). - -The `public_symbols` variable contains the list of public module symbols, -represented by the PublicSymbol namedtuple. - - -Update: Use the `mod_to_asr()` function that returns LFortran's ASR directly. -That way all the semantics is already in the (verified) ASR, and one can use -all the tooling around ASR right away without needing to learn about some -internal representation in this module that is specific to GFortran. - -## GFortran ABI - -GFortran ABI is stable for a given GFortran module file version. The module -file version stays the same between releases (4.5.0 and 4.5.2), but usually -changes between minor versions (4.5 vs. 4.6). Here is a correspondence of -GFortran compiler versions and GFortran module file versions: - -GFortran version module file version ---------------------------------------- -<= 4.3 unversioned -4.4 (Apr 2009) 0 -4.5 (Apr 2010) 4 -4.6 (Mar 2011) 6 -4.7 (Mar 2012) 9 -4.8 (Mar 2013) 10 -4.9 (Apr 2014) 12 -5.x (Apr 2015) 14 -6.x (Apr 2016) 14 -7.x (May 2017) 14 -8.x (May 2018) 15 -9.x (??? 2019) ?? - -The GFortran array descriptor is defined in libgfortran.h. -Module file version 15: - -https://github.com/gcc-mirror/gcc/blob/gcc-8_1_0-release/libgfortran/libgfortran.h#L324 - - typedef struct descriptor_dimension - { - index_type _stride; - index_type lower_bound; - index_type _ubound; - } - descriptor_dimension; - - typedef struct dtype_type - { - size_t elem_len; - int version; - signed char rank; - signed char type; - signed short attribute; - } - dtype_type; - - #define GFC_FULL_ARRAY_DESCRIPTOR(r, type) \ - struct {\ - type *base_addr;\ - size_t offset;\ - dtype_type dtype;\ - index_type span;\ - descriptor_dimension dim[r];\ - } - -Module file versions 0..14 (changes from 15: no `span` member, `dtype` is -an integer instead of a struct): - -https://github.com/gcc-mirror/gcc/blob/gcc-7_1_0-release/libgfortran/libgfortran.h#L328 -https://github.com/gcc-mirror/gcc/blob/gcc-4_4_0-release/libgfortran/libgfortran.h#L298 - - typedef struct descriptor_dimension - { - index_type _stride; - index_type lower_bound; - index_type _ubound; - } - descriptor_dimension; - - #define GFC_ARRAY_DESCRIPTOR(r, type) \ - struct {\ - type *base_addr;\ - size_t offset;\ - index_type dtype;\ - descriptor_dimension dim[r];\ - } - -Then there is the CFI array descriptor from ISO_Fortran_binding.h: - -https://github.com/gcc-mirror/gcc/blob/c3ce5d657bac95a3ac5c0457ac48b47a9710c838/libgfortran/ISO_Fortran_binding.h#L69 - - typedef struct CFI_dim_t - { - CFI_index_t lower_bound; - CFI_index_t extent; - CFI_index_t sm; - } - CFI_dim_t; - - #define CFI_CDESC_TYPE_T(r, base_type) \ - struct { \ - base_type *base_addr; \ - size_t elem_len; \ - int version; \ - CFI_rank_t rank; \ - CFI_attribute_t attribute; \ - CFI_type_t type; \ - CFI_dim_t dim[r]; \ - } - -GFortran then converts between its own array descriptor and the CFI -descriptor, for example here is the code that converts from CFI to -GFortran: - -https://github.com/gcc-mirror/gcc/blob/c3ce5d657bac95a3ac5c0457ac48b47a9710c838/libgfortran/runtime/ISO_Fortran_binding.c#L37 - -""" - -from collections import namedtuple -import gzip - -from lfortran.asr import asr -from lfortran.asr.asr_check import verify_asr -from lfortran.asr.builder import (make_translation_unit, - translation_unit_make_module, scope_add_function, make_type_integer, - make_type_real, type_eq, make_binop, scope_add_symbol) - - -def string_to_type(stype, kind=None): - """ - Converts a string `stype` and a numerical `kind` to an ASR type. - """ - if stype == "integer": - return make_type_integer(kind) - elif stype == "real": - return make_type_real(kind) - elif stype == "complex": - raise NotImplementedError("Complex not implemented") - elif stype == "character": - raise NotImplementedError("Complex not implemented") - elif stype == "logical": - raise NotImplementedError("Complex not implemented") - raise Exception("Unknown type") - -def tofortran_bound(symtab, lscope, b): - if isinstance(b, Integer): - return asr.Num(n=b.i, type=make_type_integer()) - elif isinstance(b, VarIdx): - v = symtab[b.idx] - w = lscope.resolve(v.name) - assert type_eq(w.type, string_to_type(v.type)) - return w - raise NotImplementedError("Unsupported bound type") - -def convert_arg(table, lscope, idx): - arg = table[idx] - assert isinstance(arg.name, str) - assert isinstance(arg.type, str) - a = asr.VariableOld(name=arg.name, type=string_to_type(arg.type), dummy=True) - assert isinstance(arg.intent, str) - a.intent = arg.intent - - if arg.bounds: - dims = [] - for bound in arg.bounds: - lb, ub = bound - if lb: - lb = tofortran_bound(table, lscope, lb) - if ub: - ub = tofortran_bound(table, lscope, ub) - dims.append(asr.dimension(lb, ub)) - a.type.dims = dims - return a - -def convert_function(symtab, table, f): - assert isinstance(f, Procedure) - assert isinstance(f.name, str) - assert isinstance(f.type, str) - return_var = asr.VariableOld(name=f.name, type=string_to_type(f.type)) - lf = scope_add_function(symtab, f.name, return_var=return_var) - args = [] - for arg in f.args: - assert isinstance(arg, VarIdx) - larg = convert_arg(table, lf.symtab, arg.idx) - scope_add_symbol(lf.symtab, larg) - args.append(larg) - lf.args = args - -def convert_module(table, public_symbols): - # Determine the module name - module_name = None - for sym in public_symbols: - s = table[sym.idx.idx] - if isinstance(s, Module): - # Skip modules if they are listed in public symbols - continue - assert isinstance(s, Procedure) - if module_name: - assert module_name == s.mod - else: - module_name = s.mod - - - u = make_translation_unit() - m = translation_unit_make_module(u, module_name) - - # Convert functions - for sym in public_symbols: - s = table[sym.idx.idx] - if isinstance(s, Module): - continue - assert isinstance(s, Procedure) - convert_function(m.symtab, table, s) - - return u - - - - -class GFortranModuleParseError(Exception): - pass - -Module = namedtuple("Module", ["name"]) -Procedure = namedtuple("Procedure", ["name", "mod", "type", "args", - "return_sym"]) -Variable = namedtuple("Variable", ["name", "mod", "type", "bounds", - "dummy", "intent"]) - -VarIdx = namedtuple("VarIdx", ["idx"]) - -Integer = namedtuple("Integer", ["i"]) -Expr = namedtuple("Expr", []) - -PublicSymbol = namedtuple("PublicSymbol", ["name", "ambiguous_flag", - "idx"]) - -def str_(s): - if not (isinstance(s, str) and len(s) >= 2 and s[0] == "'" and \ - s[-1] == "'"): - raise GFortranModuleParseError("Invalid string") - return s[1:-1] - -def parse_type(t): - if t[0] == "INTEGER": - type_ = "integer" - else: - raise GFortranModuleParseError("Type not implemented") - return type_ - -def parse_bound(b): - if len(b) == 0: - return None - if b[0] == "CONSTANT": - type_ = parse_type(b[1]) - val = str_(b[3]) - if type_ == "integer": - return Integer(i=int(val)) - else: - raise GFortranModuleParseError("Unsupported constant type") - elif b[0] == "VARIABLE": - var_index = b[3] - return VarIdx(idx=var_index) - elif b[0] == "OP": - return Expr() - raise GFortranModuleParseError("Unsupported bound type") - -def parse_symbol(name, mod, info): - sym_info, _, sym_type, _, _, dummy_args, sym_array, return_sym, \ - _, _, _, _ = info - if sym_info[0] == "VARIABLE": - if sym_array: - ndim, _, atype = sym_array[:3] - bounds = sym_array[3:] - if len(bounds) != 2*ndim: - raise GFortranModuleParseError("number of bounds not equal to " - "2*ndim") - bounds2 = [] - for i in range(ndim): - lb = parse_bound(bounds[2*i]) - ub = parse_bound(bounds[2*i+1]) - bounds2.append([lb, ub]) - assert len(bounds2) == ndim - if atype == "ASSUMED_SHAPE": - for b in bounds2: - if b[1] is not None: - raise GFortranModuleParseError("Assumed shape upper " - "bound must be None") - elif atype == "EXPLICIT": - for b in bounds2: - if b[1] is None: - raise GFortranModuleParseError("Explicit shape upper " - "bound must not be None") - else: - bounds2 = None - if "DIMENSION" in sym_info: - assert bounds2 - if sym_info[1] == "IN": - intent = "in" - elif sym_info[1] == "OUT": - intent = "out" - elif sym_info[1] == "UNKNOWN-INTENT": - intent = None - else: - raise GFortranModuleParseError("Unknown intent") - v = Variable( - name=name, - mod=mod, - type=parse_type(sym_type), - bounds=bounds2, - dummy="DUMMY" in sym_info, - intent=intent - ) - return v - elif sym_info[0] == "PROCEDURE": - assert not sym_array - if return_sym: - return_sym = VarIdx(idx=return_sym) - p = Procedure( - name=name, - mod=mod, - type=parse_type(sym_type), - args=[VarIdx(idx=x) for x in dummy_args], - return_sym=return_sym - ) - return p - elif sym_info[0] == "MODULE": - m = Module(name=name) - return m - else: - print(sym_info) - raise GFortranModuleParseError("Unknown symbol") - -#------------------------------------------------------------------------------- -# -# The following four functions were originally taken from: -# http://norvig.com/lispy.html -# https://github.com/norvig/pytudes/blob/6b430d707dfdbb80eba44813263cde504a68d419/py/lis.py -# They are licensed under an MIT license. -# -# Copyright (c) 2010-2017 Peter Norvig -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -def parse(program): - "Read a Lisp expression from a string." - return read_from_tokens(tokenize(program)) - -def tokenize(s): - "Convert a string into a list of tokens." - return s.replace('(',' ( ').replace(')',' ) ').split() - -def read_from_tokens(tokens): - "Read an expression from a sequence of tokens." - if len(tokens) == 0: - raise SyntaxError('unexpected EOF while reading') - token = tokens.pop(0) - if '(' == token: - L = [] - while tokens[0] != ')': - L.append(read_from_tokens(tokens)) - tokens.pop(0) # pop off ')' - return L - elif ')' == token: - raise SyntaxError('unexpected )') - else: - return atom(token) - -def atom(token): - "Ints become ints; every other token is a str." - try: - return int(token) - except ValueError: - return str(token) - -#------------------------------------------------------------------------------- - - -def load_module(filename): - """ - Loads the gfortran module 'filename' and parses the data. - - The high level structure of the file as documented at [1] is parsed and the - lisp syntax is transformed into lists of lists. - - Returns: - - version ..... gfortran module version - orig_file ... the original Fortran file that produced the module - symtab ...... the symbol table - symtree ..... list of public symbols in the module - - The symbol table `symtab` is transformed into a dictionary, the key is the - symbol number and the value is a particular named tuple, containing the - details about the symbol. - - The list of public symbols `symtree` is a list of PublicSymbol named tuples - containing the name, ambiguous flag and the symbol index (into `symtab`). - - Documentation for GFortran module files: - [1] https://github.com/gcc-mirror/gcc/blob/898c6fe1170c03ca9f469ffa3565342942e96049/gcc/fortran/module.c#L22 - - """ - with gzip.open(filename) as f: - x = f.read().decode() - lines = x.split("\n") - header = lines[0] - body = "(" + "\n".join(lines[1:]) + ")" - h = header.split() - if not h[0] == "GFORTRAN": - raise GFortranModuleParseError("Not a GFortran module file") - version = int(str_(h[3])) - orig_file = h[-1] - if version == 14: - p = parse(body) - if len(p) != 8: - raise GFortranModuleParseError("Wrong number of items") - _, _, _, _, _, _, symtab, symtree = p - # Shape symtab into groups of 6 - if len(symtab) % 6 != 0: - raise GFortranModuleParseError("symtab not multiple of 3") - symtab = list(zip(*[iter(symtab)]*6)) - # Create a dictionary based on the index (first element in each group) - symtab_dict = {} - for s in symtab: - symbol_number, symbol_name, module_name, _, _, symbol_info = s - assert isinstance(symbol_number, int) - assert symbol_number not in symtab_dict - symtab_dict[symbol_number] = parse_symbol(str_(symbol_name), - str_(module_name), symbol_info) - # Shape symtree into groups of 3 - if len(symtree) % 3 != 0: - raise GFortranModuleParseError("symtree not multiple of 3") - symtree = list(zip(*[iter(symtree)]*3)) - # Transform into a list of namedtuples - symtree_list = [] - for s in symtree: - symtree_list.append(PublicSymbol(str_(s[0]), s[1], - VarIdx(idx=s[2]))) - return version, orig_file, symtab_dict, symtree_list - else: - raise GFortranModuleParseError("Unsupported version") - -def mod_to_asr(filename): - version, orig_file, table, public_symbols = load_module(filename) - u = convert_module(table, public_symbols) - verify_asr(u) - return u diff --git a/lfortran/asr/__init__.py b/lfortran/asr/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/asr/asr_check.py b/lfortran/asr/asr_check.py deleted file mode 100644 index 4ccf5cdabb..0000000000 --- a/lfortran/asr/asr_check.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -# ASR Check - -This goes over the whole ASR and checks that all requirements are met: - -* It is a valid Fortran code -* All additional internal consistency requirements are satisfied - -This is not meant to report nice user errors, this is only meant to be run in -Debug mode to ensure that LFortran always constructs ASR in the correct form. - -If one *knows* (by checking in Debug mode) that a given algorithm constructs -ASR in the correct form, then one can construct ASR directly using the -classes in the `asr.asr` module. Otherwise one should use the `asr.builder` -module, which will always construct ASR in the correct form, or report a nice -error (that can then be forwarded to the user by LFortran) even in both Debug -and Release modes. The `asr.builder` is built to be robust and handle any -(valid or invalid) input. - -The semantic phase then traverses the AST and uses `asr.builder` to construct -ASR. Thus the `asr.builder` does most of the semantic checks for the semantic -analyzer (which only forwards the errors to the user), thus greatly simplifying -the semantic part of the compiler. - -The hard work of doing semantic checks is encoded in the ASR module, which -does not depend on the rest of LFortran and can be used, verified and -improved independently. -""" - -from . import asr - -class SemanticError(Exception): - pass - -class UndeclaredVariableError(SemanticError): - pass - -class TypeMismatch(SemanticError): - pass - - -class ASRVerifyVisitor(asr.ASTVisitor): - - def visit_TranslationUnit(self, node): - for s in node.global_scope.symbols: - sym = node.global_scope.symbols[s] - self.visit(sym) - - def visit_Module(self, node): - for s in node.symtab.symbols: - sym = node.symtab.symbols[s] - self.visit(sym) - - def visit_Function(self, node): - def var_in_symtab(v, symtab): - assert isinstance(v, asr.VariableOld) - assert v.name in symtab.symbols - assert v == symtab.symbols[v.name] - def check_bound(b): - if b is None: - pass - elif isinstance(b, asr.Num): - assert isinstance(b.type, asr.Integer) - elif isinstance(b, asr.VariableOld): - var_in_symtab(b, node.symtab) - else: - raise NotImplementedError() - for arg in node.args: - var_in_symtab(arg, node.symtab) - assert arg.dummy == True - for d in arg.type.dims: - # After #55 is fixed, this will be checked by ASR itself, - # or by calling a check() method - assert isinstance(d, asr.dimension) - lb, ub = d.start, d.end - check_bound(lb) - check_bound(ub) - assert isinstance(node.return_var, asr.VariableOld) - assert node.return_var.name in node.symtab.symbols - assert node.return_var.dummy == True - assert node.return_var.intent is None - - def visit_VariableOld(self, node): - pass - - -def verify_asr(asr): - """ - Verifies the ASR. - - Before this function is called, the ASR nodes are mutable and one can - construct ASR piece by piece, filling in more information as it becomes - available. However, once verify_asr() is called, the nodes are considered - correct and immutable; the rest of the code can depend on it. - """ - v = ASRVerifyVisitor() - return v.visit(asr) diff --git a/lfortran/asr/asr_to_ast.py b/lfortran/asr/asr_to_ast.py deleted file mode 100644 index db534911d4..0000000000 --- a/lfortran/asr/asr_to_ast.py +++ /dev/null @@ -1,189 +0,0 @@ -from ..ast import ast -from . import asr -from ..semantic import kinds - -class ASR2ASTVisitor(asr.ASTVisitor): - - def visit_sequence(self, seq): - r = [] - if seq is not None: - for node in seq: - r.append(self.visit(node)) - return r - - def visit_TranslationUnit(self, node): - decl = [] - items = [] - for s in node.global_scope.symbols: - sym = node.global_scope.symbols[s] - if isinstance(sym, asr.VariableOld): - stype = self.visit(sym.type) - decl.append(ast.Declaration(vars=[ - ast.decl(sym=sym.name, sym_type=stype)])) - else: - items.append(self.visit(sym)) - for item in node.items: - items.append(self.visit(item)) - return ast.TranslationUnit(items=decl+items) - - for s in node.symtab.symbols: - sym = node.symtab.symbols[s] - if sym.dummy: - continue - stype = self.visit(sym.type) - decl.append(ast.Declaration(vars=[ - ast.decl(sym=sym.name, sym_type=stype)])) - - def visit_Module(self, node): - decl = [] - contains = [] - for s in node.symtab.symbols: - sym = node.symtab.symbols[s] - if isinstance(sym, asr.Function): - if sym.body: - contains.append(self.visit(sym)) - else: - decl.append( - ast.Interface2(procs=[self.visit(sym)]) - ) - else: - raise NotImplementedError() - return ast.Module(name=node.name, decl=decl, contains=contains) - - def visit_Assignment(self, node): - target = self.visit(node.target) - value = self.visit(node.value) - return ast.Assignment(target, value) - - def visit_BinOp(self, node): - left = self.visit(node.left) - right = self.visit(node.right) - if isinstance(node.op, asr.Add): - op = ast.Add() - elif isinstance(node.op, asr.Mul): - op = ast.Mul() - else: - raise NotImplementedError() - return ast.BinOp(left, op, right) - - def visit_VariableOld(self, node): - return ast.Name(id=node.name) - - def visit_Num(self, node): - return ast.Num(n=node.n) - - def visit_Integer(self, node): - if node.kind == kinds.int32: - return "integer" - else: - return "integer(kind=%d)" % node.kind - - def visit_Derived(self, node): - return "type(%s)" % node.name - - def visit_Function(self, node): - body = self.visit_sequence(node.body) - args = [] - decl = [] - use = [] - for arg in node.args: - args.append(ast.arg(arg=arg.name)) - stype = self.visit(arg.type) - attrs = [] - if arg.intent: - attrs = [ - ast.Attribute(name="intent", - args=[ast.attribute_arg(arg=arg.intent)]), - ] - dims = [] - for d in arg.type.dims: - lb, ub = d.start, d.end - assert lb is not None - if isinstance(lb, asr.Num) \ - and isinstance(lb.type, asr.Integer) \ - and lb.n == 1: - # 1 is the default for lower bound, no need to specify - # explicitly - lb = None - else: - lb = self.visit(lb) - if ub: - ub = self.visit(ub) - dims.append(ast.dimension(lb, ub)) - if isinstance(arg.type, asr.Derived): - if arg.type.module: - use.append( - ast.Use( - module=arg.type.module, - symbols=[] - ) - ) - decl.append(ast.Declaration(vars=[ - ast.decl(sym=arg.name, sym_type=stype, - attrs=attrs, dims=dims)])) - for s in node.symtab.symbols: - sym = node.symtab.symbols[s] - if isinstance(sym, asr.VariableOld): - if sym.dummy: - continue - stype = self.visit(sym.type) - decl.append(ast.Declaration(vars=[ - ast.decl(sym=sym.name, sym_type=stype)])) - elif isinstance(sym, asr.Function): - if sym.body: - raise NotImplementedError("Nested functions") - else: - if sym.module: - use.append( - ast.Use( - module=sym.module, - symbols=[] - ) - ) - else: - decl.append( - ast.Interface2( - name="", - procs=[ - self.visit(sym) - ], - ) - ) - else: - raise NotImplementedError() - return_type = self.visit(node.return_var.type) - if node.return_var.name == node.name: - return_var = None - else: - return_var = self.visit(node.return_var) - if node.bind: - bind_args = [] - if node.bind.lang != "": - bind_args.append(ast.keyword( - arg=None, - value=ast.Name(id=node.bind.lang) - )) - if node.bind.name != "": - bind_args.append(ast.keyword( - arg="name", - value=ast.Str(s=node.bind.name) - )) - bind = ast.Bind(args=bind_args) - else: - bind = None - return ast.Function( - name=node.name, args=args, return_type=return_type, - return_var=return_var, bind=bind, - decl=decl, body=body, use=use) - - def visit_FuncCall(self, node): - return ast.FuncCall( - func=node.func.name, - args=self.visit_sequence(node.args), - keywords=[] - ) - - -def asr_to_ast(a): - v = ASR2ASTVisitor() - return v.visit(a) diff --git a/lfortran/asr/builder.py b/lfortran/asr/builder.py deleted file mode 100644 index c5b1777363..0000000000 --- a/lfortran/asr/builder.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -# ASR Builder - -Using the ASR builder has the following advantages over constructing the ASR -directly: - -* The ASR is constructed correctly, or a nice error is given -* Is easier to use, for example it handles the scoped symbol table - automatically -* The API is natural to be used in the semantic analyzer, making its AST - visitor as simple as possible (by handling many things automatically) - -## TODO - -* Add asr.FunctionType: The FunctionType will not have a symbol table, but will - have a list of arguments as Variables. FunctionType has a name associated - with it --- this will either be the name used in the `procedure(some_name)` - declaration, or as a function name if used in Function(..). - -* Rename FunctionBuilder() to FunctionTypeBuilder(), and once build, the - symbol table will have an asr.FunctionType() instance. - -* the asr.Function will just be asr.Function(FunctionType(), Body()), the name - of the function is stored in FunctionType. - -* asr.Function will have a symbol table, but asr.FunctionSignature() will not - -* Add a VariableBuilder to construct Variable field by field, and it's - VariableBuilder.finalize() method will be called from - FunctionTypeBuilder.finalize() - -Function call will simply reference the symbol table which has a FunctionType -symbol. - -## Immutability - -All ASR classes are mutable when constructing them. One is free to create just -asr.Variable() and populate it later. Then one calls "verify_asr()", everything -gets checked and error reported. After that, all classes are immutable. - -""" - -from . import asr -from .asr_check import TypeMismatch -from ..semantic.analyze import Scope -from ..semantic import kinds - - -def scope_add_symbol(scope, v): - scope.symbols[v.name] = v - v.scope = scope - -def make_type_integer(kind=None): - if not kind: - kind = kinds.int32 - return asr.Integer(kind=kind) - -def make_type_real(kind=None): - if not kind: - kind = kinds.real32 - return asr.Real(kind=kind) - -def type_eq(type1, type2): - if isinstance(type1, asr.ttype) and isinstance(type2, asr.ttype): - if type(type1) != type(type2): - return False - return type1.kind == type2.kind - # TODO: implement other types comparisons here. In the meantime return - # False: - return False - -def array_is_assumed_shape(type): - if type.dims: - if type.dims[-1].end is None: - return True - return False - -def make_translation_unit(): - return asr.TranslationUnit(global_scope=Scope()) - -def translation_unit_make_module(unit, name): - module_scope = Scope(unit.global_scope) - m = asr.Module(name=name, symtab=module_scope) - scope_add_symbol(unit.global_scope, m) - return m - -def scope_add_function(scope, name, args=[], return_var=None, body=None, - module=None): - assert isinstance(scope, Scope) - parent_scope = scope - function_scope = Scope(parent_scope) - args_ = [] - for arg in args: - if isinstance(arg, str): - arg = asr.VariableOld(name=arg, type=make_type_integer()) - arg.dummy = True - scope_add_symbol(function_scope, arg) - args_.append(arg) - if return_var: - if isinstance(return_var, str): - return_var = asr.VariableOld(name=return_var, type=make_type_integer()) - return_var.dummy = True - scope_add_symbol(function_scope, return_var) - if body is None: - # TODO: body=None should mean no body, and body=[] an empty body - body = [] - f = asr.Function(name=name, symtab=function_scope, - args=args_, return_var=return_var, body=body, module=module) - scope_add_symbol(parent_scope, f) - return f - -def function_make_var(fn, name, type): - v = asr.VariableOld(name=name, dummy=False, type=type) - scope_add_symbol(fn.symtab, v) - return v - -def make_binop(left, op, right): - if type_eq(left.type, right.type): - type = left.type - else: - print(left.type) - print(right.type) - raise TypeMismatch("Type mismatch") - # TODO: add explicit type casting nodes here - return asr.BinOp(left=left, op=op, right=right, type=type) diff --git a/lfortran/asr/pprint.py b/lfortran/asr/pprint.py deleted file mode 100644 index cef5174ae1..0000000000 --- a/lfortran/asr/pprint.py +++ /dev/null @@ -1,44 +0,0 @@ -from lfortran.asr import asr -from lfortran.ast.utils import fmt, iter_fields, make_tree -from lfortran.semantic.analyze import Scope - -def pprint_asr(asr): - print(pprint_asr_str(asr)) - -def pprint_asr_str(node, color=True): - def _format(node, print_scope=False): - if isinstance(node, asr.AST): - t = node.__class__.__bases__[0] - if isinstance(node, asr.VariableOld) and not print_scope: - return fmt("%s" % node.name) - if issubclass(t, asr.AST): - root = t.__name__ + "." - else: - root = "" - root += node.__class__.__name__ - if color: - root = fmt("%s" % root) - children = [] - for a, b in iter_fields(node): - if isinstance(b, list): - if len(b) == 0: - children.append(make_tree(a + "=[]", [], color)) - else: - children.append(make_tree(a + "=↓", - [_format(x) for x in b], color)) - else: - children.append(a + "=" + _format(b)) - return make_tree(root, children, color) - elif isinstance(node, Scope): - root = "Scope" - children = [] - for k, v in node.symbols.items(): - children.append("%s = %s" % (k, _format(v, print_scope=True))) - return make_tree(root, children, color) - r = repr(node) - if color: - r = fmt("%s" % r) - return r - if not isinstance(node, asr.AST): - raise TypeError('expected AST, got %r' % node.__class__.__name__) - return _format(node) diff --git a/lfortran/asr/tests/__init__.py b/lfortran/asr/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/asr/tests/test_builder.py b/lfortran/asr/tests/test_builder.py deleted file mode 100644 index ce2aa2d736..0000000000 --- a/lfortran/asr/tests/test_builder.py +++ /dev/null @@ -1,43 +0,0 @@ -from lfortran.ast.ast_to_src import ast_to_src -from lfortran.asr import asr, asr_to_ast -from lfortran.asr.asr_check import verify_asr -from lfortran.asr.builder import (make_type_integer, make_translation_unit, - translation_unit_make_module, scope_add_function, function_make_var) - -def test_builder_module1(): - integer = make_type_integer() - unit = make_translation_unit() - m = translation_unit_make_module(unit, "mod1") - - f = scope_add_function(unit.global_scope, "f", args=["a", "b"], - return_var="c") - a, b = f.args - a.intent = "in"; a.type = integer - b.intent = "in"; b.type = integer - c = f.return_var - c.type = integer - d = function_make_var(f, name="d", type=integer) - f.body.extend([ - asr.Assignment(d, asr.Num(n=5, type=integer)), - asr.Assignment(c, asr.BinOp(d, asr.Mul(), - asr.BinOp(a, asr.Add(), b, integer), integer)) - ]) - - a = asr.VariableOld(name="a", intent="in", type=integer) - b = asr.VariableOld(name="b", intent="in", type=integer) - c = asr.VariableOld(name="c", type=integer) - f = scope_add_function(m.symtab, name="g", args=[a, b], return_var=c) - - verify_asr(unit) - a = asr_to_ast.asr_to_ast(unit) - s = ast_to_src(a) - # Check that the generated source code contains a few "key" parts, which - # are reasonably robust against changes in the way the source code is - # generated from ASR. - def has(s, a): - assert s.find(a) > 0 - has(s, "function f(a, b)") - has(s, "d = 5\n") - has(s, "(a + b)") - has(s, "interface\n") - has(s, "function g(a, b)") diff --git a/lfortran/asr/tests/test_pprint.py b/lfortran/asr/tests/test_pprint.py deleted file mode 100644 index 08b654c663..0000000000 --- a/lfortran/asr/tests/test_pprint.py +++ /dev/null @@ -1,12 +0,0 @@ -from lfortran import src_to_ast, ast_to_asr -from lfortran.asr.pprint import pprint_asr_str - -def test_pprint1(): - src = """\ -integer function f(x) result(r) -integer, intent(in) :: x -r = x+x -end function -""" - asr = ast_to_asr(src_to_ast(src, translation_unit=False)) - s = pprint_asr_str(asr) diff --git a/lfortran/ast/__init__.py b/lfortran/ast/__init__.py deleted file mode 100644 index 6d45ab4fef..0000000000 --- a/lfortran/ast/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -# AST module - -This module provides classes to represent an AST, a `src_to_ast()` function that can -parse Fortran code and returns an AST and some other utility functions. - -The AST classes are generated from `Fortran.asdl`. The `src_to_ast()` function -internally calls a particular parser implementation from the `parser` module, -however, the result of `src_to_ast()` is an AST that is independent of any -particular parser implementation. As such, this `ast` module serves as a -starting point for the compiler and other tools. The only thing one has to -understand is the AST, which is fully described by `Fortran.asdl`. -""" - -from .utils import (src_to_ast, parse_file, dump, print_tree, print_tree_typed, - SyntaxErrorException) diff --git a/lfortran/ast/ast_to_src.py b/lfortran/ast/ast_to_src.py deleted file mode 100644 index b3077c8abd..0000000000 --- a/lfortran/ast/ast_to_src.py +++ /dev/null @@ -1,182 +0,0 @@ -from . import ast - -class FortranPrinterVisitor(ast.ASTVisitor): - - def indent(self, lines, spaces=4): - return [" "*spaces+x if x != "" else x for x in lines] - - def visit_sequence(self, seq, separate_line=False): - lines = [] - if seq is not None: - for node in seq: - lines.extend(self.visit(node)) - if separate_line: - if node != seq[-1]: - lines.append("") - return lines - - def visit_TranslationUnit(self, node): - # TODO: Separate modules by 2 lines, functions by 1 line - # and statements/expressions by 0 lines. - return self.visit_sequence(node.items) - - def visit_Module(self, node): - use = self.visit_sequence(node.use) - decl = self.visit_sequence(node.decl, separate_line=True) - contains = self.visit_sequence(node.contains, separate_line=True) - lines = [ - "module %s" % node.name, - ] + use + [ - "implicit none", - "", - ] + decl + [ - "", - "contains", - "", - ] + contains + [ - "", - "end module" - "", - ] - return lines - - def visit_Interface2(self, node): - ifaces = self.visit_sequence(node.procs, separate_line=True) - lines = [ - "interface", - ] - lines.extend(self.indent(ifaces)) - lines.extend([ - "end interface", - ]) - return lines - - def visit_Function(self, node): - use = self.visit_sequence(node.use) - if node.return_type: - return_type = node.return_type + " " - else: - return_type = "" - if node.return_var: - return_var = " result(%s)" % self.visit(node.return_var) - else: - return_var = "" - if node.bind: - parts = [] - for k in node.bind.args: - s = "" - if k.arg: - s += k.arg + "=" - s += self.visit(k.value) - parts.append(s) - bind = " bind(" + ", ".join(parts) + ")" - else: - bind = "" - lines = [ - return_type + "function %s(%s)" % (node.name, - ", ".join([str(x.arg) for x in node.args])) + return_var + bind, - ] + use \ - + self.visit_sequence(node.decl) \ - + self.visit_sequence(node.body) + [ - "end function" - ] - return lines - - def visit_Declaration(self, node): - lines = [] - for decl in node.vars: - parts = [decl.sym_type] - for attr in decl.attrs: - parts.append(self.visit(attr)) - dims = [] - for dim in decl.dims: - # If a bound is None, we do not print it, otherwise we - # explicitly print it (even if it is 1). - lb, ub = dim.start, dim.end - if lb: - lb = self.visit(lb) - else: - lb = "" - if ub: - ub = self.visit(ub) - else: - ub = "" - if ub == "": - # assumed-shape - dims.append("%s:%s" % (lb, ub)) - else: - # explicit-shape - if lb == "": - dims.append("%s" % (ub)) - else: - dims.append("%s:%s" % (lb, ub)) - if dims: - sdim = "("+",".join(dims)+")" - else: - sdim = "" - - lines.append(", ".join(parts) + " :: " + decl.sym + sdim) - return lines - - def visit_Attribute(self, node): - args = [] - for arg in node.args: - args.append(arg.arg) - s = node.name - if args: - s += "(" + ",".join(args) + ")" - return s - - def visit_Assignment(self, node): - target = self.visit(node.target) - value = self.visit(node.value) - return [target + " = " + value] - - def visit_Name(self, node): - return node.id - - def visit_Num(self, node): - return str(node.n) - - def visit_Str(self, node): - return '"' + node.s + '"' - - def visit_BinOp(self, node): - left = self.visit(node.left) - right = self.visit(node.right) - if isinstance(node.op, ast.Add): - op = "+" - return "%s %s %s" % (left, op, right) - elif isinstance(node.op, ast.Mul): - op = "*" - return "(%s) %s (%s)" % (left, op, right) - else: - raise NotImplementedError() - - def visit_FuncCallOrArray(self, node): - return node.func + "(" + \ - ", ".join([self.visit(arg) for arg in node.args]) + ")" - - def visit_FuncCall(self, node): - return node.func + "(" + \ - ", ".join([self.visit(arg) for arg in node.args]) + ")" - - def visit_Use(self, node): - if node.symbols: - syms = ", only: " + ", ".join([self.visit(x) for x in node.symbols]) - else: - syms = "" - return ["use " + node.module + syms] - - def visit_UseSymbol(self, node): - if node.rename: - s = "%s => %s" % (node.rename, node.sym) - else: - s = "%s" % node.sym - return s - - -def ast_to_src(a): - v = FortranPrinterVisitor() - lines = v.visit(a) - return "\n".join(lines) + "\n" diff --git a/lfortran/ast/tests/__init__.py b/lfortran/ast/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/ast/tests/case_sensitivity_results.py b/lfortran/ast/tests/case_sensitivity_results.py deleted file mode 100644 index 0753c16b60..0000000000 --- a/lfortran/ast/tests/case_sensitivity_results.py +++ /dev/null @@ -1,13 +0,0 @@ -results = [ - ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'c', 'integer', [], [('Attribute', 'dimension(9,10)', [])], None)]), - ('Declaration', (1, 1), [('decl', 'e', 'integer', [], [('Attribute', 'dimension(:,:)', []), ('Attribute', 'intent', [('attribute_arg', 'in')])], None)]), - ('Declaration', (1, 1), [('decl', 'i', 'integer', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [('dimension', None, None), ('dimension', None, None)], [('Attribute', 'allocatable', [])], None)]), - ('Declaration', (1, 1), [('decl', 'c', 'character', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'x', 'type', [], [('Attribute', 'intent', [('attribute_arg', 'inout')])], None), ('decl', 'y', 'type', [], [('Attribute', 'intent', [('attribute_arg', 'inout')])], None)]), -] diff --git a/lfortran/ast/tests/controlflow_results.py b/lfortran/ast/tests/controlflow_results.py deleted file mode 100644 index fa9fafb94d..0000000000 --- a/lfortran/ast/tests/controlflow_results.py +++ /dev/null @@ -1,22 +0,0 @@ -results = [ - ('WhileLoop', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'x'), ('Eq',), ('Name', (1, 1), 'y')), [('Assignment', (1, 1), ('Name', (1, 1), 'i'), ('BinOp', (1, 1), ('Name', (1, 1), 'i'), ('Add',), ('Num', (1, 1), '1'))), ('Cycle', (1, 1)), ('Exit', (1, 1))]), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))], [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '2'))])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))], [('If', (1, 1), ('Name', (1, 1), 'b'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '2'))], [])])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))], [('If', (1, 1), ('Name', (1, 1), 'b'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '2'))], [('If', (1, 1), ('Name', (1, 1), 'c'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '2'))], [])])])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))], [])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1')), ('Assignment', (1, 1), ('Name', (1, 1), 'y'), ('Num', (1, 1), '2'))], [])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))], [])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))], [])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('If', (1, 1), ('Name', (1, 1), 'a'), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))], [])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('DoLoop', (1, 1), None, None, None, None, [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1'))])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('DoLoop', (1, 1), 'i', ('Num', (1, 1), '1'), ('Num', (1, 1), '5'), None, [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('BinOp', (1, 1), ('Name', (1, 1), 'x'), ('Add',), ('Name', (1, 1), 'i')))])], []), - ('Subroutine', (1, 1), 'a', [], [], [], [('DoLoop', (1, 1), 'i', ('Num', (1, 1), '1'), ('Num', (1, 1), '5'), ('UnaryOp', (1, 1), ('USub',), ('Num', (1, 1), '1')), [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Name', (1, 1), 'i'))])], []), - ('Select', (1, 1), ('Name', (1, 1), 'k'), [('CaseStmt', ('Num', (1, 1), '1'), [('SubroutineCall', (1, 1), 'a', [])]), ('CaseStmt', ('Name', (1, 1), 'i'), [('SubroutineCall', (1, 1), 'b', [])])], []), - ('Select', (1, 1), ('Name', (1, 1), 'k'), [('CaseStmt', ('Num', (1, 1), '1'), [('SubroutineCall', (1, 1), 'a', [])]), ('CaseStmt', ('Name', (1, 1), 'i'), [('SubroutineCall', (1, 1), 'b', [])])], [('SubroutineCall', (1, 1), 'c', [])]), - ('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '5')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '1'))], []), - ('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '5')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '1'))], []), - ('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '5')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '1'))], [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '0'))]), - ('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '5')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '1'))], [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '0'))]), - ('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '5')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '1'))], [('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '7')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '0'))], [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '3'))])]), - ('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '5')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '1'))], [('Where', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Lt',), ('Num', (1, 1), '7')), [('Assignment', (1, 1), ('Name', (1, 1), 'B'), ('Num', (1, 1), '0'))], [])]), -] diff --git a/lfortran/ast/tests/decl_results.py b/lfortran/ast/tests/decl_results.py deleted file mode 100644 index b31304d51e..0000000000 --- a/lfortran/ast/tests/decl_results.py +++ /dev/null @@ -1,18 +0,0 @@ -results = [ - ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'integer', [('dimension', None, ('Num', (1, 1), '9')), ('dimension', None, ('Num', (1, 1), '10'))], [], None), ('decl', 'b', 'integer', [('dimension', None, ('Num', (1, 1), '10'))], [], None)]), - ('Declaration', (1, 1), [('decl', 'c', 'integer', [], [('Attribute', 'dimension(9,10)', [])], None)]), - ('Declaration', (1, 1), [('decl', 'e', 'integer', [], [('Attribute', 'dimension(:,:)', []), ('Attribute', 'intent', [('attribute_arg', 'in')])], None)]), - ('Declaration', (1, 1), [('decl', 'i', 'integer', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [], [], None), ('decl', 'b', 'real', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [('dimension', None, ('Num', (1, 1), '9')), ('dimension', None, ('Num', (1, 1), '10'))], [], None), ('decl', 'b', 'real', [('dimension', None, ('Num', (1, 1), '10'))], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [('dimension', None, ('Name', (1, 1), 'm')), ('dimension', None, ('Name', (1, 1), 'n'))], [], None)]), - ('Declaration', (1, 1), [('decl', 'a', 'real', [('dimension', None, None), ('dimension', None, None)], [('Attribute', 'allocatable', [])], None)]), - ('Declaration', (1, 1), [('decl', 'y', 'real', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'f', 'real', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'c', 'character', [], [], None)]), - ('Declaration', (1, 1), [('decl', 'x', 'type', [], [('Attribute', 'intent', [('attribute_arg', 'inout')])], None), ('decl', 'y', 'type', [], [('Attribute', 'intent', [('attribute_arg', 'inout')])], None)]), -] diff --git a/lfortran/ast/tests/expr_results.py b/lfortran/ast/tests/expr_results.py deleted file mode 100644 index 63b0077c41..0000000000 --- a/lfortran/ast/tests/expr_results.py +++ /dev/null @@ -1,57 +0,0 @@ -results = [ - ('Num', (1, 1), '1'), - ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Add',), ('Num', (1, 1), '3')), - ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '1'), ('Add',), ('Num', (1, 1), '3')), ('Mul',), ('Num', (1, 1), '4')), - ('BinOp', (1, 1), ('Num', (1, 1), '1'), ('Add',), ('BinOp', (1, 1), ('Num', (1, 1), '3'), ('Mul',), ('Num', (1, 1), '4'))), - ('Name', (1, 1), 'x'), - ('Name', (1, 1), 'yx'), - ('BinOp', (1, 1), ('Name', (1, 1), 'x'), ('Add',), ('Name', (1, 1), 'y')), - ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Add',), ('Name', (1, 1), 'x')), - ('BinOp', (1, 1), ('BinOp', (1, 1), ('Name', (1, 1), 'x'), ('Add',), ('Name', (1, 1), 'y')), ('Pow',), ('Num', (1, 1), '2')), - ('BinOp', (1, 1), ('BinOp', (1, 1), ('Name', (1, 1), 'x'), ('Add',), ('Name', (1, 1), 'y')), ('Mul',), ('Num', (1, 1), '3')), - ('BinOp', (1, 1), ('Name', (1, 1), 'x'), ('Add',), ('BinOp', (1, 1), ('Name', (1, 1), 'y'), ('Mul',), ('Num', (1, 1), '3'))), - ('BinOp', (1, 1), ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '1'), ('Add',), ('Num', (1, 1), '2')), ('Add',), ('Name', (1, 1), 'a')), ('Mul',), ('Num', (1, 1), '3')), - ('BinOp', (1, 1), ('FuncCallOrArray', (1, 1), 'f', [('Num', (1, 1), '3')], []), ('Add',), ('Num', (1, 1), '6')), - ('FuncCallOrArray', (1, 1), 'f', [('BinOp', (1, 1), ('Num', (1, 1), '3'), ('Add',), ('Num', (1, 1), '6'))], []), - ('FuncCallOrArray', (1, 1), 'real', [('Name', (1, 1), 'b'), ('Name', (1, 1), 'dp')], []), - ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Mul',), ('Name', (1, 1), 'u')), ('Sub',), ('Num', (1, 1), '1')), - ('FuncCallOrArray', (1, 1), 'sum', [('BinOp', (1, 1), ('Name', (1, 1), 'u'), ('Pow',), ('Num', (1, 1), '2'))], []), - ('FuncCallOrArray', (1, 1), 'u', [('Num', (1, 1), '2')], []), - ('BinOp', (1, 1), ('Name', (1, 1), 'u'), ('Mul',), ('FuncCallOrArray', (1, 1), 'sqrt', [('UnaryOp', (1, 1), ('USub',), ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Mul',), ('FuncCallOrArray', (1, 1), 'log', [('Name', (1, 1), 'r2')], [])), ('Div',), ('Name', (1, 1), 'r2')))], [])), - ('UnaryOp', (1, 1), ('Not',), ('Name', (1, 1), 'first')), - ('BinOp', (1, 1), ('Name', (1, 1), 'a'), ('Sub',), ('BinOp', (1, 1), ('Num', (1, 1), '1._dp'), ('Div',), ('Num', (1, 1), '3'))), - ('BinOp', (1, 1), ('Num', (1, 1), '1'), ('Div',), ('FuncCallOrArray', (1, 1), 'sqrt', [('BinOp', (1, 1), ('Num', (1, 1), '9'), ('Mul',), ('Name', (1, 1), 'd'))], [])), - ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '1'), ('Add',), ('BinOp', (1, 1), ('Name', (1, 1), 'c'), ('Mul',), ('Name', (1, 1), 'x'))), ('Pow',), ('Num', (1, 1), '3')), - ('BinOp', (1, 1), ('Name', (1, 1), 'i'), ('Add',), ('Num', (1, 1), '1')), - ('Str', (1, 1), 's'), - ('Str', (1, 1), 'some text'), - ('Array', (1, 1), 'a', [('ArrayIndex', None, None, None), ('ArrayIndex', None, None, None)]), - ('Array', (1, 1), 'b', [('ArrayIndex', None, None, None)]), - ('BinOp', (1, 1), ('Array', (1, 1), 'a', [('ArrayIndex', None, None, None), ('ArrayIndex', None, None, None)]), ('Add',), ('Array', (1, 1), 'b', [('ArrayIndex', None, None, None)])), - ('ArrayInitializer', (1, 1), [('Num', (1, 1), '1'), ('Num', (1, 1), '2'), ('Num', (1, 1), '3'), ('Name', (1, 1), 'i')]), - ('FuncCallOrArray', (1, 1), 'f', [], []), - ('Name', (1, 1), 'a'), - ('FuncCallOrArray', (1, 1), 'a', [], []), - ('FuncCallOrArray', (1, 1), 'b', [('Name', (1, 1), 'i'), ('Name', (1, 1), 'j')], []), - ('Array', (1, 1), 'c', [('ArrayIndex', ('Num', (1, 1), '5'), None, None), ('ArrayIndex', None, None, None)]), - ('Name', (1, 1), 'a'), - ('FuncCallOrArray', (1, 1), 'b', [('Name', (1, 1), 'i'), ('Name', (1, 1), 'j')], []), - ('Array', (1, 1), 'c', [('ArrayIndex', ('Num', (1, 1), '5'), None, None), ('ArrayIndex', None, None, None)]), - ('Str', (1, 1), "a'b'c"), - ('Str', (1, 1), 'a"b"c'), - ('Str', (1, 1), 'a""bc""x'), - ('Str', (1, 1), 'a"c'), - ('Str', (1, 1), 'a"b"c'), - ('Str', (1, 1), '"zippo"'), - ('Str', (1, 1), "a'c"), - ('Str', (1, 1), "a'b'c"), - ('Str', (1, 1), "'zippo'"), - ('BoolOp', (1, 1), ('Num', (1, 1), '1'), ('And',), ('Num', (1, 1), '2')), - ('BoolOp', (1, 1), ('Name', (1, 1), 'a'), ('And',), ('Name', (1, 1), 'b')), - ('BoolOp', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Eq',), ('Num', (1, 1), '1')), ('And',), ('Compare', (1, 1), ('Name', (1, 1), 'b'), ('Eq',), ('Num', (1, 1), '2'))), - ('BoolOp', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Eq',), ('Num', (1, 1), '1')), ('Or',), ('Compare', (1, 1), ('Name', (1, 1), 'b'), ('Eq',), ('Num', (1, 1), '2'))), - ('BoolOp', (1, 1), ('BoolOp', (1, 1), ('Name', (1, 1), 'a'), ('And',), ('Name', (1, 1), 'b')), ('And',), ('Name', (1, 1), 'c')), - ('BoolOp', (1, 1), ('BoolOp', (1, 1), ('Name', (1, 1), 'a'), ('Or',), ('Name', (1, 1), 'b')), ('Or',), ('Name', (1, 1), 'c')), - ('UnaryOp', (1, 1), ('Not',), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Eq',), ('Num', (1, 1), '1'))), - ('BoolOp', (1, 1), ('Compare', (1, 1), ('Name', (1, 1), 'a'), ('Eq',), ('Num', (1, 1), '1')), ('And',), ('UnaryOp', (1, 1), ('Not',), ('Compare', (1, 1), ('Name', (1, 1), 'b'), ('Eq',), ('Num', (1, 1), '2')))), -] diff --git a/lfortran/ast/tests/interactive_results.py b/lfortran/ast/tests/interactive_results.py deleted file mode 100644 index e779ac0e55..0000000000 --- a/lfortran/ast/tests/interactive_results.py +++ /dev/null @@ -1,11 +0,0 @@ -results = [ - [('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '5')), ('Assignment', (1, 1), ('Name', (1, 1), 'b'), ('Num', (1, 1), '6'))], - [('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '5')), ('Assignment', (1, 1), ('Name', (1, 1), 'b'), ('Num', (1, 1), '6'))], - [('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '5')), ('Print', (1, 1), None, [('Name', (1, 1), 'a')])], - [('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '5')), ('Subroutine', (1, 1), 'p', [], [], [], [('Print', (1, 1), None, [('Name', (1, 1), 'a')])], []), ('SubroutineCall', (1, 1), 'p', [])], - [('Module', 'a', [], [('Declaration', (1, 1), [('decl', 'i', 'integer', [], [], None)])], []), ('Use', (1, 1), 'a', [('UseSymbol', 'i', None)]), ('Assignment', (1, 1), ('Name', (1, 1), 'i'), ('Num', (1, 1), '5'))], - [('Use', (1, 1), 'a', [('UseSymbol', 'i', None)]), ('Assignment', (1, 1), ('Name', (1, 1), 'i'), ('Num', (1, 1), '5'))], - [('Use', (1, 1), 'a', [('UseSymbol', 'i', None)]), ('Assignment', (1, 1), ('Name', (1, 1), 'i'), ('Num', (1, 1), '5'))], - ('SubroutineCall', (1, 1), 'plot', [('Name', (1, 1), 'x'), ('Name', (1, 1), 'y'), ('Str', (1, 1), 'o-')]), - [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('ArrayInitializer', (1, 1), [('Num', (1, 1), '1'), ('Num', (1, 1), '2'), ('Num', (1, 1), '3')])), ('Assignment', (1, 1), ('Name', (1, 1), 'y'), ('ArrayInitializer', (1, 1), [('Num', (1, 1), '1'), ('Num', (1, 1), '2'), ('Num', (1, 1), '1')])), ('SubroutineCall', (1, 1), 'plot', [('Name', (1, 1), 'x'), ('Name', (1, 1), 'y'), ('Str', (1, 1), 'o-')])], -] diff --git a/lfortran/ast/tests/module_results.py b/lfortran/ast/tests/module_results.py deleted file mode 100644 index be60b1906c..0000000000 --- a/lfortran/ast/tests/module_results.py +++ /dev/null @@ -1,17 +0,0 @@ -results = [ - ('Module', 'test', [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Private', (1, 1), []), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Private', (1, 1), ['x', 'y']), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None), ('decl', 'y', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Private', (1, 1), ['x', 'y']), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None), ('decl', 'y', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Public', (1, 1), []), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Public', (1, 1), ['x', 'y']), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None), ('decl', 'y', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Public', (1, 1), ['x', 'y']), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None), ('decl', 'y', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Private', (1, 1), []), ('Public', (1, 1), ['x', 'y']), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None), ('decl', 'y', 'integer', [], [], None)])], []), - ('Module', 'test', [], [('Private', (1, 1), ['x']), ('Public', (1, 1), ['y']), ('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None), ('decl', 'y', 'integer', [], [], None)])], []), - ('Module', 'test', [], [], [('Subroutine', (1, 1), 'a', [('arg', 'b')], [], [('Declaration', (1, 1), [('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)])], [], [])]), - ('Module', 'test', [], [], [('Subroutine', (1, 1), 'a', [('arg', 'b')], [], [('Declaration', (1, 1), [('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)])], [], []), ('Subroutine', (1, 1), 'f', [('arg', 'b')], [], [('Declaration', (1, 1), [('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)])], [], [])]), - ('Module', 'test', [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [('Subroutine', (1, 1), 'a', [('arg', 'b')], [], [('Declaration', (1, 1), [('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)])], [], [])]), - ('Module', 'test', [], [], [('Function', (1, 1), 'f', [], None, ('Name', (1, 1), 'y'), None, [], [], [('Assignment', (1, 1), ('Name', (1, 1), 'y'), ('Num', (1, 1), '0'))], [])]), - ('Module', 'test', [], [('Interface', (1, 1), 'name', ['a', 'b', 'c'])], []), -] diff --git a/lfortran/ast/tests/program_results.py b/lfortran/ast/tests/program_results.py deleted file mode 100644 index cf5099e5d0..0000000000 --- a/lfortran/ast/tests/program_results.py +++ /dev/null @@ -1,6 +0,0 @@ -results = [ - ('Program', 'test', [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1')), ('SubroutineCall', (1, 1), 'a', [('Name', (1, 1), 'x')])], []), - ('Program', 'test', [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1')), ('SubroutineCall', (1, 1), 'a', [('Name', (1, 1), 'x')])], []), - ('Program', 'test', [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1')), ('SubroutineCall', (1, 1), 'a', [('Name', (1, 1), 'x')])], [('Subroutine', (1, 1), 'a', [('arg', 'b')], [], [('Declaration', (1, 1), [('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)])], [], [])]), - ('Program', 'test', [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1')), ('SubroutineCall', (1, 1), 'a', [('Name', (1, 1), 'x')])], [('Subroutine', (1, 1), 'a', [('arg', 'b')], [], [('Declaration', (1, 1), [('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)])], [], []), ('Subroutine', (1, 1), 'f', [('arg', 'b')], [], [('Declaration', (1, 1), [('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)])], [], [])]), -] diff --git a/lfortran/ast/tests/statements_results.py b/lfortran/ast/tests/statements_results.py deleted file mode 100644 index b395697ddb..0000000000 --- a/lfortran/ast/tests/statements_results.py +++ /dev/null @@ -1,49 +0,0 @@ -results = [ - ('SubroutineCall', (1, 1), 'random_number', [('Name', (1, 1), 'u')]), - ('Assignment', (1, 1), ('Name', (1, 1), 'u'), ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Mul',), ('Name', (1, 1), 'u')), ('Sub',), ('Num', (1, 1), '1'))), - ('Assignment', (1, 1), ('Name', (1, 1), 'r2'), ('FuncCallOrArray', (1, 1), 'sum', [('BinOp', (1, 1), ('Name', (1, 1), 'u'), ('Pow',), ('Num', (1, 1), '2'))], [])), - ('Assignment', (1, 1), ('Name', (1, 1), 'u'), ('BinOp', (1, 1), ('Name', (1, 1), 'u'), ('Mul',), ('FuncCallOrArray', (1, 1), 'sqrt', [('UnaryOp', (1, 1), ('USub',), ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Mul',), ('FuncCallOrArray', (1, 1), 'log', [('Name', (1, 1), 'r2')], [])), ('Div',), ('Name', (1, 1), 'r2')))], []))), - ('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('FuncCallOrArray', (1, 1), 'u', [('Num', (1, 1), '1')], [])), - ('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('FuncCallOrArray', (1, 1), 'u', [('Num', (1, 1), '2')], [])), - ('Assignment', (1, 1), ('Name', (1, 1), 'first'), ('UnaryOp', (1, 1), ('Not',), ('Name', (1, 1), 'first'))), - ('Assignment', (1, 1), ('Name', (1, 1), 'd'), ('BinOp', (1, 1), ('Name', (1, 1), 'a'), ('Sub',), ('BinOp', (1, 1), ('Num', (1, 1), '1._dp'), ('Div',), ('Num', (1, 1), '3')))), - ('Assignment', (1, 1), ('Name', (1, 1), 'c'), ('BinOp', (1, 1), ('Num', (1, 1), '1'), ('Div',), ('FuncCallOrArray', (1, 1), 'sqrt', [('BinOp', (1, 1), ('Num', (1, 1), '9'), ('Mul',), ('Name', (1, 1), 'd'))], []))), - ('Assignment', (1, 1), ('Name', (1, 1), 'v'), ('BinOp', (1, 1), ('BinOp', (1, 1), ('Num', (1, 1), '1'), ('Add',), ('BinOp', (1, 1), ('Name', (1, 1), 'c'), ('Mul',), ('Name', (1, 1), 'x'))), ('Pow',), ('Num', (1, 1), '3'))), - ('Assignment', (1, 1), ('Name', (1, 1), 'fn_val'), ('BinOp', (1, 1), ('Name', (1, 1), 'd'), ('Mul',), ('Name', (1, 1), 'v'))), - ('Exit', (1, 1)), - ('Cycle', (1, 1)), - ('SubroutineCall', (1, 1), 'randn', [('FuncCallOrArray', (1, 1), 'x', [('Name', (1, 1), 'i')], [])]), - ('SubroutineCall', (1, 1), 'randn', [('Name', (1, 1), 'x')]), - ('SubroutineCall', (1, 1), 'random_number', [('Name', (1, 1), 'U')]), - ('SubroutineCall', (1, 1), 'rand_gamma0', [('Name', (1, 1), 'a'), ('Constant', (1, 1), True), ('Name', (1, 1), 'x')]), - ('SubroutineCall', (1, 1), 'rand_gamma0', [('Name', (1, 1), 'a'), ('Constant', (1, 1), True), ('FuncCallOrArray', (1, 1), 'x', [('Num', (1, 1), '1')], [])]), - ('SubroutineCall', (1, 1), 'rand_gamma0', [('Name', (1, 1), 'a'), ('Constant', (1, 1), False), ('FuncCallOrArray', (1, 1), 'x', [('Name', (1, 1), 'i')], [])]), - ('SubroutineCall', (1, 1), 'rand_gamma_vector_n', [('Name', (1, 1), 'a'), ('FuncCallOrArray', (1, 1), 'size', [('Name', (1, 1), 'x')], []), ('Name', (1, 1), 'x')]), - ('SubroutineCall', (1, 1), 'f', [('Num', (1, 1), '4'), ('Num', (1, 1), '6'), ('Name', (1, 1), 'i')]), - ('BuiltinCall', (1, 1), 'open', [('Name', (1, 1), 'a'), ('Name', (1, 1), 'b'), ('Name', (1, 1), 'c')]), - ('BuiltinCall', (1, 1), 'allocate', [('FuncCallOrArray', (1, 1), 'c', [('Num', (1, 1), '4')], []), ('FuncCallOrArray', (1, 1), 'd', [('Num', (1, 1), '4')], [])]), - ('BuiltinCall', (1, 1), 'close', [('Name', (1, 1), 'u')]), - [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1')), ('Assignment', (1, 1), ('Name', (1, 1), 'y'), ('Num', (1, 1), '2'))], - [('Assignment', (1, 1), ('Name', (1, 1), 'y'), ('Num', (1, 1), '5')), ('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '1')), ('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('FuncCallOrArray', (1, 1), 'u', [('Num', (1, 1), '2')], []))], - ('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '5')), - [('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('Num', (1, 1), '1')), ('Assignment', (1, 1), ('Name', (1, 1), 'y'), ('Num', (1, 1), '2'))], - [('Assignment', (1, 1), ('Name', (1, 1), 'y'), ('Num', (1, 1), '5')), ('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '1')), ('Assignment', (1, 1), ('Name', (1, 1), 'x'), ('FuncCallOrArray', (1, 1), 'u', [('Num', (1, 1), '2')], []))], - ('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Num', (1, 1), '5')), - None, - ('Stop', (1, 1), None), - ('Print', (1, 1), None, [('Num', (1, 1), '45')]), - ('Print', (1, 1), None, [('Num', (1, 1), '45'), ('Str', (1, 1), 'sss'), ('BinOp', (1, 1), ('Name', (1, 1), 'a'), ('Add',), ('Num', (1, 1), '1'))]), - ('SubroutineCall', (1, 1), 'g', [('Array', (1, 1), 'a', [('ArrayIndex', None, None, None), ('ArrayIndex', None, None, None)]), ('Array', (1, 1), 'b', [('ArrayIndex', None, None, None)])]), - ('SubroutineCall', (1, 1), 'g', [('Array', (1, 1), 'a', [('ArrayIndex', None, None, None), ('ArrayIndex', None, None, None)]), ('Array', (1, 1), 'b', [('ArrayIndex', None, None, None)])]), - ('Assignment', (1, 1), ('Name', (1, 1), 'c'), ('ArrayInitializer', (1, 1), [('Num', (1, 1), '1'), ('Num', (1, 1), '2'), ('Num', (1, 1), '3'), ('Name', (1, 1), 'i')])), - ('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Name', (1, 1), 'a')), - ('Assignment', (1, 1), ('Name', (1, 1), 'b'), ('FuncCallOrArray', (1, 1), 'b', [('Name', (1, 1), 'i'), ('Name', (1, 1), 'j')], [])), - ('Assignment', (1, 1), ('Name', (1, 1), 'c'), ('Array', (1, 1), 'c', [('ArrayIndex', ('Num', (1, 1), '5'), None, None), ('ArrayIndex', None, None, None)])), - ('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Name', (1, 1), 'a')), - ('Assignment', (1, 1), ('Name', (1, 1), 'b'), ('FuncCallOrArray', (1, 1), 'b', [('Name', (1, 1), 'i'), ('Name', (1, 1), 'j')], [])), - ('Assignment', (1, 1), ('Name', (1, 1), 'c'), ('Array', (1, 1), 'c', [('ArrayIndex', ('Num', (1, 1), '5'), None, None), ('ArrayIndex', None, None, None)])), - ('Assignment', (1, 1), ('Name', (1, 1), 'a'), ('Name', (1, 1), 'a')), - ('Assignment', (1, 1), ('FuncCallOrArray', (1, 1), 'b', [('Name', (1, 1), 'i'), ('Name', (1, 1), 'j')], []), ('Name', (1, 1), 'b')), - ('Assignment', (1, 1), ('Array', (1, 1), 'c', [('ArrayIndex', ('Num', (1, 1), '5'), None, None), ('ArrayIndex', None, None, None)]), ('Name', (1, 1), 'c')), - ('SubroutineCall', (1, 1), 'e', []), -] diff --git a/lfortran/ast/tests/subroutine_results.py b/lfortran/ast/tests/subroutine_results.py deleted file mode 100644 index 8abc5e7753..0000000000 --- a/lfortran/ast/tests/subroutine_results.py +++ /dev/null @@ -1,11 +0,0 @@ -results = [ - ('Function', (1, 1), 'dp', [('arg', 'e')], None, ('Name', (1, 1), 'f'), None, [], [], [('Assignment', (1, 1), ('Name', (1, 1), 'r'), ('Num', (1, 1), '1'))], []), - ('Function', (1, 1), 'dp', [('arg', 'e')], None, ('Name', (1, 1), 'f'), None, [], [], [('Assignment', (1, 1), ('Name', (1, 1), 'r'), ('Num', (1, 1), '1'))], []), - ('Function', (1, 1), 'f', [('arg', 'e')], None, None, None, [], [], [('Assignment', (1, 1), ('Name', (1, 1), 'f'), ('Num', (1, 1), '1'))], []), - ('Function', (1, 1), 'f', [('arg', 'e')], None, None, None, [], [], [('Assignment', (1, 1), ('Name', (1, 1), 'f'), ('Num', (1, 1), '1'))], []), - ('Subroutine', (1, 1), 'f', [], [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [], []), - ('Subroutine', (1, 1), 'f', [], [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [], []), - ('Subroutine', (1, 1), 'f', [], [], [('Declaration', (1, 1), [('decl', 'x', 'integer', [], [], None)])], [], []), - ('Subroutine', (1, 1), 'f', [('arg', 'a'), ('arg', 'b'), ('arg', 'c'), ('arg', 'd')], [], [('Declaration', (1, 1), [('decl', 'a', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None), ('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)]), ('Declaration', (1, 1), [('decl', 'c', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None), ('decl', 'd', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'in')])], None)]), ('Declaration', (1, 1), [('decl', 'z', 'integer', [], [], None)]), ('Declaration', (1, 1), [('decl', 'y', 'integer', [], [], None)])], [], []), - ('Subroutine', (1, 1), 'f', [('arg', 'a'), ('arg', 'b'), ('arg', 'c'), ('arg', 'd')], [], [('Declaration', (1, 1), [('decl', 'a', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'out')])], None), ('decl', 'b', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'out')])], None)]), ('Declaration', (1, 1), [('decl', 'c', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'inout')])], None), ('decl', 'd', 'integer', [], [('Attribute', 'intent', [('attribute_arg', 'inout')])], None)]), ('Declaration', (1, 1), [('decl', 'z', 'integer', [], [], None)]), ('Declaration', (1, 1), [('decl', 'y', 'integer', [], [], None)])], [], []), -] diff --git a/lfortran/ast/tests/test_ast.py b/lfortran/ast/tests/test_ast.py deleted file mode 100644 index 6fd13a88d3..0000000000 --- a/lfortran/ast/tests/test_ast.py +++ /dev/null @@ -1,47 +0,0 @@ -from lfortran.ast import ast - -class CountNum(ast.GenericASTVisitor): - - def __init__(self): - self.count = 0 - - def visit_Num(self, node): - self.count += 1 - - -def test_num(): - value = 42 - node = ast.Num(value, lineno=1, col_offset=1) - assert node.n == value - v = ast.GenericASTVisitor() - node.walkabout(v) - c = CountNum() - node.walkabout(c) - assert c.count == 1 - -def test_expr(): - value = 42 - node = ast.Num(value, lineno=1, col_offset=1) - p = ast.Print(fmt=None, values=[node], lineno=1, col_offset=1) - assert p.values[0].n == value - v = ast.GenericASTVisitor() - p.walkabout(v) - c = CountNum() - p.walkabout(c) - assert c.count == 1 - -def test_BinOp(): - i1 = 1 - i2 = 2 - val1 = ast.Num(i1, lineno=1, col_offset=1) - val2 = ast.Num(i2, lineno=1, col_offset=1) - node = ast.BinOp(left=val1, right=val2, op=ast.Add(), - lineno=1, col_offset=1) - assert isinstance(node.op, ast.Add) - assert node.left.n == i1 - assert node.right.n == i2 - v = ast.GenericASTVisitor() - node.walkabout(v) - c = CountNum() - node.walkabout(c) - assert c.count == 2 diff --git a/lfortran/ast/tests/test_cparser.py b/lfortran/ast/tests/test_cparser.py deleted file mode 100644 index 7a15a9b428..0000000000 --- a/lfortran/ast/tests/test_cparser.py +++ /dev/null @@ -1,22 +0,0 @@ -#from lfortran.parser.cparser import parse, Parser, AST - -def _test_parse1(): - assert parse("1+1") == "(+ 1 1)" - assert parse("""\ -if (x > 0) then - a = 1 -else - a = 2 -end if""") == "(if (> x 0) [(= a 1)] [(= a 2)])" - -def _test_parse2(): - p = Parser() - a = p.parse("1+1") - assert a.pickle() == "(+ 1 1)" - a = p.parse("""\ -if (x > 0) then - a = 1 -else - a = 2 -end if""") - assert a.pickle() == "(if (> x 0) [(= a 1)] [(= a 2)])" diff --git a/lfortran/ast/tests/test_dump.py b/lfortran/ast/tests/test_dump.py deleted file mode 100644 index 1e3c1122f8..0000000000 --- a/lfortran/ast/tests/test_dump.py +++ /dev/null @@ -1,39 +0,0 @@ -from lfortran.ast import src_to_ast, dump - -def test_dump_expr(): - assert dump(src_to_ast("1+1", False)) == \ - "BinOp(left=Num(n='1'), op=Add(), right=Num(n='1'))" - assert dump(src_to_ast("1+x", False)) == \ - "BinOp(left=Num(n='1'), op=Add(), right=Name(id='x'))" - assert dump(src_to_ast("(x+y)**2", False)) == \ - "BinOp(left=BinOp(left=Name(id='x'), op=Add(), " \ - "right=Name(id='y')), op=Pow(), right=Num(n='2'))" - -def test_dump_statements(): - assert dump(src_to_ast("if (x == 1) stop\n", False)) == \ - "If(test=Compare(left=Name(id='x'), op=Eq(), right=Num(n='1')), " \ - "body=[Stop(code=None)], orelse=[])" - assert dump(src_to_ast("x == 1\n", False)) == \ - "Compare(left=Name(id='x'), op=Eq(), right=Num(n='1'))" - -def test_dump_subroutines(): - assert dump(src_to_ast("""\ -subroutine f -integer :: a, b -b = (1+2+a)*3 -end subroutine -""", False)) == "Subroutine(name='f', args=[], use=[], decl=[Declaration(vars=[decl(sym='a', sym_type='integer', dims=[], attrs=[], initializer=None), decl(sym='b', sym_type='integer', dims=[], attrs=[], initializer=None)])], body=[Assignment(target=Name(id='b'), value=BinOp(left=BinOp(left=BinOp(left=Num(n='1'), op=Add(), right=Num(n='2')), op=Add(), right=Name(id='a')), op=Mul(), right=Num(n='3')))], contains=[])" - assert dump(src_to_ast("""\ -subroutine f(x, y) -integer, intent(out) :: x, y -x = 1 -end subroutine -""", False)) == "Subroutine(name='f', args=[arg(arg='x'), arg(arg='y')], use=[], decl=[Declaration(vars=[decl(sym='x', sym_type='integer', dims=[], attrs=[Attribute(name='intent', args=[attribute_arg(arg='out')])], initializer=None), decl(sym='y', sym_type='integer', dims=[], attrs=[Attribute(name='intent', args=[attribute_arg(arg='out')])], initializer=None)])], body=[Assignment(target=Name(id='x'), value=Num(n='1'))], contains=[])" - -def test_dump_programs(): - assert dump(src_to_ast("""\ -program a -integer :: b -b = 1 -end program -""")) == "Program(name='a', use=[], decl=[Declaration(vars=[decl(sym='b', sym_type='integer', dims=[], attrs=[], initializer=None)])], body=[Assignment(target=Name(id='b'), value=Num(n='1'))], contains=[])" diff --git a/lfortran/ast/tests/test_files.py b/lfortran/ast/tests/test_files.py deleted file mode 100644 index b78cdde71c..0000000000 --- a/lfortran/ast/tests/test_files.py +++ /dev/null @@ -1,420 +0,0 @@ -from glob import glob -import os - -from lfortran.ast import src_to_ast - -def test_files(): - sources = [file1, file2, file3, file4, file5, file6, file7, file8, file9] - assert len(sources) == 9 - print("Testing filenames:") - for source in sources: - src_to_ast(source) - -file1 = """\ -module bsplines - -use types, only: dp -use lapack, only: dgesv, dgbsv -use utils, only: stop_error -implicit none -private -public bspline, bspline_der, bspline_der2 - -contains - -pure recursive function bspline(t, i, k, r) result(B) -! Returns values of a B-spline. -! There are set of `n` B-splines of order `k`. The mesh is composed of `n+k` -! knots, stored in the t(:) array. -real(dp), intent(in) :: t(:) ! {t_i}, i = 1, 2, ..., n+k -integer, intent(in) :: i ! i = 1..n ? -integer, intent(in) :: k ! Order of the spline k = 1, 2, 3, ... -real(dp), intent(in) :: r(:) ! points to evaluate the spline at -real(dp) :: B(size(r)) -if (k == 1) then - if ((t(size(t)) - t(i+1)) < tiny(1._dp) .and. & - (t(i+1) - t(i)) > tiny(1._dp)) then - ! If this is the last non-zero knot span, include the right end point, - ! to ensure that the last basis function goes to 1. - where (t(i) <= r .and. r <= t(i+1)) - B = 1 - else where - B = 0 - end where - else - ! Otherwise exclude the right end point - where (t(i) <= r .and. r < t(i+1)) - B = 1 - else where - B = 0 - end where - end if -else - B = 0 - if (t(i+k-1)-t(i) > tiny(1._dp)) then - B = B + (r-t(i)) / (t(i+k-1)-t(i)) * bspline(t, i, k-1, r) - end if - if (t(i+k)-t(i+1) > tiny(1._dp)) then - B = B + (t(i+k)-r) / (t(i+k)-t(i+1)) * bspline(t, i+1, k-1, r) - end if -end if -end function - -pure function bspline_der(t, i, k, r) result(B) -! Returns values of a derivative of a B-spline. -! There are set of `n` B-splines of order `k`. The mesh is composed of `n+k` -! knots, stored in the t(:) array. -real(dp), intent(in) :: t(:) ! {t_i}, i = 1, 2, ..., n+k -integer, intent(in) :: i ! i = 1..n ? -integer, intent(in) :: k ! Order of the spline k = 1, 2, 3, ... -real(dp), intent(in) :: r(:) ! points to evaluate the spline at -real(dp) :: B(size(r)) -if (k == 1) then - B = 0 -else - B = 0 - if (t(i+k-1)-t(i) > tiny(1._dp)) then - B = B + (k-1) / (t(i+k-1)-t(i)) * bspline(t, i, k-1, r) - end if - if (t(i+k)-t(i+1) > tiny(1._dp)) then - B = B - (k-1) / (t(i+k)-t(i+1)) * bspline(t, i+1, k-1, r) - end if -end if -end function - -pure function bspline_der2(t, i, k, r) result(B) -! Returns values of a second derivative of a B-spline. -! There are set of `n` B-splines of order `k`. The mesh is composed of `n+k` -! knots, stored in the t(:) array. -real(dp), intent(in) :: t(:) ! {t_i}, i = 1, 2, ..., n+k -integer, intent(in) :: i ! i = 1..n ? -integer, intent(in) :: k ! Order of the spline k = 1, 2, 3, ... -real(dp), intent(in) :: r(:) ! points to evaluate the spline at -real(dp) :: B(size(r)) -if (k == 1) then - B = 0 -else - B = 0 - if (t(i+k-1)-t(i) > tiny(1._dp)) then - B = B + (k-1) / (t(i+k-1)-t(i)) * bspline_der(t, i, k-1, r) - end if - if (t(i+k)-t(i+1) > tiny(1._dp)) then - B = B - (k-1) / (t(i+k)-t(i+1)) * bspline_der(t, i+1, k-1, r) - end if -end if -end function - -end module -""" - -file2 = """\ -! Some constants - -module constants -use types, only: dp -implicit none -private -public pi, e_, i_, bohr2ang, ang2bohr, Ha2eV, kB, K2au, density2gcm3, u2au, & - s2au, kJmol2Ha - -! Constants contain more digits than double precision, so that -! they are rounded correctly. Single letter constants contain underscore so -! that they do not clash with user variables ("e" and "i" are frequently used as -! loop variables) -real(dp), parameter :: pi = 3.1415926535897932384626433832795_dp -real(dp), parameter :: e_ = 2.7182818284590452353602874713527_dp -complex(dp), parameter :: i_ = (0, 1) - -real(dp), parameter :: Na = 6.02214129e23_dp ! Avogadro constant -! Standard uncertainty 0.00000027 (Source: 2010 CODATA) -real(dp), parameter :: Ha2eV = 27.21138505_dp ! 1 Ha = (1 * Ha2eV) eV -! Standard uncertainty is 0.00000060 eV (Source: 2010 CODATA) - -real(dp), parameter :: J2Ha = 2.29371248e17_dp ! 1 J = (1 * J2Ha) Ha -! Standard uncertainty is 0.00000010 eV (Source: 2010 CODATA) - -! Reduced Planck constant -real(dp), parameter :: hbar = 1.054571726e-34_dp ! [J s] -! Standard uncertainty is 0.000000047 eV (Source: 2010 CODATA) - -! Covert Ha to cm^{-1} (energy equivalent) -! 1 Ha = (1 * Ha2invcm) cm^{-1} -real(dp), parameter :: Ha2invcm = 219474.6313708_dp -! Standard uncertainty is 0.0000011 cm^{-1} (Source: 2010 CODATA) - -real(dp), parameter :: kB = 1.3806488e-23_dp ! Boltzmann constant [J/K] -! Standard uncertainty is 0.0000013 J/K (Source: 2010 CODATA) - -real(dp), parameter :: me = 9.10938291e-31_dp ! electron rest mass [kg] -! Standard uncertainty is 0.00000040 eV (Source: 2010 CODATA) - -! Converts K to a.u.: -real(dp), parameter :: K2au = J2Ha*kB ! 1 K = (1 * K2au) a.u. - -! Conversion between Bohr (Hartree atomic units) and Angstrom -real(dp), parameter :: bohr2ang = 0.529177249_dp -real(dp), parameter :: ang2bohr = 1 / bohr2ang - -! Converts eV to kcal/mol, it is assumed, that the number in eV is given per -! molecule. 1 eV = (1 * eV2kcalmol) kcal/mol -real(dp), parameter :: kcalmol2kJmol = 4.184_dp -real(dp), parameter :: kJmol2Ha = 1000 * J2Ha / Na - -! Converts density from a.u. to g/cm^3 -real(dp), parameter :: density2gcm3 = me*1e3_dp / (bohr2ang*1e-8_dp)**3 - -! Converts u (atomic mass unit) to a.u. -real(dp), parameter :: u2au = 1 / (Na * me * 1e3_dp) - -! Converts s to a.u. -real(dp), parameter :: s2au = 1 / (J2Ha*hbar) - -end module -""" - -file3 = """\ -module expr1 -implicit none - -contains - -subroutine a -integer :: a, b -a = 1+2*3 -b = (1+2+a)*3 -end subroutine - -end module -""" - -file4 = """\ -program expr2 -implicit none - -integer :: x - -x = (2+3)*5 -print *, x - -end program -""" - -file5 = """\ -module m1 -implicit none -private -public sp, dp, hp - -integer, parameter :: dp=kind(0.d0), & ! double precision - hp=selected_real_kind(15), & ! high precision - sp=kind(0.) ! single precision - -end module -""" - -file6 = """\ -program main_prog -implicit none - -integer :: x - -x = 1 -print *, "OK.", x - -end program -""" - -file7 = """\ -module random - -use types, only: dp -use utils, only: stop_error -implicit none -private -public randn, rand_gamma - -interface randn - module procedure randn_scalar - module procedure randn_vector - module procedure randn_matrix - module procedure randn_vector_n -end interface - -interface rand_gamma - module procedure rand_gamma_scalar - module procedure rand_gamma_vector - module procedure rand_gamma_matrix - module procedure rand_gamma_vector_n -end interface - -contains - -subroutine randn_scalar(x) -! Returns a psuedorandom scalar drawn from the standard normal distribution. -! -! [1] Marsaglia, G., & Bray, T. A. (1964). A Convenient Method for Generating -! Normal Variables. SIAM Review, 6(3), 260-264. -real(dp), intent(out) :: x -logical, save :: first = .true. -real(dp), save :: u(2) -real(dp) :: r2 -if (first) then - do - call random_number(u) - u = 2*u-1 - r2 = sum(u**2) - if (r2 < 1 .and. r2 > 0) exit - end do - u = u * sqrt(-2*log(r2)/r2) - x = u(1) -else - x = u(2) -end if -first = .not. first -end subroutine - -subroutine randn_vector_n(n, x) -integer, intent(in) :: n -real(dp), intent(out) :: x(n) -integer :: i -do i = 1, size(x) - call randn(x(i)) -end do -end subroutine - -subroutine randn_vector(x) -real(dp), intent(out) :: x(:) -call randn_vector_n(size(x), x) -end subroutine - -subroutine randn_matrix(x) -real(dp), intent(out) :: x(:, :) -call randn_vector_n(size(x), x) -end subroutine - -subroutine rand_gamma0(a, first, fn_val) -! Returns a psuedorandom scalar drawn from the gamma distribution. -! -! The shape parameter a >= 1. -! -! [1] Marsaglia, G., & Tsang, W. W. (2000). A Simple Method for Generating -! Gamma Variables. ACM Transactions on Mathematical Software (TOMS), 26(3), -! 363-372. -real(dp), intent(in) :: a -logical, intent(in) :: first -real(dp), intent(out) :: fn_val -real(dp), save :: c, d -real(dp) :: U, v, x -if (a < 1) call stop_error("Shape parameter must be >= 1") -if (first) then - d = a - 1._dp/3 - c = 1/sqrt(9*d) -end if -do - do - call randn(x) - v = (1 + c*x)**3 - if (v > 0) exit - end do - call random_number(U) - ! Note: the number 0.0331 below is exact, see [1]. - if (U < 1 - 0.0331_dp*x**4) then - fn_val = d*v - exit - else if (log(U) < x**2/2 + d*(1 - v + log(v))) then - fn_val = d*v - exit - end if -end do -end subroutine - -subroutine rand_gamma_scalar(a, x) -real(dp), intent(in) :: a -real(dp), intent(out) :: x -call rand_gamma0(a, .true., x) -end subroutine - -subroutine rand_gamma_vector_n(a, n, x) -real(dp), intent(in) :: a -integer, intent(in) :: n -real(dp), intent(out) :: x(n) -integer :: i -call rand_gamma0(a, .true., x(1)) -do i = 2, size(x) - call rand_gamma0(a, .false., x(i)) -end do -end subroutine - -subroutine rand_gamma_vector(a, x) -real(dp), intent(in) :: a -real(dp), intent(out) :: x(:) -call rand_gamma_vector_n(a, size(x), x) -end subroutine - -subroutine rand_gamma_matrix(a, x) -real(dp), intent(in) :: a -real(dp), intent(out) :: x(:, :) -call rand_gamma_vector_n(a, size(x), x) -end subroutine - -end module -""" - -file8 = """\ -module subroutine1 -implicit none - -contains - -subroutine some_subroutine -integer :: a, b, c -a = 1 -b = 8 -end subroutine - -subroutine some_other_subroutine -integer :: x, y -y = 5 -x = y -call some_subroutine() -end subroutine - -end module -""" - -file9 = """\ -program main_rand -implicit none -integer, parameter :: dp=kind(0.d0) -real(dp) :: a -integer :: i -print *, "Random numbers:" -do i = 1, 10 - call rand(a) - print *, a -end do - -contains - - subroutine rand(x) - real(dp), intent(out) :: x - logical, save :: first = .true. - real(dp), save :: u(2) - real(dp) :: r2 - if (first) then - do - call random_number(u) - u = 2*u-1 - r2 = sum(u**2) - if (r2 < 1 .and. r2 > 0) exit - end do - u = u * sqrt(-2*log(r2)/r2) - x = u(1) - else - x = u(2) - end if - first = .not. first - end subroutine - -end program -""" diff --git a/lfortran/ast/tests/test_parser.py b/lfortran/ast/tests/test_parser.py deleted file mode 100644 index 4f14dc4f9c..0000000000 --- a/lfortran/ast/tests/test_parser.py +++ /dev/null @@ -1,724 +0,0 @@ -import os - -from lfortran.ast import src_to_ast, dump, SyntaxErrorException - -def to_tuple(t): - if t is None or isinstance(t, (str, int, complex)): - return t - elif isinstance(t, list): - return [to_tuple(e) for e in t] - result = [t.__class__.__name__] - if hasattr(t, 'lineno') and hasattr(t, 'col_offset'): - result.append((t.lineno, t.col_offset)) - if t._fields is None: - return tuple(result) - for f in t._fields: - result.append(to_tuple(getattr(t, f))) - return tuple(result) - -def run_tests(tests, filename, translation_unit=False): - results = [] - for s in tests: - results.append(to_tuple(src_to_ast(s, translation_unit))) - - here = os.path.dirname(__file__) - results_filename = os.path.abspath(os.path.join(here, filename)) - try: - with open(results_filename) as f: - d = {} - exec(f.read(), d) - results_ref = d["results"] - equal = (results == results_ref) - report = True - except FileNotFoundError: - equal = False - report = False - print("Results file does not exist.") - if not equal: - results_str = "results = [\n" - for r in results: - results_str += " %r,\n" % (r,) - results_str += "]\n" - with open(results_filename+".latest", "w") as f: - f.write(results_str) - print("Results file generated. If you want to use it, execute:\n" \ - "cp '{0}.latest' '{0}'".format(results_filename)) - if report: - print() - if (len(results) == len(results_ref)): - print("REPORT:") - print("Printing failed tests:") - for i, t, s, l in zip(range(len(tests)), tests, results, - results_ref): - if s != l: - print("n test") - print("%d: %s" % (i, t)) - print(s) - print(l) - print() - else: - print("Results lists have different lengths.") - assert equal - -def parses(test, translation_unit=False): - """ - Returns True if and only if the string `test` parses to AST. - """ - try: - s = src_to_ast(test, translation_unit) - passed = True - except SyntaxErrorException: - passed = False - return passed - -def all_fail(tests, translation_unit=False): - for test in tests: - assert not parses(test, translation_unit) - - -# ------------------------------------------------------------------------- -# Tests: - -def test_to_tuple(): - ast_tree = src_to_ast("2+3", False) - t = to_tuple(ast_tree) - t_ref = ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Add',), ('Num', (1, 1), - '3')) - assert t == t_ref - - ast_tree = src_to_ast("2+x", False) - t = to_tuple(ast_tree) - t_ref = ('BinOp', (1, 1), ('Num', (1, 1), '2'), ('Add',), ('Name', (1, 1), - 'x')) - assert t == t_ref - - ast_tree = src_to_ast("(x+y)**2", False) - t = to_tuple(ast_tree) - t_ref = ('BinOp', (1, 1), ('BinOp', (1, 1), ('Name', (1, 1), 'x'), - ('Add',), ('Name', (1, 1), 'y')), ('Pow',), ('Num', (1, 1), '2')) - assert t == t_ref - - -def test_expr1(): - tests = [ - "1", - "2+3", - "(1+3)*4", - "1+3*4", - "x", - "yx", - "x+y", - "2+x", - "(x+y)**2", - "(x+y)*3", - "x+y*3", - "(1+2+a)*3", - "f(3)+6", - "f(3+6)", - "real(b, dp)", - "2*u-1", - "sum(u**2)", - "u(2)", - "u * sqrt(-2*log(r2)/r2)", - ".not. first", - "a - 1._dp/3", - "1/sqrt(9*d)", - "(1 + c*x)**3", - "i + 1", - '"s"', - '"some text"', - "a(3:5,i:j)", - "b(:)", - "a(:5,i:j) + b(1:)", - "[1, 2, 3, i]", - "f()", - "x%a", - "x%a()", - "x%b(i, j)", - "y%c(5, :)", - "x%f%a", - "x%g%b(i, j)", - "y%h%c(5, :)", - """ "a'b'c" """, - """ 'a"b"c'""", - """ 'a""bc""x'""", - """ "a""c" """, - """ "a""b""c" """, - """ \"\"\"zippo\"\"\" """, - """ 'a''c'""", - """ 'a''b''c'""", - """ '''zippo'''""", - #""" "aaa" // str(x) // "bb" """, - #""" "a" // "b" """, - - "1 .and. 2", - "a .and. b", - "a == 1 .and. b == 2", - "a == 1 .or. b == 2", - "a .and. b .and. c", - "a .or. b .or. c", - ".not. (a == 1)", - "(a == 1) .and. .not. (b == 2)", - ] - run_tests(tests, "expr_results.py") - -def test_expr2(): - tests = [ - "1x", - "1+", - "(1+", - "(1+2", - "1+2*", - "f(3+6", - ] - all_fail(tests) - -def test_statements1(): - tests = [ - "call random_number(u)", - "u = 2*u-1", - "r2 = sum(u**2)", - "u = u * sqrt(-2*log(r2)/r2)", - "x = u(1)", - "x = u(2)", - "first = .not. first", - "d = a - 1._dp/3", - "c = 1/sqrt(9*d)", - "v = (1 + c*x)**3", - "fn_val = d*v", - "exit", - "cycle", - "call randn(x(i))", - "call randn(x)", - "call random_number(U)", - "call rand_gamma0(a, .true., x)", - "call rand_gamma0(a, .true., x(1))", - "call rand_gamma0(a, .false., x(i))", - "call rand_gamma_vector_n(a, size(x), x)", - "call f(a=4, b=6, c=i)", - "open(newunit=a, b, c)", - "allocate(c(4), d(4))", - "close(u)", - "x = 1; y = 2", - "y = 5; a = 1; x = u(2)", - "a = 5", - "x = 1; y = 2;", - "y = 5; a = 1; x = u(2);", - "a = 5;", - "; ;", - 'stop "OK"', - #'write (*,"(i4)") 45', - #'write (*,*) 45, "ss"', - 'print "(i4)", 45', - 'print *, 45, "sss", a+1', - #"x => y", - #"x => y(1:4, 5)", - "call g(a(3:5,i:j), b(:))", - "call g(a(:5,i:j), b(1:))", - "c = [1, 2, 3, i]", - "a = x%a", - "b = x%b(i, j)", - "c = y%c(5, :)", - "a = x%f%a", - "b = x%g%b(i, j)", - "c = y%h%c(5, :)", - "x%f%a = a", - "x%g%b(i, j) = b", - "y%h%c(5, :) = c", - "call x%f%e()", - ] - tests = [x+"\n" for x in tests] - run_tests(tests, "statements_results.py") - -def test_control_flow1(): - tests = [ - """\ -do while(x == y) - i = i +1 - cycle - exit -end do -""", - """\ -subroutine a -if (a) then - x = 1 -else - x = 2 -end if -end subroutine -""", - """\ -subroutine a -if (a) then - x = 1 -else if (b) then - x = 2 -end if -end subroutine -""", - """\ -subroutine a -if (a) then - x = 1 -else if (b) then - x = 2 -else if (c) then - x = 2 -end if -end subroutine -""", - """\ -subroutine a -if (a) then - x = 1 -end if -end subroutine -""", - """\ -subroutine a -if (a) then - x = 1 - y = 2 -end if -end subroutine -""", - """\ -subroutine a -if (a) x = 1 -end subroutine -""", - """\ -subroutine a -if (a) & - x = 1 -end subroutine -""", - """\ -subroutine a -if (a) & ! if statement - x = 1 -end subroutine -""", - """\ -subroutine a -do - x = 1 -end do -end subroutine -""", - """\ -subroutine a -do i = 1, 5 - x = x + i -end do -end subroutine -""", - """\ -subroutine a -do i = 1, 5, -1 - x = i -end do -end subroutine -""", - """\ -select case(k) - case(1) - call a() - case(i) - call b() -end select -""", - """\ -select case(k) - case(1) - call a() - case(i) - call b() - case default - call c() -end select -""", - """\ -where (a < 5) B = 1 -""", - """\ -where (a < 5) - B = 1 -end where -""", - """\ -where (a < 5) - B = 1 -else where - B = 0 -end where -""", - """\ -where (a < 5) - B = 1 -else - B = 0 -end where -""", - """\ -where (a < 5) - B = 1 -else where (a < 7) - B = 0 -else where - B = 3 -end where -""", - """\ -where (a < 5) - B = 1 -else where (a < 7) - B = 0 -end where -""", - ] - run_tests(tests, "controlflow_results.py") - -def test_decl(): - tests = [ - "integer x", - "integer :: x", - "integer :: a(9,10), b(10)", - "integer, dimension(9,10) :: c", - "integer, dimension(:,:), intent(in) :: e", - "integer(c_int) :: i", - - "real a", - "real :: a", - "real(dp) :: a, b", - "real(dp) :: a(9,10), b(10)", - "real(dp) :: a(m,n)", - "real(dp), allocatable :: a(:,:)", - "real(dp) y = 5", - "real(c_double) :: f", - - "character(len=*) :: c", - - "type(xx), intent(inout) :: x, y", - ] - tests = [x+"\n" for x in tests] - run_tests(tests, "decl_results.py") - -def test_use(): - tests = [ - "use b", - "use a, only: b, c", - "use a, only: x => b, c, d => a", - ] - tests = [x+"\n" for x in tests] - run_tests(tests, "use_results.py") - -def test_subroutines_functions(): - tests = [ - """\ -real(dp) pure function f(e) result(r) -r = 1 -end function -""", - """\ -real(dp) recursive function f(e) result(r) -r = 1 -end function -""", - """\ -function f(e) -f = 1 -end function -""", - """\ -function f(e) -f = 1 -end function""", - """\ -subroutine f -integer :: x -end subroutine -""", - """\ -subroutine f() -! Some comment -integer :: x -! Some other comment -end subroutine -""", - """\ -subroutine f() -integer :: x -end subroutine""", - """\ -subroutine f(a, b, c, d) -integer, intent(in) :: a, b -integer, intent ( in ) :: c, d -integer :: z -integer::y -end subroutine -""", - """\ -subroutine f(a, b, c, d) -integer, intent(out) :: a, b -integer, intent(inout) :: c, d -integer :: z -integer::y -end subroutine -""", - ] - run_tests(tests, "subroutine_results.py") - -def test_program(): - tests = [ - """\ -program test -implicit none -integer :: x -x = 1 -call a(x) -end program -""", - """\ -program test -implicit none -integer :: x -x = 1 -call a(x) -end program""", - """\ -program test -implicit none -integer :: x -x = 1 -call a(x) -contains - subroutine a(b) - integer, intent(in) :: b - end subroutine -end program -""", - """\ -program test -implicit none -integer :: x -x = 1 -call a(x) -contains - subroutine a(b) - integer, intent(in) :: b - end subroutine - - subroutine f(b) - integer, intent(in) :: b - end subroutine -end program -""", - ] - run_tests(tests, "program_results.py", True) - -def test_module(): - tests = [ - """\ -module test -implicit none -integer :: x -end module -""", - """\ -module test -implicit none -integer :: x -end module""", - """\ -module test -implicit none -private -integer :: x -end module -""", - """\ -module test -implicit none -private x, y -integer :: x, y -end module -""", - """\ -module test -implicit none -private :: x, y -integer :: x, y -end module -""", - """\ -module test -implicit none -public -integer :: x -end module -""", - """\ -module test -implicit none -public x, y -integer :: x, y -end module -""", - """\ -module test -implicit none -public :: x, y -integer :: x, y -end module -""", - """\ -module test -implicit none -private -public :: x, y -integer :: x, y -end module -""", - """\ -module test -implicit none -private x -public y -integer :: x, y -end module -""", - """\ -module test -implicit none -contains - subroutine a(b) - integer, intent(in) :: b - end subroutine -end module -""", - """\ -module test -implicit none -contains - subroutine a(b) - integer, intent(in) :: b - end subroutine - - subroutine f(b) - integer, intent(in) :: b - end subroutine -end module -""", - """\ -module test -implicit none -integer :: x -contains - subroutine a(b) - integer, intent(in) :: b - end subroutine -end module -""", - """\ -module test -implicit none -contains - function f() result(y) - y = 0 - end function -end module -""", - - # interface - """\ -module test -implicit none -interface name - module procedure a - module procedure b - module procedure c -end interface -end module -""", - ] - run_tests(tests, "module_results.py", True) - -def test_interactive(): - tests = [ - """\ -a = 5; b = 6 -""", - """\ -a = 5 -b = 6 -""", - """\ -a = 5 -print *, a -""", - """\ -a = 5 - -subroutine p() -print *, a -end subroutine - -call p() -""", - """\ -module a -implicit none -integer :: i -end module - -use a, only: i - -i = 5 -""", - """\ -use a, only: i - -i = 5 -""", - """\ -use a, only: i -i = 5 -""", - """\ -!x = [1, 2, 3] -!y = [1, 2, 1] -call plot(x, y, "o-") -""", - """\ -x = [1, 2, 3] -y = [1, 2, 1] -call plot(x, y, "o-") -""", - ] - run_tests(tests, "interactive_results.py", False) - -def test_interactive2(): - tests = [ - "use a i=5", - ] - all_fail(tests) - -def test_case_sensitivity(): - tests = [ - "Integer :: x", - "INTEGER :: x", - "iNteger :: x", - "integeR, dImenSion(9,10) :: c", - "integer, DIMENSION(:,:), intenT(In) :: e", - "integer(c_Int) :: i", - - "Real a", - "REAL :: a", - "real(dp), aLLocatable :: a(:,:)", - "cHAracter(len=*) :: c", - - "tYPe(xx), inTEnt(inOUt) :: x, y", - ] - run_tests(tests, "case_sensitivity_results.py") diff --git a/lfortran/ast/tests/test_utils.py b/lfortran/ast/tests/test_utils.py deleted file mode 100644 index 8379e263a5..0000000000 --- a/lfortran/ast/tests/test_utils.py +++ /dev/null @@ -1,79 +0,0 @@ -from lfortran.ast.utils import make_tree - -def test_tree1(): - assert make_tree("a", []) == """\ -a\ -""" - assert make_tree("a", ["1"]) == """\ -a -╰─1\ -""" - assert make_tree("a", ["1", "2"]) == """\ -a -├─1 -╰─2\ -""" - t = make_tree("a", ["1", "2", "3"]) - assert t == """\ -a -├─1 -├─2 -╰─3\ -""" - assert make_tree("a", [t, "2", "3"]) == """\ -a -├─a -│ ├─1 -│ ├─2 -│ ╰─3 -├─2 -╰─3\ -""" - assert make_tree("a", ["1", t, "3"]) == """\ -a -├─1 -├─a -│ ├─1 -│ ├─2 -│ ╰─3 -╰─3\ -""" - assert make_tree("a", ["1", "2", t]) == """\ -a -├─1 -├─2 -╰─a - ├─1 - ├─2 - ╰─3\ -""" - assert make_tree("a", ["1", t]) == """\ -a -├─1 -╰─a - ├─1 - ├─2 - ╰─3\ -""" - assert make_tree("a", [t]) == """\ -a -╰─a - ├─1 - ├─2 - ╰─3\ -""" - assert make_tree("a", ["1\n2", "3"]) == """\ -a -├─1 -│ 2 -╰─3\ -""" - assert make_tree("a", ["1\n\n\n\n2", "3"]) == """\ -a -├─1 -│ -│ -│ -│ 2 -╰─3\ -""" \ No newline at end of file diff --git a/lfortran/ast/tests/test_visitor.py b/lfortran/ast/tests/test_visitor.py deleted file mode 100644 index 3e4668ae63..0000000000 --- a/lfortran/ast/tests/test_visitor.py +++ /dev/null @@ -1,128 +0,0 @@ -from lfortran import ast - -class SubroutinesVisitor(ast.ast.GenericASTVisitor): - - def __init__(self): - self.subroutine_list = [] - - def visit_Subroutine(self, node): - self.subroutine_list.append("subroutine %s(%s)" % (node.name, - ", ".join([x.arg for x in node.args]))) - self.visit_sequence(node.body) - - def get_subroutine_list(self): - return "\n".join(self.subroutine_list) - - -def test_list_subroutines(): - source = """\ -module subroutine1 -implicit none - -contains - -subroutine sub1(a, b) -integer, intent(in) :: a -integer, intent(out) :: b -b = a + 1 -end subroutine - -subroutine sub2(c) -integer, intent(out) :: c -call sub1(8, c) -end subroutine - -end module -""" - tree = ast.src_to_ast(source) - v = SubroutinesVisitor() - v.visit(tree) - assert v.get_subroutine_list() == """\ -subroutine sub1(a, b) -subroutine sub2(c)""" - -class SubroutinesVisitor2(ast.utils.NodeVisitor): - - def __init__(self): - self.subroutine_list = [] - - def visit_Subroutine(self, node): - self.subroutine_list.append("subroutine %s(%s)" % (node.name, - ", ".join([x.arg for x in node.args]))) - self.visit_sequence(node.body) - - def get_subroutine_list(self): - return "\n".join(self.subroutine_list) - - -def test_list_subroutines2(): - source = """\ -module subroutine1 -implicit none - -contains - -subroutine sub1(a, b) -integer, intent(in) :: a -integer, intent(out) :: b -b = a + 1 -end subroutine - -subroutine sub2(c) -integer, intent(out) :: c -call sub1(8, c) -end subroutine - -end module -""" - tree = ast.src_to_ast(source) - v = SubroutinesVisitor2() - v.visit(tree) - assert v.get_subroutine_list() == """\ -subroutine sub1(a, b) -subroutine sub2(c)""" - - - - -class DoLoopTransformer(ast.utils.NodeTransformer): - - def visit_DoLoop(self, node): - if node.var: - cond = ast.ast.Compare(ast.ast.Name(node.var, - lineno=1, col_offset=1), - ast.ast.LtE(), node.end, lineno=1, col_offset=1) - if node.increment: - step = node.increment - else: - step = ast.ast.Num(n="1", lineno=1, col_offset=1) - else: - cond = ast.ast.Constant(True, lineno=1, col_offset=1) - varname = ast.ast.Name(node.var, lineno=1, col_offset=1) - body = self.visit_sequence(node.body) - body = [ast.ast.Assignment(varname, - ast.ast.BinOp(varname, - ast.ast.Add(), step, lineno=1, col_offset=1), lineno=1, - col_offset=1)] + body - return [ast.ast.Assignment(varname, node.start, - lineno=1, col_offset=1), - ast.ast.WhileLoop(cond, body, lineno=1, col_offset=1)] - - -def test_doloop_transformer(): - source = """\ -subroutine test() -integer :: i, j -j = 0 -do i = 1, 10 - j = j + i -end do -if (j /= 55) error stop -end subroutine -""" - tree = ast.src_to_ast(source, False) - v = DoLoopTransformer() - assert isinstance(tree.body[1], ast.ast.DoLoop) - tree = v.visit(tree) - assert isinstance(tree.body[1], ast.ast.Assignment) - assert isinstance(tree.body[2], ast.ast.WhileLoop) diff --git a/lfortran/ast/tests/use_results.py b/lfortran/ast/tests/use_results.py deleted file mode 100644 index 24e6104f78..0000000000 --- a/lfortran/ast/tests/use_results.py +++ /dev/null @@ -1,5 +0,0 @@ -results = [ - ('Use', (1, 1), 'b', []), - ('Use', (1, 1), 'a', [('UseSymbol', 'b', None), ('UseSymbol', 'c', None)]), - ('Use', (1, 1), 'a', [('UseSymbol', 'x', 'b'), ('UseSymbol', 'c', None), ('UseSymbol', 'd', 'a')]), -] diff --git a/lfortran/ast/utils.py b/lfortran/ast/utils.py deleted file mode 100644 index f8660dc80c..0000000000 --- a/lfortran/ast/utils.py +++ /dev/null @@ -1,337 +0,0 @@ -import io -from prompt_toolkit.output.vt100 import Vt100_Output -from prompt_toolkit import print_formatted_text, HTML - -from . import ast - -from ..parser.parser import antlr_parse - -class SyntaxErrorException(Exception): - pass - -def src_to_ast(source, translation_unit=True): - """ - Parse the `source` string into an AST node. - """ - return antlr_parse(source, translation_unit) - -def parse_file(filename): - source = open(filename).read() - return src_to_ast(source) - -def iter_fields(node): - """ - Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields`` - that is present on *node*. - """ - for field in node._fields: - try: - yield field, getattr(node, field) - except AttributeError: - pass - -def dump(node, annotate_fields=True, include_attributes=False, - include_type=False): - """ - Return a formatted dump of the tree in *node*. This is mainly useful for - debugging purposes. The returned string will show the names and the values - for fields. This makes the code impossible to evaluate, so if evaluation is - wanted *annotate_fields* must be set to False. Attributes such as line - numbers and column offsets are not dumped by default. If this is wanted, - *include_attributes* can be set to True. - """ - def _format(node): - if isinstance(node, ast.AST): - fields = [(a, _format(b)) for a, b in iter_fields(node)] - rv = '%s(%s' % (node.__class__.__name__, ', '.join( - ('%s=%s' % field for field in fields) - if annotate_fields else - (b for a, b in fields) - )) - if include_attributes and node._attributes: - rv += fields and ', ' or ' ' - rv += ', '.join('%s=%s' % (a, _format(getattr(node, a))) - for a in node._attributes) - if include_type and node._type: - rv += ', type=%s' % node._type - return rv + ')' - elif isinstance(node, list): - return '[%s]' % ', '.join(_format(x) for x in node) - return repr(node) - if not isinstance(node, (ast.AST, list)): - raise TypeError('expected AST, got %r' % node.__class__.__name__) - return _format(node) - -def make_tree(root, children, color=False): - """ - Takes strings `root` and a list of strings `children` and it returns a - string with the tree properly formatted. - - color ... True: print the tree in color, False: no colors - - Example: - - >>> from lfortran.ast.utils import make_tree - >>> print(make_tree("a", ["1", "2"])) - a - ├─1 - ╰─2 - >>> print(make_tree("a", [make_tree("A", ["B", "C"]), "2"])) - a - ├─A - │ ├─B - │ ╰─C - ╰─2 - """ - def indent(s, type=1, color=False): - x = s.split("\n") - r = [] - if type == 1: - tree_char = "├─" - else: - tree_char = "╰─" - if color: - tree_char = fmt("%s" \ - % tree_char) - r.append(tree_char + x[0]) - for a in x[1:]: - if type == 1: - tree_char = "│ " - else: - tree_char = " " - if color: - tree_char = fmt("%s" \ - % tree_char) - r.append(tree_char + a) - return '\n'.join(r) - f = [] - f.append(root) - if len(children) > 0: - for a in children[:-1]: - f.append(indent(a, 1, color)) - f.append(indent(children[-1], 2, color)) - return '\n'.join(f) - -def fmt(text): - s = io.StringIO() - o = Vt100_Output(s, lambda : 80, write_binary=False) - print_formatted_text(HTML(text), end='', output=o) - return s.getvalue() - -def print_tree(node, color=True): - def _format(node): - if isinstance(node, ast.AST): - t = node.__class__.__bases__[0] - if issubclass(t, ast.AST): - root = t.__name__ + "." - else: - root = "" - root += node.__class__.__name__ - if color: - root = fmt("%s" % root) - children = [] - for a, b in iter_fields(node): - if isinstance(b, list): - if len(b) == 0: - children.append(make_tree(a + "=[]", [], color)) - else: - children.append(make_tree(a + "=↓", - [_format(x) for x in b], color)) - else: - children.append(a + "=" + _format(b)) - return make_tree(root, children, color) - r = repr(node) - if color: - r = fmt("%s" % r) - return r - if not isinstance(node, ast.AST): - raise TypeError('expected AST, got %r' % node.__class__.__name__) - s = "" - if color: - s += fmt("Legend: " - "Node, " - "Field, " - "Token" - "\n" - ) - s += _format(node) - print(s) - -def print_tree_typed(node, color=True): - def sym_str(sym): - """ - Print useful information about the symbol `sym`. - """ - s = "" - for a in sym: - if a == "intent" and sym[a]: - s += ", %s(%s)" % (a, sym[a]) - elif a == "dummy" and sym[a]: - s += ", %s" % a - return s - def _format(node): - if isinstance(node, ast.AST): - t = node.__class__.__bases__[0] - if issubclass(t, ast.AST): - root = t.__name__ + "." - else: - root = "" - root += node.__class__.__name__ - if color: - root = fmt("%s" % root) - if isinstance(node, (ast.expr)): - # FIXME: expr.Name should have a type - if not isinstance(node, ast.Name): - assert node._type is not None - root_type = repr(node._type) - if color: - root_type = fmt("%s" % root_type) - root_type = " " + root_type - root += root_type - else: - # FIXME: stmt.Assignment should not have a type - if not isinstance(node, (ast.Assignment, ast.arg)): - assert node._type is None - if isinstance(node, (ast.Subroutine, ast.Function, ast.Program)): - scope = "\n│ Local Scope:" - for (s, sym) in node._scope.symbols.items(): - if color: - scope += fmt("\n│ %s:" - "%s%s" % (s, - repr(sym["type"]), sym_str(sym))) - else: - scope += " %s:%s;" % (s, repr(sym["type"])) - root += scope - children = [] - for a, b in iter_fields(node): - if isinstance(b, list): - if len(b) == 0: - children.append(make_tree(a + "=[]", [], color)) - else: - children.append(make_tree(a + "=↓", - [_format(x) for x in b], color)) - else: - children.append(a + "=" + _format(b)) - return make_tree(root, children, color) - if node is None: - r = "None" - else: - r = repr(node) - if color: - r = fmt("%s" % r) - return r - if not isinstance(node, ast.AST): - raise TypeError('expected AST, got %r' % node.__class__.__name__) - s = "" - if color: - s += fmt("Legend: " - "Node, " - "Field, " - "Token, " - "Type, " - "Variables" - "n" - ) - s += _format(node) - print(s) - -class NodeVisitor(object): - """ - A node visitor base class that walks the abstract syntax tree and calls a - visitor function for every node found. This function may return a value - which is forwarded by the `visit` method. - - This class is meant to be subclassed, with the subclass adding visitor - methods. - - Per default the visitor functions for the nodes are ``'visit_'`` + - class name of the node. So a `TryFinally` node visit function would - be `visit_TryFinally`. This behavior can be changed by overriding - the `visit` method. If no visitor function exists for a node - (return value `None`) the `generic_visit` visitor is used instead. - - Don't use the `NodeVisitor` if you want to apply changes to nodes during - traversing. For this a special visitor exists (`NodeTransformer`) that - allows modifications. - """ - - def visit(self, node): - """Visit a node.""" - method = 'visit_' + node.__class__.__name__ - visitor = getattr(self, method, self.generic_visit) - return visitor(node) - - def visit_sequence(self, value): - for item in value: - if isinstance(item, ast.AST): - self.visit(item) - - def generic_visit(self, node): - """Called if no explicit visitor function exists for a node.""" - for field, value in iter_fields(node): - if isinstance(value, list): - self.visit_sequence(value) - elif isinstance(value, ast.AST): - self.visit(value) - - -class NodeTransformer(NodeVisitor): - """ - A :class:`NodeVisitor` subclass that walks the abstract syntax tree and - allows modification of nodes. - - The `NodeTransformer` will walk the AST and use the return value of the - visitor methods to replace or remove the old node. If the return value of - the visitor method is ``None``, the node will be removed from its location, - otherwise it is replaced with the return value. The return value may be the - original node in which case no replacement takes place. - - Here is an example transformer that rewrites all occurrences of name lookups - (``foo``) to ``data['foo']``:: - - class RewriteName(NodeTransformer): - - def visit_Name(self, node): - return copy_location(Subscript( - value=Name(id='data', ctx=Load()), - slice=Index(value=Str(s=node.id)), - ctx=node.ctx - ), node) - - Keep in mind that if the node you're operating on has child nodes you must - either transform the child nodes yourself or call the :meth:`generic_visit` - method for the node first. - - For nodes that were part of a collection of statements (that applies to all - statement nodes), the visitor may also return a list of nodes rather than - just a single node. - - Usually you use the transformer like this:: - - node = YourTransformer().visit(node) - """ - - def visit_sequence(self, old_value): - new_values = [] - for value in old_value: - if isinstance(value, ast.AST): - value = self.visit(value) - if value is None: - continue - elif not isinstance(value, ast.AST): - new_values.extend(value) - continue - new_values.append(value) - return new_values - - def generic_visit(self, node): - for field, old_value in iter_fields(node): - if isinstance(old_value, list): - old_value[:] = self.visit_sequence(old_value) - elif isinstance(old_value, ast.AST): - new_node = self.visit(old_value) - if new_node is None: - delattr(node, field) - else: - setattr(node, field, new_node) - return node diff --git a/lfortran/cli.py b/lfortran/cli.py deleted file mode 100644 index 7b7bf8d525..0000000000 --- a/lfortran/cli.py +++ /dev/null @@ -1,233 +0,0 @@ -import argparse -import os -import sys - -import llvmlite.binding as llvm - -def get_lib_path(): - here = os.path.abspath(os.path.dirname(__file__)) - if here.startswith(sys.prefix): - # We are installed, use the install location - root_dir = sys.prefix - else: - # We run from git, use the relative location - root_dir = os.path.abspath(os.path.join(here, "..")) - if sys.platform == "win32": - base_dir = os.path.join(root_dir, "bin") - else: - base_dir = os.path.join(root_dir, "share", "lfortran", "lib") - if not os.path.exists(base_dir): - raise Exception("LFortran runtime library path does not exist: %s" \ - % base_dir) - return base_dir - -_lfortran_runtime_library_loaded = False - -def load_lfortran_runtime_library(): - """ - Locates and loads the LFortran runtime library. - - If the library is already loaded, it will not load it again. - """ - global _lfortran_runtime_library_loaded - if not _lfortran_runtime_library_loaded: - base_dir = get_lib_path() - if sys.platform == "linux": - shprefix = "lib" - shsuffix = "so" - elif sys.platform == "win32": - shprefix = "" - shsuffix = "dll" - elif sys.platform == "darwin": - shprefix = "lib" - shsuffix = "dylib" - else: - raise NotImplementedError("Platform not supported yet.") - liblfortran_so = os.path.join(base_dir, shprefix + "lfortran_runtime." \ - + shsuffix) - llvm.load_library_permanently(liblfortran_so) - _lfortran_runtime_library_loaded = True - -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) diff --git a/lfortran/codegen/__init__.py b/lfortran/codegen/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/codegen/asr_to_llvm.py b/lfortran/codegen/asr_to_llvm.py deleted file mode 100644 index 0c34186869..0000000000 --- a/lfortran/codegen/asr_to_llvm.py +++ /dev/null @@ -1,130 +0,0 @@ -from llvmlite import ir - -from ..asr import asr -from ..semantic import kinds - -def asr_type_to_llvm(type): - """ - Converts an ASR type to an LLVM type. - """ - if isinstance(type, asr.Integer): - if type.kind == kinds.int8: - return ir.IntType(8) - elif type.kind == kinds.int16: - return ir.IntType(16) - elif type.kind == kinds.int32: - return ir.IntType(32) - elif type.kind == kinds.int64: - return ir.IntType(64) - elif type.kind == kinds.int128: - return ir.IntType(128) - else: - raise NotImplementedError("Integer kind not implemented") - elif isinstance(type, asr.Real): - if type.kind == kinds.real32: - return ir.DoubleType(32) - elif type.kind == kinds.real64: - return ir.DoubleType(64) - elif type.kind == kinds.real80: - return ir.DoubleType(80) - elif type.kind == kinds.real128: - return ir.DoubleType(128) - else: - raise NotImplementedError("Real kind not implemented") - elif isinstance(type, asr.Logical): - return ir.IntType(1) - raise NotImplementedError("Type not implemented") - -class ASR2LLVMVisitor(asr.ASTVisitor): - - def visit_TranslationUnit(self, node): - self._sym2ptr = {} - self._sym2argn = {} - self._module = ir.Module() - self._func = None - self._builder = None - - for s in node.global_scope.symbols: - sym = node.global_scope.symbols[s] - self.visit(sym) - for item in node.items: - self.visit(item) - - def visit_Assignment(self, node): - if isinstance(node.target, asr.VariableOld): - target = self.visit(node.target) - value = self.visit(node.value) - ptr = self._sym2ptr[node.target] - assert value.type == ptr.type.pointee - self._builder.store(value, ptr) - else: - raise NotImplementedError("Array") - - def visit_BinOp(self, node): - op = node.op - lhs = self.visit(node.left) - rhs = self.visit(node.right) - if isinstance(node.type, asr.Integer): - if isinstance(op, asr.Mul): - return self._builder.mul(lhs, rhs) - elif isinstance(op, asr.Div): - return self._builder.udiv(lhs, rhs) - elif isinstance(op, asr.Add): - return self._builder.add(lhs, rhs) - elif isinstance(op, asr.Sub): - return self._builder.sub(lhs, rhs) - else: - raise NotImplementedError("Pow") - else: - if isinstance(op, asr.Mul): - return self._builder.fmul(lhs, rhs) - elif isinstance(op, asr.Div): - return self._builder.fdiv(lhs, rhs) - elif isinstance(op, asr.Add): - return self._builder.fadd(lhs, rhs) - elif isinstance(op, asr.Sub): - return self._builder.fsub(lhs, rhs) - else: - raise NotImplementedError("Pow") - - def visit_VariableOld(self, node): - return self._builder.load(self._sym2ptr[node]) - - def visit_Function(self, node): - args = [] - for n, arg in enumerate(node.args): - llvm_type = asr_type_to_llvm(arg.type) - args.append(llvm_type.as_pointer()) - self._sym2argn[arg] = n - return_type = asr_type_to_llvm(node.return_var.type) - fn = ir.FunctionType(return_type, args) - func = ir.Function(self._module, fn, name=node.name) - block = func.append_basic_block(name='.entry') - builder = ir.IRBuilder(block) - for s in node.symtab.symbols: - sym = node.symtab.symbols[s] - if sym.dummy and sym != node.return_var: - ptr = func.args[self._sym2argn[sym]] - else: - llvm_type = asr_type_to_llvm(sym.type) - ptr = builder.alloca(llvm_type, name=sym.name) - self._sym2ptr[sym] = ptr - - old = [self._func, self._builder] - self._func, self._builder = func, builder - - self.visit_sequence(node.body) - retval = self._builder.load(self._sym2ptr[node.return_var]) - self._builder.ret(retval) - - self._func, self._builder = old - - - - - -def asr_to_llvm(a): - assert isinstance(a, asr.TranslationUnit) - v = ASR2LLVMVisitor() - v.visit(a) - return v._module diff --git a/lfortran/codegen/evaluator.py b/lfortran/codegen/evaluator.py deleted file mode 100644 index 94152c8ac0..0000000000 --- a/lfortran/codegen/evaluator.py +++ /dev/null @@ -1,195 +0,0 @@ -from ctypes import CFUNCTYPE, c_int -from copy import deepcopy - -import llvmlite.binding as llvm - -from ..ast import src_to_ast, dump, SyntaxErrorException, ast -from ..semantic.analyze import SymbolTableVisitor, annotate_tree -from .gen import codegen -from ..cli import load_lfortran_runtime_library - - -class FortranEvaluator(object): - - def __init__(self): - self.lle = LLVMEvaluator() - - self.symbol_table_visitor = SymbolTableVisitor() - self._global_scope = self.symbol_table_visitor._global_scope - - self.anonymous_fn_counter = 0 - - # Magic intrinsics: - from llvmlite import ir - from .gen import create_callback_py - mod = ir.Module() - def _lfort_plot_test(a, b): - return a+b - def _lfort_plot(a, b, c): - import pylab - pylab.plot([1, 2, 3], [a, b, c], "o-") - return 0 - self._show_counter = 0 - def _lfort_show(): - self._show_counter += 1 - import pylab - filename = "show_output%d.png" % self._show_counter - pylab.savefig(filename) - pylab.clf() - return self._show_counter - def _lfort_savefig(i): - import pylab - filename = "output%d.png" % i - print("Saving to %s." % filename) - pylab.savefig(filename) - return 0 - create_callback_py(mod, _lfort_plot_test) - create_callback_py(mod, _lfort_plot) - create_callback_py(mod, _lfort_savefig) - create_callback_py(mod, _lfort_show) - self.lle.add_module(str(mod)) - - def parse(self, source): - return src_to_ast(source, translation_unit=False) - - def semantic_analysis(self, ast_tree): - self.is_expr = isinstance(ast_tree, ast.expr) - self.is_stmt = isinstance(ast_tree, ast.stmt) - if self.is_expr: - # if `ast_tree` is an expression, wrap it in an anonymous function - self.anonymous_fn_counter += 1 - self.anonymous_fn_name = "_run%d" % self.anonymous_fn_counter - body = [ast.Assignment(ast.Name(self.anonymous_fn_name, - lineno=1, col_offset=1), - ast_tree, lineno=1, col_offset=1)] - - ast_tree = ast.Function(name=self.anonymous_fn_name, args=[], - return_type=None, return_var=None, bind=None, - use=[], - decl=[], body=body, contains=[], - lineno=1, col_offset=1) - - if self.is_stmt: - # if `ast_tree` is a statement, wrap it in an anonymous subroutine - self.anonymous_fn_counter += 1 - self.anonymous_fn_name = "_run%d" % self.anonymous_fn_counter - body = [ast_tree] - - ast_tree = ast.Function(name=self.anonymous_fn_name, args=[], - return_type=None, return_var=None, bind=None, - use=[], - decl=[], body=body, contains=[], - lineno=1, col_offset=1) - - self.symbol_table_visitor.mark_all_external() - self.symbol_table_visitor.visit(ast_tree) - annotate_tree(ast_tree, self._global_scope) - return ast_tree - - def llvm_code_generation(self, ast_tree, optimize=True): - source_ll = str(codegen(ast_tree, - self.symbol_table_visitor._global_scope)) - self._source_ll = source_ll - mod = self.lle.parse(self._source_ll) - if optimize: - self.lle.optimize(mod) - self._source_ll_opt = str(mod) - else: - self._source_ll_opt = None - return mod - - def machine_code_generation_load_run(self, mod): - self.lle.add_module_mod(mod) - self._source_asm = self.lle.get_asm(mod) - - if self.is_expr: - return self.lle.intfn(self.anonymous_fn_name) - - if self.is_stmt: - self.lle.voidfn(self.anonymous_fn_name) - return - - def evaluate_statement(self, ast_tree0, optimize=True): - if ast_tree0 is None: - return - ast_tree = self.semantic_analysis(ast_tree0) - mod = self.llvm_code_generation(ast_tree, optimize) - return self.machine_code_generation_load_run(mod) - - def evaluate(self, source, optimize=True): - ast_tree0 = self.parse(source) - if isinstance(ast_tree0, list): - for statement in ast_tree0: - r = self.evaluate_statement(statement, optimize) - else: - r = self.evaluate_statement(ast_tree0, optimize) - self._ast_tree0 = ast_tree0 - return r - - -class LLVMEvaluator(object): - - def __init__(self): - llvm.initialize() - llvm.initialize_native_asmprinter() - llvm.initialize_native_target() - - target = llvm.Target.from_default_triple() - self.target_machine = target.create_target_machine() - self.target_machine.set_asm_verbosity(True) - mod = llvm.parse_assembly("") - mod.verify() - self.ee = llvm.create_mcjit_compiler(mod, self.target_machine) - - pmb = llvm.create_pass_manager_builder() - pmb.opt_level = 3 - pmb.loop_vectorize = True - pmb.slp_vectorize = True - self.pm = llvm.create_module_pass_manager() - pmb.populate(self.pm) - - load_lfortran_runtime_library() - - def parse(self, source): - mod = llvm.parse_assembly(source) - mod.verify() - return mod - - def optimize(self, mod): - self.pm.run(mod) - - def add_module_mod(self, mod): - self.ee.add_module(mod) - self.ee.finalize_object() - - def get_asm(self, mod): - return self.target_machine.emit_assembly(mod) - - def add_module(self, source, optimize=True): - self.mod = self.parse(source) - if optimize: - self.optimize(self.mod) - source_opt = str(self.mod) - else: - source_opt = None - self.add_module_mod(self.mod) - return source_opt - - def intfn(self, name): - """ - `name` is a string, the name of the function of no arguments that - returns an int, the function will be called and the integer value - returned. The `name` must be present and of the correct signature, - otherwise the behavior is undefined. - """ - fptr = CFUNCTYPE(c_int)(self.ee.get_function_address(name)) - return fptr() - - def voidfn(self, name): - """ - `name` is a string, the name of the function of no arguments and no - return value, the function will be called. The `name` must be present - and of the correct signature, otherwise the behavior is undefined. - """ - fptr = CFUNCTYPE(None)(self.ee.get_function_address(name)) - return fptr() diff --git a/lfortran/codegen/gen.py b/lfortran/codegen/gen.py deleted file mode 100644 index 5f4bc97e78..0000000000 --- a/lfortran/codegen/gen.py +++ /dev/null @@ -1,679 +0,0 @@ -from llvmlite import ir -from llvmlite.binding import get_default_triple - -from ..ast import ast -from ..ast.utils import NodeTransformer -from ..semantic.analyze import Integer, Real, Logical, Array - -def get_global(module, name): - try: - return module.get_global(name) - except KeyError: - return None - -def create_global_var(module, base_name, v): - """ - Create a unique global variable with the name base_name_%d. - """ - count = 0 - while get_global(module, "%s_%d" % (base_name, count)): - count += 1 - var = ir.GlobalVariable(module, v.type, name="%s_%d" % (base_name, count)) - var.initializer = v - return var - -def create_global_const(module, base_name, v): - """ - Create a unique global constant with the name base_name_%d. - """ - var = create_global_var(module, base_name, v) - var.global_constant = True - return var - -def printf(module, builder, fmt, *args): - """ - Call printf(fmt, *args). - """ - c_ptr = ir.IntType(8).as_pointer() - - fmt_ptr = create_global_string(module, builder, fmt) - fn_printf = get_global(module, "_lfortran_printf") - if not fn_printf: - fn_type = ir.FunctionType(ir.VoidType(), [c_ptr], var_arg=True) - fn_printf = ir.Function(module, fn_type, name="_lfortran_printf") - - builder.call(fn_printf, [fmt_ptr] + list(args)) - -def exit(module, builder, n=0): - """ - Call exit(n). - """ - c_ptr = ir.IntType(8).as_pointer() - - n_ = ir.Constant(ir.IntType(64), n) - fn_exit = get_global(module, "exit") - if not fn_exit: - fn_type = ir.FunctionType(ir.VoidType(), [ir.IntType(64)]) - fn_exit = ir.Function(module, fn_type, name="exit") - - builder.call(fn_exit, [n_]) - -def is_positive(expr): - if isinstance(expr, ast.Num): - return float(expr.n) > 0 - if isinstance(expr, ast.UnaryOp): - if isinstance(expr.op, ast.USub): - return not is_positive(expr.operand) - raise Exception("Not implemented.") - -class DoLoopTransformer(NodeTransformer): - - def visit_DoLoop(self, node): - if node.var: - if node.increment: - step = node.increment - if is_positive(step): - op = ast.LtE() - else: - op = ast.GtE() - else: - step = ast.Num(n="1", lineno=1, col_offset=1) - op = ast.LtE() - cond = ast.Compare( - ast.BinOp(ast.Name(node.var, lineno=1, col_offset=1), - ast.Add(), step, lineno=1, col_offset=1), - op, node.end, lineno=1, col_offset=1) - else: - cond = ast.Constant(True, lineno=1, col_offset=1) - body = self.visit_sequence(node.body) - var_name = ast.Name(node.var, lineno=1, col_offset=1) - body = [ast.Assignment(var_name, - ast.BinOp(ast.Name(node.var, lineno=1, col_offset=1), - ast.Add(), step, lineno=1, col_offset=1), lineno=1, - col_offset=1)] + body - return [ast.Assignment(var_name, - ast.BinOp(node.start, - ast.Sub(), step, lineno=1, col_offset=1), - lineno=1, col_offset=1), - ast.WhileLoop(cond, body, lineno=1, col_offset=1)] - -def transform_doloops(tree, global_scope): - v = DoLoopTransformer() - tree = v.visit(tree) - # FIXME: after transforming do loops, we have to annotate types again: - from ..semantic.analyze import annotate_tree - annotate_tree(tree, global_scope) - return tree - -def create_global_string(module, builder, string): - c_ptr = ir.IntType(8).as_pointer() - b = bytearray((string + '\00').encode('ascii')) - string_const = ir.Constant(ir.ArrayType(ir.IntType(8), len(b)), b) - string_var = create_global_const(module, "compiler_id", string_const) - string_ptr = builder.bitcast(string_var, c_ptr) - return string_ptr - -def is_int(node): - if node._type == Integer(): - return True - if isinstance(node._type, Array): - return node._type.type_ == Integer() - return False - -_function_pointers = [] -def create_callback_py(m, f, name=None): - """ - Creates an LLVM function that calls the Python callback function `f`. - - Parameters: - - m ...... LLVM module - f ...... Python function - name ... the name of the LLVM function to create (if None, the name - of the function 'f will be used) - - It uses ctypes to create a C functin pointer and embeds this pointer into - the generated LLVM function. It returns a ctype's function type, which - you can use to type the LLVM function pointer back into a Python function. - - The C pointer is stored in the `_function_pointers` global list to - prevent it from being garbage collected. - """ - from ctypes import c_int, c_void_p, CFUNCTYPE, cast - from inspect import signature - sig = signature(f) - nargs = len(sig.parameters) - if name is None: - name = f.__name__ - ftype = CFUNCTYPE(c_int, *([c_int]*nargs)) - f2 = ftype(f) - # Store the function pointer so that it does not get garbage collected - _function_pointers.append(f2) - faddr = cast(f2, c_void_p).value - int64 = ir.IntType(64) - ftype2 = ir.FunctionType(int64, [int64]*nargs) - create_callback_stub(m, name, faddr, ftype2) - return ftype - -def create_callback_stub(m, name, faddr, ftype): - """ - Creates an LLVM function that calls the callback function at memory - address `addr`. - """ - stub = ir.Function(m, ftype, name=name) - builder = ir.IRBuilder(stub.append_basic_block('entry')) - cb = builder.inttoptr(ir.Constant(ir.IntType(64), faddr), - ftype.as_pointer()) - builder.ret(builder.call(cb, stub.args)) - -class CodeGenVisitor(ast.ASTVisitor): - """ - Loop over AST and generate LLVM IR code. - - The __init__() function initializes a new LLVM module and the codegen() - function keeps appending to it --- it can be called several times. - - Consult Fortran.asdl to see what the nodes are and their members. If a node - is encountered that is not implemented by the visit_* method, the - ASTVisitor base class raises an exception. - """ - - def __init__(self, global_scope): - self._global_scope = global_scope - self._current_scope = self._global_scope - self.module = ir.Module() - self.func = None - self.builder = None - self.types = { - Integer(): ir.IntType(64), - Real(): ir.DoubleType(), - Logical(): ir.IntType(1), - } - fn_type = ir.FunctionType(ir.DoubleType(), - [ir.IntType(64), ir.DoubleType().as_pointer()]) - fn_sum = ir.Function(self.module, fn_type, name="_lfort_sum") - self._global_scope.symbols["sum"]["fn"] = fn_sum - fn_rand = ir.Function(self.module, fn_type, name="_lfort_random_number") - self._global_scope.symbols["random_number"]["fn"] = fn_rand - self._global_scope.symbols["abs"]["fn"] = self.module.declare_intrinsic( - 'llvm.fabs', [ir.DoubleType()]) - self._global_scope.symbols["sqrt"]["fn"] = self.module.declare_intrinsic( - 'llvm.sqrt', [ir.DoubleType()]) - self._global_scope.symbols["log"]["fn"] = self.module.declare_intrinsic( - 'llvm.log', [ir.DoubleType()]) - - # plot - fn_type = ir.FunctionType(ir.IntType(64), - [ir.IntType(64), ir.IntType(64)]) - fn_plot = ir.Function(self.module, fn_type, name="_lfort_plot_test") - self._global_scope.symbols["plot_test"]["fn"] = fn_plot - fn_type = ir.FunctionType(ir.IntType(64), - [ir.IntType(64), ir.IntType(64), ir.IntType(64)]) - fn_plot = ir.Function(self.module, fn_type, name="_lfort_plot") - self._global_scope.symbols["plot"]["fn"] = fn_plot - fn_type = ir.FunctionType(ir.IntType(64), - [ir.IntType(64)]) - fn_plot = ir.Function(self.module, fn_type, name="_lfort_savefig") - self._global_scope.symbols["savefig"]["fn"] = fn_plot - fn_type = ir.FunctionType(ir.IntType(64), []) - fn_plot = ir.Function(self.module, fn_type, name="_lfort_show") - self._global_scope.symbols["show"]["fn"] = fn_plot - - def codegen(self, tree): - """ - Generates code for `tree` and appends it into the LLVM module. - """ - self.do_global_vars() - if isinstance(tree, ast.Declaration): - # `tree` is a declaration in the global scope. - # The global variable is already defined by do_global_vars(), - # nothing to do here. - return - assert isinstance(tree, (ast.Program, ast.Module, ast.Function, - ast.Subroutine)) - tree = transform_doloops(tree, self._global_scope) - self.visit(tree) - - def do_global_vars(self): - for sym in self._global_scope.symbols: - s = self._global_scope.symbols[sym] - if s["func"]: - if s["external"]: - if s["name"] in ["abs", "sqrt", "log", "sum", - "random_number"]: - # Skip these for now (they are handled in Program) - continue - if s["name"] in ["plot", "plot_test", "savefig", "show"]: - # Handled by plotting extension - continue - return_type = self.types[s["type"]] - args = [] - for n, arg in enumerate(s["args"]): - _type = s["scope"].symbols[arg.arg]["type"] - if isinstance(_type, Array): - _type = _type.type_ - args.append(self.types[_type].as_pointer()) - fn = ir.FunctionType(return_type, args) - s["fn"] = ir.Function(self.module, fn, name=s["name"]) - else: - name = s["name"] + "_0" - assert not get_global(self.module, name) - type_f = s["type"] - if isinstance(type_f, Array): - assert len(type_f.shape) == 1 - var_type = ir.ArrayType(self.types[type_f.type_], - type_f.shape[0]) - else: - var_type = self.types[type_f] - var = ir.GlobalVariable(self.module, var_type, name=name) - if not s["external"]: - # TODO: Undefined fails, but should work: - #var.initializer = ir.Undefined - # For now we initialize to 0: - if isinstance(type_f, Array): - var.initializer = ir.Constant(var_type, - [0]*type_f.shape[0]) - else: - var.initializer = ir.Constant(var_type, 0) - s["ptr"] = var - - def visit_Program(self, node): - self._current_scope = node._scope - self.module = ir.Module() - self.module.triple = get_default_triple() - self.types = { - Integer(): ir.IntType(64), - Real(): ir.DoubleType(), - Logical(): ir.IntType(1), - } - - int_type = ir.IntType(64) - fn = ir.FunctionType(int_type, []) - self.func = ir.Function(self.module, fn, name="main") - block = self.func.append_basic_block(name='.entry') - self.builder = ir.IRBuilder(block) - - for ssym in self._current_scope.symbols: - assert ssym not in ["abs", "sqrt", "log", "sum", "random_number"] - sym = self._current_scope.symbols[ssym] - type_f = sym["type"] - if isinstance(type_f, Array): - assert len(type_f.shape) == 1 - array_type = ir.ArrayType(self.types[type_f.type_], - type_f.shape[0]) - ptr = self.builder.alloca(array_type, name=sym["name"]) - else: - if type_f not in self.types: - raise Exception("Type not implemented.") - ptr = self.builder.alloca(self.types[type_f], name=sym["name"]) - sym["ptr"] = ptr - self._global_scope.symbols["abs"]["fn"] = self.module.declare_intrinsic( - 'llvm.fabs', [ir.DoubleType()]) - self._global_scope.symbols["sqrt"]["fn"] = self.module.declare_intrinsic( - 'llvm.sqrt', [ir.DoubleType()]) - self._global_scope.symbols["log"]["fn"] = self.module.declare_intrinsic( - 'llvm.log', [ir.DoubleType()]) - - fn_type = ir.FunctionType(ir.DoubleType(), - [ir.IntType(64), ir.DoubleType().as_pointer()]) - fn_sum = ir.Function(self.module, fn_type, name="_lfort_sum") - self._global_scope.symbols["sum"]["fn"] = fn_sum - fn_rand = ir.Function(self.module, fn_type, name="_lfort_random_number") - self._global_scope.symbols["random_number"]["fn"] = fn_rand - - self.visit_sequence(node.contains) - self.visit_sequence(node.body) - self.builder.ret(ir.Constant(ir.IntType(64), 0)) - self._current_scope = node._scope.parent_scope - - def visit_Assignment(self, node): - lhs = node.target - if isinstance(lhs, ast.Name): - sym = self._current_scope.resolve(lhs.id) - - value = self.visit(node.value) - - if "ptr" not in sym: - # TODO: this must happen elsewhere, in XXX1. - type_f = sym["type"] - assert not isinstance(type_f, Array) - if type_f not in self.types: - raise Exception("Type not implemented.") - ptr = sym["ptr"] - if value.type != ptr.type.pointee: - raise Exception("Type mismatch in assignment.") - self.builder.store(value, ptr) - elif isinstance(lhs, ast.FuncCallOrArray): - # array - sym = self._current_scope.resolve(lhs.func) - ptr = sym["ptr"] - assert len(sym["type"].shape) == 1 - idx = self.visit(lhs.args[0]) - value = self.visit(node.value) - # Convert 1-based indexing to 0-based - idx = self.builder.sub(idx, ir.Constant(ir.IntType(64), 1)) - addr = self.builder.gep(ptr, [ir.Constant(ir.IntType(64), 0), - idx]) - self.builder.store(value, addr) - else: - # should not happen - raise Exception("`node` must be either a variable or an array") - - def visit_Print(self, node): - for expr in node.values: - v = self.visit(expr) - if isinstance(expr, ast.Str): - printf(self.module, self.builder, "%s ", v) - elif expr._type == Integer(): - printf(self.module, self.builder, "%d ", v) - elif expr._type == Real(): - printf(self.module, self.builder, "%.17e ", v) - else: - raise Exception("Type not implemented in print.") - printf(self.module, self.builder, "\n") - - def visit_BinOp(self, node): - op = node.op - lhs = self.visit(node.left) - rhs = self.visit(node.right) - if is_int(node.left) and is_int(node.right): - if isinstance(op, ast.Mul): - return self.builder.mul(lhs, rhs) - elif isinstance(op, ast.Div): - return self.builder.udiv(lhs, rhs) - elif isinstance(op, ast.Add): - return self.builder.add(lhs, rhs) - elif isinstance(op, ast.Sub): - return self.builder.sub(lhs, rhs) - else: - raise Exception("Not implemented") - else: - if isinstance(op, ast.Mul): - return self.builder.fmul(lhs, rhs) - elif isinstance(op, ast.Div): - return self.builder.fdiv(lhs, rhs) - elif isinstance(op, ast.Add): - return self.builder.fadd(lhs, rhs) - elif isinstance(op, ast.Sub): - return self.builder.fsub(lhs, rhs) - else: - raise Exception("Not implemented") - - def visit_UnaryOp(self, node): - op = node.op - rhs = self.visit(node.operand) - if is_int(node.operand) or node.operand._type == Logical(): - if isinstance(op, ast.UAdd): - return rhs - elif isinstance(op, ast.USub): - return self.builder.neg(rhs) - elif isinstance(op, ast.Not): - return self.builder.not_(rhs) - else: - raise Exception("Not implemented") - else: - if isinstance(op, ast.UAdd): - return rhs - elif isinstance(op, ast.USub): - return self.builder.fsub(ir.Constant(ir.DoubleType(), 0), rhs) - else: - raise Exception("Not implemented") - - def visit_Num(self, node): - return ir.Constant(self.types[node._type], node.o) - - def visit_Constant(self, node): - if node.value == True: - return ir.Constant(ir.IntType(1), "true") - elif node.value == False: - return ir.Constant(ir.IntType(1), "false") - else: - raise Exception("Not implemented") - - def visit_Name(self, node): - v = node.id - sym = self._current_scope.resolve(v) - return self.builder.load(sym["ptr"]) - - def visit_Str(self, node): - return create_global_string(self.module, self.builder, node.s) - - def visit_FuncCallOrArray(self, node): - if isinstance(node._type, Array): - # Array - if len(node.args) != 1: - raise NotImplementedError("Require exactly one index for now") - idx = self.visit(node.args[0]) - # Convert 1-based indexing to 0-based - idx = self.builder.sub(idx, ir.Constant(ir.IntType(64), 1)) - sym = self._current_scope.resolve(node.func) - if sym["dummy"]: - # Dummy array argument is just a pointer directly into the - # array elements (e.g., a type i64*), so we index the pointer - # itself (i.e., just one index in the GEP instruction): - addr = self.builder.gep(sym["ptr"], - [idx]) - else: - # Non-dummy array variable is a pointer to the array (e.g., a - # type [4 x i64]*), so we first index the pointer as index 0, - # and then access the array (i.e., two indinces in the GEP - # instruction): - addr = self.builder.gep(sym["ptr"], - [ir.Constant(ir.IntType(64), 0), idx]) - return self.builder.load(addr) - else: - # Function call - sym = self._current_scope.resolve(node.func) - fn = sym["fn"] - # Temporary workarounds: - if len(node.args) == 1 and sym["name"] in ["sum"]: - # FIXME: for now we assume an array was passed in: - arg = self._current_scope.resolve(node.args[0].id) - addr = self.builder.gep(arg["ptr"], - [ir.Constant(ir.IntType(64), 0), - ir.Constant(ir.IntType(64), 0)]) - array_size = arg["ptr"].type.pointee.count - return self.builder.call(fn, - [ir.Constant(ir.IntType(64), array_size), addr]) - if len(node.args) == 1 and sym["name"] in ["abs", "sqrt", "log"]: - arg = self.visit(node.args[0]) - return self.builder.call(fn, [arg]) - if sym["name"] in ["plot", "plot_test", "savefig", "show"]: - # FIXME: Pass by value currently: - args = [] - for arg in node.args: - args.append(self.visit(arg)) - return self.builder.call(fn, args) - - args_ptr = [] - for arg in node.args: - if isinstance(arg, ast.Name): - # Get a pointer to a variable - sym = self._current_scope.resolve(arg.id) - if isinstance(sym["type"], Array): - a_ptr = self.builder.gep(sym["ptr"], - [ir.Constant(ir.IntType(64), 0), - ir.Constant(ir.IntType(64), 0)]) - else: - a_ptr = sym["ptr"] - args_ptr.append(a_ptr) - else: - # Expression is a value, get a pointer to a copy of it - a_value = self.visit(arg) - a_ptr = self.builder.alloca(a_value.type) - self.builder.store(a_value, a_ptr) - args_ptr.append(a_ptr) - return self.builder.call(fn, args_ptr) - - def visit_If(self, node): - cond = self.visit(node.test) - if not node.orelse: - # Only the `then` branch - with self.builder.if_then(cond): - self.visit_sequence(node.body) - else: - # Both `then` and `else` branches - with self.builder.if_else(cond) as (then, otherwise): - with then: - self.visit_sequence(node.body) - with otherwise: - self.visit_sequence(node.orelse) - - def visit_Compare(self, node): - op = node.op - lhs = self.visit(node.left) - rhs = self.visit(node.right) - ops = { - ast.Eq: "==", - ast.NotEq: "!=", - ast.Lt: "<", - ast.LtE: "<=", - ast.Gt: ">", - ast.GtE: ">=", - } - if is_int(node.left) and is_int(node.right): - return self.builder.icmp_signed(ops[type(op)], lhs, rhs) - else: - return self.builder.fcmp_ordered(ops[type(op)], lhs, rhs) - - def visit_Stop(self, node): - num = int(node.code) - exit(self.module, self.builder, num) - - def visit_ErrorStop(self, node): - exit(self.module, self.builder, 1) - - def visit_Exit(self, node): - self.builder.branch(self.loopend) - - def visit_Cycle(self, node): - self.builder.branch(self.loophead) - - def visit_WhileLoop(self, node): - loophead = self.func.append_basic_block('loop.header') - loopbody = self.func.append_basic_block('loop.body') - loopend = self.func.append_basic_block('loop.end') - self.loophead = loophead - self.loopend = loopend - - # header - self.builder.branch(loophead) - self.builder.position_at_end(loophead) - cond = self.visit(node.test) - self.builder.cbranch(cond, loopbody, loopend) - - # body - self.builder.position_at_end(loopbody) - self.visit_sequence(node.body) - self.builder.branch(loophead) - - # end - self.builder.position_at_end(loopend) - - def visit_Subroutine(self, node): - self._current_scope = node._scope - fn = ir.FunctionType(ir.VoidType(), [ir.IntType(64).as_pointer(), - ir.IntType(64).as_pointer()]) - func = ir.Function(self.module, fn, name=node.name) - block = func.append_basic_block(name='.entry') - builder = ir.IRBuilder(block) - old = [self.func, self.builder] - self.func, self.builder = func, builder - for n, arg in enumerate(node.args): - self._current_scope.resolve(arg.arg)["ptr"] = self.func.args[n] - - self.visit_sequence(node.body) - self.builder.ret_void() - - self.func, self.builder = old - self._current_scope = node._scope.parent_scope - - def visit_Function(self, node): - self._current_scope = node._scope - args = [] - for n, arg in enumerate(node.args): - sym = self._current_scope._local_symbols[arg.arg] - _type = sym["type"] - if isinstance(_type, Array): - _type = _type.type_ - args.append(self.types[_type].as_pointer()) - fn = ir.FunctionType(ir.IntType(64), args) - func = ir.Function(self.module, fn, name=node.name) - block = func.append_basic_block(name='.entry') - builder = ir.IRBuilder(block) - old = [self.func, self.builder] - self.func, self.builder = func, builder - for n, arg in enumerate(node.args): - sym = self._current_scope._local_symbols[arg.arg] - assert sym["name"] == arg.arg - assert sym["dummy"] == True - sym["ptr"] = self.func.args[n] - for v in self._current_scope._local_symbols: - sym = self._current_scope._local_symbols[v] - if sym["dummy"]: continue - type_f = sym["type"] - if isinstance(type_f, Array): - assert len(type_f.shape) == 1 - array_type = ir.ArrayType(self.types[type_f.type_], - type_f.shape[0]) - ptr = self.builder.alloca(array_type, name=sym["name"]) - else: - ptr = self.builder.alloca(self.types[type_f], name=sym["name"]) - sym["ptr"] = ptr - self._current_scope.resolve(node.name)["fn"] = func - - # Allocate the "result" variable - retsym = self._current_scope.resolve(node.name) - type_f = retsym["type"] - if isinstance(type_f, Array): - raise NotImplementedError("Return arrays are not implemented yet.") - else: - if type_f not in self.types: - raise Exception("Type not implemented.") - ptr = self.builder.alloca(self.types[type_f], name=retsym["name"]) - retsym["ptr"] = ptr - - self.visit_sequence(node.body) - retval = self.builder.load(retsym["ptr"]) - self.builder.ret(retval) - - self.func, self.builder = old - self._current_scope = node._scope.parent_scope - - def visit_SubroutineCall(self, node): - if node.name in ["random_number"]: - # FIXME: for now we assume an array was passed in: - sym = self._current_scope.resolve(node.name) - fn = sym["fn"] - arg = self._current_scope.resolve(node.args[0].id) - addr = self.builder.gep(arg["ptr"], - [ir.Constant(ir.IntType(64), 0), - ir.Constant(ir.IntType(64), 0)]) - array_size = arg["ptr"].type.pointee.count - return self.builder.call(fn, - [ir.Constant(ir.IntType(64), array_size), addr]) - else: - fn = get_global(self.module, node.name) - assert fn is not None - # Pass expressions by value (copying the result to a temporary variable - # and passing a pointer to that), pass variables by reference. - args_ptr = [] - for arg in node.args: - if isinstance(arg, ast.Name): - # Get a pointer to a variable - sym = self._current_scope.resolve(arg.id) - a_ptr = sym["ptr"] - args_ptr.append(a_ptr) - else: - # Expression is a value, get a pointer to a copy of it - a_value = self.visit(arg) - a_ptr = self.builder.alloca(a_value.type) - self.builder.store(a_value, a_ptr) - args_ptr.append(a_ptr) - self.builder.call(fn, args_ptr) - - -def codegen(tree, global_scope): - v = CodeGenVisitor(global_scope) - v.codegen(tree) - return v.module diff --git a/lfortran/codegen/tests/__init__.py b/lfortran/codegen/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/codegen/tests/test_arrays.py b/lfortran/codegen/tests/test_arrays.py deleted file mode 100644 index 0706ae3de4..0000000000 --- a/lfortran/codegen/tests/test_arrays.py +++ /dev/null @@ -1,96 +0,0 @@ -import pytest - -from lfortran.codegen.evaluator import FortranEvaluator -from lfortran.tests.utils import linux_only - -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 - -# FIXME: This fails on Windows, but it should work there -@linux_only -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_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 diff --git a/lfortran/codegen/tests/test_asr_to_llvm.py b/lfortran/codegen/tests/test_asr_to_llvm.py deleted file mode 100644 index b0d7f3df7e..0000000000 --- a/lfortran/codegen/tests/test_asr_to_llvm.py +++ /dev/null @@ -1,43 +0,0 @@ -from lfortran.ast import src_to_ast -from lfortran.asr.asr_check import verify_asr -from lfortran.semantic.ast_to_asr import ast_to_asr -from lfortran.codegen.asr_to_llvm import asr_to_llvm -from lfortran.codegen.evaluator import LLVMEvaluator - -def test_function1(): - source = """\ -integer function fn1(a, b) result(r) -integer, intent(in) :: a, b -r = a + b -end function -""" - ast = src_to_ast(source, translation_unit=False) - asrepr = ast_to_asr(ast) - verify_asr(asrepr) - - assert 'fn1' in asrepr.global_scope.symbols - fn1 = asrepr.global_scope.symbols['fn1'] - assert fn1.args[0].name == "a" - assert fn1.args[1].name == "b" - assert fn1.return_var.name == "r" - assert fn1.body[0].target == fn1.return_var - assert fn1.body[0].value.left == fn1.args[0] - assert fn1.body[0].value.right == fn1.args[1] - - llmod = asr_to_llvm(asrepr) - e = LLVMEvaluator() - e.add_module(str(llmod)) - e.add_module("""\ -declare i64 @fn1(i64* %".1", i64* %".2") - -define i64 @f1() -{ - %a = alloca i64 - %b = alloca i64 - store i64 2, i64* %a - store i64 3, i64* %b - %r = call i64 @fn1(i64* %a, i64* %b) - ret i64 %r -} -""") - assert e.intfn("f1") == 5 diff --git a/lfortran/codegen/tests/test_do_loops.py b/lfortran/codegen/tests/test_do_loops.py deleted file mode 100644 index 7ecb92d9e6..0000000000 --- a/lfortran/codegen/tests/test_do_loops.py +++ /dev/null @@ -1,249 +0,0 @@ -from lfortran.codegen.evaluator import FortranEvaluator - -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_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 - - -def test_while_loops_interactive(): - e = FortranEvaluator() - e.evaluate("""\ -integer :: i, j -i = 1 -j = 0 -do while (i < 11) - j = j + i - i = i + 1 -end do -""") - assert e.evaluate("i") == 11 - assert e.evaluate("j") == 55 - - e.evaluate("""\ -i = 1 -j = 0 -do while (i <= 10) - j = j + i - i = i + 1 -end do -""") - assert e.evaluate("i") == 11 - assert e.evaluate("j") == 55 - - e.evaluate("""\ -i = 1 -j = 0 -do while (i < 1) - j = j + i - i = i + 1 -end do -""") - assert e.evaluate("i") == 1 - assert e.evaluate("j") == 0 - - e.evaluate("""\ -i = 0 -j = 0 -do while (i < 10) - i = i + 1 - j = j + i -end do -""") - assert e.evaluate("i") == 10 - assert e.evaluate("j") == 55 - - e.evaluate("""\ -i = 0 -j = 0 -do while (i < 10) - i = i + 1 - if (i == 2) exit - j = j + i -end do -""") - assert e.evaluate("i") == 2 - assert e.evaluate("j") == 1 - - e.evaluate("""\ -i = 0 -j = 0 -do while (i < 10) - i = i + 1 - if (i == 2) cycle - j = j + i -end do -""") - assert e.evaluate("i") == 10 - assert e.evaluate("j") == 53 \ No newline at end of file diff --git a/lfortran/codegen/tests/test_expr.py b/lfortran/codegen/tests/test_expr.py deleted file mode 100644 index 4d108703ff..0000000000 --- a/lfortran/codegen/tests/test_expr.py +++ /dev/null @@ -1,65 +0,0 @@ -from lfortran.codegen.evaluator import FortranEvaluator - -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_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 \ No newline at end of file diff --git a/lfortran/codegen/tests/test_fortran_eval.py b/lfortran/codegen/tests/test_fortran_eval.py deleted file mode 100644 index 4962bf3ce7..0000000000 --- a/lfortran/codegen/tests/test_fortran_eval.py +++ /dev/null @@ -1,332 +0,0 @@ -from lfortran.codegen.evaluator import FortranEvaluator - -# Tests for FortranEvaluator - -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 -""") - -def test_subroutine(): - e = FortranEvaluator() - e.evaluate("""\ -subroutine sub1(a, b) -integer, intent(in) :: a -integer, intent(out) :: b -b = a + 1 -end subroutine -""") - -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 -""") - -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_f_call1(): - 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 - e.evaluate("integer :: i") - e.evaluate("i = 2") - assert e.evaluate("f(i)") == 7 - e.evaluate("i = 5") - assert e.evaluate("f(i)") == 10 - -def test_f_call2(): - e = FortranEvaluator() - e.evaluate("""\ -integer function f(a, b) -integer, intent(in) :: a, b -f = a + b -end function -""") - assert e.evaluate("f(2, 3)") == 5 - assert e.evaluate("f(5, -3)") == 2 - e.evaluate("integer :: i") - e.evaluate("i = -3") - assert e.evaluate("f(5, i)") == 2 - -def test_f_call3(): - e = FortranEvaluator() - e.evaluate("""\ -integer function f(a, b, c) -integer, intent(in) :: a, b, c -f = a + b + c -end function -""") - assert e.evaluate("f(2, 3, 4)") == 9 - assert e.evaluate("f(5, -3, -1)") == 1 - e.evaluate("integer :: i") - e.evaluate("i = -3") - assert e.evaluate("f(5, i, -1)") == 1 - -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_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 - -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 - -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_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_simple_arithmetics(): - e = FortranEvaluator() - assert e.evaluate("5+5") == 10 - assert e.evaluate("5+6") == 11 - -def test_whitespace1(): - e = FortranEvaluator() - e.evaluate("integer :: a") - e.evaluate("a = 5") - assert e.evaluate("a") == 5 - -def test_whitespace2(): - e = FortranEvaluator() - e.evaluate("""\ -integer :: a -""") - e.evaluate("""\ -a = 5 -""") - assert e.evaluate("""\ -a -""") == 5 - -def test_whitespace3(): - e = FortranEvaluator() - e.evaluate("""\ - -integer :: a - -""") - e.evaluate("""\ -a = 5 - -""") - assert e.evaluate("""\ -a - -""") == 5 - -def test_whitespace4(): - e = FortranEvaluator() - e.evaluate("""\ - -""") - e.evaluate(" ") - e.evaluate("") - -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_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_multiline3(): - 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_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_variables2(): - e = FortranEvaluator() - e.evaluate("integer :: a") - assert e._global_scope.resolve("a", False) - assert not e._global_scope.resolve("b", False) - e.evaluate("integer :: b") - assert e._global_scope.resolve("a", False) - assert e._global_scope.resolve("b", False) - e.evaluate("a = 5") - assert e.evaluate("a") == 5 - assert e._global_scope.resolve("a", False) - assert e._global_scope.resolve("b", False) - e.evaluate("b = a") - assert e.evaluate("a") == 5 - assert e.evaluate("b") == 5 - e.evaluate("b = a + 3") - assert e.evaluate("a") == 5 - assert e.evaluate("b") == 8 - assert e.evaluate("(a+b)*2") == 26 - -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" - -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 diff --git a/lfortran/codegen/tests/test_intrinsics.py b/lfortran/codegen/tests/test_intrinsics.py deleted file mode 100644 index 324e02234c..0000000000 --- a/lfortran/codegen/tests/test_intrinsics.py +++ /dev/null @@ -1,44 +0,0 @@ -from lfortran.codegen.evaluator import FortranEvaluator -from lfortran.tests.utils import linux_only - -# FIXME: This fails on Windows, but it should work there -@linux_only -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_plot(): - e = FortranEvaluator() - assert e.evaluate("""\ -integer :: a, b -a = 1 -b = 5 -plot_test(a, b) -""") == 6 diff --git a/lfortran/codegen/tests/test_llvm_eval.py b/lfortran/codegen/tests/test_llvm_eval.py deleted file mode 100644 index 944eca9a4e..0000000000 --- a/lfortran/codegen/tests/test_llvm_eval.py +++ /dev/null @@ -1,401 +0,0 @@ -import pytest - -from lfortran.codegen.evaluator import LLVMEvaluator - -# Tests for LLVMEvaluator - -def test_llvm_eval1(): - e = LLVMEvaluator() - e.add_module("""\ -define i64 @f1() -{ - ret i64 4 -} -""") - assert e.intfn("f1") == 4 - e.add_module("") - assert e.intfn("f1") == 4 - - e.add_module("""\ -define i64 @f1() -{ - ret i64 5 -} -""") - assert e.intfn("f1") == 5 - e.add_module("") - assert e.intfn("f1") == 5 - -def test_llvm_eval1_fail(): - e = LLVMEvaluator() - with pytest.raises(RuntimeError): - e.add_module("""\ -define i64 @f1() -{ - ; FAIL: "=x" is incorrect syntax - %1 =x alloca i64 -} -""") - -def test_llvm_eval2(): - e = LLVMEvaluator() - e.add_module("""\ -@count = global i64 0 - -define i64 @f1() -{ - store i64 4, i64* @count - %1 = load i64, i64* @count - ret i64 %1 -} -""") - assert e.intfn("f1") == 4 - - e.add_module("""\ -@count = external global i64 - -define i64 @f2() -{ - %1 = load i64, i64* @count - ret i64 %1 -} -""") - assert e.intfn("f2") == 4 - - with pytest.raises(RuntimeError): - e.add_module("""\ -define i64 @f3() -{ - ; FAIL: @count is not defined - %1 = load i64, i64* @count - ret i64 %1 -} -""") - -def test_llvm_eval3(): - e = LLVMEvaluator() - e.add_module("""\ -@count = global i64 5 -""") - - e.add_module("""\ -@count = external global i64 - -define i64 @f1() -{ - %1 = load i64, i64* @count - ret i64 %1 -} - -define void @inc() -{ - %1 = load i64, i64* @count - %2 = add i64 %1, 1 - store i64 %2, i64* @count - ret void -} -""") - assert e.intfn("f1") == 5 - e.voidfn("inc") - assert e.intfn("f1") == 6 - e.voidfn("inc") - assert e.intfn("f1") == 7 - - e.add_module("""\ -@count = external global i64 - -define void @inc2() -{ - %1 = load i64, i64* @count - %2 = add i64 %1, 2 - store i64 %2, i64* @count - ret void -} -""") - assert e.intfn("f1") == 7 - e.voidfn("inc2") - assert e.intfn("f1") == 9 - e.voidfn("inc") - assert e.intfn("f1") == 10 - e.voidfn("inc2") - assert e.intfn("f1") == 12 - - # Test that we can have another independent LLVMEvaluator and use both at - # the same time: - e2 = LLVMEvaluator() - e2.add_module("""\ -@count = global i64 5 - -define i64 @f1() -{ - %1 = load i64, i64* @count - ret i64 %1 -} - -define void @inc() -{ - %1 = load i64, i64* @count - %2 = add i64 %1, 1 - store i64 %2, i64* @count - ret void -} -""") - assert e2.intfn("f1") == 5 - e2.voidfn("inc") - assert e2.intfn("f1") == 6 - e2.voidfn("inc") - assert e2.intfn("f1") == 7 - - assert e.intfn("f1") == 12 - e2.voidfn("inc") - assert e2.intfn("f1") == 8 - assert e.intfn("f1") == 12 - e.voidfn("inc") - assert e2.intfn("f1") == 8 - assert e.intfn("f1") == 13 - -def test_llvm_eval4(): - e = LLVMEvaluator() - e.add_module("""\ -@count = global i64 5 - -define i64 @f1() -{ - %1 = load i64, i64* @count - ret i64 %1 -} - -define void @inc() -{ - %1 = load i64, i64* @count - %2 = add i64 %1, 1 - store i64 %2, i64* @count - ret void -} -""") - assert e.intfn("f1") == 5 - e.voidfn("inc") - assert e.intfn("f1") == 6 - e.voidfn("inc") - assert e.intfn("f1") == 7 - - e.add_module("""\ -declare void @inc() - -define void @inc2() -{ - call void @inc() - call void @inc() - ret void -} -""") - assert e.intfn("f1") == 7 - e.voidfn("inc2") - assert e.intfn("f1") == 9 - e.voidfn("inc") - assert e.intfn("f1") == 10 - e.voidfn("inc2") - assert e.intfn("f1") == 12 - - with pytest.raises(RuntimeError): - e.add_module("""\ -define void @inc2() -{ - ; FAIL: @inc is not defined - call void @inc() - call void @inc() - ret void -} -""") - -def test_llvm_callback0(): - from ctypes import c_int, c_void_p, CFUNCTYPE, cast - data = [0, 0] - ftype = CFUNCTYPE(c_int, c_int, c_int) - @ftype - def f(a, b): - data[0] = a - data[1] = b - return a + b - faddr = cast(f, c_void_p).value - e = LLVMEvaluator() - e.add_module("""\ -define i64 @addrcaller(i64 %a, i64 %b) -{ - %f = inttoptr i64 %ADDR to i64 (i64, i64)* - %r = call i64 %f(i64 %a, i64 %b) - ret i64 %r -} -""".replace("%ADDR", str(faddr))) - addrcaller = ftype(e.ee.get_function_address('addrcaller')) - assert data == [0, 0] - assert addrcaller(2, 3) == 5 - assert data == [2, 3] - -def test_llvm_callback_stub(): - from ctypes import c_int, c_void_p, CFUNCTYPE, cast - from lfortran.codegen.gen import create_callback_stub - from llvmlite import ir - data = [0, 0] - ftype = CFUNCTYPE(c_int, c_int, c_int) - @ftype - def f(a, b): - data[0] = a - data[1] = b - return a + b - faddr = cast(f, c_void_p).value - mod = ir.Module() - create_callback_stub(mod, "f", faddr, - ir.FunctionType(ir.IntType(64), [ir.IntType(64), ir.IntType(64)])) - e = LLVMEvaluator() - e.add_module(str(mod)) - stub = ftype(e.ee.get_function_address('f')) - assert data == [0, 0] - assert stub(2, 3) == 5 - assert data == [2, 3] - -def test_llvm_callback_py0(): - from lfortran.codegen.gen import create_callback_py - from llvmlite import ir - data = [0] - def f(): - return data[0] - mod = ir.Module() - ftype = create_callback_py(mod, f) - e = LLVMEvaluator() - e.add_module(str(mod)) - stub = ftype(e.ee.get_function_address('f')) - assert data == [0] - assert stub() == 0 - data[0] = 2 - assert stub() == 2 - data[0] = 5 - assert stub() == 5 - -def test_llvm_callback_py2(): - from lfortran.codegen.gen import create_callback_py - from llvmlite import ir - data = [0, 0] - def g(a, b): - data[0] = a - data[1] = b - return a + b - mod = ir.Module() - ftype = create_callback_py(mod, g) - e = LLVMEvaluator() - e.add_module(str(mod)) - stub = ftype(e.ee.get_function_address('g')) - assert data == [0, 0] - assert stub(2, 3) == 5 - assert data == [2, 3] - -def test_llvm_callback_py3(): - from lfortran.codegen.gen import create_callback_py - from llvmlite import ir - data = [0, 0, 0] - def f(a, b, c): - data[0] = a - data[1] = b - data[2] = c - return a + b + c - mod = ir.Module() - ftype = create_callback_py(mod, f, "h") - e = LLVMEvaluator() - e.add_module(str(mod)) - stub = ftype(e.ee.get_function_address('h')) - assert data == [0, 0, 0] - assert stub(2, 3, 5) == 10 - assert data == [2, 3, 5] - -def test_llvm_array1(): - """ - This test represents the array directly as a pointer. - """ - e = LLVMEvaluator() - e.add_module("""\ -; Sum the three elements in %a -define i64 @sum3(i64* %a) -{ - %a1addr = getelementptr i64, i64* %a, i64 0 - %a1 = load i64, i64* %a1addr - - %a2addr = getelementptr i64, i64* %a, i64 1 - %a2 = load i64, i64* %a2addr - - %a3addr = getelementptr i64, i64* %a, i64 2 - %a3 = load i64, i64* %a3addr - - %tmp = add i64 %a2, %a1 - %r = add i64 %a3, %tmp - - ret i64 %r -} - - -define i64 @f() -{ - %a = alloca [3 x i64] - - %a1 = getelementptr [3 x i64], [3 x i64]* %a, i64 0, i64 0 - store i64 1, i64* %a1 - - %a2 = getelementptr [3 x i64], [3 x i64]* %a, i64 0, i64 1 - store i64 2, i64* %a2 - - %a3 = getelementptr [3 x i64], [3 x i64]* %a, i64 0, i64 2 - store i64 3, i64* %a3 - - %r = call i64 @sum3(i64* %a1) - ret i64 %r -} -""") - assert e.intfn("f") == 6 - -def test_llvm_array2(): - """ - This test represents the array as a structure that contains the array - size and data. - """ - e = LLVMEvaluator() - e.add_module("""\ - -%array = type {i64, [3 x i64]} - -; Sum the three elements in %a -define i64 @sum3(%array* %a) -{ - %a1addr = getelementptr %array, %array* %a, i64 0, i32 1, i64 0 - %a1 = load i64, i64* %a1addr - - %a2addr = getelementptr %array, %array* %a, i64 0, i32 1, i64 1 - %a2 = load i64, i64* %a2addr - - %a3addr = getelementptr %array, %array* %a, i64 0, i32 1, i64 2 - %a3 = load i64, i64* %a3addr - - %tmp = add i64 %a2, %a1 - %r = add i64 %a3, %tmp - - ret i64 %r -} - - -define i64 @f() -{ - %a = alloca %array - - %idx0 = getelementptr %array, %array* %a, i64 0, i32 0 - store i64 3, i64* %idx0 - - %idx1 = getelementptr %array, %array* %a, i64 0, i32 1, i64 0 - store i64 1, i64* %idx1 - %idx2 = getelementptr %array, %array* %a, i64 0, i32 1, i64 1 - store i64 2, i64* %idx2 - %idx3 = getelementptr %array, %array* %a, i64 0, i32 1, i64 2 - store i64 3, i64* %idx3 - - %r = call i64 @sum3(%array* %a) - ret i64 %r -} -""") - assert e.intfn("f") == 6 \ No newline at end of file diff --git a/lfortran/codegen/tests/test_symbol_scope.py b/lfortran/codegen/tests/test_symbol_scope.py deleted file mode 100644 index 0177c7ff5d..0000000000 --- a/lfortran/codegen/tests/test_symbol_scope.py +++ /dev/null @@ -1,73 +0,0 @@ -from lfortran.codegen.evaluator import FortranEvaluator - -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_fn_global(): - e = FortranEvaluator() - e.evaluate("integer :: b") - e.evaluate("b = 5") - e.evaluate("""\ -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_fn_global_set(): - e = FortranEvaluator() - e.evaluate("integer :: b") - e.evaluate("""\ -function f(a) -integer, intent(in) :: a -b = a -f = 0 -end function -""") - e.evaluate("f(2)") - assert e.evaluate("b") == 2 - e.evaluate("f(5)") - assert e.evaluate("b") == 5 - -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_fn_local_shadow(): - e = FortranEvaluator() - e.evaluate("integer :: b") - e.evaluate("b = 1") - e.evaluate("""\ -function f1(a) -integer, intent(in) :: a -integer :: b -b = 5 -f1 = a + b -end function -""") - e.evaluate("""\ -function f2(a) -integer, intent(in) :: a -f2 = a + b -end function -""") - assert e.evaluate("f1(2)") == 7 - assert e.evaluate("f2(2)") == 3 \ No newline at end of file diff --git a/lfortran/parser/CMakeLists.txt b/lfortran/parser/CMakeLists.txt deleted file mode 100644 index 0f600d3909..0000000000 --- a/lfortran/parser/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -Python_add_library(cparser MODULE cparser.c) -target_link_libraries(cparser PRIVATE lfortran_lib) -if("${CMAKE_INSTALL_PREFIX}/lfortran/parser" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") - message("Note: cparser already built in install directory") -else() - install(TARGETS cparser DESTINATION lfortran/parser) -endif() diff --git a/lfortran/parser/__init__.py b/lfortran/parser/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/parser/cparser.pyx b/lfortran/parser/cparser.pyx deleted file mode 100644 index 25431febd3..0000000000 --- a/lfortran/parser/cparser.pyx +++ /dev/null @@ -1,49 +0,0 @@ -cimport cwrapper - -cdef class Parser(object) - -cdef class AST(object): - cdef cwrapper.lfortran_ast_t *thisptr - cdef Parser parser - - @staticmethod - cdef create(Parser p, cwrapper.lfortran_ast_t *ast): - cdef AST a = AST.__new__(AST) - a.parser = p - a.thisptr = ast - return a - - def pickle(self): - cdef char *out - e = cwrapper.lfortran_parser_pickle(self.thisptr, &out) - if (e != cwrapper.LFORTRAN_NO_EXCEPTION): - raise Exception("parser_pickle failed") - sout = out.decode() - e = cwrapper.lfortran_str_free(out) - if (e != cwrapper.LFORTRAN_NO_EXCEPTION): - raise Exception("str_free failed") - return sout - -cdef class Parser(object): - cdef cwrapper.LFortranCParser *h; - - def __cinit__(self): - self.h = cwrapper.lfortran_parser_new() - - def __dealloc__(self): - cwrapper.lfortran_parser_free(self.h) - - def parse(self, s): - sb = s.encode() - cdef char *str = sb - cdef cwrapper.lfortran_ast_t *ast; - e = cwrapper.lfortran_parser_parse(self.h, str, &ast) - if (e != cwrapper.LFORTRAN_NO_EXCEPTION): - raise Exception("parser_parse failed") - return AST.create(self, ast) - -def parse(s): - p = Parser() - a = p.parse(s) - s = a.pickle() - return s diff --git a/lfortran/parser/cwrapper.pxd b/lfortran/parser/cwrapper.pxd deleted file mode 100644 index 322b55ec59..0000000000 --- a/lfortran/parser/cwrapper.pxd +++ /dev/null @@ -1,20 +0,0 @@ -cdef extern from "lfortran/cwrapper.h": - - ctypedef enum lfortran_exceptions_t: - LFORTRAN_NO_EXCEPTION - LFORTRAN_RUNTIME_ERROR - LFORTRAN_TOKENIZER_ERROR - LFORTRAN_PARSER_ERROR - - ctypedef struct LFortranCParser: - pass - ctypedef struct lfortran_ast_t: - pass - - LFortranCParser *lfortran_parser_new() nogil - void lfortran_parser_free(LFortranCParser *self) nogil - lfortran_exceptions_t lfortran_parser_parse(LFortranCParser *self, - const char *input, lfortran_ast_t **ast) nogil - lfortran_exceptions_t lfortran_parser_pickle(lfortran_ast_t* ast, - char **str) nogil - lfortran_exceptions_t lfortran_str_free(char *str) nogil diff --git a/lfortran/parser/parser.py b/lfortran/parser/parser.py deleted file mode 100644 index ad5d1101c4..0000000000 --- a/lfortran/parser/parser.py +++ /dev/null @@ -1,595 +0,0 @@ -""" -# Fortran Parser - -This module provides a parser implementation for the `ast` module. This module -should not be used directly, use `ast.src_to_ast()` instead. - -Internally, `ast.src_to_ast()` calls `antlr_parse()` provided by this module. The -`antlr_parse()` function accepts source code as a string and then uses ANTLR4 -to create a parse tree and then converts the parse tree to an AST (using the -classes from the `ast` module) and returns it. - -The returned AST (and thus the rest of the code) does not depend on ANTLR in -any way. As such, alternative parser implementations can be used --- all they -have to do is to return an AST, and one can just update the `ast.src_to_ast()` to -use them. The rest of the code does not depend on the parser implementation. - -""" - -import antlr4 -from antlr4.error.ErrorListener import ErrorListener -from .fortranLexer import fortranLexer -from .fortranParser import fortranParser -from .fortranVisitor import fortranVisitor -from ..ast import ast, utils - -def get_line(s, l): - return s.split("\n")[l-1] - -class VerboseErrorListener(ErrorListener): - def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): - stack = recognizer.getRuleInvocationStack() - stack.reverse() - # Here is how to get a rule stack: str(stack) - message = "Syntax Error:%d:%d: %s\n%s\n%s\n" % (line, column, msg, - get_line(self.source, line), " "*(column-1) + "^") - raise utils.SyntaxErrorException(message) - -class ASTBuilderVisitor(fortranVisitor): - """ - Converts the ANTLR parse tree to AST. - - The file fortran.g4 defines the parse tree nodes. The file Fortran.asdl - defines the AST nodes. This visitor converts from the first to the second. - When fortran.g4 is changed, then this visitor must be changed accordingly - because the parse tree nodes change. When Fortran.asdl is changed, then - this visitor also must be updated, because the AST nodes change. - - The AST that this visitor returns does not depend on ANTLR in any way. - ANTLR is just used to construct it. - """ - - def __init__(self): - pass - - def aggregateResult(self, aggregate, nextResult): - if aggregate is None: - return nextResult - elif nextResult is None: - return aggregate - else: - if isinstance(aggregate, list) and isinstance(nextResult, list): - return aggregate + nextResult - elif isinstance(aggregate, list): - return aggregate + [nextResult] - elif isinstance(nextResult, list): - return [aggregate] + nextResult - else: - return [aggregate, nextResult] - - - # Visit a parse tree produced by fortranParser#program. - def visitProgram(self, ctx:fortranParser.ProgramContext): - name = ctx.ident(0).getText() - use, decl, body, contains = self.process_sub_block(ctx.sub_block()) - return ast.Program(name=name, use=use, decl=decl, body=body, - contains=contains) - - def process_sub_block(self, ctx:fortranParser.Sub_blockContext): - # Returns (use=[], decl=[], body=[], contains=[]) - use = [] - decl = [] - for u in ctx.use_statement(): - use.append(self.visit(u)) - for u in ctx.var_decl(): - decl.append(self.visit(u)) - if ctx.statements(): - body = self.statements2list(ctx.statements()) - else: - body = [] - if ctx.contains_block(): - contains = self.contains_block2list(ctx.contains_block()) - else: - contains = [] - return (use, decl, body, contains) - - # Visit a parse tree produced by fortranParser#module. - def visitModule(self, ctx:fortranParser.ModuleContext): - name = ctx.ident(0).getText() - use = [] - decl = [] - for u in ctx.use_statement(): - use.append(self.visit(u)) - for u in ctx.module_decl(): - decl.append(self.visit(u)) - if ctx.contains_block(): - contains = self.contains_block2list(ctx.contains_block()) - else: - contains = [] - return ast.Module(name=name, use=[], decl=decl, contains=contains) - - def contains_block2list(self, ctx:fortranParser.Contains_blockContext): - # Returns a list - units = [] - for unit in ctx.sub_or_func(): - units.append(self.visit(unit)) - return units - - # Visit a parse tree produced by fortranParser#contains_block. - def visitContains_block(self, ctx:fortranParser.Contains_blockContext): - pass - - # Visit a parse tree produced by fortranParser#private_decl. - def visitPrivate_decl(self, ctx:fortranParser.Private_declContext): - syms = [] - if ctx.id_list(): - for sym in ctx.id_list().ident(): - syms.append(sym.getText()) - return ast.Private(vars=syms, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#public_decl. - def visitPublic_decl(self, ctx:fortranParser.Public_declContext): - syms = [] - if ctx.id_list(): - for sym in ctx.id_list().ident(): - syms.append(sym.getText()) - return ast.Public(vars=syms, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#subroutine. - def visitSubroutine(self, ctx:fortranParser.SubroutineContext): - name = ctx.ident(0).getText() - args = [] - if ctx.id_list(): - for arg in ctx.id_list().ident(): - args.append(ast.arg(arg=arg.getText())) - use, decl, body, contains = self.process_sub_block(ctx.sub_block()) - return ast.Subroutine(name=name, args=args, use=use, - decl=decl, body=body, contains=contains, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#function. - def visitFunction(self, ctx:fortranParser.FunctionContext): - name = ctx.ident(0).getText() - args = [] - if ctx.id_list(): - for arg in ctx.id_list().ident(): - args.append(ast.arg(arg=arg.getText())) - use, decl, body, contains = self.process_sub_block(ctx.sub_block()) - return_type = None - if ctx.ident(1): - return_var = ast.Name(id=ctx.ident(1).getText()) - else: - return_var = None - return ast.Function(name=name, args=args, return_type=return_type, - return_var=return_var, bind=None, use=use, decl=decl, body=body, - contains=contains, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#subroutine_call. - def visitSubroutine_call(self, ctx:fortranParser.Subroutine_callContext): - name = ctx.ident().getText() - args = [] - if ctx.arg_list(): - for arg in ctx.arg_list().arg(): - if arg.ident(): - # TODO: handle kwargs, we ignore the name for now - kwarg = arg.ident().getText() - args.append(self.visit(arg)) - return ast.SubroutineCall(name, args, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#builtin_statement. - def visitBuiltin_statement(self, ctx:fortranParser.Builtin_statementContext): - name = ctx.name.text - args = [] - if ctx.arg_list(): - for arg in ctx.arg_list().arg(): - if arg.ident(): - # TODO: handle kwargs, we ignore the name for now - kwarg = arg.ident().getText() - args.append(self.visit(arg)) - return ast.BuiltinCall(name, args, lineno=1, col_offset=1) - - - # Visit a parse tree produced by fortranParser#assignment_statement. - def visitAssignment_statement(self, ctx:fortranParser.Assignment_statementContext): - if ctx.op.text == "=>": - raise Exception("operator => not implemented") - assert ctx.op.text == "=" - lhs = self.visit(ctx.expr(0)) - value = self.visit(ctx.expr(1)) - return ast.Assignment(lhs, value, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#var_decl. - def visitVar_decl(self, ctx:fortranParser.Var_declContext): - attrs = [] - for a in ctx.var_modifier(): - if a.KW_INTENT(): - if a.KW_IN(): - arg = ast.attribute_arg(arg="in") - elif a.KW_OUT(): - arg = ast.attribute_arg(arg="out") - elif a.KW_INOUT(): - arg = ast.attribute_arg(arg="inout") - else: - assert False - attr = ast.Attribute(name=a.KW_INTENT().getText().lower(), - args=[arg]) - else: - attr = ast.Attribute(name=a.getText().lower(), args=[]) - attrs.append(attr) - d = [] - for v in ctx.var_sym_decl(): - sym = v.ident().getText() - sym_type = ctx.var_type().getText().lower() - dims = [] - if v.array_decl(): - for dim in v.array_decl().array_comp_decl(): - e = dim.expr() - if len(e) == 1: - end = self.visit(e[0]) - else: - # TODO: implement expr:expr - end = None - dims.append(ast.dimension(start=None, end=end)) - d.append(ast.decl(sym, sym_type, dims, attrs)) - return ast.Declaration(d, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#print_statement. - def visitPrint_statement(self, ctx:fortranParser.Print_statementContext): - values = [] - for expr in ctx.expr_list().expr(): - v = self.visit(expr) - values.append(v) - return ast.Print(fmt=None, values=values, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_array_const. - def visitExpr_array_const(self, ctx:fortranParser.Expr_array_constContext): - values = [] - for expr in ctx.expr_list().expr(): - v = self.visit(expr) - values.append(v) - return ast.ArrayInitializer(args=values, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_string. - def visitExpr_string(self, ctx:fortranParser.Expr_stringContext): - s = ctx.STRING().getText() - if s[0] == '"': - s = s[1:-1] - s = s.replace('""', '"') - elif s[0] == "'": - s = s[1:-1] - s = s.replace("''", "'") - else: - raise Exception("Incorrect string") - return ast.Str(s=s, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#number_real. - def visitNumber_real(self, ctx:fortranParser.Number_realContext): - num = ctx.NUMBER().getText() - return ast.Num(n=num, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_id. - def visitExpr_id(self, ctx:fortranParser.Expr_idContext): - v = ctx.ident().getText() - return ast.Name(id=v, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_not. - def visitExpr_not(self, ctx:fortranParser.Expr_notContext): - rhs = self.visit(ctx.expr()) - return ast.UnaryOp(op=ast.Not(), operand=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_and. - def visitExpr_and(self, ctx:fortranParser.Expr_andContext): - lhs = self.visit(ctx.expr(0)) - rhs = self.visit(ctx.expr(1)) - return ast.BoolOp(left=lhs, op=ast.And(), right=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_or. - def visitExpr_or(self, ctx:fortranParser.Expr_orContext): - lhs = self.visit(ctx.expr(0)) - rhs = self.visit(ctx.expr(1)) - return ast.BoolOp(left=lhs, op=ast.Or(), right=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_muldiv. - def visitExpr_addsub(self, ctx:fortranParser.Expr_muldivContext): - op = ctx.op.text - lhs = self.visit(ctx.expr(0)) - rhs = self.visit(ctx.expr(1)) - if op == '+': - return ast.BinOp(left=lhs, op=ast.Add(), right=rhs, - lineno=1, col_offset=1) - else: - return ast.BinOp(left=lhs, op=ast.Sub(), right=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_muldiv. - def visitExpr_muldiv(self, ctx:fortranParser.Expr_muldivContext): - op = ctx.op.text - lhs = self.visit(ctx.expr(0)) - rhs = self.visit(ctx.expr(1)) - if op == '*': - return ast.BinOp(left=lhs, op=ast.Mul(), right=rhs, - lineno=1, col_offset=1) - else: - return ast.BinOp(left=lhs, op=ast.Div(), right=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_pow. - def visitExpr_pow(self, ctx:fortranParser.Expr_powContext): - lhs = self.visit(ctx.expr(0)) - rhs = self.visit(ctx.expr(1)) - return ast.BinOp(left=lhs, op=ast.Pow(), right=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_truefalse. - def visitExpr_truefalse(self, ctx:fortranParser.Expr_truefalseContext): - op = ctx.op.text - if op == '.true.': - return ast.Constant(value=True, lineno=1, col_offset=1) - else: - return ast.Constant(value=False, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_unary. - def visitExpr_unary(self, ctx:fortranParser.Expr_unaryContext): - op = ctx.op.text - rhs = self.visit(ctx.expr()) - if op == '+': - return ast.UnaryOp(op=ast.UAdd(), operand=rhs, - lineno=1, col_offset=1) - else: - return ast.UnaryOp(op=ast.USub(), operand=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_rel. - def visitExpr_rel(self, ctx:fortranParser.Expr_relContext): - op = ctx.op.text - lhs = self.visit(ctx.expr(0)) - rhs = self.visit(ctx.expr(1)) - ops = { - "==": ast.Eq(), - ".eq.": ast.Eq(), - "/=": ast.NotEq(), - ".neq.": ast.NotEq(), - "<": ast.Lt(), - ".lt.": ast.Lt(), - "<=": ast.LtE(), - ".le.": ast.LtE(), - ">": ast.Gt(), - ".gt.": ast.Gt(), - ">=": ast.GtE(), - ".ge.": ast.GtE(), - } - return ast.Compare(left=lhs, op=ops[op], right=rhs, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_nest. - def visitExpr_nest(self, ctx:fortranParser.Expr_nestContext): - return self.visit(ctx.expr()) - - # Visit a parse tree produced by fortranParser#stop_statement. - def visitStop_statement(self, ctx:fortranParser.Stop_statementContext): - if ctx.NUMBER(): - num = int(ctx.NUMBER().getText()) - else: - num = None - return ast.Stop(code=num, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#error_stop_statement. - def visitError_stop_statement(self, ctx:fortranParser.Error_stop_statementContext): - return ast.ErrorStop(lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#if_single_line. - def visitIf_single_line(self, ctx:fortranParser.If_single_lineContext): - cond = self.visit(ctx.if_cond().expr()) - body = self.visit(ctx.statement()) - if not isinstance(body, list): - body = [body] - return ast.If(test=cond, body=body, orelse=[], lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#if_block. - def visitIf_block(self, ctx:fortranParser.If_blockContext): - cond = self.visit(ctx.if_cond().expr()) - body = self.statements2list(ctx.statements()) - if ctx.if_else_block(): - orelse = self.visit(ctx.if_else_block()) - else: - orelse = [] - return ast.If(test=cond, body=body, orelse=orelse, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#if_else_block. - def visitIf_else_block(self, ctx:fortranParser.If_else_blockContext): - # This method returns a list [] of statements. - if ctx.statements(): - return self.statements2list(ctx.statements()) - if ctx.if_block(): - return [self.visit(ctx.if_block())] - raise Exception("The grammar should not allow this.") - - # Visit a parse tree produced by fortranParser#where_single_line. - def visitWhere_single_line(self, ctx:fortranParser.Where_single_lineContext): - cond = self.visit(ctx.where_cond().expr()) - body = self.visit(ctx.statement()) - if not isinstance(body, list): - body = [body] - return ast.Where(test=cond, body=body, orelse=[], - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#where_block. - def visitWhere_block(self, ctx:fortranParser.Where_blockContext): - cond = self.visit(ctx.where_cond().expr()) - body = self.statements2list(ctx.statements()) - if ctx.where_else_block(): - orelse = self.visit(ctx.where_else_block()) - else: - orelse = [] - return ast.Where(test=cond, body=body, orelse=orelse, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#where_else_block. - def visitWhere_else_block(self, ctx:fortranParser.Where_else_blockContext): - # This method returns a list [] of statements. - if ctx.statements(): - return self.statements2list(ctx.statements()) - if ctx.where_block(): - return [self.visit(ctx.where_block())] - raise Exception("The grammar should not allow this.") - - # Visit a parse tree produced by fortranParser#expr_array_call. - def visitExpr_array_call(self, ctx:fortranParser.Expr_array_callContext): - name = ctx.ident().getText() - args = [] - for arg in ctx.array_index_list().array_index(): - args.append(self.visit(arg)) - return ast.Array(name, args, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#expr_fn_call. - def visitExpr_fn_call(self, ctx:fortranParser.Expr_fn_callContext): - name = ctx.ident().getText() - args = [] - if ctx.arg_list(): - for arg in ctx.arg_list().arg(): - if arg.ident(): - # TODO: handle kwargs, we ignore the name for now - kwarg = arg.ident().getText() - args.append(self.visit(arg)) - return ast.FuncCallOrArray(func=name, args=args, keywords=[], - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#array_index_simple. - def visitArray_index_simple(self, ctx:fortranParser.Array_index_simpleContext): - return ast.ArrayIndex(left=self.visit(ctx.expr()), right=None, - step=None) - - # Visit a parse tree produced by fortranParser#array_index_slice. - def visitArray_index_slice(self, ctx:fortranParser.Array_index_sliceContext): - # TODO: figure out how to access things like 3:4, or :4. - return ast.ArrayIndex(left=None, right=None, - step=None) - - # Visit a parse tree produced by fortranParser#do_statement. - def visitDo_statement(self, ctx:fortranParser.Do_statementContext): - body = self.statements2list(ctx.statements()) - if ctx.ident(): - var = ctx.ident().getText() - start = self.visit(ctx.expr(0)) - end = self.visit(ctx.expr(1)) - if len(ctx.expr()) == 3: - increment = self.visit(ctx.expr(2)) - else: - increment = None - return ast.DoLoop(var=var, start=start, end=end, - increment=increment, body=body, lineno=1, col_offset=1) - else: - return ast.DoLoop(var=None, start=None, end=None, - increment=None, body=body, lineno=1, col_offset=1) - - def statements2list(self, ctx:fortranParser.StatementsContext): - # Returns a list - statements = [] - for stat in ctx.statement(): - s = self.visit(stat) - if s is not None: - statements.append(s) - return statements - - # Visit a parse tree produced by fortranParser#while_statement. - def visitWhile_statement(self, ctx:fortranParser.While_statementContext): - test = self.visit(ctx.expr()) - body = self.statements2list(ctx.statements()) - return ast.WhileLoop(test=test, body=body, lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#cycle_statement. - def visitCycle_statement(self, ctx:fortranParser.Cycle_statementContext): - return ast.Cycle(lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#exit_statement. - def visitExit_statement(self, ctx:fortranParser.Exit_statementContext): - return ast.Exit(lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#select_statement. - def visitSelect_statement(self, ctx:fortranParser.Select_statementContext): - expr = self.visit(ctx.expr()) - body = [] - for case in ctx.case_statement(): - test = self.visit(case.expr()) - case_body = self.statements2list(case.statements()) - body.append(ast.CaseStmt(test=test, body=case_body)) - if ctx.select_default_statement(): - default_body = self.statements2list( \ - ctx.select_default_statement().statements()) - default = default_body - else: - default = [] - return ast.Select(test=expr, body=body, default=default, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#use_statement. - def visitUse_statement(self, ctx:fortranParser.Use_statementContext): - module = ctx.ident().getText() - symbols = [] - if ctx.use_symbol_list(): - for s in ctx.use_symbol_list().use_symbol(): - symbols.append(self.visit(s)) - return ast.Use(module=module, symbols=symbols, - lineno=1, col_offset=1) - - # Visit a parse tree produced by fortranParser#use_symbol. - def visitUse_symbol(self, ctx:fortranParser.Use_symbolContext): - if len(ctx.ident()) == 1: - return ast.UseSymbol(sym=ctx.ident(0).getText(), rename=None) - elif len(ctx.ident()) == 2: - return ast.UseSymbol(sym=ctx.ident(0).getText(), - rename=ctx.ident(1).getText()) - else: - raise Exception("The grammar should not allow this.") - - # Visit a parse tree produced by fortranParser#interface_decl. - def visitInterface_decl(self, ctx:fortranParser.Interface_declContext): - name = ctx.ident(0).getText() - procs = [] - for proc_line in ctx.id_list(): - for proc in proc_line.ident(): - procs.append(proc.getText()) - return ast.Interface(name=name, procs=procs, - lineno=1, col_offset=1) - - -def antlr_parse(source, translation_unit=False): - """ - Parse the `source` string into an AST node. - - We first call ANTLR4 to convert the `source` string into a parse tree. Then - we convert the parse tree into an AST. - - translation_unit ... if True, only accept full programs or modules (the - 'root' rule). If False, accept any valid Fortran code (the 'unit' rule). - """ - if source.strip() == "": - return - stream = antlr4.InputStream(source) - lexer = fortranLexer(stream) - tokens = antlr4.CommonTokenStream(lexer) - parser = fortranParser(tokens) - parser.removeErrorListeners() - err = VerboseErrorListener() - err.source = source - parser.addErrorListener(err) - if translation_unit: - parse_tree = parser.root() - else: - parse_tree = parser.units() - v = ASTBuilderVisitor() - ast_tree = v.visit(parse_tree) - if isinstance(ast_tree, list): - assert len(ast_tree) > 1 - for x in ast_tree: - assert isinstance(x, ast.AST) - elif ast_tree is None: - pass - else: - assert isinstance(ast_tree, ast.AST) - return ast_tree diff --git a/lfortran/prompt.py b/lfortran/prompt.py deleted file mode 100644 index f02341ef32..0000000000 --- a/lfortran/prompt.py +++ /dev/null @@ -1,126 +0,0 @@ -from ctypes import CFUNCTYPE, c_double - -from pygments.lexers import FortranLexer - -from prompt_toolkit import PromptSession, print_formatted_text, HTML -from prompt_toolkit.lexers import PygmentsLexer -from prompt_toolkit.key_binding import KeyBindings - -import llvmlite.binding as llvm - -from lfortran.ast import (dump, print_tree, print_tree_typed, - SyntaxErrorException) -from lfortran.semantic.analyze import SemanticError -from lfortran.codegen.evaluator import FortranEvaluator - - -def print_bold(text): - print_formatted_text(HTML('%s' % text)) - -def print_stage(text): - print() - print_formatted_text(HTML('↓ Stage: %s' \ - % text)) - print() - -def handle_input(engine, evaluator, source, verbose=True): - if verbose: - print_bold("Input:") - print(source) - - - print_stage("Parse") - try: - ast_tree0 = evaluator.parse(source) - except SyntaxErrorException as e: - print(e) - return - if verbose: - print_bold("Parse AST:") - print_tree(ast_tree0) - - if isinstance(ast_tree0, list): - statements = ast_tree0 - else: - statements = [ast_tree0] - - for ast_tree0 in statements: - if verbose: - print_stage("Semantic Analysis") - try: - ast_tree = evaluator.semantic_analysis(ast_tree0) - except SemanticError as e: - print(e) - return - if verbose: - print_bold("Semantic AST:") - print_tree_typed(ast_tree) - print() - print_bold("Symbol table:") - print(list(evaluator._global_scope.symbols.keys())) - - print_stage("LLVM Code Generation") - mod = evaluator.llvm_code_generation(ast_tree) - if verbose: - print_bold("Initial LLVM IR:") - print(evaluator._source_ll) - print() - print_bold("Optimized LLVM IR:") - print(evaluator._source_ll_opt) - - print_stage("Machine Code Generation, Load and Run") - result = evaluator.machine_code_generation_load_run(mod) - if verbose: - print_bold("Machine code ASM:") - print(evaluator._source_asm) - print_bold("Result:") - if verbose or result is not None: - print(result) - -kb = KeyBindings() - -@kb.add('escape', 'enter') -def _(event): - event.current_buffer.insert_text('\n') - -@kb.add('enter') -def _(event): - event.current_buffer.validate_and_handle() - -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.") \ No newline at end of file diff --git a/lfortran/semantic/__init__.py b/lfortran/semantic/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/semantic/analyze.py b/lfortran/semantic/analyze.py deleted file mode 100644 index 057ac3b5a5..0000000000 --- a/lfortran/semantic/analyze.py +++ /dev/null @@ -1,456 +0,0 @@ -""" -Semantic analysis module. - -It declares Fortran types as Python classes. It contains a visitor pattern to -create a symbol table (SymbolTableVisitor) that is run first. Then it -contains another visitor pattern that walks all expressions and assigns/check -types based on the symbol table (ExprVisitor) that is run second. -""" - -from ..ast import ast - -class SemanticError(Exception): - pass - -class UndeclaredVariableError(SemanticError): - pass - -class TypeMismatch(SemanticError): - pass - - -# ---------------------------- - -# Types are immutable. Once instantiated, they never change. - -class Type(object): - - def __neq__(self, other): - return not self.__eq__(other) - -class Intrinsic(Type): - def __init__(self, kind=None): - #super(Intrinsic, self).__init__() - self.kind = kind - - def __eq__(self, other): - if type(self) != type(other): - return False - return self.kind == other.kind - - def __hash__(self): - return 1 - -class Integer(Intrinsic): - def __repr__(self): - return "Integer()" -class Real(Intrinsic): - def __repr__(self): - return "Real()" -class Complex(Intrinsic): - def __repr__(self): - return "Complex()" -class Character(Intrinsic): - def __repr__(self): - return "Character()" -class Logical(Intrinsic): - def __repr__(self): - return "Logical()" - -class Derived(Type): - def __repr__(self): - return "Derived()" - - -class Array(Type): - - def __init__(self, type_, shape): - self.type_ = type_ - self.shape = shape - - def __eq__(self, other): - if type(self) != type(other): - return False - return self.type_ == other.type_ and self.shape == other.shape - - def __hash__(self): - return 1 - - def __repr__(self): - return "Array(%r, %r)" % (self.type_, self.shape) - - -# -------------------------------- - -class Scope: - """ - A Scope contains local symbols and a link to the parent scope. - - It is attached directly to the AST nodes for functions, subroutines and - programs. When using a visitor pattern, one must propagate the "current - scope" by hand, so that one can access the function's scope from, say, - the assignment statement. - """ - - def __init__(self, parent_scope=None): - self._parent_scope = parent_scope - self._local_symbols = {} - - @property - def parent_scope(self): - return self._parent_scope - - @property - def symbols(self): - return self._local_symbols - - def resolve(self, sym, raise_exception=True): - if sym in self._local_symbols: - return self._local_symbols[sym] - elif self._parent_scope: - return self._parent_scope.resolve(sym, raise_exception) - else: - # Symbol not found - if raise_exception: - # This only happens when there is a bug. The semantic phase - # should call resolve() with raise_exception=False and create - # nice user errors. The code generation phase calls resolve() - # with raise_exception=True. - raise Exception("Internal error: Symbol '%s' not declared." \ - % sym) - else: - return None - - -class SymbolTableVisitor(ast.GenericASTVisitor): - - def __init__(self): - # Mapping between Fortran type strings and LFortran type classes - self.types = { - "integer": Integer, - "real": Real, - "complex": Complex, - "character": Character, - "logical": Logical, - } - - self._global_scope = Scope() - self._global_scope._local_symbols = { x: { - "name": x, - "type": Real(), - "external": True, - "func": True, - "subroutine": False, - "global": True, - } for x in [ - "abs", - "sqrt", - "log", - "sum", - "random_number", - ]} - - self._global_scope._local_symbols["plot"] = { - "name": "plot", - "type": Integer(), - "external": True, - "func": True, # Function or Subroutine - "global": True, - } - self._global_scope._local_symbols["savefig"] = { - "name": "savefig", - "type": Integer(), - "external": True, - "func": True, # Function or Subroutine - "global": True, - } - self._global_scope._local_symbols["show"] = { - "name": "show", - "type": Integer(), - "external": True, - "func": True, # Function or Subroutine - "global": True, - } - self._global_scope._local_symbols["plot_test"] = { - "name": "plot_test", - "type": Integer(), - "external": True, - "func": True, # Function or Subroutine - "global": True, - } - - self._current_scope = self._global_scope - - def mark_all_external(self): - """ - Marks all symbols in the symbol table as external. - """ - for sym in self._global_scope.symbols: - self._global_scope.symbols[sym]["external"] = True - - def visit_Declaration(self, node): - for v in node.vars: - sym = v.sym - type_f = v.sym_type - if type_f not in self.types: - # This shouldn't happen, as the parser checks types - raise SemanticError("Type not implemented.") - dims = [] - for dim in v.dims: - if isinstance(dim.end, ast.Num): - dims.append(int(dim.end.n)) - else: - raise NotImplementedError("Index not a number") - if dim.start: - raise NotImplementedError("start index") - type_ = self.types[type_f]() - if len(dims) > 0: - type_ = Array(type_, dims) - sym_data = {"name": sym, "type": type_, - "external": False, "func": False, "dummy": False, - "intent": None} - for a in v.attrs: - if a.name == "intent": - sym_data["intent"] = a.args[0].arg - self._current_scope._local_symbols[sym] = sym_data - - def visit_Function(self, node): - sym = node.name - # TODO: for now we assume integer result, but we should read the AST - # and determine the type of the result. - type_ = self.types["integer"]() - - sym_data = { - "name": sym, - "type": type_, - "args": node.args, - "external": False, - "func": True, - } - - self._current_scope._local_symbols[sym] = sym_data - - node._scope = Scope(self._current_scope) - self._current_scope = node._scope - sym_data["scope"] = node._scope - - self.visit_sequence(node.decl) - # Go over arguments and set them as dummy - for arg in node.args: - if not arg.arg in self._current_scope._local_symbols: - raise SemanticError("Dummy variable '%s' not declared" % arg.arg) - self._current_scope._local_symbols[arg.arg]["dummy"] = True - # Check that non-dummy variables do not use the intent(..) attribute - for sym in self._current_scope._local_symbols: - s = self._current_scope._local_symbols[sym] - if not s["dummy"]: - if s["intent"]: - raise SemanticError("intent(..) is used for a non-dummy variable '%s'" % \ - s["name"]) - - # Iterate over nested functions - self.visit_sequence(node.contains) - - self._current_scope = node._scope.parent_scope - - def visit_Program(self, node): - node._scope = Scope(self._current_scope) - self._current_scope = node._scope - - self.visit_sequence(node.decl) - #self.visit_sequence(node.body) - self.visit_sequence(node.contains) - - self._current_scope = node._scope.parent_scope - - def visit_Subroutine(self, node): - node._scope = Scope(self._current_scope) - self._current_scope = node._scope - - self.visit_sequence(node.args) - self.visit_sequence(node.decl) - #self.visit_sequence(node.body) - self.visit_sequence(node.contains) - - self._current_scope = node._scope.parent_scope - -def create_symbol_table(tree): - v = SymbolTableVisitor() - v.visit(tree) - return v._global_scope - - - -class ExprVisitor(ast.GenericASTVisitor): - - def __init__(self, global_scope): - self._current_scope = global_scope - - def visit_Program(self, node): - self._current_scope = node._scope - self.visit_sequence(node.decl) - self.visit_sequence(node.body) - self.visit_sequence(node.contains) - self._current_scope = node._scope.parent_scope - - def visit_Subroutine(self, node): - self._current_scope = node._scope - self.visit_sequence(node.args) - self.visit_sequence(node.decl) - self.visit_sequence(node.body) - self.visit_sequence(node.contains) - self._current_scope = node._scope.parent_scope - - def visit_Function(self, node): - self._current_scope = node._scope - self.visit_sequence(node.args) - self.visit_sequence(node.decl) - self.visit_sequence(node.body) - self.visit_sequence(node.contains) - self._current_scope = node._scope.parent_scope - - def visit_Num(self, node): - try: - node.o = int(node.n) - node._type = Integer() - except ValueError: - try: - node.o = float(node.n) - node._type = Real() - except ValueError: - if node.n.endswith("_dp"): - node.o = float(node.n[:-3]) - node._type = Real() - else: - try: - node_exp = node.n.lower().replace('d', 'e') - node.o = float(node_exp) - node._type = Real() - except ValueError: - raise SemanticError("Unknown number syntax.") - - def visit_Constant(self, node): - node._type = Logical() - - def visit_Name(self, node): - if not self._current_scope.resolve(node.id, False): - raise UndeclaredVariableError("Variable '%s' not declared." \ - % node.id) - node._type = self._current_scope.resolve(node.id)["type"] - - def visit_FuncCallOrArray(self, node): - if not self._current_scope.resolve(node.func, False): - raise UndeclaredVariableError("Func or Array '%s' not declared." \ - % node.func) - self.visit_sequence(node.args) - node._type = self._current_scope.resolve(node.func)["type"] - - def visit_BinOp(self, node): - self.visit(node.left) - self.visit(node.right) - if node.left._type == node.right._type: - node._type = node.left._type - else: - if isinstance(node.left._type, Array) and \ - isinstance(node.right._type, Array): - if node.left._type.type_ != node.right._type.type_: - raise TypeMismatch("Array Type mismatch") - node._type = node.right._type.type_ - elif isinstance(node.left._type, Array): - if node.left._type.type_ != node.right._type: - raise TypeMismatch("Array Type mismatch") - node._type = node.right._type - elif isinstance(node.right._type, Array): - if node.right._type.type_ != node.left._type: - raise TypeMismatch("Array Type mismatch") - node._type = node.left._type - else: - # TODO: allow combinations of Real/Integer - raise TypeMismatch("Type mismatch") - - def visit_UnaryOp(self, node): - self.visit(node.operand) - node._type = node.operand._type - - def visit_Compare(self, node): - self.visit(node.left) - self.visit(node.right) - if node.left._type != node.right._type: - if isinstance(node.left._type, Array): - if node.left._type.type_ != node.right._type: - raise TypeMismatch("Array Type mismatch") - elif isinstance(node.right._type, Array): - if node.right._type.type_ != node.left._type: - raise TypeMismatch("Array Type mismatch") - else: - # TODO: allow combinations of Real/Integer - raise TypeMismatch("Type mismatch") - node._type = Logical() - - def visit_If(self, node): - self.visit(node.test) - if node.test._type != Logical(): - raise TypeMismatch("If condition must be of type logical.") - self.visit_sequence(node.body) - self.visit_sequence(node.orelse) - - def visit_Assignment(self, node): - if isinstance(node.target, ast.Name): - if not self._current_scope.resolve(node.target.id, False): - raise UndeclaredVariableError("Variable '%s' not declared." \ - % node.target.id) - node._type = self._current_scope.resolve(node.target.id)["type"] - self.visit(node.value) - if node.value._type != node._type: - if isinstance(node._type, Array): - # FIXME: this shouldn't happen --- this is handled by the - # next if - if node._type.type_ != node.value._type: - raise TypeMismatch("LHS Array Type mismatch") - if isinstance(node.value._type, Array): - if node._type != node.value._type.type_: - raise TypeMismatch("RHS Array Type mismatch") - else: - raise TypeMismatch("Type mismatch: " \ - "LHS=%s (%s), RHS=%s (%s)" % (node.target.id, - node._type, node.value, node.value._type)) - elif isinstance(node.target, ast.FuncCallOrArray): - if not self._current_scope.resolve(node.target.func, False): - raise UndeclaredVariableError("Array '%s' not declared." \ - % node.target.func) - node._type = self._current_scope.resolve(node.target.func)["type"] - # TODO: based on symbol_table, figure out if `node.target` is an - # array or a function call. Annotate the `node` to reflect that. - # Then in later stage the node can be replaced, based on the - # annotation. Extend Fortran.asdl to include FuncCall and - # ArrayRef, and change all occurrences of FuncCallOrArray to one of - # those. - # For now we assume that FuncCallOrArray is an ArrayRef. - self.visit_sequence(node.target.args) - if len(node.target.args) != 1: - raise NotImplementedError("Require exactly one index for now") - idx = node.target.args[0] - if idx._type != Integer(): - raise TypeMismatch("Array index must be an integer") - self.visit(node.value) - if node.value._type != node._type: - if isinstance(node._type, Array): - if isinstance(node.value._type, Array): - if node._type.type_ != node.value._type.type_: - raise TypeMismatch("Array Type mismatch") - else: - if node._type.type_ != node.value._type: - raise TypeMismatch("Array Type mismatch") - else: - # FIXME: this shouldn't happen --- this is handled by the - # above if - raise TypeMismatch("Type mismatch") - else: - raise SemanticError("LHS must be a variable or an array") - -def annotate_tree(tree, global_scope): - """ - Annotates the `tree` with types. - """ - v = ExprVisitor(global_scope) - v.visit(tree) diff --git a/lfortran/semantic/ast_to_asr.py b/lfortran/semantic/ast_to_asr.py deleted file mode 100644 index 14feccaf19..0000000000 --- a/lfortran/semantic/ast_to_asr.py +++ /dev/null @@ -1,210 +0,0 @@ -""" -Converts AST to ASR. - -This is a work in progress module, which will eventually replace analyze.py -once it reaches feature parity with it. -""" - -from ..ast import ast -from ..asr import asr -from ..asr.builder import (make_translation_unit, - translation_unit_make_module, scope_add_function, make_type_integer, - make_type_real, type_eq, make_binop, scope_add_symbol) - -from .analyze import TypeMismatch - -def string_to_type(stype, kind=None): - """ - Converts a string `stype` and a numerical `kind` to an ASR type. - """ - if stype == "integer": - return make_type_integer(kind) - elif stype == "real": - return make_type_real(kind) - elif stype == "complex": - raise NotImplementedError("Complex not implemented") - elif stype == "character": - raise NotImplementedError("Complex not implemented") - elif stype == "logical": - raise NotImplementedError("Complex not implemented") - raise Exception("Unknown type") - -class Stack: - - def __init__(self, scopes): - self._scopes = scopes - - def __enter__(self): - pass - - def __exit__(self, exc_type, exc_value, traceback): - self._scopes.pop() - -class SymbolTableVisitor(ast.GenericASTVisitor): - - def __init__(self): - self._scopes = [] - - def add_scope(self, scope): - self._scopes.append(scope) - return Stack(self._scopes) - - @property - def scope(self): - """ - Return the current scope - """ - return self._scopes[-1] - - def visit_TranslationUnit(self, node): - self._unit = make_translation_unit() - with self.add_scope(self._unit.global_scope): - for item in node.items: - self.visit(item) - - def visit_Module(self, node): - module = translation_unit_make_module(self._unit, node.name) - with self.add_scope(module.symtab): - self.visit_sequence(node.contains) - - def visit_Function(self, node): - args = [arg.arg for arg in node.args] - if node.return_var: - name = node.return_var.id # Name of the result(...) var - else: - name = node.name # Name of the function - if node.return_type: - type = string_to_type(node.return_type) - else: - # FIXME: should return None here - #type = None - type = make_type_integer() - return_var = asr.VariableOld(name=name, type=type) - f = scope_add_function(self.scope, node.name, - args=args, return_var=return_var) - with self.add_scope(f.symtab): - self.visit_sequence(node.decl) - - def visit_Declaration(self, node): - for v in node.vars: - name = v.sym - type = string_to_type(v.sym_type) - dims = [] - for dim in v.dims: - if isinstance(dim.end, ast.Num): - dims.append(int(dim.end.n)) - else: - raise NotImplementedError("Index not a number") - if dim.start: - raise NotImplementedError("start index") - #if len(dims) > 0: - # type = Array(type, dims) - if name in self.scope.symbols: - sym = self.scope.symbols[name] - else: - sym = asr.VariableOld(name=name, type=type, dummy=False) - scope_add_symbol(self.scope, sym) - assert sym.name == name - for a in v.attrs: - if a.name == "intent": - sym.intent = a.args[0].arg - -class BodyVisitor(ast.ASTVisitor): - - def __init__(self, unit): - self._unit = unit - self._scopes = [] - - def add_scope(self, scope): - self._scopes.append(scope) - return Stack(self._scopes) - - @property - def scope(self): - """ - Return the current scope - """ - return self._scopes[-1] - - def visit_sequence(self, seq): - r = [] - if seq is not None: - for node in seq: - r.append(self.visit(node)) - return r - - def visit_TranslationUnit(self, node): - with self.add_scope(self._unit.global_scope): - items = [] - for item in node.items: - a = self.visit(item) - if a: - items.append(a) - self._unit.items = items - - def visit_Module(self, node): - with self.add_scope(self.scope.symbols[node.name].symtab): - self.visit_sequence(node.contains) - - def visit_Function(self, node): - self._current_function = self.scope.symbols[node.name] - with self.add_scope(self.scope.symbols[node.name].symtab): - body = self.visit_sequence(node.body) - self._current_function.body = body - self.visit_sequence(node.contains) - - def visit_Declaration(self, node): - return - - def visit_Assignment(self, node): - if isinstance(node.target, ast.Name): - r = self.scope.symbols[node.target.id] - value = self.visit(node.value) - return asr.Assignment(r, value) - else: - raise NotImplementedError() - - def visit_BinOp(self, node): - left = self.visit(node.left) - right = self.visit(node.right) - if isinstance(node.op, ast.Add): - op = asr.Add() - elif isinstance(node.op, ast.Sub): - op = asr.Sub() - elif isinstance(node.op, ast.Mul): - op = asr.Mul() - elif isinstance(node.op, ast.Div): - op = asr.Div() - elif isinstance(node.op, ast.Pow): - op = asr.Pow() - else: - assert False - return make_binop(left=left, op=op, right=right) - - def visit_Name(self, node): - if not self.scope.resolve(node.id, False): - raise UndeclaredVariableError("Variable '%s' not declared." \ - % node.id) - return self.scope.symbols[node.id] - -def wrap_ast_translation_unit(astree): - # Note: We wrap the `astree` into an ast.TranslationUnit. This should - # eventually be moved into src_to_ast() itself (the rest of LFortran would - # need to be updated). - assert not isinstance(astree, ast.TranslationUnit) - if isinstance(astree, list): - items = astree - else: - items = [astree] - return ast.TranslationUnit(items=items) - -def ast_to_asr(astree): - astree = wrap_ast_translation_unit(astree) - v = SymbolTableVisitor() - assert isinstance(astree, ast.TranslationUnit) - v.visit(astree) - unit = v._unit - - v = BodyVisitor(unit) - v.visit(astree) - return unit diff --git a/lfortran/semantic/kinds.py b/lfortran/semantic/kinds.py deleted file mode 100644 index 05922a4106..0000000000 --- a/lfortran/semantic/kinds.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -LFortran type kind numbers - -The contents of this module was generated by the following code, -compiled with GFortran 9.1.0: - -```fortran -program print_kinds -use iso_fortran_env -implicit none -integer :: i -do i = 1, size(integer_kinds) - print "('int', i0, ' = ', i0)", integer_kinds(i)*8, integer_kinds(i) -end do -print * -do i = 1, size(real_kinds) - print "('real', i0, ' = ', i0)", real_kinds(i)*8, real_kinds(i) -end do -print * -do i = 1, size(logical_kinds) - print "('logical', i0, ' = ', i0)", logical_kinds(i)*8, logical_kinds(i) -end do -print * -do i = 1, size(character_kinds) - print "('char', i0, ' = ', i0)", character_kinds(i)*8, character_kinds(i) -end do -end -``` - -""" - -int8 = 1 -int16 = 2 -int32 = 4 -int64 = 8 -int128 = 16 - -real32 = 4 -real64 = 8 -real80 = 10 -real128 = 16 - -logical8 = 1 -logical16 = 2 -logical32 = 4 -logical64 = 8 -logical128 = 16 - -char8 = 1 -char32 = 4 diff --git a/lfortran/semantic/tests/__init__.py b/lfortran/semantic/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/semantic/tests/test_ast_to_asr.py b/lfortran/semantic/tests/test_ast_to_asr.py deleted file mode 100644 index bbf6beb7c7..0000000000 --- a/lfortran/semantic/tests/test_ast_to_asr.py +++ /dev/null @@ -1,95 +0,0 @@ -import pytest - -from lfortran.semantic.ast_to_asr import ast_to_asr -from lfortran.ast import src_to_ast -from lfortran.asr import asr -from lfortran.asr.asr_check import verify_asr - -from lfortran.ast.ast_to_src import ast_to_src -from lfortran.asr.asr_to_ast import asr_to_ast - - -def test_function1(): - source = """\ -module test -implicit none -contains - - integer function fn1(a, b) result(r) - integer, intent(in) :: a, b - r = a + b - end function - -end module -""" - ast = src_to_ast(source) - asrepr = ast_to_asr(ast) - verify_asr(asrepr) - assert isinstance(asrepr, asr.TranslationUnit) - assert 'test' in asrepr.global_scope.symbols - m = asrepr.global_scope.symbols['test'] - assert isinstance(m, asr.Module) - fn1 = m.symtab.symbols["fn1"] - assert isinstance(fn1, asr.Function) - assert fn1.args[0].name == "a" - assert fn1.args[1].name == "b" - assert fn1.return_var.name == "r" - assert fn1.body[0].target == fn1.return_var - assert fn1.body[0].value.left == fn1.args[0] - assert fn1.body[0].value.right == fn1.args[1] - -def test_function2(): - source = """\ -integer function fn1(a, b) result(r) -integer, intent(in) :: a, b -r = a + b -end function -""" - ast = src_to_ast(source, translation_unit=False) - asrepr = ast_to_asr(ast) - verify_asr(asrepr) - assert isinstance(asrepr, asr.TranslationUnit) - assert 'fn1' in asrepr.global_scope.symbols - fn1 = asrepr.global_scope.symbols['fn1'] - assert isinstance(fn1, asr.Function) - assert fn1.args[0].name == "a" - assert fn1.args[1].name == "b" - assert fn1.return_var.name == "r" - assert fn1.body[0].target == fn1.return_var - assert fn1.body[0].value.left == fn1.args[0] - assert fn1.body[0].value.right == fn1.args[1] - - s = ast_to_src(asr_to_ast(asrepr)) - assert s == """\ -integer function fn1(a, b) result(r) -integer, intent(in) :: a -integer, intent(in) :: b -r = a + b -end function -""" - -def test_statements(): - source = """\ -integer :: a, b, r -r = a + b -""" - ast = src_to_ast(source, translation_unit=False) - asrepr = ast_to_asr(ast) - verify_asr(asrepr) - assert isinstance(asrepr, asr.TranslationUnit) - assert 'a' in asrepr.global_scope.symbols - assert 'b' in asrepr.global_scope.symbols - assert 'r' in asrepr.global_scope.symbols - body = asrepr.items - assert isinstance(body[0], asr.Assignment) - assert body[0].target == asrepr.global_scope.symbols["r"] - assert body[0].value.left == asrepr.global_scope.symbols["a"] - assert body[0].value.right == asrepr.global_scope.symbols["b"] - - s = ast_to_src(asr_to_ast(asrepr)) - assert s == """\ -integer :: a -integer :: b -integer :: r -r = a + b -""" diff --git a/lfortran/semantic/tests/test_variables.py b/lfortran/semantic/tests/test_variables.py deleted file mode 100644 index 112b381b4f..0000000000 --- a/lfortran/semantic/tests/test_variables.py +++ /dev/null @@ -1,441 +0,0 @@ -import pytest - -from lfortran.semantic.analyze import (create_symbol_table, Integer, Real, - Array, Logical, UndeclaredVariableError, annotate_tree, TypeMismatch) -from lfortran.ast import src_to_ast, dump - -def test_types(): - r = Real() - i = Integer() - assert r == r - assert not (r != r) - assert r == Real() - - assert i == i - assert not (i != i) - assert i == Integer() - - assert i != r - assert not (i == r) - assert not (i == Real()) - assert i != Real() - - assert r != i - assert not (r == i) - assert not (r == Integer()) - assert r != Integer() - -def test_types_arrays(): - i = Integer() - dims = [9, 10] - a = Array(i, dims) - assert a == a - assert not (a != a) - assert a == Array(i, dims) - assert a == Array(Integer(), [9, 10]) - assert a != Array(Integer(), [9, 11]) - assert a != Array(Real(), [9, 10]) - -def test_variables1(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a, b) - integer, intent(in) :: a - real, intent(out) :: b - b = a + 1 - end subroutine - -end module -""" - tree = src_to_ast(source) - global_scope = create_symbol_table(tree) - assert not global_scope.resolve("a", False) - sym = tree.contains[0]._scope.resolve("a") - assert sym["type"] == Integer() - assert sym["name"] == "a" - sym = tree.contains[0]._scope.resolve("b") - assert sym["type"] == Real() - assert sym["name"] == "b" - assert not tree.contains[0]._scope.resolve("c", False) - -def test_unknown_type1(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a) - integer, intent(in) :: a - a = b - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - with pytest.raises(UndeclaredVariableError): - annotate_tree(tree, symbol_table) - -def test_unknown_type2(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a) - integer, intent(in) :: a - a = (1+b)**2 - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - with pytest.raises(UndeclaredVariableError): - annotate_tree(tree, symbol_table) - -def test_unknown_type2b(): - source = """\ -subroutine sub1(a) -integer, intent(in) :: a -b = 1 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - with pytest.raises(UndeclaredVariableError): - annotate_tree(tree, symbol_table) - -def test_unknown_type3(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a) - integer, intent(in) :: a - a = (1+a)**2 - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - -def test_type1(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a, b) - integer, intent(in) :: a, b - a = b - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - assert tree.contains[0].body[0]._type == Integer() - -def test_type2(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a, b) - integer, intent(in) :: a - real, intent(in) :: b - a = b - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - with pytest.raises(TypeMismatch): - annotate_tree(tree, symbol_table) - -def test_type3(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a, b) - integer, intent(in) :: a - integer, intent(in) :: b - a = b + 1 - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - assert tree.contains[0].body[0]._type == Integer() - -def test_type4(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a, b) - integer, intent(in) :: a - real, intent(in) :: b - a = b + 1 - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - with pytest.raises(TypeMismatch): - annotate_tree(tree, symbol_table) - -def test_type5(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a, b) - integer, intent(in) :: a - integer, intent(in) :: b - a = (b + 1)*a*5 - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - assert tree.contains[0].body[0]._type == Integer() - -def test_type6(): - source = """\ -module test -implicit none -contains - - subroutine sub1(a, b) - integer, intent(in) :: a - real, intent(in) :: b - a = (b + 1)*a*5 - end subroutine - -end module -""" - tree = src_to_ast(source) - symbol_table = create_symbol_table(tree) - with pytest.raises(TypeMismatch): - annotate_tree(tree, symbol_table) - -def test_type7(): - source = """\ -subroutine sub1(a, b) -real, intent(in) :: a -real, intent(in) :: b -a = (b + a)*a -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - assert tree.body[0]._type == Real() - -def test_dump(): - source = """\ -subroutine sub1(a, b) -integer, intent(in) :: a -integer, intent(in) :: b -a = (b + 1)*a*5 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - assert dump(tree, include_type=True) == "Subroutine(name='sub1', args=[arg(arg='a'), arg(arg='b')], use=[], decl=[Declaration(vars=[decl(sym='a', sym_type='integer', dims=[], attrs=[Attribute(name='intent', args=[attribute_arg(arg='in')])], initializer=None)]), Declaration(vars=[decl(sym='b', sym_type='integer', dims=[], attrs=[Attribute(name='intent', args=[attribute_arg(arg='in')])], initializer=None)])], body=[Assignment(target=Name(id='a'), value=BinOp(left=BinOp(left=BinOp(left=Name(id='b', type=Integer()), op=Add(), right=Num(n='1', type=Integer()), type=Integer()), op=Mul(), right=Name(id='a', type=Integer()), type=Integer()), op=Mul(), right=Num(n='5', type=Integer()), type=Integer()), type=Integer())], contains=[])" - -def test_logical1(): - source = """\ -subroutine sub1(a, b) -integer, intent(in) :: a -integer, intent(in) :: b -logical :: r -r = (a == b) -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - assert tree.body[0]._type == Logical() - -def test_logical2(): - source = """\ -subroutine sub1(a) -integer, intent(in) :: a -logical :: r -r = a -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - with pytest.raises(TypeMismatch): - annotate_tree(tree, symbol_table) - -def test_logical3(): - source = """\ -subroutine sub1(a, b) -integer, intent(in) :: a, b -integer :: c -if (a == b) c = 1 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - -def test_logical4(): - source = """\ -subroutine sub1(a, b) -integer, intent(in) :: a, b -integer :: c -if (a) c = 1 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - with pytest.raises(TypeMismatch): - annotate_tree(tree, symbol_table) - -def test_logical5(): - source = """\ -subroutine sub1(a, b) -integer, intent(in) :: a, b -integer :: c -if (a == b) then - d = 1 -end if -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - with pytest.raises(UndeclaredVariableError): - annotate_tree(tree, symbol_table) - -def test_logical6(): - source = """\ -subroutine sub1(a, b) -integer, intent(in) :: a(3), b(3) -integer :: c -if (a == b) c = 1 -if (a(1) == 1) c = 1 -if (1 == a(1)) c = 1 -if (a(1) == a(1)) c = 1 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - -def test_arrays1(): - source = """\ -subroutine sub1() -integer :: a(3), i -a(1) = 1 -i = 2 -a(2) = i -a(i) = i+1 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - -def test_arrays2(): - source = """\ -subroutine sub1() -integer :: a(3) -real :: r -a(1) = 1 -r = 2 -a(r) = 2 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - with pytest.raises(TypeMismatch): - annotate_tree(tree, symbol_table) - -def test_arrays3(): - # Here we test assigning the wrong type to an array. Since only real and - # integer types are implemented for now, just test that real cannot be - # assinged to an integer. Later we can change this to, say, a character. - source = """\ -subroutine sub1() -integer :: a(3), i -real :: r -i = 1 -a(i) = r -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - with pytest.raises(TypeMismatch): - annotate_tree(tree, symbol_table) - -def test_arrays4(): - source = """\ -subroutine sub1() -integer :: a(3), b(4), i -a(1) = b(2) -a(i) = b(2) -a(1) = b(2) + 1 -a(1) = 1 + b(2) -a(1) = b(i) + 1 -a(1) = b(i) + b(1) -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - - -def test_subroutines1(): - source = """\ -subroutine sub1(a, b) -integer, intent(in) :: a -integer, intent(out) :: b -b = a + 1 -end subroutine -""" - tree = src_to_ast(source, False) - symbol_table = create_symbol_table(tree) - annotate_tree(tree, symbol_table) - - -def get_num(src): - numexpr = src_to_ast(src, translation_unit=False) - symbol_table = create_symbol_table(numexpr) - annotate_tree(numexpr, symbol_table) - return numexpr.o - - -def test_d_exponent(): - assert get_num("0d0") == 0.0 - assert get_num("42d0") == 42.0 - assert get_num("7.000d0") == 7.0 - assert get_num("1.0d-1") == 0.1 - assert get_num("0.000000001d10") == 10.0 - - assert get_num("0.D0") == 0.0 - assert get_num("0.01D2") == 1.0 diff --git a/lfortran/tests/__init__.py b/lfortran/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lfortran/tests/test_lld.py b/lfortran/tests/test_lld.py deleted file mode 100644 index cd78594fa3..0000000000 --- a/lfortran/tests/test_lld.py +++ /dev/null @@ -1,120 +0,0 @@ -import os -from subprocess import call -import sys -from tempfile import TemporaryDirectory - -import llvmlite.binding as llvm - -from .utils import linux_only - -def linker(args): - try: - llvm.lld_main(["ld.lld"] + args) - except AttributeError: - call(["ld"] + args) - -@linux_only -def test_linux64_program(): - """ - This is the simplest assembly program that uses Linux 64bit syscall to - return an exit value. - """ - # Named registers are used in the `asm` block, so that LLVM handles - # register allocation. - # - # The calling convention for syscall on x86-64 (see `man syscall`) is to - # pass the system call number in {rax}, the return value is returned in - # {rax}, and the system call arguments in: - # {rdi},{rsi},{rdx},{r10},{r8},{r9} - # The syscall kernel call clobbers {rcx} and {r11} registers. - # - # The LLVM's `asm` call itself clobbers the following registers: - # * {flags} (EFLAGS: status flags register) - # * {dirflag} (DF: direction flag; modeled separately from {flags}) - # * {fpsr} (floating point status register) - source_ll = r""" -; exit(int exit_code) -define void @exit(i64 %exit_code) { - call i64 asm sideeffect "syscall", - "={rax},{rax},{rdi},~{rcx},~{r11},~{dirflag},~{fpsr},~{flags}" - ( i64 60 ; {rax} SYSCALL_EXIT - , i64 %exit_code ; {rdi} exit_code - ) - ret void -} - -define void @_start() { - call void @exit(i64 42) - ret void -} - """ - with TemporaryDirectory() as tmpdir: - objfile = os.path.join(tmpdir, "test1.o") - binfile = os.path.join(tmpdir, "test1") - llvm.initialize() - llvm.initialize_native_asmprinter() - llvm.initialize_native_asmparser() - llvm.initialize_native_target() - target = llvm.Target.from_triple(llvm.get_default_triple()) - target_machine = target.create_target_machine() - mod = llvm.parse_assembly(source_ll) - mod.verify() - with open(objfile, "wb") as o: - o.write(target_machine.emit_object(mod)) - linker(["-o", binfile, objfile]) - r = call("%s" % binfile) - assert r == 42 - -@linux_only -def test_linux64_program_write(capfd): - source_ll = r""" -@.message = internal constant [14 x i8] c"Hello, world!\0A" - -; write(STDOUT, message, message_len) -define i64 @write(i64 %STDOUT, i8* %message, i64 %message_len) { - %1 = call i64 asm sideeffect "syscall", - "={rax},{rax},{rdi},{rsi},{rdx},~{rcx},~{r11},~{dirflag},~{fpsr},~{flags}" - ( i64 1 ; {rax} SYSCALL_WRITE - , i64 %STDOUT ; {rdi} STDOUT - , i8* %message ; {rsi} message - , i64 %message_len ; {rdx} message_len - ) - ret i64 %1 -} - -; exit(int exit_code) -define void @exit(i64 %exit_code) { - call i64 asm sideeffect "syscall", - "={rax},{rax},{rdi},~{rcx},~{r11},~{dirflag},~{fpsr},~{flags}" - ( i64 60 ; {rax} SYSCALL_EXIT - , i64 %exit_code ; {rdi} exit_code - ) - ret void -} - -define void @_start() { - %message_ptr = getelementptr [14 x i8], [14 x i8]* @.message , i64 0, i64 0 - - call i64 @write(i64 1, i8* %message_ptr, i64 14) - call void @exit(i64 42) - ret void -} - """ - with TemporaryDirectory() as tmpdir: - objfile = os.path.join(tmpdir, "test1.o") - binfile = os.path.join(tmpdir, "test1") - llvm.initialize() - llvm.initialize_native_asmprinter() - llvm.initialize_native_asmparser() - llvm.initialize_native_target() - target = llvm.Target.from_triple(llvm.get_default_triple()) - target_machine = target.create_target_machine() - mod = llvm.parse_assembly(source_ll) - mod.verify() - with open(objfile, "wb") as o: - o.write(target_machine.emit_object(mod)) - linker(["-o", binfile, objfile]) - r = call("%s" % binfile) - assert r == 42 - out = capfd.readouterr().out - assert out == "Hello, world!\n" diff --git a/lfortran/tests/utils.py b/lfortran/tests/utils.py deleted file mode 100644 index 0afd91bf5a..0000000000 --- a/lfortran/tests/utils.py +++ /dev/null @@ -1,5 +0,0 @@ -import sys -import pytest - -linux_only = pytest.mark.skipif(sys.platform != "linux", - reason="Runs on Linux only")