From 54e35e2b89ce44c15a3b5e13128ccbc22a9a6792 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 9 Feb 2021 10:56:17 +0000 Subject: [PATCH] Initial commit --- .gitignore | 149 +++++ LICENSE | 26 + README.md | 24 + chocopy-ref.jar | Bin 0 -> 144764 bytes pom.xml | 330 ++++++++++ src/main/cup/chocopy/pa1/ChocoPy.cup | 214 ++++++ src/main/java/chocopy/common/Utils.java | 64 ++ .../chocopy/common/analysis/NodeAnalyzer.java | 100 +++ .../chocopy/common/astnodes/AssignStmt.java | 36 + .../chocopy/common/astnodes/BinaryExpr.java | 40 ++ .../common/astnodes/BooleanLiteral.java | 29 + .../chocopy/common/astnodes/CallExpr.java | 36 + .../chocopy/common/astnodes/ClassDef.java | 50 ++ .../chocopy/common/astnodes/ClassType.java | 28 + .../common/astnodes/CompilerError.java | 64 ++ .../chocopy/common/astnodes/Declaration.java | 23 + .../java/chocopy/common/astnodes/Errors.java | 90 +++ .../java/chocopy/common/astnodes/Expr.java | 22 + .../chocopy/common/astnodes/ExprStmt.java | 29 + .../java/chocopy/common/astnodes/ForStmt.java | 43 ++ .../java/chocopy/common/astnodes/FuncDef.java | 61 ++ .../chocopy/common/astnodes/GlobalDecl.java | 34 + .../chocopy/common/astnodes/Identifier.java | 29 + .../java/chocopy/common/astnodes/IfExpr.java | 40 ++ .../java/chocopy/common/astnodes/IfStmt.java | 45 ++ .../chocopy/common/astnodes/IndexExpr.java | 35 + .../common/astnodes/IntegerLiteral.java | 29 + .../chocopy/common/astnodes/ListExpr.java | 32 + .../chocopy/common/astnodes/ListType.java | 30 + .../java/chocopy/common/astnodes/Literal.java | 18 + .../chocopy/common/astnodes/MemberExpr.java | 36 + .../common/astnodes/MethodCallExpr.java | 38 ++ .../java/chocopy/common/astnodes/Node.java | 204 ++++++ .../chocopy/common/astnodes/NonLocalDecl.java | 34 + .../chocopy/common/astnodes/NoneLiteral.java | 21 + .../java/chocopy/common/astnodes/Program.java | 70 ++ .../chocopy/common/astnodes/ReturnStmt.java | 30 + .../java/chocopy/common/astnodes/Stmt.java | 21 + .../common/astnodes/StringLiteral.java | 29 + .../common/astnodes/TypeAnnotation.java | 16 + .../chocopy/common/astnodes/TypedVar.java | 36 + .../chocopy/common/astnodes/UnaryExpr.java | 36 + .../java/chocopy/common/astnodes/VarDef.java | 42 ++ .../chocopy/common/astnodes/WhileStmt.java | 39 ++ src/main/java/chocopy/pa1/StudentParser.java | 25 + src/main/jflex/chocopy/pa1/ChocoPy.jflex | 82 +++ src/test/data/pa1/sample/bad_assign_expr1.py | 1 + .../data/pa1/sample/bad_assign_expr1.py.ast | 16 + src/test/data/pa1/sample/bad_assign_expr2.py | 1 + .../data/pa1/sample/bad_assign_expr2.py.ast | 16 + src/test/data/pa1/sample/bad_func_def.py | 6 + src/test/data/pa1/sample/bad_func_def.py.ast | 64 ++ src/test/data/pa1/sample/bad_indentation.py | 3 + .../data/pa1/sample/bad_indentation.py.ast | 47 ++ src/test/data/pa1/sample/bad_stmt.py | 4 + src/test/data/pa1/sample/bad_stmt.py.ast | 65 ++ .../pa1/sample/chained_mixed_assignments.py | 2 + .../sample/chained_mixed_assignments.py.ast | 85 +++ .../pa1/sample/chained_var_assignments.py | 1 + .../pa1/sample/chained_var_assignments.py.ast | 32 + src/test/data/pa1/sample/class_attr.py | 4 + src/test/data/pa1/sample/class_attr.py.ast | 65 ++ src/test/data/pa1/sample/class_attr_get.py | 5 + .../data/pa1/sample/class_attr_get.py.ast | 91 +++ src/test/data/pa1/sample/class_attr_set.py | 5 + .../data/pa1/sample/class_attr_set.py.ast | 87 +++ src/test/data/pa1/sample/class_constructor.py | 8 + .../data/pa1/sample/class_constructor.py.ast | 159 +++++ src/test/data/pa1/sample/class_method.py | 9 + src/test/data/pa1/sample/class_method.py.ast | 181 ++++++ src/test/data/pa1/sample/coverage.py | 38 ++ src/test/data/pa1/sample/coverage.py.ast | 613 ++++++++++++++++++ src/test/data/pa1/sample/def_func.py | 4 + src/test/data/pa1/sample/def_func.py.ast | 48 ++ src/test/data/pa1/sample/def_func_args.py | 4 + src/test/data/pa1/sample/def_func_args.py.ast | 92 +++ src/test/data/pa1/sample/def_func_global.py | 7 + .../data/pa1/sample/def_func_global.py.ast | 105 +++ src/test/data/pa1/sample/def_func_nested.py | 10 + .../data/pa1/sample/def_func_nested.py.ast | 187 ++++++ src/test/data/pa1/sample/def_func_nonlocal.py | 11 + .../data/pa1/sample/def_func_nonlocal.py.ast | 186 ++++++ src/test/data/pa1/sample/expr_if.py | 1 + src/test/data/pa1/sample/expr_if.py.ast | 43 ++ src/test/data/pa1/sample/expr_if_chained.py | 1 + .../data/pa1/sample/expr_if_chained.py.ast | 67 ++ src/test/data/pa1/sample/expr_index.py | 1 + src/test/data/pa1/sample/expr_index.py.ast | 47 ++ src/test/data/pa1/sample/expr_plus.py | 1 + src/test/data/pa1/sample/expr_plus.py.ast | 39 ++ src/test/data/pa1/sample/expr_unary.py | 1 + src/test/data/pa1/sample/expr_unary.py.ast | 24 + src/test/data/pa1/sample/global.py | 5 + src/test/data/pa1/sample/global.py.ast | 63 ++ src/test/data/pa1/sample/literals.py | 7 + src/test/data/pa1/sample/literals.py.ast | 70 ++ src/test/data/pa1/sample/stmt_call.py | 1 + src/test/data/pa1/sample/stmt_call.py.ast | 28 + src/test/data/pa1/sample/stmt_for.py | 4 + src/test/data/pa1/sample/stmt_for.py.ast | 76 +++ src/test/data/pa1/sample/stmt_if.py | 3 + src/test/data/pa1/sample/stmt_if.py.ast | 29 + src/test/data/pa1/sample/stmt_if_elif.py | 6 + src/test/data/pa1/sample/stmt_if_elif.py.ast | 112 ++++ src/test/data/pa1/sample/stmt_if_elif_else.py | 8 + .../data/pa1/sample/stmt_if_elif_else.py.ast | 129 ++++ src/test/data/pa1/sample/stmt_ifelse.py | 5 + src/test/data/pa1/sample/stmt_ifelse.py.ast | 37 ++ src/test/data/pa1/sample/stmt_list_assign.py | 4 + .../data/pa1/sample/stmt_list_assign.py.ast | 88 +++ src/test/data/pa1/sample/stmt_while.py | 3 + src/test/data/pa1/sample/stmt_while.py.ast | 20 + src/test/data/pa1/student_contributed/bad.py | 1 + src/test/data/pa1/student_contributed/good.py | 1 + 114 files changed, 5696 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 chocopy-ref.jar create mode 100644 pom.xml create mode 100644 src/main/cup/chocopy/pa1/ChocoPy.cup create mode 100644 src/main/java/chocopy/common/Utils.java create mode 100644 src/main/java/chocopy/common/analysis/NodeAnalyzer.java create mode 100644 src/main/java/chocopy/common/astnodes/AssignStmt.java create mode 100644 src/main/java/chocopy/common/astnodes/BinaryExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/BooleanLiteral.java create mode 100644 src/main/java/chocopy/common/astnodes/CallExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/ClassDef.java create mode 100644 src/main/java/chocopy/common/astnodes/ClassType.java create mode 100644 src/main/java/chocopy/common/astnodes/CompilerError.java create mode 100644 src/main/java/chocopy/common/astnodes/Declaration.java create mode 100644 src/main/java/chocopy/common/astnodes/Errors.java create mode 100644 src/main/java/chocopy/common/astnodes/Expr.java create mode 100644 src/main/java/chocopy/common/astnodes/ExprStmt.java create mode 100644 src/main/java/chocopy/common/astnodes/ForStmt.java create mode 100644 src/main/java/chocopy/common/astnodes/FuncDef.java create mode 100644 src/main/java/chocopy/common/astnodes/GlobalDecl.java create mode 100644 src/main/java/chocopy/common/astnodes/Identifier.java create mode 100644 src/main/java/chocopy/common/astnodes/IfExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/IfStmt.java create mode 100644 src/main/java/chocopy/common/astnodes/IndexExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/IntegerLiteral.java create mode 100644 src/main/java/chocopy/common/astnodes/ListExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/ListType.java create mode 100644 src/main/java/chocopy/common/astnodes/Literal.java create mode 100644 src/main/java/chocopy/common/astnodes/MemberExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/MethodCallExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/Node.java create mode 100644 src/main/java/chocopy/common/astnodes/NonLocalDecl.java create mode 100644 src/main/java/chocopy/common/astnodes/NoneLiteral.java create mode 100644 src/main/java/chocopy/common/astnodes/Program.java create mode 100644 src/main/java/chocopy/common/astnodes/ReturnStmt.java create mode 100644 src/main/java/chocopy/common/astnodes/Stmt.java create mode 100644 src/main/java/chocopy/common/astnodes/StringLiteral.java create mode 100644 src/main/java/chocopy/common/astnodes/TypeAnnotation.java create mode 100644 src/main/java/chocopy/common/astnodes/TypedVar.java create mode 100644 src/main/java/chocopy/common/astnodes/UnaryExpr.java create mode 100644 src/main/java/chocopy/common/astnodes/VarDef.java create mode 100644 src/main/java/chocopy/common/astnodes/WhileStmt.java create mode 100644 src/main/java/chocopy/pa1/StudentParser.java create mode 100644 src/main/jflex/chocopy/pa1/ChocoPy.jflex create mode 100644 src/test/data/pa1/sample/bad_assign_expr1.py create mode 100644 src/test/data/pa1/sample/bad_assign_expr1.py.ast create mode 100644 src/test/data/pa1/sample/bad_assign_expr2.py create mode 100644 src/test/data/pa1/sample/bad_assign_expr2.py.ast create mode 100644 src/test/data/pa1/sample/bad_func_def.py create mode 100644 src/test/data/pa1/sample/bad_func_def.py.ast create mode 100644 src/test/data/pa1/sample/bad_indentation.py create mode 100644 src/test/data/pa1/sample/bad_indentation.py.ast create mode 100644 src/test/data/pa1/sample/bad_stmt.py create mode 100644 src/test/data/pa1/sample/bad_stmt.py.ast create mode 100644 src/test/data/pa1/sample/chained_mixed_assignments.py create mode 100644 src/test/data/pa1/sample/chained_mixed_assignments.py.ast create mode 100644 src/test/data/pa1/sample/chained_var_assignments.py create mode 100644 src/test/data/pa1/sample/chained_var_assignments.py.ast create mode 100644 src/test/data/pa1/sample/class_attr.py create mode 100644 src/test/data/pa1/sample/class_attr.py.ast create mode 100644 src/test/data/pa1/sample/class_attr_get.py create mode 100644 src/test/data/pa1/sample/class_attr_get.py.ast create mode 100644 src/test/data/pa1/sample/class_attr_set.py create mode 100644 src/test/data/pa1/sample/class_attr_set.py.ast create mode 100644 src/test/data/pa1/sample/class_constructor.py create mode 100644 src/test/data/pa1/sample/class_constructor.py.ast create mode 100644 src/test/data/pa1/sample/class_method.py create mode 100644 src/test/data/pa1/sample/class_method.py.ast create mode 100644 src/test/data/pa1/sample/coverage.py create mode 100644 src/test/data/pa1/sample/coverage.py.ast create mode 100644 src/test/data/pa1/sample/def_func.py create mode 100644 src/test/data/pa1/sample/def_func.py.ast create mode 100644 src/test/data/pa1/sample/def_func_args.py create mode 100644 src/test/data/pa1/sample/def_func_args.py.ast create mode 100644 src/test/data/pa1/sample/def_func_global.py create mode 100644 src/test/data/pa1/sample/def_func_global.py.ast create mode 100644 src/test/data/pa1/sample/def_func_nested.py create mode 100644 src/test/data/pa1/sample/def_func_nested.py.ast create mode 100644 src/test/data/pa1/sample/def_func_nonlocal.py create mode 100644 src/test/data/pa1/sample/def_func_nonlocal.py.ast create mode 100644 src/test/data/pa1/sample/expr_if.py create mode 100644 src/test/data/pa1/sample/expr_if.py.ast create mode 100644 src/test/data/pa1/sample/expr_if_chained.py create mode 100644 src/test/data/pa1/sample/expr_if_chained.py.ast create mode 100644 src/test/data/pa1/sample/expr_index.py create mode 100644 src/test/data/pa1/sample/expr_index.py.ast create mode 100644 src/test/data/pa1/sample/expr_plus.py create mode 100644 src/test/data/pa1/sample/expr_plus.py.ast create mode 100644 src/test/data/pa1/sample/expr_unary.py create mode 100644 src/test/data/pa1/sample/expr_unary.py.ast create mode 100644 src/test/data/pa1/sample/global.py create mode 100644 src/test/data/pa1/sample/global.py.ast create mode 100644 src/test/data/pa1/sample/literals.py create mode 100644 src/test/data/pa1/sample/literals.py.ast create mode 100644 src/test/data/pa1/sample/stmt_call.py create mode 100644 src/test/data/pa1/sample/stmt_call.py.ast create mode 100644 src/test/data/pa1/sample/stmt_for.py create mode 100644 src/test/data/pa1/sample/stmt_for.py.ast create mode 100644 src/test/data/pa1/sample/stmt_if.py create mode 100644 src/test/data/pa1/sample/stmt_if.py.ast create mode 100644 src/test/data/pa1/sample/stmt_if_elif.py create mode 100644 src/test/data/pa1/sample/stmt_if_elif.py.ast create mode 100644 src/test/data/pa1/sample/stmt_if_elif_else.py create mode 100644 src/test/data/pa1/sample/stmt_if_elif_else.py.ast create mode 100644 src/test/data/pa1/sample/stmt_ifelse.py create mode 100644 src/test/data/pa1/sample/stmt_ifelse.py.ast create mode 100644 src/test/data/pa1/sample/stmt_list_assign.py create mode 100644 src/test/data/pa1/sample/stmt_list_assign.py.ast create mode 100644 src/test/data/pa1/sample/stmt_while.py create mode 100644 src/test/data/pa1/sample/stmt_while.py.ast create mode 100644 src/test/data/pa1/student_contributed/bad.py create mode 100644 src/test/data/pa1/student_contributed/good.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21cc758 --- /dev/null +++ b/.gitignore @@ -0,0 +1,149 @@ +.DS_Store +__pycache__ +target + +# Created by https://www.gitignore.io/api/java,eclipse,intellij,emacs,vim + +### Java ### +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + + +### Eclipse ### +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse + + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties + + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ + + +### Vim ### +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0808d4b --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2017-2018 The Regents of the University of California + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f6e4b4a --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# NYU Compiler Construction CSCI-GA.2130/Spring 2021: Programming Assignment 1 + +This assignment is adapted from https://github.com/cs164berkeley/pa1-chocopy-parser/ with the authors' permission. + +See the PA1 document on Piazza for a detailed specification. + +## Quickstart + +Run the following commands to generate and compile your parser and run the tests: +``` +mvn clean package +java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \ + --pass=s --test --dir src/test/data/pa1/sample/ +``` + +`--pass=s` uses your parser (`s` for `student`), and with the starter code, only one test should pass. +`--pass=r` uses the reference parser (`r` for `reference`), which should pass all tests. + +In addition to running in test mode with `--test`, you can also observe the actual output +of your (or reference) parser with: +``` +java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \ + --pass=s src/test/data/pa1/sample/expr_plus.py +``` diff --git a/chocopy-ref.jar b/chocopy-ref.jar new file mode 100644 index 0000000000000000000000000000000000000000..31646a6ca4588df335c5496d7972482855979b76 GIT binary patch literal 144764 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

x3)#!N_eS1Nd-YOw2dAQ~<{0?#1`%i#$|KRe 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 G?EeF4FMZnp literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..1766e51 --- /dev/null +++ b/pom.xml @@ -0,0 +1,330 @@ + + 4.0.0 + chocopy + chocopy + jar + 2.2-SNAPSHOT + chocopy + http://maven.apache.org + + + + false + + + + + + + + de.jflex + jflex-maven-plugin + 1.6.1 + + + com.github.vbmacher + cup-maven-plugin + 11b-20160615 + + + maven-assembly-plugin + 3.1.0 + + + maven-jar-plugin + 3.1.0 + + + maven-site-plugin + 3.7.1 + + + + + + + maven-assembly-plugin + + + jar-with-dependencies + + assignment + false + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + UTF-8 + 1.8 + 1.8 + true + true + + + + + + + src/main/asm + + **/*.s + **/*.os + + + **/reference/*.s + + + + + + + + reference + + + + src/main/java/chocopy/reference/ + + + + + + + maven-jar-plugin + + + **/pa1/* + **/pa2/* + **/pa3/* + + + + + + maven-assembly-plugin + + + jar-with-dependencies + + chocopy-ref + false + + + + + de.jflex + jflex-maven-plugin + + + jflex-reference + + generate + + + + src/main/jflex/chocopy/reference/ChocoPy.jflex + + ${chocopy.debug} + true + + + + + + + com.github.vbmacher + cup-maven-plugin + + + cup-reference + + generate + + + src/main/cup/chocopy/reference/ChocoPy.cup + chocopy.reference + ChocoPyParser + ChocoPyTokens + ${chocopy.debug} + ${chocopy.debug} + ${chocopy.debug} + true + + + + + + + maven-compiler-plugin + + true + none + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.1 + + + copy-dependencies + package + + copy-dependencies + + + + + + + + + + pa1 + + + + src/main/java/chocopy/pa1 + + + + + + + de.jflex + jflex-maven-plugin + + + jflex-pa1 + + generate + + + + src/main/jflex/chocopy/pa1/ChocoPy.jflex + + ${chocopy.debug} + true + + + + + + + com.github.vbmacher + cup-maven-plugin + + + cup-pa1 + + generate + + + src/main/cup/chocopy/pa1/ChocoPy.cup + chocopy.pa1 + ChocoPyParser + ChocoPyTokens + ${chocopy.debug} + ${chocopy.debug} + ${chocopy.debug} + true + + + + + + + + + pa2 + + + + src/main/java/chocopy/pa2 + + + + + pa3 + + + + src/main/java/chocopy/pa3 + + + + + + + + + venus164-repo + Repository for Venus164 + https://raw.githubusercontent.com/chocopy/venus/maven-repository/ + + + + + + net.sourceforge.argparse4j + argparse4j + 0.8.1 + + + com.fasterxml.jackson.core + jackson-databind + [2.9.10.1,) + + + com.fasterxml.jackson.module + jackson-module-parameter-names + 2.9.10 + + + com.github.vbmacher + java-cup-runtime + 11b-20160615 + + + + de.jflex + jflex + 1.6.1 + + + org.jetbrains.kotlin + kotlin-stdlib + 1.2.71 + + + edu.berkeley.eecs.venus164 + venus164 + 0.2.4 + + + junit + junit + 4.12 + test + + + net.sf.proguard + proguard-base + 6.0.3 + + + diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup new file mode 100644 index 0000000..d4ff444 --- /dev/null +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -0,0 +1,214 @@ +import java.util.ArrayList; +import java.util.List; + +import java_cup.runtime.*; +import chocopy.common.astnodes.*; + +/* The following code section is copied verbatim to the generated + * parser class. */ +parser code {: + + /* The following fields and methods deal with error reporting + * Avoid changing these unless you know what you are doing. */ + + /** Node that accumulates error messages to be added to the Program + * node produced as a result. */ + public final Errors errors = new Errors(new ArrayList<>()); + + /** Return the Program node that results from parsing the stream of + * tokens produced by lexical analysis. In the case of syntax errors, + * the program may be empty, but will have error messages. */ + public Program parseProgram(boolean debug) { + try { + Symbol result = debug ? debug_parse() : parse(); + if (result == null || !(result.value instanceof Program)) { + return new Program(new Location(0, 0), new Location(0, 0), + new ArrayList(), + new ArrayList(), + errors); + } else { + return (Program) result.value; + } + } catch (RuntimeException excp) { + throw excp; + } catch (Exception excp) { + String msg = + String.format("Internal parser error detected: %s%n", excp); + throw new AssertionError(msg); + } + } + + @Override + public SymbolFactory getSymbolFactory() { + return ((ChocoPyLexer) getScanner()).symbolFactory; + } + + @Override + public void syntax_error(Symbol cur_token) { + String token = symbl_name_from_id(cur_token.sym); + String text = ((ChocoPyLexer) getScanner()).yytext(); + errors.syntaxError( + ((ComplexSymbolFactory.ComplexSymbol) cur_token).xleft, + ((ComplexSymbolFactory.ComplexSymbol) cur_token).xright, + "Parse error near token %s: %s", token, text); + } + + @Override + public void unrecovered_syntax_error(Symbol cur_token) { + /* Do not die */ + } +:} + + +/************************************************************************** + * FEEL FREE TO MODIFY ANYTHING BELOW THIS LINE + * + * The rules provided below parse expressions of the form + + ... + * You can re-use these rules or edit them as you wish. The start rule + * should return a node of type Program. + * + * Tips: Production rules are usually followed by action code that will be + * copied to the generated parser to be executed immediately after a reduce + * operation; that is, when a production rule has been matched. You can name + * a nonterminal or terminal symbol in a production rule using the colon + * notation, e.g. expr_stmt ::= expr:e, to get the AST node for the matched + * expression. In the action code, `e` will be a variable of whatever type + * has been declared for the corresponding nonterminal, such as `Expr`. + * Therefore, you can construct an AST Node of type `ExprStmt` with `e` in the + * constructor: `new ExprStmt(exleft, exright, e)` + * + * The variables `exleft` and `exright` are automatically generated by CUP + * and contain Location objects for the start and end of the expression `e`. + * You can collect start and line number info for AST nodes by taking the + * location of the left end of the leftmost symbol in a rule and the + * location of the right end of the rightmost symbol. The auto-generated + * variables have names `xleft` and `xright`, where is the + * name given to the symbol using the colon notation. + * + * When you have nonterminals that are lists of things, e.g. List or + * List, it is helpful to get the leftmost and rightmost + * source location from within this list; we have provided some utility + * functions below to do just that. + **************************************************************************/ + + +/* The following code section is copied verbatim to the class that performs + * production-rule actions. */ +action code {: + + /** Return a mutable list initially containing the single value ITEM. */ + List single(T item) { + List list = new ArrayList<>(); + if (item != null) { + list.add(item); + } + return list; + } + + /** If ITEM is non-null, appends it to the end of LIST. Then returns + * LIST. */ + List combine(List list, T item) { + if (item != null) { + list.add(item); + } + return list; + } + + /** Return a mutable empty list. */ + List empty() { + return new ArrayList(); + } + + /** Return the leftmost non-whitespace location in NODES, or null if NODES + * is empty. Assumes that the nodes of NODES are ordered in increasing + * order of location, from left to right. */ + ComplexSymbolFactory.Location getLeft(List nodes) { + if (nodes.isEmpty()) { + return null; + } + Node first = nodes.get(0); + return new ComplexSymbolFactory.Location(first.getLocation()[0], + first.getLocation()[1]); + } + +:} + +/* Terminal symbols (tokens returned by the lexer). The declaration + * terminal , , ...; + * declares each as the denotation of a distinct type terminal + * symbol for use in the grammar. The declaration + * terminal , ...; + * does the same, and in addition indicates that the lexer supplies a + * semantic value of type for these symbols that may be referenced + * in actions ( {: ... :} ). + */ +terminal NEWLINE; +terminal String PLUS; +terminal Integer NUMBER; +/* Returned by the lexer for erroneous tokens. Since it does not appear in + * the grammar, it indicates a syntax error. */ +terminal UNRECOGNIZED; + +/* Nonterminal symbols (defined in production rules below). + * As for terminal symbols, + * non terminal , ..., ; + * defines the listed nonterminal identifier symbols to have semantic values + * of type . */ +non terminal Program program; +non terminal List program_head; +non terminal List stmt_list, opt_stmt_list; +non terminal Stmt stmt, expr_stmt; +non terminal Expr expr, binary_expr; + +/* Precedences (lowest to highest) for resolving what would otherwise be + * ambiguities in the form of shift/reduce conflicts.. */ +precedence left PLUS; + +/* The start symbol. */ +start with program; + + +/***** GRAMMAR RULES *****/ + +program ::= program_head:d opt_stmt_list:s + {: RESULT = new Program(d.isEmpty() ? getLeft(s) : getLeft(d), + sxright, d, s, errors); + :} + ; + +/* Initial list of declarations. */ +program_head ::= /* not implemented; currently matches empty string */ + {: RESULT = empty(); :} + ; + +opt_stmt_list ::= {: RESULT = empty(); :} + | stmt_list:s {: RESULT = s; :} + ; + +stmt_list ::= stmt:s {: RESULT = single(s); :} + | stmt_list:l stmt:s {: RESULT = combine(l, s); :} + | stmt_list:l error {: RESULT = l; :} + /* If there is a syntax error in the source, this says to discard + * symbols from the parsing stack and perform reductions until + * there is a stmt_list on top of the stack, and then to discard + * input symbols until it is possible to shift again, reporting + * a syntax error. */ + ; + +stmt ::= expr_stmt:s NEWLINE {: RESULT = s; :} + ; + +expr_stmt ::= expr:e {: RESULT = new ExprStmt(exleft, exright, e); :} + ; + +expr ::= binary_expr:e {: RESULT = e; :} + | NUMBER:n {: RESULT = new IntegerLiteral(nxleft, nxright, n); :} + ; + + +/* A binary expression, illustrating how to find the left and right + * source position of a phrase. */ +binary_expr ::= expr:e1 PLUS:op expr:e2 + {: RESULT = new BinaryExpr(e1xleft, e2xright, + e1, op, e2); :} + ; diff --git a/src/main/java/chocopy/common/Utils.java b/src/main/java/chocopy/common/Utils.java new file mode 100644 index 0000000..661dfd3 --- /dev/null +++ b/src/main/java/chocopy/common/Utils.java @@ -0,0 +1,64 @@ +package chocopy.common; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.stream.Collectors; + + +/** + * Utility functions for general use. + */ +public class Utils { + + /** + * Return resource file FILENAME's contents as a string. FILENAME + * can refer to a file within the class hierarchy, so that a text + * resource in file resource.txt in the chocopy.common.codegen + * package, for example, could be referred to with FILENAME + * chocopy/common/codegen/resource.txt. + *

+ * Credit: Lucio Paiva. + */ + public static String getResourceFileAsString(String fileName) { + InputStream is = + Utils.class.getClassLoader().getResourceAsStream(fileName); + if (is != null) { + BufferedReader reader = + new BufferedReader + (new InputStreamReader(is, StandardCharsets.UTF_8)); + return reader.lines().collect + (Collectors.joining(System.lineSeparator())); + } + return null; + } + + /** + * Return an exception signalling a fatal error having a message + * formed from MSGFORMAT and ARGS, as for String.format. + */ + public static Error fatal(String msgFormat, Object... args) { + return new Error(String.format(msgFormat, args)); + } + + /** + * Return the string S padded with FILL to TOLEN characters. Padding + * is on the left if PADONLEFT, and otherwise on the right. If S is + * already at least TOLEN characters, returns S. + */ + public static String pad(String s, Character fill, int toLen, + boolean padOnLeft) { + StringBuilder result = new StringBuilder(toLen); + if (!padOnLeft) { + result.append(s); + } + for (int n = s.length(); n < toLen; n += 1) { + result.append(fill); + } + if (padOnLeft) { + result.append(s); + } + return result.toString(); + } +} diff --git a/src/main/java/chocopy/common/analysis/NodeAnalyzer.java b/src/main/java/chocopy/common/analysis/NodeAnalyzer.java new file mode 100644 index 0000000..5ea8a6c --- /dev/null +++ b/src/main/java/chocopy/common/analysis/NodeAnalyzer.java @@ -0,0 +1,100 @@ +package chocopy.common.analysis; + +import chocopy.common.astnodes.*; + +/** + * This interface can be used to separate logic for various concrete + * classes in the AST class hierarchy. + *

+ * The idea is that a phase of the analysis is encapsulated in a class + * that implements this interface, and contains an overriding of the + * analyze method for each concrete Node class that needs something + * other than default processing. Each concrete node class, C, implements + * a generic dispatch method that takes a NodeAnalyzer argument and + * calls the overloading of analyze that takes an argument of type C. + * The effect is that anode.dispatch(anAnalyzer) executes the method + * anAnalyzer.analyze that is appropriate to aNode's dynamic type. + * As a result each NodeAnalyzer subtype encapsulates all + * implementations of a particular action on Nodes. Thus, it inverts + * the usual OO pattern in which the implementations of analysis A for + * each different class are scattered among the class bodies + * themselves as overridings of a method A on the Node class. + *

+ * The class AbstractNodeAnalyzer provides empty default + * implementations for these methods. + *

+ * The type T is the type of result returned by the encapsulated analysis. + */ +public interface NodeAnalyzer { + + T analyze(AssignStmt node); + + T analyze(BinaryExpr node); + + T analyze(BooleanLiteral node); + + T analyze(CallExpr node); + + T analyze(ClassDef node); + + T analyze(ClassType node); + + T analyze(CompilerError node); + + T analyze(Errors node); + + T analyze(ExprStmt node); + + T analyze(ForStmt node); + + T analyze(FuncDef node); + + T analyze(GlobalDecl node); + + T analyze(Identifier node); + + T analyze(IfExpr node); + + T analyze(IfStmt node); + + T analyze(IndexExpr node); + + T analyze(IntegerLiteral node); + + T analyze(ListExpr node); + + T analyze(ListType node); + + T analyze(MemberExpr node); + + T analyze(MethodCallExpr node); + + T analyze(NoneLiteral node); + + T analyze(NonLocalDecl node); + + T analyze(Program node); + + T analyze(ReturnStmt node); + + T analyze(StringLiteral node); + + T analyze(TypedVar node); + + T analyze(UnaryExpr node); + + T analyze(VarDef node); + + T analyze(WhileStmt node); + + /** + * Set the default value returned by calls to analyze that are not + * overridden to VALUE. By default, this is null. + */ + void setDefault(T value); + + /** + * Default value for non-overridden methods. + */ + T defaultAction(Node node); +} diff --git a/src/main/java/chocopy/common/astnodes/AssignStmt.java b/src/main/java/chocopy/common/astnodes/AssignStmt.java new file mode 100644 index 0000000..8b3f49c --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/AssignStmt.java @@ -0,0 +1,36 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * Single and multiple assignments. + */ +public class AssignStmt extends Stmt { + /** + * List of left-hand sides. + */ + public final List targets; + /** + * Right-hand-side value to be assigned. + */ + public final Expr value; + + /** + * AST for TARGETS[0] = TARGETS[1] = ... = VALUE spanning source locations + * [LEFT..RIGHT]. + */ + public AssignStmt(Location left, Location right, + List targets, Expr value) { + super(left, right); + this.targets = targets; + this.value = value; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/BinaryExpr.java b/src/main/java/chocopy/common/astnodes/BinaryExpr.java new file mode 100644 index 0000000..3ef3d46 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/BinaryExpr.java @@ -0,0 +1,40 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * . + */ +public class BinaryExpr extends Expr { + + /** + * Left operand. + */ + public final Expr left; + /** + * Operator name. + */ + public final String operator; + /** + * Right operand. + */ + public final Expr right; + + /** + * An AST for expressions of the form LEFTEXPR OP RIGHTEXPR + * from text in range [LEFTLOC..RIGHTLOC]. + */ + public BinaryExpr(Location leftLoc, Location rightLoc, Expr leftExpr, + String op, Expr rightExpr) { + super(leftLoc, rightLoc); + left = leftExpr; + operator = op; + right = rightExpr; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/BooleanLiteral.java b/src/main/java/chocopy/common/astnodes/BooleanLiteral.java new file mode 100644 index 0000000..bf13f08 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/BooleanLiteral.java @@ -0,0 +1,29 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Literals True or False. + */ +public final class BooleanLiteral extends Literal { + + /** + * True iff I represent True. + */ + public final boolean value; + + /** + * An AST for the token True or False at [LEFT..RIGHT], depending on + * VALUE. + */ + public BooleanLiteral(Location left, Location right, boolean value) { + super(left, right); + this.value = value; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/CallExpr.java b/src/main/java/chocopy/common/astnodes/CallExpr.java new file mode 100644 index 0000000..80272ee --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/CallExpr.java @@ -0,0 +1,36 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * A function call. + */ +public class CallExpr extends Expr { + + /** + * The called function. + */ + public final Identifier function; + /** + * The actual parameter expressions. + */ + public final List args; + + /** + * AST for FUNCTION(ARGS) at [LEFT..RIGHT]. + */ + public CallExpr(Location left, Location right, Identifier function, + List args) { + super(left, right); + this.function = function; + this.args = args; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/ClassDef.java b/src/main/java/chocopy/common/astnodes/ClassDef.java new file mode 100644 index 0000000..982d128 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/ClassDef.java @@ -0,0 +1,50 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * A class definition. + */ +public class ClassDef extends Declaration { + + /** + * Name of the declared class. + */ + public final Identifier name; + /** + * Name of the parent class. + */ + public final Identifier superClass; + /** + * Body of the class. + */ + public final List declarations; + + /** + * An AST for class + * NAME(SUPERCLASS): + * DECLARATIONS. + * spanning source locations [LEFT..RIGHT]. + */ + public ClassDef(Location left, Location right, + Identifier name, Identifier superClass, + List declarations) { + super(left, right); + this.name = name; + this.superClass = superClass; + this.declarations = declarations; + } + + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + + @Override + public Identifier getIdentifier() { + return this.name; + } +} diff --git a/src/main/java/chocopy/common/astnodes/ClassType.java b/src/main/java/chocopy/common/astnodes/ClassType.java new file mode 100644 index 0000000..eab39af --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/ClassType.java @@ -0,0 +1,28 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * A simple class type name. + */ +public final class ClassType extends TypeAnnotation { + + /** + * The denotation of the class in source. + */ + public final String className; + + /** + * An AST denoting a type named CLASSNAME0 at [LEFT..RIGHT]. + */ + public ClassType(Location left, Location right, String className0) { + super(left, right); + className = className0; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/CompilerError.java b/src/main/java/chocopy/common/astnodes/CompilerError.java new file mode 100644 index 0000000..c61617e --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/CompilerError.java @@ -0,0 +1,64 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import com.fasterxml.jackson.annotation.JsonInclude; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Represents a single error. Does not correspond to any Python source + * construct. + */ +public class CompilerError extends Node { + + /** + * Represents an error with message MESSAGE. Iff SYNTAX, it is a + * syntactic error. The error applies to source text at [LEFT..RIGHT]. + */ + public CompilerError(Location left, Location right, String message, + boolean syntax) { + super(left, right); + this.message = message; + this.syntax = syntax; + } + + @JsonInclude(JsonInclude.Include.NON_DEFAULT) + public boolean isSyntax() { + return syntax; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CompilerError that = (CompilerError) o; + return Objects.equals(message, that.message) + && Arrays.equals(getLocation(), that.getLocation()); + } + + @Override + public int hashCode() { + int result = Objects.hash(message); + result = 31 * result + Arrays.hashCode(getLocation()); + return result; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + + /** + * The error message. + */ + public final String message; + /** + * True if this is a syntax error. + */ + private final boolean syntax; +} diff --git a/src/main/java/chocopy/common/astnodes/Declaration.java b/src/main/java/chocopy/common/astnodes/Declaration.java new file mode 100644 index 0000000..769ece3 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Declaration.java @@ -0,0 +1,23 @@ +package chocopy.common.astnodes; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Base of all AST nodes representing definitions or declarations. + */ +public abstract class Declaration extends Node { + + /** + * A definition or declaration spanning source locations [LEFT..RIGHT]. + */ + public Declaration(Location left, Location right) { + super(left, right); + } + + /** + * Return the identifier defined by this Declaration. + */ + @JsonIgnore + public abstract Identifier getIdentifier(); +} diff --git a/src/main/java/chocopy/common/astnodes/Errors.java b/src/main/java/chocopy/common/astnodes/Errors.java new file mode 100644 index 0000000..cea2c5b --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Errors.java @@ -0,0 +1,90 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * Collects the error messages in a Program. There is exactly one per + * Program node. + */ +public class Errors extends Node { + + /** + * The accumulated error messages in the order added. + */ + public final List errors; + + /** + * True iff multiple semantic errors allowed on a node. + */ + @JsonIgnore + private boolean allowMultipleErrors; + + /** + * An Errors whose list of CompilerErrors is ERRORS. The list should be + * modified using this.add. + */ + @JsonCreator + public Errors(List errors) { + super(null, null); + this.errors = errors; + allowMultipleErrors = true; + } + + /** + * Return true iff there are any errors. + */ + public boolean hasErrors() { + return !this.errors.isEmpty(); + } + + /** + * Prevent multiple semantic errors on the same node. + */ + public void suppressMultipleErrors() { + allowMultipleErrors = false; + } + + /** + * Add a new semantic error message attributed to NODE, with message + * String.format(MESSAGEFORM, ARGS). + */ + public void semError(Node node, String messageForm, Object... args) { + if (allowMultipleErrors || !node.hasError()) { + String msg = String.format(messageForm, args); + CompilerError err = new CompilerError(null, null, msg, false); + err.setLocation(node.getLocation()); + add(err); + if (!node.hasError()) { + node.setErrorMsg(msg); + } + } + } + + /** + * Add a new syntax error message attributed to the source text + * between LEFT and RIGHT, and with message + * String.format(MESSAGEFORM, ARGS). + */ + public void syntaxError(Location left, Location right, + String messageForm, Object... args) { + add(new CompilerError(left, right, String.format(messageForm, args), + true)); + } + + /** + * Add ERR to the list of errors. + */ + public void add(CompilerError err) { + errors.add(err); + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/Expr.java b/src/main/java/chocopy/common/astnodes/Expr.java new file mode 100644 index 0000000..c5cb884 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Expr.java @@ -0,0 +1,22 @@ +package chocopy.common.astnodes; + +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Base of all AST nodes representing expressions. + *

+ * There is nothing in this class, but there will be many AST + * node types that have fields that are *any expression*. For those + * cases, having a field of this type will encompass all types of + * expressions such as binary expressions and literals that subclass + * this class. + */ +public abstract class Expr extends Node { + + /** + * A Python expression spanning source locations [LEFT..RIGHT]. + */ + public Expr(Location left, Location right) { + super(left, right); + } +} diff --git a/src/main/java/chocopy/common/astnodes/ExprStmt.java b/src/main/java/chocopy/common/astnodes/ExprStmt.java new file mode 100644 index 0000000..177c407 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/ExprStmt.java @@ -0,0 +1,29 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Statements consisting of expressions. + */ +public final class ExprStmt extends Stmt { + + /** + * The expression I evaluate. + */ + public final Expr expr; + + /** + * The AST for EXPR spanning source locations [LEFT..RIGHT] + * in a statement context. + */ + public ExprStmt(Location left, Location right, Expr expr) { + super(left, right); + this.expr = expr; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/ForStmt.java b/src/main/java/chocopy/common/astnodes/ForStmt.java new file mode 100644 index 0000000..8463da1 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/ForStmt.java @@ -0,0 +1,43 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * For statements. + */ +public class ForStmt extends Stmt { + /** + * Control variable. + */ + public final Identifier identifier; + /** + * Source of values of control statement. + */ + public final Expr iterable; + /** + * Repeated statements. + */ + public final List body; + + /** + * The AST for + * for IDENTIFIER in ITERABLE: + * BODY + * spanning source locations [LEFT..RIGHT]. + */ + public ForStmt(Location left, Location right, + Identifier identifier, Expr iterable, List body) { + super(left, right); + this.identifier = identifier; + this.iterable = iterable; + this.body = body; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/FuncDef.java b/src/main/java/chocopy/common/astnodes/FuncDef.java new file mode 100644 index 0000000..42f67bf --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/FuncDef.java @@ -0,0 +1,61 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * Def statements. + */ +public class FuncDef extends Declaration { + + /** + * Defined name. + */ + public final Identifier name; + /** + * Formal parameters. + */ + public final List params; + /** + * Return type annotation. + */ + public final TypeAnnotation returnType; + /** + * Local-variable,inner-function, global, and nonlocal declarations. + */ + public final List declarations; + /** + * Other statements. + */ + public final List statements; + + /** + * The AST for + * def NAME(PARAMS) -> RETURNTYPE: + * DECLARATIONS + * STATEMENTS + * spanning source locations [LEFT..RIGHT]. + */ + public FuncDef(Location left, Location right, + Identifier name, List params, + TypeAnnotation returnType, + List declarations, List statements) { + super(left, right); + this.name = name; + this.params = params; + this.returnType = returnType; + this.declarations = declarations; + this.statements = statements; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + + @Override + public Identifier getIdentifier() { + return this.name; + } +} diff --git a/src/main/java/chocopy/common/astnodes/GlobalDecl.java b/src/main/java/chocopy/common/astnodes/GlobalDecl.java new file mode 100644 index 0000000..3bac547 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/GlobalDecl.java @@ -0,0 +1,34 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Declaration of global variable. + */ +public class GlobalDecl extends Declaration { + + /** + * The declared variable. + */ + public final Identifier variable; + + /** + * The AST for the declaration + * global VARIABLE + * spanning source locations [LEFT..RIGHT]. + */ + public GlobalDecl(Location left, Location right, Identifier variable) { + super(left, right); + this.variable = variable; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + + @Override + public Identifier getIdentifier() { + return this.variable; + } +} diff --git a/src/main/java/chocopy/common/astnodes/Identifier.java b/src/main/java/chocopy/common/astnodes/Identifier.java new file mode 100644 index 0000000..b1aeea5 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Identifier.java @@ -0,0 +1,29 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * A simple identifier. + */ +public class Identifier extends Expr { + + /** + * Text of the identifier. + */ + public final String name; + + /** + * An AST for the variable, method, or parameter named NAME, spanning + * source locations [LEFT..RIGHT]. + */ + public Identifier(Location left, Location right, String name) { + super(left, right); + this.name = name; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/IfExpr.java b/src/main/java/chocopy/common/astnodes/IfExpr.java new file mode 100644 index 0000000..67d5b13 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/IfExpr.java @@ -0,0 +1,40 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Conditional expressions. + */ +public class IfExpr extends Expr { + /** + * Boolean condition. + */ + public final Expr condition; + /** + * True branch. + */ + public final Expr thenExpr; + /** + * False branch. + */ + public final Expr elseExpr; + + /** + * The AST for + * THENEXPR if CONDITION else ELSEEXPR + * spanning source locations [LEFT..RIGHT]. + */ + public IfExpr(Location left, Location right, + Expr condition, Expr thenExpr, Expr elseExpr) { + super(left, right); + this.condition = condition; + this.thenExpr = thenExpr; + this.elseExpr = elseExpr; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/IfStmt.java b/src/main/java/chocopy/common/astnodes/IfStmt.java new file mode 100644 index 0000000..16da823 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/IfStmt.java @@ -0,0 +1,45 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * Conditional statement. + */ +public class IfStmt extends Stmt { + /** + * Test condition. + */ + public final Expr condition; + /** + * "True" branch. + */ + public final List thenBody; + /** + * "False" branch. + */ + public final List elseBody; + + /** + * The AST for + * if CONDITION: + * THENBODY + * else: + * ELSEBODY + * spanning source locations [LEFT..RIGHT]. + */ + public IfStmt(Location left, Location right, + Expr condition, List thenBody, List elseBody) { + super(left, right); + this.condition = condition; + this.thenBody = thenBody; + this.elseBody = elseBody; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/IndexExpr.java b/src/main/java/chocopy/common/astnodes/IndexExpr.java new file mode 100644 index 0000000..8038c3f --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/IndexExpr.java @@ -0,0 +1,35 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * List-indexing expression. + */ +public class IndexExpr extends Expr { + + /** + * Indexed list. + */ + public final Expr list; + /** + * Expression for index value. + */ + public final Expr index; + + /** + * The AST for + * LIST[INDEX]. + * spanning source locations [LEFT..RIGHT]. + */ + public IndexExpr(Location left, Location right, Expr list, Expr index) { + super(left, right); + this.list = list; + this.index = index; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/IntegerLiteral.java b/src/main/java/chocopy/common/astnodes/IntegerLiteral.java new file mode 100644 index 0000000..d383472 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/IntegerLiteral.java @@ -0,0 +1,29 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Integer numerals. + */ +public final class IntegerLiteral extends Literal { + + /** + * Value denoted. + */ + public final int value; + + /** + * The AST for the literal VALUE, spanning source + * locations [LEFT..RIGHT]. + */ + public IntegerLiteral(Location left, Location right, int value) { + super(left, right); + this.value = value; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/ListExpr.java b/src/main/java/chocopy/common/astnodes/ListExpr.java new file mode 100644 index 0000000..226d42b --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/ListExpr.java @@ -0,0 +1,32 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * List displays. + */ +public final class ListExpr extends Expr { + + /** + * List of element expressions. + */ + public final List elements; + + /** + * The AST for + * [ ELEMENTS ]. + * spanning source locations [LEFT..RIGHT]. + */ + public ListExpr(Location left, Location right, List elements) { + super(left, right); + this.elements = elements; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/ListType.java b/src/main/java/chocopy/common/astnodes/ListType.java new file mode 100644 index 0000000..0cbf0a0 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/ListType.java @@ -0,0 +1,30 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Type denotation for a list type. + */ +public final class ListType extends TypeAnnotation { + + /** + * The element of list element. + */ + public final TypeAnnotation elementType; + + /** + * The AST for the type annotation + * [ ELEMENTTYPE ]. + * spanning source locations [LEFT..RIGHT]. + */ + public ListType(Location left, Location right, TypeAnnotation elementType) { + super(left, right); + this.elementType = elementType; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/Literal.java b/src/main/java/chocopy/common/astnodes/Literal.java new file mode 100644 index 0000000..ac2c026 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Literal.java @@ -0,0 +1,18 @@ +package chocopy.common.astnodes; + +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Base of all the literal nodes. + *

+ * There is nothing in this class, but it is useful to isolate + * expressions that are constant literals. + */ +public abstract class Literal extends Expr { + /** + * A literal spanning source locations [LEFT..RIGHT]. + */ + public Literal(Location left, Location right) { + super(left, right); + } +} diff --git a/src/main/java/chocopy/common/astnodes/MemberExpr.java b/src/main/java/chocopy/common/astnodes/MemberExpr.java new file mode 100644 index 0000000..a59abe7 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/MemberExpr.java @@ -0,0 +1,36 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Attribute accessor. + */ +public class MemberExpr extends Expr { + + /** + * Object selected from. + */ + public final Expr object; + /** + * Name of attribute (instance variable or method). + */ + public final Identifier member; + + /** + * The AST for + * OBJECT.MEMBER. + * spanning source locations [LEFT..RIGHT]. + */ + public MemberExpr(Location left, Location right, + Expr object, Identifier member) { + super(left, right); + this.object = object; + this.member = member; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/MethodCallExpr.java b/src/main/java/chocopy/common/astnodes/MethodCallExpr.java new file mode 100644 index 0000000..7674a13 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/MethodCallExpr.java @@ -0,0 +1,38 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * Method calls. + */ +public class MethodCallExpr extends Expr { + + /** + * Expression for the bound method to be called. + */ + public final MemberExpr method; + /** + * Actual parameters. + */ + public final List args; + + /** + * The AST for + * METHOD(ARGS). + * spanning source locations [LEFT..RIGHT]. + */ + public MethodCallExpr(Location left, Location right, + MemberExpr method, List args) { + super(left, right); + this.method = method; + this.args = args; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/Node.java b/src/main/java/chocopy/common/astnodes/Node.java new file mode 100644 index 0000000..d84345b --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Node.java @@ -0,0 +1,204 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.io.IOException; + +/** + * Root of the AST class hierarchy. Every node has a left and right + * location, indicating the start and end of the represented construct + * in the source text. + *

+ * Every node can be marked with an error message, which serves two purposes: + * 1. It indicates that an error message has been issued for this + * Node, allowing tne program to reduce cascades of error + * messages. + * 2. It aids in debugging by making it convenient to see which + * Nodes have caused an error. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXISTING_PROPERTY, + property = "kind") +/* List of all concrete subclasses of Node. */ +@JsonSubTypes({ + @JsonSubTypes.Type(AssignStmt.class), + @JsonSubTypes.Type(BinaryExpr.class), + @JsonSubTypes.Type(BooleanLiteral.class), + @JsonSubTypes.Type(CallExpr.class), + @JsonSubTypes.Type(ClassDef.class), + @JsonSubTypes.Type(ClassType.class), + @JsonSubTypes.Type(CompilerError.class), + @JsonSubTypes.Type(Errors.class), + @JsonSubTypes.Type(ExprStmt.class), + @JsonSubTypes.Type(ForStmt.class), + @JsonSubTypes.Type(FuncDef.class), + @JsonSubTypes.Type(GlobalDecl.class), + @JsonSubTypes.Type(Identifier.class), + @JsonSubTypes.Type(IfExpr.class), + @JsonSubTypes.Type(IfStmt.class), + @JsonSubTypes.Type(IndexExpr.class), + @JsonSubTypes.Type(IntegerLiteral.class), + @JsonSubTypes.Type(ListExpr.class), + @JsonSubTypes.Type(ListType.class), + @JsonSubTypes.Type(MemberExpr.class), + @JsonSubTypes.Type(MethodCallExpr.class), + @JsonSubTypes.Type(NoneLiteral.class), + @JsonSubTypes.Type(NonLocalDecl.class), + @JsonSubTypes.Type(Program.class), + @JsonSubTypes.Type(ReturnStmt.class), + @JsonSubTypes.Type(StringLiteral.class), + @JsonSubTypes.Type(TypedVar.class), + @JsonSubTypes.Type(UnaryExpr.class), + @JsonSubTypes.Type(VarDef.class), + @JsonSubTypes.Type(WhileStmt.class), +}) +public abstract class Node { + + /** + * Node-type indicator for JSON form. + */ + public final String kind; + + /** + * Source position information: 0: line number of start, 1: column number + * of start, 2: line number of end, 3: column number of end. + */ + private final int[] location = new int[4]; + + /** + * First error message "blamed" on this Node. When non-null, indicates + * that an error has been found in this Node. + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private String errorMsg; + + /** + * A Node corresponding to source text between LEFT and RIGHT. + */ + public Node(Location left, Location right) { + if (left != null) { + location[0] = left.getLine(); + location[1] = left.getColumn(); + } + if (right != null) { + location[2] = right.getLine(); + location[3] = right.getColumn(); + } + this.kind = getClass().getSimpleName(); + this.errorMsg = null; + } + + /** + * Return my source location as + * { , , , }. + * Result should not be modified, and contents will change after + * setLocation(). + */ + public int[] getLocation() { + return location; + } + + /** + * Copy LOCATION as getLocation(). + */ + public void setLocation(final int[] location) { + System.arraycopy(location, 0, this.location, 0, 4); + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String msg) { + this.errorMsg = msg; + } + + /** + * Return true iff I have been marked with an error message. + */ + @JsonIgnore + public boolean hasError() { + return this.errorMsg != null; + } + + /** + * Invoke ANALYZER on me as a node of static type T. See the comment + * on NodeAnalyzer. Returns modified Node. + */ + public abstract T dispatch(NodeAnalyzer analyzer); + + /** + * Print out the AST in JSON format. + */ + @Override + public String toString() { + try { + return toJSON(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * Return a serialization of this node in JSON format. + */ + public String toJSON() throws JsonProcessingException { + return mapper.writeValueAsString(this); + } + + /** + * Mapper to-and-from serialized JSON. + */ + private static final ObjectMapper mapper = new ObjectMapper(); + + static { + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.registerModule(new ParameterNamesModule()); + } + + /** + * Returns a T from JSON, a JSON-serialized T value with class + * CLAS. + */ + public static T fromJSON(String json, Class clas) + throws IOException { + return mapper.readValue(json, clas); + } + + /** + * Returns the result of converting JSON, a JSon-serialization of + * a Node value, into the value it serializes. + */ + public static Node fromJSON(String json) + throws IOException { + return fromJSON(json, Node.class); + } + + /** + * Returns the result of converting TREE to the value of type T + * that it represents, where CLAS reflects T. + */ + public static T fromJSON(JsonNode tree, Class clas) + throws IOException { + return mapper.treeToValue(tree, clas); + } + + /** + * Returns the translation of serialized value SRC into the + * corresponding JSON tree. + */ + public static JsonNode readTree(String src) throws IOException { + return mapper.readTree(src); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/NonLocalDecl.java b/src/main/java/chocopy/common/astnodes/NonLocalDecl.java new file mode 100644 index 0000000..d03508e --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/NonLocalDecl.java @@ -0,0 +1,34 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Nonlocal declaration. + */ +public class NonLocalDecl extends Declaration { + + /** + * Name of identifier being declared. + */ + public final Identifier variable; + + /** + * The AST for + * nonlocal VARIABLE + * spanning source locations [LEFT..RIGHT]. + */ + public NonLocalDecl(Location left, Location right, Identifier variable) { + super(left, right); + this.variable = variable; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + + @Override + public Identifier getIdentifier() { + return this.variable; + } +} diff --git a/src/main/java/chocopy/common/astnodes/NoneLiteral.java b/src/main/java/chocopy/common/astnodes/NoneLiteral.java new file mode 100644 index 0000000..d38211c --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/NoneLiteral.java @@ -0,0 +1,21 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * The expression 'None'. + */ +public final class NoneLiteral extends Literal { + + /** + * The AST for None, spanning source locations [LEFT..RIGHT]. + */ + public NoneLiteral(Location left, Location right) { + super(left, right); + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } +} diff --git a/src/main/java/chocopy/common/astnodes/Program.java b/src/main/java/chocopy/common/astnodes/Program.java new file mode 100644 index 0000000..29dd28e --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Program.java @@ -0,0 +1,70 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.ArrayList; +import java.util.List; + +/** + * An entire ChocoPy program. + */ +public class Program extends Node { + + /** + * Initial variable, class, and function declarations. + */ + public final List declarations; + /** + * Trailing statements. + */ + public final List statements; + /** + * Accumulated errors. + */ + public final Errors errors; + + /** + * The AST for the program + * DECLARATIONS + * STATEMENTS + * spanning source locations [LEFT..RIGHT]. + *

+ * ERRORS is the container for all error messages applying to the + * program. + */ + public Program(Location left, Location right, + List declarations, List statements, + Errors errors) { + super(left, right); + this.declarations = declarations; + this.statements = statements; + if (errors == null) { + this.errors = new Errors(new ArrayList<>()); + } else { + this.errors = errors; + } + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + + /** + * Returns true iff there is at least one error in the program. + */ + @JsonIgnore + public boolean hasErrors() { + return errors.hasErrors(); + } + + /** + * A convenience method returning the list of all CompilerErrors for + * this program. + */ + @JsonIgnore + public List getErrorList() { + return errors.errors; + } +} diff --git a/src/main/java/chocopy/common/astnodes/ReturnStmt.java b/src/main/java/chocopy/common/astnodes/ReturnStmt.java new file mode 100644 index 0000000..f4751c7 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/ReturnStmt.java @@ -0,0 +1,30 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Return from function. + */ +public class ReturnStmt extends Stmt { + + /** + * Returned value. + */ + public final Expr value; + + /** + * The AST for + * return VALUE + * spanning source locations [LEFT..RIGHT]. + */ + public ReturnStmt(Location left, Location right, Expr value) { + super(left, right); + this.value = value; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/Stmt.java b/src/main/java/chocopy/common/astnodes/Stmt.java new file mode 100644 index 0000000..a2642fd --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/Stmt.java @@ -0,0 +1,21 @@ +package chocopy.common.astnodes; + +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Base of all AST nodes representing statements. + *

+ * There is nothing in this class, but there will be some AST + * node types that have fields that are *any statement* or a + * list of statements. For those cases, having a field of this type will + * encompass all types of statements such as expression statements, + * if statements, while statements, etc. + */ +public abstract class Stmt extends Node { + /** + * A statement spanning source locations [LEFT..RIGHT]. + */ + public Stmt(Location left, Location right) { + super(left, right); + } +} diff --git a/src/main/java/chocopy/common/astnodes/StringLiteral.java b/src/main/java/chocopy/common/astnodes/StringLiteral.java new file mode 100644 index 0000000..5adb024 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/StringLiteral.java @@ -0,0 +1,29 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * String constants. + */ +public final class StringLiteral extends Literal { + + /** + * Contents of the literal, not including quotation marks. + */ + public final String value; + + /** + * The AST for a string literal containing VALUE, spanning source + * locations [LEFT..RIGHT]. + */ + public StringLiteral(Location left, Location right, String value) { + super(left, right); + this.value = value; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/TypeAnnotation.java b/src/main/java/chocopy/common/astnodes/TypeAnnotation.java new file mode 100644 index 0000000..1002a86 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/TypeAnnotation.java @@ -0,0 +1,16 @@ +package chocopy.common.astnodes; + +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * Base of all AST nodes representing type annotations (list or class + * types. + */ +public abstract class TypeAnnotation extends Node { + /** + * An annotation spanning source locations [LEFT..RIGHT]. + */ + public TypeAnnotation(Location left, Location right) { + super(left, right); + } +} diff --git a/src/main/java/chocopy/common/astnodes/TypedVar.java b/src/main/java/chocopy/common/astnodes/TypedVar.java new file mode 100644 index 0000000..7593775 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/TypedVar.java @@ -0,0 +1,36 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * An identifier with attached type annotation. + */ +public class TypedVar extends Node { + + /** + * The typed identifier. + */ + public final Identifier identifier; + /** + * The declared type. + */ + public final TypeAnnotation type; + + /** + * The AST for + * IDENTIFIER : TYPE. + * spanning source locations [LEFT..RIGHT]. + */ + public TypedVar(Location left, Location right, + Identifier identifier, TypeAnnotation type) { + super(left, right); + this.identifier = identifier; + this.type = type; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/UnaryExpr.java b/src/main/java/chocopy/common/astnodes/UnaryExpr.java new file mode 100644 index 0000000..10ba57f --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/UnaryExpr.java @@ -0,0 +1,36 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * An expression applying a unary operator. + */ +public class UnaryExpr extends Expr { + + /** + * The text representation of the operator. + */ + public final String operator; + /** + * The operand to which it is applied. + */ + public final Expr operand; + + /** + * The AST for + * OPERATOR OPERAND + * spanning source locations [LEFT..RIGHT]. + */ + public UnaryExpr(Location left, Location right, + String operator, Expr operand) { + super(left, right); + this.operator = operator; + this.operand = operand; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/common/astnodes/VarDef.java b/src/main/java/chocopy/common/astnodes/VarDef.java new file mode 100644 index 0000000..047b63b --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/VarDef.java @@ -0,0 +1,42 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/** + * A declaration of a variable (i.e., with type annotation). + */ +public class VarDef extends Declaration { + /** + * The variable and its assigned type. + */ + public final TypedVar var; + /** + * The initial value assigned. + */ + public final Literal value; + + /** + * The AST for + * VAR = VALUE + * where VAR has a type annotation, and spanning source + * locations [LEFT..RIGHT]. + */ + public VarDef(Location left, Location right, TypedVar var, Literal value) { + super(left, right); + this.var = var; + this.value = value; + } + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + + /** + * The identifier defined by this declaration. + */ + @Override + public Identifier getIdentifier() { + return this.var.identifier; + } +} diff --git a/src/main/java/chocopy/common/astnodes/WhileStmt.java b/src/main/java/chocopy/common/astnodes/WhileStmt.java new file mode 100644 index 0000000..2936771 --- /dev/null +++ b/src/main/java/chocopy/common/astnodes/WhileStmt.java @@ -0,0 +1,39 @@ +package chocopy.common.astnodes; + +import chocopy.common.analysis.NodeAnalyzer; +import java_cup.runtime.ComplexSymbolFactory.Location; + +import java.util.List; + +/** + * Indefinite repetition construct. + */ +public class WhileStmt extends Stmt { + /** + * Test for whether to continue. + */ + public final Expr condition; + /** + * Loop body. + */ + public final List body; + + /** + * The AST for + * while CONDITION: + * BODY + * spanning source locations [LEFT..RIGHT]. + */ + public WhileStmt(Location left, Location right, + Expr condition, List body) { + super(left, right); + this.condition = condition; + this.body = body; + } + + + public T dispatch(NodeAnalyzer analyzer) { + return analyzer.analyze(this); + } + +} diff --git a/src/main/java/chocopy/pa1/StudentParser.java b/src/main/java/chocopy/pa1/StudentParser.java new file mode 100644 index 0000000..c29db68 --- /dev/null +++ b/src/main/java/chocopy/pa1/StudentParser.java @@ -0,0 +1,25 @@ +package chocopy.pa1; + +import chocopy.common.astnodes.Program; +import java_cup.runtime.ComplexSymbolFactory; + +import java.io.StringReader; + +/** + * Interface between driver and parser. + */ +public class StudentParser { + + /** + * Return the Program AST resulting from parsing INPUT. Turn on + * parser debugging iff DEBUG. + */ + public static Program process(String input, boolean debug) { + ChocoPyLexer lexer = new ChocoPyLexer(new StringReader(input)); + ChocoPyParser parser = + new ChocoPyParser(lexer, new ComplexSymbolFactory()); + return parser.parseProgram(debug); + } +} + + diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex new file mode 100644 index 0000000..9aafe7f --- /dev/null +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -0,0 +1,82 @@ +package chocopy.pa1; +import java_cup.runtime.*; + +%% + +/*** Do not change the flags below unless you know what you are doing. ***/ + +%unicode +%line +%column + +%class ChocoPyLexer +%public + +%cupsym ChocoPyTokens +%cup +%cupdebug + +%eofclose false + +/*** Do not change the flags above unless you know what you are doing. ***/ + +/* The following code section is copied verbatim to the + * generated lexer class. */ +%{ + /* The code below includes some convenience methods to create tokens + * of a given type and optionally a value that the CUP parser can + * understand. Specifically, a lot of the logic below deals with + * embedded information about where in the source code a given token + * was recognized, so that the parser can report errors accurately. + * (It need not be modified for this project.) */ + + /** Producer of token-related values for the parser. */ + final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); + + /** Return a terminal symbol of syntactic category TYPE and no + * semantic value at the current source location. */ + private Symbol symbol(int type) { + return symbol(type, yytext()); + } + + /** Return a terminal symbol of syntactic category TYPE and semantic + * value VALUE at the current source location. */ + private Symbol symbol(int type, Object value) { + return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[type], type, + new ComplexSymbolFactory.Location(yyline + 1, yycolumn + 1), + new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), + value); + } + +%} + +/* Macros (regexes used in rules below) */ + +WhiteSpace = [ \t] +LineBreak = \r|\n|\r\n + +IntegerLiteral = 0 | [1-9][0-9]* + +%% + + + { + + /* Delimiters. */ + {LineBreak} { return symbol(ChocoPyTokens.NEWLINE); } + + /* Literals. */ + {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, + Integer.parseInt(yytext())); } + + /* Operators. */ + "+" { return symbol(ChocoPyTokens.PLUS, yytext()); } + + /* Whitespace. */ + {WhiteSpace} { /* ignore */ } +} + +<> { return symbol(ChocoPyTokens.EOF); } + +/* Error fallback. */ +[^] { return symbol(ChocoPyTokens.UNRECOGNIZED); } diff --git a/src/test/data/pa1/sample/bad_assign_expr1.py b/src/test/data/pa1/sample/bad_assign_expr1.py new file mode 100644 index 0000000..ccc8c3e --- /dev/null +++ b/src/test/data/pa1/sample/bad_assign_expr1.py @@ -0,0 +1 @@ +x = (y = 2) diff --git a/src/test/data/pa1/sample/bad_assign_expr1.py.ast b/src/test/data/pa1/sample/bad_assign_expr1.py.ast new file mode 100644 index 0000000..d134770 --- /dev/null +++ b/src/test/data/pa1/sample/bad_assign_expr1.py.ast @@ -0,0 +1,16 @@ +{ + "kind" : "Program", + "location" : [ 1, 6, 1, 6 ], + "declarations" : [ ], + "statements" : [ ], + "errors" : { + "errors" : [ { + "kind" : "CompilerError", + "location" : [ 1, 8, 1, 8 ], + "message" : "Parse error near token EQ: =", + "syntax" : true + } ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/bad_assign_expr2.py b/src/test/data/pa1/sample/bad_assign_expr2.py new file mode 100644 index 0000000..444bc53 --- /dev/null +++ b/src/test/data/pa1/sample/bad_assign_expr2.py @@ -0,0 +1 @@ +print(x = 1) diff --git a/src/test/data/pa1/sample/bad_assign_expr2.py.ast b/src/test/data/pa1/sample/bad_assign_expr2.py.ast new file mode 100644 index 0000000..53e699c --- /dev/null +++ b/src/test/data/pa1/sample/bad_assign_expr2.py.ast @@ -0,0 +1,16 @@ +{ + "kind" : "Program", + "location" : [ 1, 7, 1, 7 ], + "declarations" : [ ], + "statements" : [ ], + "errors" : { + "errors" : [ { + "kind" : "CompilerError", + "location" : [ 1, 9, 1, 9 ], + "message" : "Parse error near token EQ: =", + "syntax" : true + } ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/bad_func_def.py b/src/test/data/pa1/sample/bad_func_def.py new file mode 100644 index 0000000..ebd2373 --- /dev/null +++ b/src/test/data/pa1/sample/bad_func_def.py @@ -0,0 +1,6 @@ +def foo(a, b) -> 1: + x:int = a + return 1 + +print(1) +print(3**6) diff --git a/src/test/data/pa1/sample/bad_func_def.py.ast b/src/test/data/pa1/sample/bad_func_def.py.ast new file mode 100644 index 0000000..934bef0 --- /dev/null +++ b/src/test/data/pa1/sample/bad_func_def.py.ast @@ -0,0 +1,64 @@ +{ + "kind" : "Program", + "location" : [ 2, 13, 6, 8 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 2, 13, 2, 13 ], + "expr" : { + "kind" : "Identifier", + "location" : [ 2, 13, 2, 13 ], + "name" : "a" + } + }, { + "kind" : "ReturnStmt", + "location" : [ 3, 5, 3, 12 ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 12, 3, 12 ], + "value" : 1 + } + }, { + "kind" : "ExprStmt", + "location" : [ 5, 1, 5, 8 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 5, 1, 5, 8 ], + "function" : { + "kind" : "Identifier", + "location" : [ 5, 1, 5, 5 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 5, 7, 5, 7 ], + "value" : 1 + } ] + } + } ], + "errors" : { + "errors" : [ { + "kind" : "CompilerError", + "location" : [ 1, 10, 1, 10 ], + "message" : "Parse error near token COMMA: ,", + "syntax" : true + }, { + "kind" : "CompilerError", + "location" : [ 2, 13, 2, 13 ], + "message" : "Parse error near token IDENTIFIER: a", + "syntax" : true + }, { + "kind" : "CompilerError", + "location" : [ 5, 1, 5, 0 ], + "message" : "Parse error near token DEDENT: ", + "syntax" : true + }, { + "kind" : "CompilerError", + "location" : [ 6, 9, 6, 9 ], + "message" : "Parse error near token TIMES: *", + "syntax" : true + } ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/bad_indentation.py b/src/test/data/pa1/sample/bad_indentation.py new file mode 100644 index 0000000..670b7ab --- /dev/null +++ b/src/test/data/pa1/sample/bad_indentation.py @@ -0,0 +1,3 @@ +x = 1 + y = 2 +z = 3 diff --git a/src/test/data/pa1/sample/bad_indentation.py.ast b/src/test/data/pa1/sample/bad_indentation.py.ast new file mode 100644 index 0000000..f37b92e --- /dev/null +++ b/src/test/data/pa1/sample/bad_indentation.py.ast @@ -0,0 +1,47 @@ +{ + "kind" : "Program", + "location" : [ 2, 3, 3, 6 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 2, 3, 2, 7 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 2, 3, 2, 3 ], + "name" : "y" + } ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 7, 2, 7 ], + "value" : 2 + } + }, { + "kind" : "AssignStmt", + "location" : [ 3, 1, 3, 5 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 3, 1, 3, 1 ], + "name" : "z" + } ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 5, 3, 5 ], + "value" : 3 + } + } ], + "errors" : { + "errors" : [ { + "kind" : "CompilerError", + "location" : [ 2, 1, 2, 2 ], + "message" : "Parse error near token INDENT: ", + "syntax" : true + }, { + "kind" : "CompilerError", + "location" : [ 3, 1, 3, 0 ], + "message" : "Parse error near token DEDENT: ", + "syntax" : true + } ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/bad_stmt.py b/src/test/data/pa1/sample/bad_stmt.py new file mode 100644 index 0000000..8e8a4da --- /dev/null +++ b/src/test/data/pa1/sample/bad_stmt.py @@ -0,0 +1,4 @@ +1 + 2 +3 == 4 or (not False && True) +5 + 6 +7 << 8 diff --git a/src/test/data/pa1/sample/bad_stmt.py.ast b/src/test/data/pa1/sample/bad_stmt.py.ast new file mode 100644 index 0000000..afe9602 --- /dev/null +++ b/src/test/data/pa1/sample/bad_stmt.py.ast @@ -0,0 +1,65 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 4, 7 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 5 ], + "expr" : { + "kind" : "BinaryExpr", + "location" : [ 1, 1, 1, 5 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 1, 1, 1 ], + "value" : 1 + }, + "operator" : "+", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 5, 1, 5 ], + "value" : 2 + } + } + }, { + "kind" : "ExprStmt", + "location" : [ 3, 1, 3, 5 ], + "expr" : { + "kind" : "BinaryExpr", + "location" : [ 3, 1, 3, 5 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 1, 3, 1 ], + "value" : 5 + }, + "operator" : "+", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 5, 3, 5 ], + "value" : 6 + } + } + }, { + "kind" : "ExprStmt", + "location" : [ 4, 6, 4, 6 ], + "expr" : { + "kind" : "IntegerLiteral", + "location" : [ 4, 6, 4, 6 ], + "value" : 8 + } + } ], + "errors" : { + "errors" : [ { + "kind" : "CompilerError", + "location" : [ 2, 22, 2, 22 ], + "message" : "Parse error near token UNRECOGNIZED: &", + "syntax" : true + }, { + "kind" : "CompilerError", + "location" : [ 4, 4, 4, 4 ], + "message" : "Parse error near token LT: <", + "syntax" : true + } ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/chained_mixed_assignments.py b/src/test/data/pa1/sample/chained_mixed_assignments.py new file mode 100644 index 0000000..46a230a --- /dev/null +++ b/src/test/data/pa1/sample/chained_mixed_assignments.py @@ -0,0 +1,2 @@ +x[0] = y = z.f = 1 +z.g = y = x[0] diff --git a/src/test/data/pa1/sample/chained_mixed_assignments.py.ast b/src/test/data/pa1/sample/chained_mixed_assignments.py.ast new file mode 100644 index 0000000..9654bf6 --- /dev/null +++ b/src/test/data/pa1/sample/chained_mixed_assignments.py.ast @@ -0,0 +1,85 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 2, 15 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 1, 1, 1, 18 ], + "targets" : [ { + "kind" : "IndexExpr", + "location" : [ 1, 1, 1, 4 ], + "list" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 1 ], + "name" : "x" + }, + "index" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 3, 1, 3 ], + "value" : 0 + } + }, { + "kind" : "Identifier", + "location" : [ 1, 8, 1, 8 ], + "name" : "y" + }, { + "kind" : "MemberExpr", + "location" : [ 1, 12, 1, 14 ], + "object" : { + "kind" : "Identifier", + "location" : [ 1, 12, 1, 12 ], + "name" : "z" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 1, 14, 1, 14 ], + "name" : "f" + } + } ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 18, 1, 18 ], + "value" : 1 + } + }, { + "kind" : "AssignStmt", + "location" : [ 2, 1, 2, 14 ], + "targets" : [ { + "kind" : "MemberExpr", + "location" : [ 2, 1, 2, 3 ], + "object" : { + "kind" : "Identifier", + "location" : [ 2, 1, 2, 1 ], + "name" : "z" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 2, 3, 2, 3 ], + "name" : "g" + } + }, { + "kind" : "Identifier", + "location" : [ 2, 7, 2, 7 ], + "name" : "y" + } ], + "value" : { + "kind" : "IndexExpr", + "location" : [ 2, 11, 2, 14 ], + "list" : { + "kind" : "Identifier", + "location" : [ 2, 11, 2, 11 ], + "name" : "x" + }, + "index" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 13, 2, 13 ], + "value" : 0 + } + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/chained_var_assignments.py b/src/test/data/pa1/sample/chained_var_assignments.py new file mode 100644 index 0000000..b253c2a --- /dev/null +++ b/src/test/data/pa1/sample/chained_var_assignments.py @@ -0,0 +1 @@ +x = y = z = 1 diff --git a/src/test/data/pa1/sample/chained_var_assignments.py.ast b/src/test/data/pa1/sample/chained_var_assignments.py.ast new file mode 100644 index 0000000..28f0ea7 --- /dev/null +++ b/src/test/data/pa1/sample/chained_var_assignments.py.ast @@ -0,0 +1,32 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 1, 14 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 1, 1, 1, 13 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 1 ], + "name" : "x" + }, { + "kind" : "Identifier", + "location" : [ 1, 5, 1, 5 ], + "name" : "y" + }, { + "kind" : "Identifier", + "location" : [ 1, 9, 1, 9 ], + "name" : "z" + } ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 13, 1, 13 ], + "value" : 1 + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/class_attr.py b/src/test/data/pa1/sample/class_attr.py new file mode 100644 index 0000000..bb1e1cd --- /dev/null +++ b/src/test/data/pa1/sample/class_attr.py @@ -0,0 +1,4 @@ +class Foo(object): + x:int = 1 + +f = Foo() diff --git a/src/test/data/pa1/sample/class_attr.py.ast b/src/test/data/pa1/sample/class_attr.py.ast new file mode 100644 index 0000000..4fdab40 --- /dev/null +++ b/src/test/data/pa1/sample/class_attr.py.ast @@ -0,0 +1,65 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 4, 10 ], + "declarations" : [ { + "kind" : "ClassDef", + "location" : [ 1, 1, 2, 14 ], + "name" : { + "kind" : "Identifier", + "location" : [ 1, 7, 1, 9 ], + "name" : "Foo" + }, + "superClass" : { + "kind" : "Identifier", + "location" : [ 1, 11, 1, 16 ], + "name" : "object" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 2, 5, 2, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 2, 5, 2, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 5 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 2, 7, 2, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 13, 2, 13 ], + "value" : 1 + } + } ] + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 4, 1, 4, 9 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 4, 1, 4, 1 ], + "name" : "f" + } ], + "value" : { + "kind" : "CallExpr", + "location" : [ 4, 5, 4, 9 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 5, 4, 7 ], + "name" : "Foo" + }, + "args" : [ ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/class_attr_get.py b/src/test/data/pa1/sample/class_attr_get.py new file mode 100644 index 0000000..b4e6365 --- /dev/null +++ b/src/test/data/pa1/sample/class_attr_get.py @@ -0,0 +1,5 @@ +class Foo(object): + x:int = 1 + +f = Foo() +print(f.x) diff --git a/src/test/data/pa1/sample/class_attr_get.py.ast b/src/test/data/pa1/sample/class_attr_get.py.ast new file mode 100644 index 0000000..f286342 --- /dev/null +++ b/src/test/data/pa1/sample/class_attr_get.py.ast @@ -0,0 +1,91 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 5, 11 ], + "declarations" : [ { + "kind" : "ClassDef", + "location" : [ 1, 1, 2, 14 ], + "name" : { + "kind" : "Identifier", + "location" : [ 1, 7, 1, 9 ], + "name" : "Foo" + }, + "superClass" : { + "kind" : "Identifier", + "location" : [ 1, 11, 1, 16 ], + "name" : "object" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 2, 5, 2, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 2, 5, 2, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 5 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 2, 7, 2, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 13, 2, 13 ], + "value" : 1 + } + } ] + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 4, 1, 4, 9 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 4, 1, 4, 1 ], + "name" : "f" + } ], + "value" : { + "kind" : "CallExpr", + "location" : [ 4, 5, 4, 9 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 5, 4, 7 ], + "name" : "Foo" + }, + "args" : [ ] + } + }, { + "kind" : "ExprStmt", + "location" : [ 5, 1, 5, 10 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 5, 1, 5, 10 ], + "function" : { + "kind" : "Identifier", + "location" : [ 5, 1, 5, 5 ], + "name" : "print" + }, + "args" : [ { + "kind" : "MemberExpr", + "location" : [ 5, 7, 5, 9 ], + "object" : { + "kind" : "Identifier", + "location" : [ 5, 7, 5, 7 ], + "name" : "f" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 5, 9, 5, 9 ], + "name" : "x" + } + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/class_attr_set.py b/src/test/data/pa1/sample/class_attr_set.py new file mode 100644 index 0000000..ac94bf8 --- /dev/null +++ b/src/test/data/pa1/sample/class_attr_set.py @@ -0,0 +1,5 @@ +class Foo(object): + x:int = 1 + +f = Foo() +f.x = 2 diff --git a/src/test/data/pa1/sample/class_attr_set.py.ast b/src/test/data/pa1/sample/class_attr_set.py.ast new file mode 100644 index 0000000..03d6bba --- /dev/null +++ b/src/test/data/pa1/sample/class_attr_set.py.ast @@ -0,0 +1,87 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 5, 8 ], + "declarations" : [ { + "kind" : "ClassDef", + "location" : [ 1, 1, 2, 14 ], + "name" : { + "kind" : "Identifier", + "location" : [ 1, 7, 1, 9 ], + "name" : "Foo" + }, + "superClass" : { + "kind" : "Identifier", + "location" : [ 1, 11, 1, 16 ], + "name" : "object" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 2, 5, 2, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 2, 5, 2, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 5 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 2, 7, 2, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 13, 2, 13 ], + "value" : 1 + } + } ] + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 4, 1, 4, 9 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 4, 1, 4, 1 ], + "name" : "f" + } ], + "value" : { + "kind" : "CallExpr", + "location" : [ 4, 5, 4, 9 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 5, 4, 7 ], + "name" : "Foo" + }, + "args" : [ ] + } + }, { + "kind" : "AssignStmt", + "location" : [ 5, 1, 5, 7 ], + "targets" : [ { + "kind" : "MemberExpr", + "location" : [ 5, 1, 5, 3 ], + "object" : { + "kind" : "Identifier", + "location" : [ 5, 1, 5, 1 ], + "name" : "f" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 5, 3, 5, 3 ], + "name" : "x" + } + } ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 5, 7, 5, 7 ], + "value" : 2 + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/class_constructor.py b/src/test/data/pa1/sample/class_constructor.py new file mode 100644 index 0000000..46d7ccb --- /dev/null +++ b/src/test/data/pa1/sample/class_constructor.py @@ -0,0 +1,8 @@ +class Foo(object): + x:int = 0 + + def __init__(self:"Foo", x:int): + self.x = x + +f = Foo(1) +print(f.x) diff --git a/src/test/data/pa1/sample/class_constructor.py.ast b/src/test/data/pa1/sample/class_constructor.py.ast new file mode 100644 index 0000000..6850e03 --- /dev/null +++ b/src/test/data/pa1/sample/class_constructor.py.ast @@ -0,0 +1,159 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 8, 11 ], + "declarations" : [ { + "kind" : "ClassDef", + "location" : [ 1, 1, 7, 0 ], + "name" : { + "kind" : "Identifier", + "location" : [ 1, 7, 1, 9 ], + "name" : "Foo" + }, + "superClass" : { + "kind" : "Identifier", + "location" : [ 1, 11, 1, 16 ], + "name" : "object" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 2, 5, 2, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 2, 5, 2, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 5 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 2, 7, 2, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 13, 2, 13 ], + "value" : 0 + } + }, { + "kind" : "FuncDef", + "location" : [ 4, 5, 5, 19 ], + "name" : { + "kind" : "Identifier", + "location" : [ 4, 9, 4, 16 ], + "name" : "__init__" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 4, 18, 4, 27 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 4, 18, 4, 21 ], + "name" : "self" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 4, 23, 4, 27 ], + "className" : "Foo" + } + }, { + "kind" : "TypedVar", + "location" : [ 4, 30, 4, 34 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 4, 30, 4, 30 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 4, 32, 4, 34 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 4, 36, 4, 36 ], + "className" : "" + }, + "declarations" : [ ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 5, 9, 5, 18 ], + "targets" : [ { + "kind" : "MemberExpr", + "location" : [ 5, 9, 5, 14 ], + "object" : { + "kind" : "Identifier", + "location" : [ 5, 9, 5, 12 ], + "name" : "self" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 5, 14, 5, 14 ], + "name" : "x" + } + } ], + "value" : { + "kind" : "Identifier", + "location" : [ 5, 18, 5, 18 ], + "name" : "x" + } + } ] + } ] + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 7, 1, 7, 10 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 7, 1, 7, 1 ], + "name" : "f" + } ], + "value" : { + "kind" : "CallExpr", + "location" : [ 7, 5, 7, 10 ], + "function" : { + "kind" : "Identifier", + "location" : [ 7, 5, 7, 7 ], + "name" : "Foo" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 7, 9, 7, 9 ], + "value" : 1 + } ] + } + }, { + "kind" : "ExprStmt", + "location" : [ 8, 1, 8, 10 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 8, 1, 8, 10 ], + "function" : { + "kind" : "Identifier", + "location" : [ 8, 1, 8, 5 ], + "name" : "print" + }, + "args" : [ { + "kind" : "MemberExpr", + "location" : [ 8, 7, 8, 9 ], + "object" : { + "kind" : "Identifier", + "location" : [ 8, 7, 8, 7 ], + "name" : "f" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 8, 9, 8, 9 ], + "name" : "x" + } + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/class_method.py b/src/test/data/pa1/sample/class_method.py new file mode 100644 index 0000000..cc03ce2 --- /dev/null +++ b/src/test/data/pa1/sample/class_method.py @@ -0,0 +1,9 @@ +class Foo(object): + x:int = 0 + + def set(self:"Foo", x:int) -> object: + self.x = x + +f = Foo() +f.set(1) +print(f.x) diff --git a/src/test/data/pa1/sample/class_method.py.ast b/src/test/data/pa1/sample/class_method.py.ast new file mode 100644 index 0000000..66bc2e1 --- /dev/null +++ b/src/test/data/pa1/sample/class_method.py.ast @@ -0,0 +1,181 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 9, 11 ], + "declarations" : [ { + "kind" : "ClassDef", + "location" : [ 1, 1, 7, 0 ], + "name" : { + "kind" : "Identifier", + "location" : [ 1, 7, 1, 9 ], + "name" : "Foo" + }, + "superClass" : { + "kind" : "Identifier", + "location" : [ 1, 11, 1, 16 ], + "name" : "object" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 2, 5, 2, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 2, 5, 2, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 5 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 2, 7, 2, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 13, 2, 13 ], + "value" : 0 + } + }, { + "kind" : "FuncDef", + "location" : [ 4, 5, 5, 19 ], + "name" : { + "kind" : "Identifier", + "location" : [ 4, 9, 4, 11 ], + "name" : "set" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 4, 13, 4, 22 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 4, 13, 4, 16 ], + "name" : "self" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 4, 18, 4, 22 ], + "className" : "Foo" + } + }, { + "kind" : "TypedVar", + "location" : [ 4, 25, 4, 29 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 4, 25, 4, 25 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 4, 27, 4, 29 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 4, 35, 4, 40 ], + "className" : "object" + }, + "declarations" : [ ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 5, 9, 5, 18 ], + "targets" : [ { + "kind" : "MemberExpr", + "location" : [ 5, 9, 5, 14 ], + "object" : { + "kind" : "Identifier", + "location" : [ 5, 9, 5, 12 ], + "name" : "self" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 5, 14, 5, 14 ], + "name" : "x" + } + } ], + "value" : { + "kind" : "Identifier", + "location" : [ 5, 18, 5, 18 ], + "name" : "x" + } + } ] + } ] + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 7, 1, 7, 9 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 7, 1, 7, 1 ], + "name" : "f" + } ], + "value" : { + "kind" : "CallExpr", + "location" : [ 7, 5, 7, 9 ], + "function" : { + "kind" : "Identifier", + "location" : [ 7, 5, 7, 7 ], + "name" : "Foo" + }, + "args" : [ ] + } + }, { + "kind" : "ExprStmt", + "location" : [ 8, 1, 8, 8 ], + "expr" : { + "kind" : "MethodCallExpr", + "location" : [ 8, 1, 8, 8 ], + "method" : { + "kind" : "MemberExpr", + "location" : [ 8, 1, 8, 5 ], + "object" : { + "kind" : "Identifier", + "location" : [ 8, 1, 8, 1 ], + "name" : "f" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 8, 3, 8, 5 ], + "name" : "set" + } + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 8, 7, 8, 7 ], + "value" : 1 + } ] + } + }, { + "kind" : "ExprStmt", + "location" : [ 9, 1, 9, 10 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 9, 1, 9, 10 ], + "function" : { + "kind" : "Identifier", + "location" : [ 9, 1, 9, 5 ], + "name" : "print" + }, + "args" : [ { + "kind" : "MemberExpr", + "location" : [ 9, 7, 9, 9 ], + "object" : { + "kind" : "Identifier", + "location" : [ 9, 7, 9, 7 ], + "name" : "f" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 9, 9, 9, 9 ], + "name" : "x" + } + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/coverage.py b/src/test/data/pa1/sample/coverage.py new file mode 100644 index 0000000..1da3446 --- /dev/null +++ b/src/test/data/pa1/sample/coverage.py @@ -0,0 +1,38 @@ +count:int = 0 + +def foo(s: str) -> int: + return len(s) + +class bar(object): + p: bool = True + + def baz(self:"bar", xx: [int]) -> str: + global count + x:int = 0 + y:int = 1 + + def qux(y: int) -> object: + nonlocal x + if x > y: + x = -1 + + for x in xx: + self.p = x == 2 + + qux(0) # Yay! ChocoPy + + count = count + 1 + + while x <= 0: + if self.p: + xx[0] = xx[1] + self.p = not self.p + x = x + 1 + elif foo("Long"[0]) == 1: + return self is None + + return "Nope" + +print(bar().baz([1,2])) + + diff --git a/src/test/data/pa1/sample/coverage.py.ast b/src/test/data/pa1/sample/coverage.py.ast new file mode 100644 index 0000000..c7bab9f --- /dev/null +++ b/src/test/data/pa1/sample/coverage.py.ast @@ -0,0 +1,613 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 36, 24 ], + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 1, 1, 1, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 1, 1, 1, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 5 ], + "name" : "count" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 1, 7, 1, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 13, 1, 13 ], + "value" : 0 + } + }, { + "kind" : "FuncDef", + "location" : [ 3, 1, 4, 18 ], + "name" : { + "kind" : "Identifier", + "location" : [ 3, 5, 3, 7 ], + "name" : "foo" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 3, 9, 3, 14 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 3, 9, 3, 9 ], + "name" : "s" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 3, 12, 3, 14 ], + "className" : "str" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 3, 20, 3, 22 ], + "className" : "int" + }, + "declarations" : [ ], + "statements" : [ { + "kind" : "ReturnStmt", + "location" : [ 4, 5, 4, 17 ], + "value" : { + "kind" : "CallExpr", + "location" : [ 4, 12, 4, 17 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 12, 4, 14 ], + "name" : "len" + }, + "args" : [ { + "kind" : "Identifier", + "location" : [ 4, 16, 4, 16 ], + "name" : "s" + } ] + } + } ] + }, { + "kind" : "ClassDef", + "location" : [ 6, 1, 36, 0 ], + "name" : { + "kind" : "Identifier", + "location" : [ 6, 7, 6, 9 ], + "name" : "bar" + }, + "superClass" : { + "kind" : "Identifier", + "location" : [ 6, 11, 6, 16 ], + "name" : "object" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 7, 5, 7, 18 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 7, 5, 7, 11 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 7, 5, 7, 5 ], + "name" : "p" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 7, 8, 7, 11 ], + "className" : "bool" + } + }, + "value" : { + "kind" : "BooleanLiteral", + "location" : [ 7, 15, 7, 18 ], + "value" : true + } + }, { + "kind" : "FuncDef", + "location" : [ 9, 5, 34, 22 ], + "name" : { + "kind" : "Identifier", + "location" : [ 9, 9, 9, 11 ], + "name" : "baz" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 9, 13, 9, 22 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 9, 13, 9, 16 ], + "name" : "self" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 9, 18, 9, 22 ], + "className" : "bar" + } + }, { + "kind" : "TypedVar", + "location" : [ 9, 25, 9, 33 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 9, 25, 9, 26 ], + "name" : "xx" + }, + "type" : { + "kind" : "ListType", + "location" : [ 9, 29, 9, 33 ], + "elementType" : { + "kind" : "ClassType", + "location" : [ 9, 30, 9, 32 ], + "className" : "int" + } + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 9, 39, 9, 41 ], + "className" : "str" + }, + "declarations" : [ { + "kind" : "GlobalDecl", + "location" : [ 10, 9, 10, 20 ], + "variable" : { + "kind" : "Identifier", + "location" : [ 10, 16, 10, 20 ], + "name" : "count" + } + }, { + "kind" : "VarDef", + "location" : [ 11, 9, 11, 17 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 11, 9, 11, 13 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 11, 9, 11, 9 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 11, 11, 11, 13 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 11, 17, 11, 17 ], + "value" : 0 + } + }, { + "kind" : "VarDef", + "location" : [ 12, 9, 12, 17 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 12, 9, 12, 13 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 12, 9, 12, 9 ], + "name" : "y" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 12, 11, 12, 13 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 12, 17, 12, 17 ], + "value" : 1 + } + }, { + "kind" : "FuncDef", + "location" : [ 14, 9, 19, 8 ], + "name" : { + "kind" : "Identifier", + "location" : [ 14, 13, 14, 15 ], + "name" : "qux" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 14, 17, 14, 22 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 14, 17, 14, 17 ], + "name" : "y" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 14, 20, 14, 22 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 14, 28, 14, 33 ], + "className" : "object" + }, + "declarations" : [ { + "kind" : "NonLocalDecl", + "location" : [ 15, 13, 15, 22 ], + "variable" : { + "kind" : "Identifier", + "location" : [ 15, 22, 15, 22 ], + "name" : "x" + } + } ], + "statements" : [ { + "kind" : "IfStmt", + "location" : [ 16, 13, 19, 8 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 16, 16, 16, 20 ], + "left" : { + "kind" : "Identifier", + "location" : [ 16, 16, 16, 16 ], + "name" : "x" + }, + "operator" : ">", + "right" : { + "kind" : "Identifier", + "location" : [ 16, 20, 16, 20 ], + "name" : "y" + } + }, + "thenBody" : [ { + "kind" : "AssignStmt", + "location" : [ 17, 17, 17, 22 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 17, 17, 17, 17 ], + "name" : "x" + } ], + "value" : { + "kind" : "UnaryExpr", + "location" : [ 17, 21, 17, 22 ], + "operator" : "-", + "operand" : { + "kind" : "IntegerLiteral", + "location" : [ 17, 22, 17, 22 ], + "value" : 1 + } + } + } ], + "elseBody" : [ ] + } ] + } ], + "statements" : [ { + "kind" : "ForStmt", + "location" : [ 19, 9, 22, 8 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 19, 13, 19, 13 ], + "name" : "x" + }, + "iterable" : { + "kind" : "Identifier", + "location" : [ 19, 18, 19, 19 ], + "name" : "xx" + }, + "body" : [ { + "kind" : "AssignStmt", + "location" : [ 20, 13, 20, 27 ], + "targets" : [ { + "kind" : "MemberExpr", + "location" : [ 20, 13, 20, 18 ], + "object" : { + "kind" : "Identifier", + "location" : [ 20, 13, 20, 16 ], + "name" : "self" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 20, 18, 20, 18 ], + "name" : "p" + } + } ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 20, 22, 20, 27 ], + "left" : { + "kind" : "Identifier", + "location" : [ 20, 22, 20, 22 ], + "name" : "x" + }, + "operator" : "==", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 20, 27, 20, 27 ], + "value" : 2 + } + } + } ] + }, { + "kind" : "ExprStmt", + "location" : [ 22, 9, 22, 14 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 22, 9, 22, 14 ], + "function" : { + "kind" : "Identifier", + "location" : [ 22, 9, 22, 11 ], + "name" : "qux" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 22, 13, 22, 13 ], + "value" : 0 + } ] + } + }, { + "kind" : "AssignStmt", + "location" : [ 24, 9, 24, 25 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 24, 9, 24, 13 ], + "name" : "count" + } ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 24, 17, 24, 25 ], + "left" : { + "kind" : "Identifier", + "location" : [ 24, 17, 24, 21 ], + "name" : "count" + }, + "operator" : "+", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 24, 25, 24, 25 ], + "value" : 1 + } + } + }, { + "kind" : "WhileStmt", + "location" : [ 26, 9, 34, 8 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 26, 15, 26, 20 ], + "left" : { + "kind" : "Identifier", + "location" : [ 26, 15, 26, 15 ], + "name" : "x" + }, + "operator" : "<=", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 26, 20, 26, 20 ], + "value" : 0 + } + }, + "body" : [ { + "kind" : "IfStmt", + "location" : [ 27, 13, 34, 8 ], + "condition" : { + "kind" : "MemberExpr", + "location" : [ 27, 16, 27, 21 ], + "object" : { + "kind" : "Identifier", + "location" : [ 27, 16, 27, 19 ], + "name" : "self" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 27, 21, 27, 21 ], + "name" : "p" + } + }, + "thenBody" : [ { + "kind" : "AssignStmt", + "location" : [ 28, 17, 28, 29 ], + "targets" : [ { + "kind" : "IndexExpr", + "location" : [ 28, 17, 28, 21 ], + "list" : { + "kind" : "Identifier", + "location" : [ 28, 17, 28, 18 ], + "name" : "xx" + }, + "index" : { + "kind" : "IntegerLiteral", + "location" : [ 28, 20, 28, 20 ], + "value" : 0 + } + } ], + "value" : { + "kind" : "IndexExpr", + "location" : [ 28, 25, 28, 29 ], + "list" : { + "kind" : "Identifier", + "location" : [ 28, 25, 28, 26 ], + "name" : "xx" + }, + "index" : { + "kind" : "IntegerLiteral", + "location" : [ 28, 28, 28, 28 ], + "value" : 1 + } + } + }, { + "kind" : "AssignStmt", + "location" : [ 29, 17, 29, 35 ], + "targets" : [ { + "kind" : "MemberExpr", + "location" : [ 29, 17, 29, 22 ], + "object" : { + "kind" : "Identifier", + "location" : [ 29, 17, 29, 20 ], + "name" : "self" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 29, 22, 29, 22 ], + "name" : "p" + } + } ], + "value" : { + "kind" : "UnaryExpr", + "location" : [ 29, 26, 29, 35 ], + "operator" : "not", + "operand" : { + "kind" : "MemberExpr", + "location" : [ 29, 30, 29, 35 ], + "object" : { + "kind" : "Identifier", + "location" : [ 29, 30, 29, 33 ], + "name" : "self" + }, + "member" : { + "kind" : "Identifier", + "location" : [ 29, 35, 29, 35 ], + "name" : "p" + } + } + } + }, { + "kind" : "AssignStmt", + "location" : [ 30, 17, 30, 25 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 30, 17, 30, 17 ], + "name" : "x" + } ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 30, 21, 30, 25 ], + "left" : { + "kind" : "Identifier", + "location" : [ 30, 21, 30, 21 ], + "name" : "x" + }, + "operator" : "+", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 30, 25, 30, 25 ], + "value" : 1 + } + } + } ], + "elseBody" : [ { + "kind" : "IfStmt", + "location" : [ 31, 13, 34, 8 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 31, 18, 31, 36 ], + "left" : { + "kind" : "CallExpr", + "location" : [ 31, 18, 31, 31 ], + "function" : { + "kind" : "Identifier", + "location" : [ 31, 18, 31, 20 ], + "name" : "foo" + }, + "args" : [ { + "kind" : "IndexExpr", + "location" : [ 31, 22, 31, 30 ], + "list" : { + "kind" : "StringLiteral", + "location" : [ 31, 22, 31, 27 ], + "value" : "Long" + }, + "index" : { + "kind" : "IntegerLiteral", + "location" : [ 31, 29, 31, 29 ], + "value" : 0 + } + } ] + }, + "operator" : "==", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 31, 36, 31, 36 ], + "value" : 1 + } + }, + "thenBody" : [ { + "kind" : "ReturnStmt", + "location" : [ 32, 17, 32, 35 ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 32, 24, 32, 35 ], + "left" : { + "kind" : "Identifier", + "location" : [ 32, 24, 32, 27 ], + "name" : "self" + }, + "operator" : "is", + "right" : { + "kind" : "NoneLiteral", + "location" : [ 32, 32, 32, 35 ] + } + } + } ], + "elseBody" : [ ] + } ] + } ] + }, { + "kind" : "ReturnStmt", + "location" : [ 34, 9, 34, 21 ], + "value" : { + "kind" : "StringLiteral", + "location" : [ 34, 16, 34, 21 ], + "value" : "Nope" + } + } ] + } ] + } ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 36, 1, 36, 23 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 36, 1, 36, 23 ], + "function" : { + "kind" : "Identifier", + "location" : [ 36, 1, 36, 5 ], + "name" : "print" + }, + "args" : [ { + "kind" : "MethodCallExpr", + "location" : [ 36, 7, 36, 22 ], + "method" : { + "kind" : "MemberExpr", + "location" : [ 36, 7, 36, 15 ], + "object" : { + "kind" : "CallExpr", + "location" : [ 36, 7, 36, 11 ], + "function" : { + "kind" : "Identifier", + "location" : [ 36, 7, 36, 9 ], + "name" : "bar" + }, + "args" : [ ] + }, + "member" : { + "kind" : "Identifier", + "location" : [ 36, 13, 36, 15 ], + "name" : "baz" + } + }, + "args" : [ { + "kind" : "ListExpr", + "location" : [ 36, 17, 36, 21 ], + "elements" : [ { + "kind" : "IntegerLiteral", + "location" : [ 36, 18, 36, 18 ], + "value" : 1 + }, { + "kind" : "IntegerLiteral", + "location" : [ 36, 20, 36, 20 ], + "value" : 2 + } ] + } ] + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/def_func.py b/src/test/data/pa1/sample/def_func.py new file mode 100644 index 0000000..55e9c43 --- /dev/null +++ b/src/test/data/pa1/sample/def_func.py @@ -0,0 +1,4 @@ +def foo() -> int: + return 1 + +foo() diff --git a/src/test/data/pa1/sample/def_func.py.ast b/src/test/data/pa1/sample/def_func.py.ast new file mode 100644 index 0000000..00a7e65 --- /dev/null +++ b/src/test/data/pa1/sample/def_func.py.ast @@ -0,0 +1,48 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 4, 6 ], + "declarations" : [ { + "kind" : "FuncDef", + "location" : [ 1, 1, 2, 13 ], + "name" : { + "kind" : "Identifier", + "location" : [ 1, 5, 1, 7 ], + "name" : "foo" + }, + "params" : [ ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 1, 14, 1, 16 ], + "className" : "int" + }, + "declarations" : [ ], + "statements" : [ { + "kind" : "ReturnStmt", + "location" : [ 2, 5, 2, 12 ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 2, 12, 2, 12 ], + "value" : 1 + } + } ] + } ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 4, 1, 4, 5 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 4, 1, 4, 5 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 1, 4, 3 ], + "name" : "foo" + }, + "args" : [ ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/def_func_args.py b/src/test/data/pa1/sample/def_func_args.py new file mode 100644 index 0000000..196f504 --- /dev/null +++ b/src/test/data/pa1/sample/def_func_args.py @@ -0,0 +1,4 @@ +def foo(x:int, y:int) -> bool: + return x > y + +foo(1,2) diff --git a/src/test/data/pa1/sample/def_func_args.py.ast b/src/test/data/pa1/sample/def_func_args.py.ast new file mode 100644 index 0000000..77d9dc9 --- /dev/null +++ b/src/test/data/pa1/sample/def_func_args.py.ast @@ -0,0 +1,92 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 4, 9 ], + "declarations" : [ { + "kind" : "FuncDef", + "location" : [ 1, 1, 2, 17 ], + "name" : { + "kind" : "Identifier", + "location" : [ 1, 5, 1, 7 ], + "name" : "foo" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 1, 9, 1, 13 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 1, 9, 1, 9 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 1, 11, 1, 13 ], + "className" : "int" + } + }, { + "kind" : "TypedVar", + "location" : [ 1, 16, 1, 20 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 1, 16, 1, 16 ], + "name" : "y" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 1, 18, 1, 20 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 1, 26, 1, 29 ], + "className" : "bool" + }, + "declarations" : [ ], + "statements" : [ { + "kind" : "ReturnStmt", + "location" : [ 2, 5, 2, 16 ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 2, 12, 2, 16 ], + "left" : { + "kind" : "Identifier", + "location" : [ 2, 12, 2, 12 ], + "name" : "x" + }, + "operator" : ">", + "right" : { + "kind" : "Identifier", + "location" : [ 2, 16, 2, 16 ], + "name" : "y" + } + } + } ] + } ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 4, 1, 4, 8 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 4, 1, 4, 8 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 1, 4, 3 ], + "name" : "foo" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 4, 5, 4, 5 ], + "value" : 1 + }, { + "kind" : "IntegerLiteral", + "location" : [ 4, 7, 4, 7 ], + "value" : 2 + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/def_func_global.py b/src/test/data/pa1/sample/def_func_global.py new file mode 100644 index 0000000..12f9dfc --- /dev/null +++ b/src/test/data/pa1/sample/def_func_global.py @@ -0,0 +1,7 @@ +z:int = 0 + +def foo(x:int) -> bool: + global z + return x > z + +foo(1) diff --git a/src/test/data/pa1/sample/def_func_global.py.ast b/src/test/data/pa1/sample/def_func_global.py.ast new file mode 100644 index 0000000..736af77 --- /dev/null +++ b/src/test/data/pa1/sample/def_func_global.py.ast @@ -0,0 +1,105 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 7, 7 ], + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 1, 1, 1, 9 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 1, 1, 1, 5 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 1 ], + "name" : "z" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 1, 3, 1, 5 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 9, 1, 9 ], + "value" : 0 + } + }, { + "kind" : "FuncDef", + "location" : [ 3, 1, 5, 17 ], + "name" : { + "kind" : "Identifier", + "location" : [ 3, 5, 3, 7 ], + "name" : "foo" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 3, 9, 3, 13 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 3, 9, 3, 9 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 3, 11, 3, 13 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 3, 19, 3, 22 ], + "className" : "bool" + }, + "declarations" : [ { + "kind" : "GlobalDecl", + "location" : [ 4, 5, 4, 12 ], + "variable" : { + "kind" : "Identifier", + "location" : [ 4, 12, 4, 12 ], + "name" : "z" + } + } ], + "statements" : [ { + "kind" : "ReturnStmt", + "location" : [ 5, 5, 5, 16 ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 5, 12, 5, 16 ], + "left" : { + "kind" : "Identifier", + "location" : [ 5, 12, 5, 12 ], + "name" : "x" + }, + "operator" : ">", + "right" : { + "kind" : "Identifier", + "location" : [ 5, 16, 5, 16 ], + "name" : "z" + } + } + } ] + } ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 7, 1, 7, 6 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 7, 1, 7, 6 ], + "function" : { + "kind" : "Identifier", + "location" : [ 7, 1, 7, 3 ], + "name" : "foo" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 7, 5, 7, 5 ], + "value" : 1 + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/def_func_nested.py b/src/test/data/pa1/sample/def_func_nested.py new file mode 100644 index 0000000..835614e --- /dev/null +++ b/src/test/data/pa1/sample/def_func_nested.py @@ -0,0 +1,10 @@ + +def foo(x:int) -> bool: + a:int = 0 + b:int = 1 + def bar(y: int) -> int: + a:int = 2 + return y + return bar(x) > a + +foo(1) diff --git a/src/test/data/pa1/sample/def_func_nested.py.ast b/src/test/data/pa1/sample/def_func_nested.py.ast new file mode 100644 index 0000000..0024178 --- /dev/null +++ b/src/test/data/pa1/sample/def_func_nested.py.ast @@ -0,0 +1,187 @@ +{ + "kind" : "Program", + "location" : [ 2, 1, 10, 7 ], + "declarations" : [ { + "kind" : "FuncDef", + "location" : [ 2, 1, 8, 22 ], + "name" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 7 ], + "name" : "foo" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 2, 9, 2, 13 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 9, 2, 9 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 2, 11, 2, 13 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 2, 19, 2, 22 ], + "className" : "bool" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 3, 5, 3, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 3, 5, 3, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 3, 5, 3, 5 ], + "name" : "a" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 3, 7, 3, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 13, 3, 13 ], + "value" : 0 + } + }, { + "kind" : "VarDef", + "location" : [ 4, 5, 4, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 4, 5, 4, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 4, 5, 4, 5 ], + "name" : "b" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 4, 7, 4, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 4, 13, 4, 13 ], + "value" : 1 + } + }, { + "kind" : "FuncDef", + "location" : [ 5, 5, 7, 17 ], + "name" : { + "kind" : "Identifier", + "location" : [ 5, 9, 5, 11 ], + "name" : "bar" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 5, 13, 5, 18 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 5, 13, 5, 13 ], + "name" : "y" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 5, 16, 5, 18 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 5, 24, 5, 26 ], + "className" : "int" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 6, 9, 6, 17 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 6, 9, 6, 13 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 6, 9, 6, 9 ], + "name" : "a" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 6, 11, 6, 13 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 6, 17, 6, 17 ], + "value" : 2 + } + } ], + "statements" : [ { + "kind" : "ReturnStmt", + "location" : [ 7, 9, 7, 16 ], + "value" : { + "kind" : "Identifier", + "location" : [ 7, 16, 7, 16 ], + "name" : "y" + } + } ] + } ], + "statements" : [ { + "kind" : "ReturnStmt", + "location" : [ 8, 5, 8, 21 ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 8, 12, 8, 21 ], + "left" : { + "kind" : "CallExpr", + "location" : [ 8, 12, 8, 17 ], + "function" : { + "kind" : "Identifier", + "location" : [ 8, 12, 8, 14 ], + "name" : "bar" + }, + "args" : [ { + "kind" : "Identifier", + "location" : [ 8, 16, 8, 16 ], + "name" : "x" + } ] + }, + "operator" : ">", + "right" : { + "kind" : "Identifier", + "location" : [ 8, 21, 8, 21 ], + "name" : "a" + } + } + } ] + } ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 10, 1, 10, 6 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 10, 1, 10, 6 ], + "function" : { + "kind" : "Identifier", + "location" : [ 10, 1, 10, 3 ], + "name" : "foo" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 10, 5, 10, 5 ], + "value" : 1 + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/def_func_nonlocal.py b/src/test/data/pa1/sample/def_func_nonlocal.py new file mode 100644 index 0000000..1304328 --- /dev/null +++ b/src/test/data/pa1/sample/def_func_nonlocal.py @@ -0,0 +1,11 @@ + +def foo(x:int) -> bool: + a:int = 0 + b:int = 1 + def bar(y: int) -> int: + nonlocal a + a = 2 + return y + return bar(x) > a + +foo(1) diff --git a/src/test/data/pa1/sample/def_func_nonlocal.py.ast b/src/test/data/pa1/sample/def_func_nonlocal.py.ast new file mode 100644 index 0000000..5c1e1de --- /dev/null +++ b/src/test/data/pa1/sample/def_func_nonlocal.py.ast @@ -0,0 +1,186 @@ +{ + "kind" : "Program", + "location" : [ 2, 1, 11, 7 ], + "declarations" : [ { + "kind" : "FuncDef", + "location" : [ 2, 1, 9, 22 ], + "name" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 7 ], + "name" : "foo" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 2, 9, 2, 13 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 9, 2, 9 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 2, 11, 2, 13 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 2, 19, 2, 22 ], + "className" : "bool" + }, + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 3, 5, 3, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 3, 5, 3, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 3, 5, 3, 5 ], + "name" : "a" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 3, 7, 3, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 13, 3, 13 ], + "value" : 0 + } + }, { + "kind" : "VarDef", + "location" : [ 4, 5, 4, 13 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 4, 5, 4, 9 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 4, 5, 4, 5 ], + "name" : "b" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 4, 7, 4, 9 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 4, 13, 4, 13 ], + "value" : 1 + } + }, { + "kind" : "FuncDef", + "location" : [ 5, 5, 8, 17 ], + "name" : { + "kind" : "Identifier", + "location" : [ 5, 9, 5, 11 ], + "name" : "bar" + }, + "params" : [ { + "kind" : "TypedVar", + "location" : [ 5, 13, 5, 18 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 5, 13, 5, 13 ], + "name" : "y" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 5, 16, 5, 18 ], + "className" : "int" + } + } ], + "returnType" : { + "kind" : "ClassType", + "location" : [ 5, 24, 5, 26 ], + "className" : "int" + }, + "declarations" : [ { + "kind" : "NonLocalDecl", + "location" : [ 6, 9, 6, 18 ], + "variable" : { + "kind" : "Identifier", + "location" : [ 6, 18, 6, 18 ], + "name" : "a" + } + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 7, 9, 7, 13 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 7, 9, 7, 9 ], + "name" : "a" + } ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 7, 13, 7, 13 ], + "value" : 2 + } + }, { + "kind" : "ReturnStmt", + "location" : [ 8, 9, 8, 16 ], + "value" : { + "kind" : "Identifier", + "location" : [ 8, 16, 8, 16 ], + "name" : "y" + } + } ] + } ], + "statements" : [ { + "kind" : "ReturnStmt", + "location" : [ 9, 5, 9, 21 ], + "value" : { + "kind" : "BinaryExpr", + "location" : [ 9, 12, 9, 21 ], + "left" : { + "kind" : "CallExpr", + "location" : [ 9, 12, 9, 17 ], + "function" : { + "kind" : "Identifier", + "location" : [ 9, 12, 9, 14 ], + "name" : "bar" + }, + "args" : [ { + "kind" : "Identifier", + "location" : [ 9, 16, 9, 16 ], + "name" : "x" + } ] + }, + "operator" : ">", + "right" : { + "kind" : "Identifier", + "location" : [ 9, 21, 9, 21 ], + "name" : "a" + } + } + } ] + } ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 11, 1, 11, 6 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 11, 1, 11, 6 ], + "function" : { + "kind" : "Identifier", + "location" : [ 11, 1, 11, 3 ], + "name" : "foo" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 11, 5, 11, 5 ], + "value" : 1 + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/expr_if.py b/src/test/data/pa1/sample/expr_if.py new file mode 100644 index 0000000..e9e9c26 --- /dev/null +++ b/src/test/data/pa1/sample/expr_if.py @@ -0,0 +1 @@ +3 if 1 > 2 else 4 diff --git a/src/test/data/pa1/sample/expr_if.py.ast b/src/test/data/pa1/sample/expr_if.py.ast new file mode 100644 index 0000000..0ed9a55 --- /dev/null +++ b/src/test/data/pa1/sample/expr_if.py.ast @@ -0,0 +1,43 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 1, 18 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 17 ], + "expr" : { + "kind" : "IfExpr", + "location" : [ 1, 1, 1, 17 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 1, 6, 1, 10 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 6, 1, 6 ], + "value" : 1 + }, + "operator" : ">", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 10, 1, 10 ], + "value" : 2 + } + }, + "thenExpr" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 1, 1, 1 ], + "value" : 3 + }, + "elseExpr" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 17, 1, 17 ], + "value" : 4 + } + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/expr_if_chained.py b/src/test/data/pa1/sample/expr_if_chained.py new file mode 100644 index 0000000..4a7837e --- /dev/null +++ b/src/test/data/pa1/sample/expr_if_chained.py @@ -0,0 +1 @@ +3 if 1 > 2 else 4 if 1 < 0 else 5 diff --git a/src/test/data/pa1/sample/expr_if_chained.py.ast b/src/test/data/pa1/sample/expr_if_chained.py.ast new file mode 100644 index 0000000..2776da9 --- /dev/null +++ b/src/test/data/pa1/sample/expr_if_chained.py.ast @@ -0,0 +1,67 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 1, 34 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 33 ], + "expr" : { + "kind" : "IfExpr", + "location" : [ 1, 1, 1, 33 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 1, 6, 1, 10 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 6, 1, 6 ], + "value" : 1 + }, + "operator" : ">", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 10, 1, 10 ], + "value" : 2 + } + }, + "thenExpr" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 1, 1, 1 ], + "value" : 3 + }, + "elseExpr" : { + "kind" : "IfExpr", + "location" : [ 1, 17, 1, 33 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 1, 22, 1, 26 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 22, 1, 22 ], + "value" : 1 + }, + "operator" : "<", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 26, 1, 26 ], + "value" : 0 + } + }, + "thenExpr" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 17, 1, 17 ], + "value" : 4 + }, + "elseExpr" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 33, 1, 33 ], + "value" : 5 + } + } + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/expr_index.py b/src/test/data/pa1/sample/expr_index.py new file mode 100644 index 0000000..8e95ff2 --- /dev/null +++ b/src/test/data/pa1/sample/expr_index.py @@ -0,0 +1 @@ +a + b[i][j] diff --git a/src/test/data/pa1/sample/expr_index.py.ast b/src/test/data/pa1/sample/expr_index.py.ast new file mode 100644 index 0000000..a5f97ee --- /dev/null +++ b/src/test/data/pa1/sample/expr_index.py.ast @@ -0,0 +1,47 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 1, 12 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 11 ], + "expr" : { + "kind" : "BinaryExpr", + "location" : [ 1, 1, 1, 11 ], + "left" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 1 ], + "name" : "a" + }, + "operator" : "+", + "right" : { + "kind" : "IndexExpr", + "location" : [ 1, 5, 1, 11 ], + "list" : { + "kind" : "IndexExpr", + "location" : [ 1, 5, 1, 8 ], + "list" : { + "kind" : "Identifier", + "location" : [ 1, 5, 1, 5 ], + "name" : "b" + }, + "index" : { + "kind" : "Identifier", + "location" : [ 1, 7, 1, 7 ], + "name" : "i" + } + }, + "index" : { + "kind" : "Identifier", + "location" : [ 1, 10, 1, 10 ], + "name" : "j" + } + } + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/expr_plus.py b/src/test/data/pa1/sample/expr_plus.py new file mode 100644 index 0000000..8138b36 --- /dev/null +++ b/src/test/data/pa1/sample/expr_plus.py @@ -0,0 +1 @@ +1 + 2 + 3 diff --git a/src/test/data/pa1/sample/expr_plus.py.ast b/src/test/data/pa1/sample/expr_plus.py.ast new file mode 100644 index 0000000..f924e67 --- /dev/null +++ b/src/test/data/pa1/sample/expr_plus.py.ast @@ -0,0 +1,39 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 1, 10 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 9 ], + "expr" : { + "kind" : "BinaryExpr", + "location" : [ 1, 1, 1, 9 ], + "left" : { + "kind" : "BinaryExpr", + "location" : [ 1, 1, 1, 5 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 1, 1, 1 ], + "value" : 1 + }, + "operator" : "+", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 5, 1, 5 ], + "value" : 2 + } + }, + "operator" : "+", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 9, 1, 9 ], + "value" : 3 + } + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/expr_unary.py b/src/test/data/pa1/sample/expr_unary.py new file mode 100644 index 0000000..3a2e3f4 --- /dev/null +++ b/src/test/data/pa1/sample/expr_unary.py @@ -0,0 +1 @@ +-1 diff --git a/src/test/data/pa1/sample/expr_unary.py.ast b/src/test/data/pa1/sample/expr_unary.py.ast new file mode 100644 index 0000000..e4ef8d2 --- /dev/null +++ b/src/test/data/pa1/sample/expr_unary.py.ast @@ -0,0 +1,24 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 1, 3 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 2 ], + "expr" : { + "kind" : "UnaryExpr", + "location" : [ 1, 1, 1, 2 ], + "operator" : "-", + "operand" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 2, 1, 2 ], + "value" : 1 + } + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/global.py b/src/test/data/pa1/sample/global.py new file mode 100644 index 0000000..779d3bb --- /dev/null +++ b/src/test/data/pa1/sample/global.py @@ -0,0 +1,5 @@ +x:int = 1 + +x = 2 + +print(x) diff --git a/src/test/data/pa1/sample/global.py.ast b/src/test/data/pa1/sample/global.py.ast new file mode 100644 index 0000000..84b42b1 --- /dev/null +++ b/src/test/data/pa1/sample/global.py.ast @@ -0,0 +1,63 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 5, 9 ], + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 1, 1, 1, 9 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 1, 1, 1, 5 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 1 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 1, 3, 1, 5 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 9, 1, 9 ], + "value" : 1 + } + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 3, 1, 3, 5 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 3, 1, 3, 1 ], + "name" : "x" + } ], + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 5, 3, 5 ], + "value" : 2 + } + }, { + "kind" : "ExprStmt", + "location" : [ 5, 1, 5, 8 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 5, 1, 5, 8 ], + "function" : { + "kind" : "Identifier", + "location" : [ 5, 1, 5, 5 ], + "name" : "print" + }, + "args" : [ { + "kind" : "Identifier", + "location" : [ 5, 7, 5, 7 ], + "name" : "x" + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/literals.py b/src/test/data/pa1/sample/literals.py new file mode 100644 index 0000000..081863e --- /dev/null +++ b/src/test/data/pa1/sample/literals.py @@ -0,0 +1,7 @@ +True +False +1 +None +"This is a string" +[1, 2, 3] + diff --git a/src/test/data/pa1/sample/literals.py.ast b/src/test/data/pa1/sample/literals.py.ast new file mode 100644 index 0000000..d6fd3bc --- /dev/null +++ b/src/test/data/pa1/sample/literals.py.ast @@ -0,0 +1,70 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 6, 10 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 4 ], + "expr" : { + "kind" : "BooleanLiteral", + "location" : [ 1, 1, 1, 4 ], + "value" : true + } + }, { + "kind" : "ExprStmt", + "location" : [ 2, 1, 2, 5 ], + "expr" : { + "kind" : "BooleanLiteral", + "location" : [ 2, 1, 2, 5 ], + "value" : false + } + }, { + "kind" : "ExprStmt", + "location" : [ 3, 1, 3, 1 ], + "expr" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 1, 3, 1 ], + "value" : 1 + } + }, { + "kind" : "ExprStmt", + "location" : [ 4, 1, 4, 4 ], + "expr" : { + "kind" : "NoneLiteral", + "location" : [ 4, 1, 4, 4 ] + } + }, { + "kind" : "ExprStmt", + "location" : [ 5, 1, 5, 18 ], + "expr" : { + "kind" : "StringLiteral", + "location" : [ 5, 1, 5, 18 ], + "value" : "This is a string" + } + }, { + "kind" : "ExprStmt", + "location" : [ 6, 1, 6, 9 ], + "expr" : { + "kind" : "ListExpr", + "location" : [ 6, 1, 6, 9 ], + "elements" : [ { + "kind" : "IntegerLiteral", + "location" : [ 6, 2, 6, 2 ], + "value" : 1 + }, { + "kind" : "IntegerLiteral", + "location" : [ 6, 5, 6, 5 ], + "value" : 2 + }, { + "kind" : "IntegerLiteral", + "location" : [ 6, 8, 6, 8 ], + "value" : 3 + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_call.py b/src/test/data/pa1/sample/stmt_call.py new file mode 100644 index 0000000..b917a72 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_call.py @@ -0,0 +1 @@ +print(1) diff --git a/src/test/data/pa1/sample/stmt_call.py.ast b/src/test/data/pa1/sample/stmt_call.py.ast new file mode 100644 index 0000000..4d0ef38 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_call.py.ast @@ -0,0 +1,28 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 1, 9 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "ExprStmt", + "location" : [ 1, 1, 1, 8 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 1, 1, 1, 8 ], + "function" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 5 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 1, 7, 1, 7 ], + "value" : 1 + } ] + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_for.py b/src/test/data/pa1/sample/stmt_for.py new file mode 100644 index 0000000..6f65c5f --- /dev/null +++ b/src/test/data/pa1/sample/stmt_for.py @@ -0,0 +1,4 @@ +x:int = 0 +for x in [1, 2, 3]: + print(x) + diff --git a/src/test/data/pa1/sample/stmt_for.py.ast b/src/test/data/pa1/sample/stmt_for.py.ast new file mode 100644 index 0000000..ba0847b --- /dev/null +++ b/src/test/data/pa1/sample/stmt_for.py.ast @@ -0,0 +1,76 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 5, 1 ], + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 1, 1, 1, 9 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 1, 1, 1, 5 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 1 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 1, 3, 1, 5 ], + "className" : "int" + } + }, + "value" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 9, 1, 9 ], + "value" : 0 + } + } ], + "statements" : [ { + "kind" : "ForStmt", + "location" : [ 2, 1, 5, 1 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 5 ], + "name" : "x" + }, + "iterable" : { + "kind" : "ListExpr", + "location" : [ 2, 10, 2, 18 ], + "elements" : [ { + "kind" : "IntegerLiteral", + "location" : [ 2, 11, 2, 11 ], + "value" : 1 + }, { + "kind" : "IntegerLiteral", + "location" : [ 2, 14, 2, 14 ], + "value" : 2 + }, { + "kind" : "IntegerLiteral", + "location" : [ 2, 17, 2, 17 ], + "value" : 3 + } ] + }, + "body" : [ { + "kind" : "ExprStmt", + "location" : [ 3, 5, 3, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 3, 5, 3, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 3, 5, 3, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "Identifier", + "location" : [ 3, 11, 3, 11 ], + "name" : "x" + } ] + } + } ] + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_if.py b/src/test/data/pa1/sample/stmt_if.py new file mode 100644 index 0000000..b87c003 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_if.py @@ -0,0 +1,3 @@ +if True: + False + diff --git a/src/test/data/pa1/sample/stmt_if.py.ast b/src/test/data/pa1/sample/stmt_if.py.ast new file mode 100644 index 0000000..2b08a8f --- /dev/null +++ b/src/test/data/pa1/sample/stmt_if.py.ast @@ -0,0 +1,29 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 4, 1 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "IfStmt", + "location" : [ 1, 1, 4, 1 ], + "condition" : { + "kind" : "BooleanLiteral", + "location" : [ 1, 4, 1, 7 ], + "value" : true + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 2, 5, 2, 9 ], + "expr" : { + "kind" : "BooleanLiteral", + "location" : [ 2, 5, 2, 9 ], + "value" : false + } + } ], + "elseBody" : [ ] + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_if_elif.py b/src/test/data/pa1/sample/stmt_if_elif.py new file mode 100644 index 0000000..7fa86dd --- /dev/null +++ b/src/test/data/pa1/sample/stmt_if_elif.py @@ -0,0 +1,6 @@ +if 1 > 2: + print(1) +elif 3 == 4: + print(2) +elif True: + print(3) diff --git a/src/test/data/pa1/sample/stmt_if_elif.py.ast b/src/test/data/pa1/sample/stmt_if_elif.py.ast new file mode 100644 index 0000000..11dcd2e --- /dev/null +++ b/src/test/data/pa1/sample/stmt_if_elif.py.ast @@ -0,0 +1,112 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 7, 1 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "IfStmt", + "location" : [ 1, 1, 7, 1 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 1, 4, 1, 8 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 4, 1, 4 ], + "value" : 1 + }, + "operator" : ">", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 8, 1, 8 ], + "value" : 2 + } + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 2, 5, 2, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 2, 5, 2, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 2, 11, 2, 11 ], + "value" : 1 + } ] + } + } ], + "elseBody" : [ { + "kind" : "IfStmt", + "location" : [ 3, 1, 7, 1 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 3, 6, 3, 11 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 6, 3, 6 ], + "value" : 3 + }, + "operator" : "==", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 11, 3, 11 ], + "value" : 4 + } + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 4, 5, 4, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 4, 5, 4, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 5, 4, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 4, 11, 4, 11 ], + "value" : 2 + } ] + } + } ], + "elseBody" : [ { + "kind" : "IfStmt", + "location" : [ 5, 1, 7, 1 ], + "condition" : { + "kind" : "BooleanLiteral", + "location" : [ 5, 6, 5, 9 ], + "value" : true + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 6, 5, 6, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 6, 5, 6, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 6, 5, 6, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 6, 11, 6, 11 ], + "value" : 3 + } ] + } + } ], + "elseBody" : [ ] + } ] + } ] + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_if_elif_else.py b/src/test/data/pa1/sample/stmt_if_elif_else.py new file mode 100644 index 0000000..161d9d9 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_if_elif_else.py @@ -0,0 +1,8 @@ +if 1 > 2: + print(1) +elif 3 == 4: + print(2) +elif True: + print(3) +else: + print(4) diff --git a/src/test/data/pa1/sample/stmt_if_elif_else.py.ast b/src/test/data/pa1/sample/stmt_if_elif_else.py.ast new file mode 100644 index 0000000..dc25855 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_if_elif_else.py.ast @@ -0,0 +1,129 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 9, 1 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "IfStmt", + "location" : [ 1, 1, 9, 1 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 1, 4, 1, 8 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 4, 1, 4 ], + "value" : 1 + }, + "operator" : ">", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 1, 8, 1, 8 ], + "value" : 2 + } + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 2, 5, 2, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 2, 5, 2, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 2, 5, 2, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 2, 11, 2, 11 ], + "value" : 1 + } ] + } + } ], + "elseBody" : [ { + "kind" : "IfStmt", + "location" : [ 3, 1, 9, 1 ], + "condition" : { + "kind" : "BinaryExpr", + "location" : [ 3, 6, 3, 11 ], + "left" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 6, 3, 6 ], + "value" : 3 + }, + "operator" : "==", + "right" : { + "kind" : "IntegerLiteral", + "location" : [ 3, 11, 3, 11 ], + "value" : 4 + } + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 4, 5, 4, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 4, 5, 4, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 4, 5, 4, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 4, 11, 4, 11 ], + "value" : 2 + } ] + } + } ], + "elseBody" : [ { + "kind" : "IfStmt", + "location" : [ 5, 1, 9, 1 ], + "condition" : { + "kind" : "BooleanLiteral", + "location" : [ 5, 6, 5, 9 ], + "value" : true + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 6, 5, 6, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 6, 5, 6, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 6, 5, 6, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 6, 11, 6, 11 ], + "value" : 3 + } ] + } + } ], + "elseBody" : [ { + "kind" : "ExprStmt", + "location" : [ 8, 5, 8, 12 ], + "expr" : { + "kind" : "CallExpr", + "location" : [ 8, 5, 8, 12 ], + "function" : { + "kind" : "Identifier", + "location" : [ 8, 5, 8, 9 ], + "name" : "print" + }, + "args" : [ { + "kind" : "IntegerLiteral", + "location" : [ 8, 11, 8, 11 ], + "value" : 4 + } ] + } + } ] + } ] + } ] + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_ifelse.py b/src/test/data/pa1/sample/stmt_ifelse.py new file mode 100644 index 0000000..f138957 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_ifelse.py @@ -0,0 +1,5 @@ +if True: + False +else: + True + diff --git a/src/test/data/pa1/sample/stmt_ifelse.py.ast b/src/test/data/pa1/sample/stmt_ifelse.py.ast new file mode 100644 index 0000000..8e23d16 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_ifelse.py.ast @@ -0,0 +1,37 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 6, 1 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "IfStmt", + "location" : [ 1, 1, 6, 1 ], + "condition" : { + "kind" : "BooleanLiteral", + "location" : [ 1, 4, 1, 7 ], + "value" : true + }, + "thenBody" : [ { + "kind" : "ExprStmt", + "location" : [ 2, 5, 2, 9 ], + "expr" : { + "kind" : "BooleanLiteral", + "location" : [ 2, 5, 2, 9 ], + "value" : false + } + } ], + "elseBody" : [ { + "kind" : "ExprStmt", + "location" : [ 4, 5, 4, 8 ], + "expr" : { + "kind" : "BooleanLiteral", + "location" : [ 4, 5, 4, 8 ], + "value" : true + } + } ] + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_list_assign.py b/src/test/data/pa1/sample/stmt_list_assign.py new file mode 100644 index 0000000..e9e31d9 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_list_assign.py @@ -0,0 +1,4 @@ +x:int = None + +x = [1, 2, 3] +x[0] = x[1] diff --git a/src/test/data/pa1/sample/stmt_list_assign.py.ast b/src/test/data/pa1/sample/stmt_list_assign.py.ast new file mode 100644 index 0000000..b65848c --- /dev/null +++ b/src/test/data/pa1/sample/stmt_list_assign.py.ast @@ -0,0 +1,88 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 4, 12 ], + "declarations" : [ { + "kind" : "VarDef", + "location" : [ 1, 1, 1, 12 ], + "var" : { + "kind" : "TypedVar", + "location" : [ 1, 1, 1, 5 ], + "identifier" : { + "kind" : "Identifier", + "location" : [ 1, 1, 1, 1 ], + "name" : "x" + }, + "type" : { + "kind" : "ClassType", + "location" : [ 1, 3, 1, 5 ], + "className" : "int" + } + }, + "value" : { + "kind" : "NoneLiteral", + "location" : [ 1, 9, 1, 12 ] + } + } ], + "statements" : [ { + "kind" : "AssignStmt", + "location" : [ 3, 1, 3, 13 ], + "targets" : [ { + "kind" : "Identifier", + "location" : [ 3, 1, 3, 1 ], + "name" : "x" + } ], + "value" : { + "kind" : "ListExpr", + "location" : [ 3, 5, 3, 13 ], + "elements" : [ { + "kind" : "IntegerLiteral", + "location" : [ 3, 6, 3, 6 ], + "value" : 1 + }, { + "kind" : "IntegerLiteral", + "location" : [ 3, 9, 3, 9 ], + "value" : 2 + }, { + "kind" : "IntegerLiteral", + "location" : [ 3, 12, 3, 12 ], + "value" : 3 + } ] + } + }, { + "kind" : "AssignStmt", + "location" : [ 4, 1, 4, 11 ], + "targets" : [ { + "kind" : "IndexExpr", + "location" : [ 4, 1, 4, 4 ], + "list" : { + "kind" : "Identifier", + "location" : [ 4, 1, 4, 1 ], + "name" : "x" + }, + "index" : { + "kind" : "IntegerLiteral", + "location" : [ 4, 3, 4, 3 ], + "value" : 0 + } + } ], + "value" : { + "kind" : "IndexExpr", + "location" : [ 4, 8, 4, 11 ], + "list" : { + "kind" : "Identifier", + "location" : [ 4, 8, 4, 8 ], + "name" : "x" + }, + "index" : { + "kind" : "IntegerLiteral", + "location" : [ 4, 10, 4, 10 ], + "value" : 1 + } + } + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/sample/stmt_while.py b/src/test/data/pa1/sample/stmt_while.py new file mode 100644 index 0000000..1aaefd8 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_while.py @@ -0,0 +1,3 @@ +while True: + pass + diff --git a/src/test/data/pa1/sample/stmt_while.py.ast b/src/test/data/pa1/sample/stmt_while.py.ast new file mode 100644 index 0000000..a564490 --- /dev/null +++ b/src/test/data/pa1/sample/stmt_while.py.ast @@ -0,0 +1,20 @@ +{ + "kind" : "Program", + "location" : [ 1, 1, 4, 1 ], + "declarations" : [ ], + "statements" : [ { + "kind" : "WhileStmt", + "location" : [ 1, 1, 4, 1 ], + "condition" : { + "kind" : "BooleanLiteral", + "location" : [ 1, 7, 1, 10 ], + "value" : true + }, + "body" : [ ] + } ], + "errors" : { + "errors" : [ ], + "kind" : "Errors", + "location" : [ 0, 0, 0, 0 ] + } +} \ No newline at end of file diff --git a/src/test/data/pa1/student_contributed/bad.py b/src/test/data/pa1/student_contributed/bad.py new file mode 100644 index 0000000..b85905e --- /dev/null +++ b/src/test/data/pa1/student_contributed/bad.py @@ -0,0 +1 @@ +1 2 3 diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py new file mode 100644 index 0000000..8138b36 --- /dev/null +++ b/src/test/data/pa1/student_contributed/good.py @@ -0,0 +1 @@ +1 + 2 + 3