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 01/67] 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 From 997178ba9cd1d191edcd01f1d896627a91f3e722 Mon Sep 17 00:00:00 2001 From: bill Date: Wed, 17 Feb 2021 20:45:38 +0800 Subject: [PATCH 02/67] initial works on the lexer --- src/main/cup/chocopy/pa1/ChocoPy.cup | 5 + src/main/jflex/chocopy/pa1/ChocoPy.jflex | 129 +- src/main/jflex/chocopy/pa1/ChocoPyLexer.java | 1260 ++++++++++++++++++ 3 files changed, 1382 insertions(+), 12 deletions(-) create mode 100644 src/main/jflex/chocopy/pa1/ChocoPyLexer.java diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index d4ff444..0bc9dd6 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -144,6 +144,11 @@ action code {: */ terminal NEWLINE; terminal String PLUS; +terminal String MINUS; +terminal String MULTIPLY; +terminal String DIVIDE; +terminal String NAMES; + terminal Integer NUMBER; /* Returned by the lexer for erroneous tokens. Since it does not appear in * the grammar, it indicates a syntax error. */ diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index 9aafe7f..e90072a 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -1,6 +1,6 @@ package chocopy.pa1; import java_cup.runtime.*; - +import java.util.ArrayList; %% /*** Do not change the flags below unless you know what you are doing. ***/ @@ -8,7 +8,7 @@ import java_cup.runtime.*; %unicode %line %column - +%states AFTER %class ChocoPyLexer %public @@ -32,11 +32,12 @@ import java_cup.runtime.*; /** Producer of token-related values for the parser. */ final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); - + private int currIndent = 0; + private ArrayList stack = new ArrayList(20); /** 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 symbol(type); } /** Return a terminal symbol of syntactic category TYPE and semantic @@ -47,7 +48,17 @@ import java_cup.runtime.*; new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), value); } - + private void push(int indent){ + stack.add(indent); + } + private int pop(){ + if(stack.isEmpty()) return 0; + return stack.remove(stack.size() - 1); + } + private int top(){ + if(stack.isEmpty) return 0; + return stack.get(stack.size() - 1); + } %} /* Macros (regexes used in rules below) */ @@ -55,25 +66,119 @@ import java_cup.runtime.*; WhiteSpace = [ \t] LineBreak = \r|\n|\r\n -IntegerLiteral = 0 | [1-9][0-9]* - +IntegerLiteral = 0|[1-9][0-9]* +StringLiteral = \"([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))*\" +Names = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z])* +Comments = #[^\r\n]* %% - - { +{ + {WhiteSpace} + { + String space = yytext(); + if(space == "\t") + currIndent += 8; + else + currIndent ++; + } + {LineBreak} + { + currIndent = 0; + } + {Comments} { /* ignored */ } + [^ \t\r\n#] + { + yypushback(1); + if(top() > currIndent) + { + pop(); + return symbol(ChocoPyTokens.DEDENT); + } + yystart(AFTER); + if(top()< currIndent) + { + push(currIndent); + return symbol(ChocoPyTokens.INDENT); + } + } +} + { /* Delimiters. */ - {LineBreak} { return symbol(ChocoPyTokens.NEWLINE); } + {LineBreak} { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0;} + ":" { return symbol(ChocoPyTokens.COLON); } + "," { return symbol(ChocoPyTokens.COMMA); } /* Literals. */ {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } + {StringLiteral} { return symbol(ChocoPyTokens.STRING, yytext());} + "False" { return symbol(ChocoPyTokens.BOOL, false); } + "True" { return symbol(ChocoPyTokens.BOOL, true); } + "None" { return symbol(ChocoPyTokens.NONE); } + + /*Keywords*/ + "if" {return symbol(ChocoPyTokens.IF);} + "else" {return symbol(ChocoPyTokens.ELSE);} + "elif" {return symbol(ChocoPyTokens.ELIF);} + "while" {return symbol(ChocoPyTokens.WHILE);} + "class" {return symbol(ChocoPyTokens.CLASS);} + "def" {return symbol(ChocoPyTokens.DEF);} + "lambda" {return symbol(ChocoPyTokens.LAMBDA);} + "as" { return symbol(ChocoPyTokens.AS); } + "for" { return symbol(ChocoPyTokens.FOR); } + "global" { return symbol(ChocoPyTokens.GLOBAL); } + "in" { return symbol(ChocoPyTokens.IN); } + "nonlocal" { return symbol(ChocoPyTokens.NONLOCAL); } + "pass" { return symbol(ChocoPyTokens.PASS); } + "return" { return symbol(ChocoPyTokens.RETURN); } + "assert" { return symbol(ChocoPyTokens.ASSERT); } + "await" { return symbol(ChocoPyTokens.AWAIT); } + "break" { return symbol(ChocoPyTokens.BREAK); } + "continue" { return symbol(ChocoPyTokens.CONTINUE); } + "del" { return symbol(ChocoPyTokens.DEL); } + "except" { return symbol(ChocoPyTokens.EXCEPT); } + "finally" { return symbol(ChocoPyTokens.FINALLY); } + "from" { return symbol(ChocoPyTokens.FROM); } + "import" { return symbol(ChocoPyTokens.IMPORT); } + "raise" { return symbol(ChocoPyTokens.RAISE); } + "try" { return symbol(ChocoPyTokens.TRY); } + "with" { return symbol(ChocoPyTokens.WITH); } + "yield" { return symbol(ChocoPyTokens.YIELD); } - /* Operators. */ - "+" { return symbol(ChocoPyTokens.PLUS, yytext()); } + /* Operators. */ + "+" { return symbol(ChocoPyTokens.PLUS); } + "-" { return symbol(ChocoPyTokens.MINUS); } + "*" { return symbol(ChocoPyTokens.MUL); } + "//" { return symbol(ChocoPyTokens.DIV); } + "/" { return symbol(ChocoPyTokens.DIV); } + "%" { return symbol(ChocoPyTokens.MOD); } + ">" { return symbol(ChocoPyTokens.GT); } + "<" { return symbol(ChocoPyTokens.LT); } + "==" { return symbol(ChocoPyTokens.EQUAL); } + "!=" { return symbol(ChocoPyTokens.NEQ); } + ">=" { return symbol(ChocoPyTokens.GEQ); } + "<=" { return symbol(ChocoPyTokens.LEQ); } + "=" { return symbol(ChocoPyTokens.ASSIGN); } + "and" { return symbol(ChocoPyTokens.AND); } + "or" { return symbol(ChocoPyTokens.OR); } + "not" { return symbol(ChocoPyTokens.NOT); } + "." { return symbol(ChocoPyTokens.DOT); } + "(" { return symbol(ChocoPyTokens.LPAR); } + ")" { return symbol(ChocoPyTokens.RPAR); } + "[" { return symbol(ChocoPyTokens.LBR); } + "]" { return symbol(ChocoPyTokens.RBR); } + "->" { return symbol(ChocoPyTokens.ARROW); } + "is" { return symbol(ChocoPyTokens.IS); } + + + /*Identifiers*/ + {Names} {return symbol(ChocoPyTokens.NAMES, yytext());} /* Whitespace. */ {WhiteSpace} { /* ignore */ } + /* Comment. */ + {Comments} { /* ignore */ } } <> { return symbol(ChocoPyTokens.EOF); } diff --git a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java new file mode 100644 index 0000000..2045209 --- /dev/null +++ b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java @@ -0,0 +1,1260 @@ +// DO NOT EDIT +// Generated by JFlex 1.8.2 http://jflex.de/ +// source: ChocoPy.jflex + +package chocopy.pa1; +import java_cup.runtime.*; +import java.util.ArrayList; + +// See https://github.com/jflex-de/jflex/issues/222 +@SuppressWarnings("FallThrough") +public class ChocoPyLexer implements java_cup.runtime.Scanner { + + /** This character denotes the end of file. */ + public static final int YYEOF = -1; + + /** Initial size of the lookahead buffer. */ + private static final int ZZ_BUFFERSIZE = 16384; + + // Lexical states. + public static final int YYINITIAL = 0; + public static final int AFTER = 2; + + /** + * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l + * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l + * at the beginning of a line + * l is of the form l = 2*k, k a non negative integer + */ + private static final int ZZ_LEXSTATE[] = { + 0, 0, 1, 1 + }; + + /** + * Top-level table for translating characters to character classes + */ + private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top(); + + private static final String ZZ_CMAP_TOP_PACKED_0 = + "\1\0\u10ff\u0100"; + + private static int [] zzUnpackcmap_top() { + int [] result = new int[4352]; + int offset = 0; + offset = zzUnpackcmap_top(ZZ_CMAP_TOP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackcmap_top(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Second-level tables for translating characters to character classes + */ + private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); + + private static final String ZZ_CMAP_BLOCKS_PACKED_0 = + "\11\0\1\1\1\2\2\0\1\3\22\0\1\1\1\4"+ + "\1\5\1\6\1\0\1\7\2\0\1\10\1\11\1\12"+ + "\1\13\1\14\1\15\1\16\1\17\1\20\11\21\1\22"+ + "\1\0\1\23\1\24\1\25\2\0\5\26\1\27\7\26"+ + "\1\30\5\26\1\31\6\26\1\32\1\33\1\34\1\0"+ + "\1\26\1\0\1\35\1\36\1\37\1\40\1\41\1\42"+ + "\1\43\1\44\1\45\1\26\1\46\1\47\1\50\1\51"+ + "\1\52\1\53\1\26\1\54\1\55\1\56\1\57\1\26"+ + "\1\60\1\61\1\62\1\26\u0185\0"; + + private static int [] zzUnpackcmap_blocks() { + int [] result = new int[512]; + int offset = 0; + offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\2\0\1\1\1\2\2\3\1\4\1\5\1\6\2\7"+ + "\2\5\1\6\1\10\1\11\1\12\1\13\1\14\1\15"+ + "\1\16\1\17\1\20\2\21\1\22\1\23\1\24\1\25"+ + "\4\26\1\27\1\30\20\26\1\31\1\0\1\32\1\0"+ + "\1\33\1\20\1\34\1\35\1\36\4\26\1\37\13\26"+ + "\1\40\1\26\1\41\1\42\2\26\1\43\12\26\1\44"+ + "\5\26\1\45\1\46\4\26\1\47\5\26\1\50\3\26"+ + "\1\51\4\26\1\52\1\53\5\26\1\54\1\55\2\26"+ + "\1\56\4\26\1\57\3\26\1\60\1\26\1\61\1\26"+ + "\1\62\1\63\1\64\7\26\1\65\1\26\1\66\1\67"+ + "\1\70\1\26\1\71\1\26\1\72\1\73\1\74\1\26"+ + "\1\75\1\26\1\76\1\26\1\77\1\100"; + + private static int [] zzUnpackAction() { + int [] result = new int[172]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\63\0\146\0\146\0\146\0\231\0\314\0\146"+ + "\0\146\0\146\0\377\0\u0132\0\u0165\0\u0198\0\146\0\146"+ + "\0\146\0\146\0\146\0\146\0\u01cb\0\146\0\u01fe\0\146"+ + "\0\u0231\0\146\0\u0264\0\u0297\0\u02ca\0\u02fd\0\u0330\0\u0363"+ + "\0\u0396\0\146\0\146\0\u03c9\0\u03fc\0\u042f\0\u0462\0\u0495"+ + "\0\u04c8\0\u04fb\0\u052e\0\u0561\0\u0594\0\u05c7\0\u05fa\0\u062d"+ + "\0\u0660\0\u0693\0\u06c6\0\146\0\u0165\0\146\0\u06f9\0\146"+ + "\0\146\0\146\0\146\0\146\0\u072c\0\u075f\0\u0792\0\u07c5"+ + "\0\u07f8\0\u082b\0\u085e\0\u0891\0\u08c4\0\u08f7\0\u092a\0\u095d"+ + "\0\u0990\0\u09c3\0\u09f6\0\u0a29\0\u02fd\0\u0a5c\0\u02fd\0\u02fd"+ + "\0\u0a8f\0\u0ac2\0\u02fd\0\u0af5\0\u0b28\0\u0b5b\0\u0b8e\0\u0bc1"+ + "\0\u0bf4\0\u0c27\0\u0c5a\0\u0c8d\0\u0cc0\0\u02fd\0\u0cf3\0\u0d26"+ + "\0\u0d59\0\u0d8c\0\u0dbf\0\u02fd\0\u02fd\0\u0df2\0\u0e25\0\u0e58"+ + "\0\u0e8b\0\u02fd\0\u0ebe\0\u0ef1\0\u0f24\0\u0f57\0\u0f8a\0\u02fd"+ + "\0\u0fbd\0\u0ff0\0\u1023\0\u02fd\0\u1056\0\u1089\0\u10bc\0\u10ef"+ + "\0\u02fd\0\u02fd\0\u1122\0\u1155\0\u1188\0\u11bb\0\u11ee\0\u02fd"+ + "\0\u02fd\0\u1221\0\u1254\0\u02fd\0\u1287\0\u12ba\0\u12ed\0\u1320"+ + "\0\u02fd\0\u1353\0\u1386\0\u13b9\0\u02fd\0\u13ec\0\u02fd\0\u141f"+ + "\0\u02fd\0\u02fd\0\u02fd\0\u1452\0\u1485\0\u14b8\0\u14eb\0\u151e"+ + "\0\u1551\0\u1584\0\u02fd\0\u15b7\0\u02fd\0\u02fd\0\u02fd\0\u15ea"+ + "\0\u02fd\0\u161d\0\u02fd\0\u02fd\0\u02fd\0\u1650\0\u02fd\0\u1683"+ + "\0\u02fd\0\u16b6\0\u02fd\0\u02fd"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[172]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\3\1\4\1\5\1\6\2\3\1\7\54\3\1\10"+ + "\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1\20"+ + "\1\21\1\22\1\23\1\24\1\25\1\26\1\27\1\30"+ + "\1\31\1\32\1\33\1\34\1\35\1\36\1\37\1\40"+ + "\1\41\1\42\1\10\1\43\1\44\1\45\1\46\1\47"+ + "\1\50\1\51\1\52\1\36\1\53\1\36\1\54\1\36"+ + "\1\55\1\56\1\57\1\60\1\36\1\61\1\36\1\62"+ + "\1\36\1\63\65\0\1\5\60\0\2\7\2\0\57\7"+ + "\2\0\1\12\104\0\1\64\36\0\5\65\1\66\25\65"+ + "\1\67\27\65\2\16\2\0\57\16\25\0\1\70\54\0"+ + "\1\71\63\0\2\31\65\0\1\72\62\0\1\73\62\0"+ + "\1\74\64\0\4\36\3\0\26\36\26\0\4\36\3\0"+ + "\1\75\25\36\26\0\4\36\3\0\15\36\1\76\10\36"+ + "\26\0\4\36\3\0\17\36\1\77\6\36\26\0\4\36"+ + "\3\0\14\36\1\100\3\36\1\101\2\36\1\102\2\36"+ + "\26\0\4\36\3\0\17\36\1\103\6\36\26\0\4\36"+ + "\3\0\12\36\1\104\2\36\1\105\10\36\26\0\4\36"+ + "\3\0\4\36\1\106\21\36\26\0\4\36\3\0\12\36"+ + "\1\107\11\36\1\110\1\36\26\0\4\36\3\0\10\36"+ + "\1\111\4\36\1\112\1\36\1\113\6\36\26\0\4\36"+ + "\3\0\12\36\1\114\13\36\26\0\4\36\3\0\5\36"+ + "\1\115\5\36\1\116\1\117\3\36\1\120\5\36\26\0"+ + "\4\36\3\0\1\121\25\36\26\0\4\36\3\0\15\36"+ + "\1\122\10\36\26\0\4\36\3\0\17\36\1\123\6\36"+ + "\26\0\4\36\3\0\1\124\25\36\26\0\4\36\3\0"+ + "\1\125\3\36\1\126\21\36\26\0\4\36\3\0\17\36"+ + "\1\127\6\36\26\0\4\36\3\0\7\36\1\130\1\131"+ + "\15\36\26\0\4\36\3\0\10\36\1\132\15\36\5\0"+ + "\1\65\25\0\1\65\15\0\1\65\2\0\1\65\1\0"+ + "\1\65\32\0\4\36\3\0\12\36\1\133\13\36\26\0"+ + "\4\36\3\0\14\36\1\134\11\36\26\0\4\36\3\0"+ + "\22\36\1\135\3\36\26\0\4\36\3\0\3\36\1\136"+ + "\22\36\26\0\4\36\3\0\20\36\1\137\5\36\26\0"+ + "\4\36\3\0\1\140\25\36\26\0\4\36\3\0\4\36"+ + "\1\141\21\36\26\0\4\36\3\0\1\142\25\36\26\0"+ + "\4\36\3\0\14\36\1\143\11\36\26\0\4\36\3\0"+ + "\5\36\1\144\4\36\1\145\13\36\26\0\4\36\3\0"+ + "\10\36\1\146\7\36\1\147\5\36\26\0\4\36\3\0"+ + "\2\36\1\150\23\36\26\0\4\36\3\0\14\36\1\151"+ + "\11\36\26\0\4\36\3\0\17\36\1\152\6\36\26\0"+ + "\4\36\3\0\15\36\1\153\10\36\26\0\4\36\3\0"+ + "\15\36\1\154\10\36\26\0\4\36\3\0\16\36\1\155"+ + "\7\36\26\0\4\36\3\0\13\36\1\156\12\36\26\0"+ + "\4\36\3\0\14\36\1\157\4\36\1\160\4\36\26\0"+ + "\4\36\3\0\20\36\1\161\5\36\26\0\4\36\3\0"+ + "\10\36\1\162\15\36\26\0\4\36\3\0\21\36\1\163"+ + "\4\36\26\0\4\36\3\0\25\36\1\164\26\0\4\36"+ + "\3\0\10\36\1\165\15\36\26\0\4\36\3\0\21\36"+ + "\1\166\4\36\26\0\4\36\3\0\4\36\1\167\21\36"+ + "\26\0\4\36\3\0\20\36\1\170\5\36\26\0\4\36"+ + "\3\0\4\36\1\171\21\36\26\0\4\36\3\0\4\36"+ + "\1\172\21\36\26\0\4\36\3\0\4\36\1\173\21\36"+ + "\26\0\4\36\3\0\10\36\1\174\15\36\26\0\4\36"+ + "\3\0\1\175\25\36\26\0\4\36\3\0\20\36\1\176"+ + "\5\36\26\0\4\36\3\0\21\36\1\177\4\36\26\0"+ + "\4\36\3\0\5\36\1\200\20\36\26\0\4\36\3\0"+ + "\4\36\1\201\21\36\26\0\4\36\3\0\4\36\1\202"+ + "\21\36\26\0\4\36\3\0\1\203\25\36\26\0\4\36"+ + "\3\0\13\36\1\204\12\36\26\0\4\36\3\0\1\36"+ + "\1\205\24\36\26\0\4\36\3\0\15\36\1\206\10\36"+ + "\26\0\4\36\3\0\1\36\1\207\24\36\26\0\4\36"+ + "\3\0\12\36\1\210\13\36\26\0\4\36\3\0\20\36"+ + "\1\211\5\36\26\0\4\36\3\0\20\36\1\212\5\36"+ + "\26\0\4\36\3\0\22\36\1\213\3\36\26\0\4\36"+ + "\3\0\12\36\1\214\13\36\26\0\4\36\3\0\7\36"+ + "\1\215\16\36\26\0\4\36\3\0\12\36\1\216\13\36"+ + "\26\0\4\36\3\0\4\36\1\217\21\36\26\0\4\36"+ + "\3\0\17\36\1\220\6\36\26\0\4\36\3\0\21\36"+ + "\1\221\4\36\26\0\4\36\3\0\11\36\1\222\14\36"+ + "\26\0\4\36\3\0\20\36\1\223\5\36\26\0\4\36"+ + "\3\0\10\36\1\224\15\36\26\0\4\36\3\0\16\36"+ + "\1\225\7\36\26\0\4\36\3\0\12\36\1\226\13\36"+ + "\26\0\4\36\3\0\1\227\25\36\26\0\4\36\3\0"+ + "\17\36\1\230\6\36\26\0\4\36\3\0\3\36\1\231"+ + "\22\36\26\0\4\36\3\0\15\36\1\232\10\36\26\0"+ + "\4\36\3\0\4\36\1\233\21\36\26\0\4\36\3\0"+ + "\17\36\1\234\6\36\26\0\4\36\3\0\4\36\1\235"+ + "\21\36\26\0\4\36\3\0\3\36\1\236\22\36\26\0"+ + "\4\36\3\0\21\36\1\237\4\36\26\0\4\36\3\0"+ + "\14\36\1\240\11\36\26\0\4\36\3\0\21\36\1\241"+ + "\4\36\26\0\4\36\3\0\12\36\1\242\13\36\26\0"+ + "\4\36\3\0\12\36\1\243\13\36\26\0\4\36\3\0"+ + "\21\36\1\244\4\36\26\0\4\36\3\0\1\245\25\36"+ + "\26\0\4\36\3\0\2\36\1\246\23\36\26\0\4\36"+ + "\3\0\14\36\1\247\11\36\26\0\4\36\3\0\22\36"+ + "\1\250\3\36\26\0\4\36\3\0\25\36\1\251\26\0"+ + "\4\36\3\0\1\252\25\36\26\0\4\36\3\0\4\36"+ + "\1\253\21\36\26\0\4\36\3\0\12\36\1\254\13\36"; + + private static int [] zzUnpackTrans() { + int [] result = new int[5865]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** Error code for "Unknown internal scanner error". */ + private static final int ZZ_UNKNOWN_ERROR = 0; + /** Error code for "could not match input". */ + private static final int ZZ_NO_MATCH = 1; + /** Error code for "pushback value was too large". */ + private static final int ZZ_PUSHBACK_2BIG = 2; + + /** + * Error messages for {@link #ZZ_UNKNOWN_ERROR}, {@link #ZZ_NO_MATCH}, and + * {@link #ZZ_PUSHBACK_2BIG} respectively. + */ + private static final String ZZ_ERROR_MSG[] = { + "Unknown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state {@code aState} + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\2\0\3\11\2\1\3\11\4\1\6\11\1\1\1\11"+ + "\1\1\1\11\1\1\1\11\7\1\2\11\20\1\1\11"+ + "\1\0\1\11\1\0\5\11\160\1"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[172]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** Input device. */ + private java.io.Reader zzReader; + + /** Current state of the DFA. */ + private int zzState; + + /** Current lexical state. */ + private int zzLexicalState = YYINITIAL; + + /** + * This buffer contains the current text to be matched and is the source of the {@link #yytext()} + * string. + */ + private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; + + /** Text position at the last accepting state. */ + private int zzMarkedPos; + + /** Current text position in the buffer. */ + private int zzCurrentPos; + + /** Marks the beginning of the {@link #yytext()} string in the buffer. */ + private int zzStartRead; + + /** Marks the last character in the buffer, that has been read from input. */ + private int zzEndRead; + + /** + * Whether the scanner is at the end of file. + * @see #yyatEOF + */ + private boolean zzAtEOF; + + /** + * The number of occupied positions in {@link #zzBuffer} beyond {@link #zzEndRead}. + * + *

When a lead/high surrogate has been read from the input stream into the final + * {@link #zzBuffer} position, this will have a value of 1; otherwise, it will have a value of 0. + */ + private int zzFinalHighSurrogate = 0; + + /** Number of newlines encountered up to the start of the matched text. */ + private int yyline; + + /** Number of characters from the last newline up to the start of the matched text. */ + private int yycolumn; + + /** Number of characters up to the start of the matched text. */ + @SuppressWarnings("unused") + private long yychar; + + /** Whether the scanner is currently at the beginning of a line. */ + @SuppressWarnings("unused") + private boolean zzAtBOL = true; + + /** Whether the user-EOF-code has already been executed. */ + @SuppressWarnings("unused") + private boolean zzEOFDone; + + /* user code: */ + /* 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(); + private int currIndent = 0; + private ArrayList stack = new ArrayList(20); + /** 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); + } + + /** 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); + } + private void push(int indent){ + stack.add(indent); + } + private int pop(){ + if(stack.isEmpty()) return 0; + return stack.remove(stack.size() - 1); + } + private int top(){ + if(stack.isEmpty) return 0; + return stack.get(stack.size() - 1); + } + + + /** + * Creates a new scanner + * + * @param in the java.io.Reader to read input from. + */ + public ChocoPyLexer(java.io.Reader in) { + this.zzReader = in; + } + + /** + * Translates raw input code points to DFA table row + */ + private static int zzCMap(int input) { + int offset = input & 255; + return offset == input ? ZZ_CMAP_BLOCKS[offset] : ZZ_CMAP_BLOCKS[ZZ_CMAP_TOP[input >> 8] | offset]; + } + + /** + * Refills the input buffer. + * + * @return {@code false} iff there was new input. + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + + /* first: make room (if you can) */ + if (zzStartRead > 0) { + zzEndRead += zzFinalHighSurrogate; + zzFinalHighSurrogate = 0; + System.arraycopy(zzBuffer, zzStartRead, + zzBuffer, 0, + zzEndRead - zzStartRead); + + /* translate stored positions */ + zzEndRead -= zzStartRead; + zzCurrentPos -= zzStartRead; + zzMarkedPos -= zzStartRead; + zzStartRead = 0; + } + + /* is the buffer big enough? */ + if (zzCurrentPos >= zzBuffer.length - zzFinalHighSurrogate) { + /* if not: blow it up */ + char newBuffer[] = new char[zzBuffer.length * 2]; + System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); + zzBuffer = newBuffer; + zzEndRead += zzFinalHighSurrogate; + zzFinalHighSurrogate = 0; + } + + /* fill the buffer with new input */ + int requested = zzBuffer.length - zzEndRead; + int numRead = zzReader.read(zzBuffer, zzEndRead, requested); + + /* not supposed to occur according to specification of java.io.Reader */ + if (numRead == 0) { + throw new java.io.IOException( + "Reader returned 0 characters. See JFlex examples/zero-reader for a workaround."); + } + if (numRead > 0) { + zzEndRead += numRead; + if (Character.isHighSurrogate(zzBuffer[zzEndRead - 1])) { + if (numRead == requested) { // We requested too few chars to encode a full Unicode character + --zzEndRead; + zzFinalHighSurrogate = 1; + } else { // There is room in the buffer for at least one more char + int c = zzReader.read(); // Expecting to read a paired low surrogate char + if (c == -1) { + return true; + } else { + zzBuffer[zzEndRead++] = (char)c; + } + } + } + /* potentially more input available */ + return false; + } + + /* numRead < 0 ==> end of stream */ + return true; + } + + + /** + * Closes the input reader. + * + * @throws java.io.IOException if the reader could not be closed. + */ + public final void yyclose() throws java.io.IOException { + zzAtEOF = true; // indicate end of file + zzEndRead = zzStartRead; // invalidate buffer + + if (zzReader != null) { + zzReader.close(); + } + } + + + /** + * Resets the scanner to read from a new input stream. + * + *

Does not close the old reader. + * + *

All internal variables are reset, the old input stream cannot be reused (internal + * buffer is discarded and lost). Lexical state is set to {@code ZZ_INITIAL}. + * + *

Internal scan buffer is resized down to its initial length, if it has grown. + * + * @param reader The new input stream. + */ + public final void yyreset(java.io.Reader reader) { + zzReader = reader; + zzEOFDone = false; + yyResetPosition(); + zzLexicalState = YYINITIAL; + if (zzBuffer.length > ZZ_BUFFERSIZE) { + zzBuffer = new char[ZZ_BUFFERSIZE]; + } + } + + /** + * Resets the input position. + */ + private final void yyResetPosition() { + zzAtBOL = true; + zzAtEOF = false; + zzCurrentPos = 0; + zzMarkedPos = 0; + zzStartRead = 0; + zzEndRead = 0; + zzFinalHighSurrogate = 0; + yyline = 0; + yycolumn = 0; + yychar = 0L; + } + + + /** + * Returns whether the scanner has reached the end of the reader it reads from. + * + * @return whether the scanner has reached EOF. + */ + public final boolean yyatEOF() { + return zzAtEOF; + } + + + /** + * Returns the current lexical state. + * + * @return the current lexical state. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state. + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + * + * @return the matched text. + */ + public final String yytext() { + return new String(zzBuffer, zzStartRead, zzMarkedPos-zzStartRead); + } + + + /** + * Returns the character at the given position from the matched text. + * + *

It is equivalent to {@code yytext().charAt(pos)}, but faster. + * + * @param position the position of the character to fetch. A value from 0 to {@code yylength()-1}. + * + * @return the character at {@code position}. + */ + public final char yycharat(int position) { + return zzBuffer[zzStartRead + position]; + } + + + /** + * How many characters were matched. + * + * @return the length of the matched text region. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occurred while scanning. + * + *

In a well-formed scanner (no or only correct usage of {@code yypushback(int)} and a + * match-all fallback rule) this method will only be called with things that + * "Can't Possibly Happen". + * + *

If this method is called, something is seriously wrong (e.g. a JFlex bug producing a faulty + * scanner etc.). + * + *

Usual syntax/scanner level error handling should be done in error fallback rules. + * + * @param errorCode the code of the error message to display. + */ + private static void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + *

They will be read again by then next call of the scanning method. + * + * @param number the number of characters to be read again. This number must not be greater than + * {@link #yylength()}. + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + + + /** + * Resumes scanning until the next regular expression is matched, the end of input is encountered + * or an I/O-Error occurs. + * + * @return the next token. + * @exception java.io.IOException if any I/O-Error occurs. + */ + @Override public java_cup.runtime.Symbol next_token() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + char[] zzBufferL = zzBuffer; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + boolean zzR = false; + int zzCh; + int zzCharCount; + for (zzCurrentPosL = zzStartRead ; + zzCurrentPosL < zzMarkedPosL ; + zzCurrentPosL += zzCharCount ) { + zzCh = Character.codePointAt(zzBufferL, zzCurrentPosL, zzMarkedPosL); + zzCharCount = Character.charCount(zzCh); + switch (zzCh) { + case '\u000B': // fall through + case '\u000C': // fall through + case '\u0085': // fall through + case '\u2028': // fall through + case '\u2029': + yyline++; + yycolumn = 0; + zzR = false; + break; + case '\r': + yyline++; + yycolumn = 0; + zzR = true; + break; + case '\n': + if (zzR) + zzR = false; + else { + yyline++; + yycolumn = 0; + } + break; + default: + zzR = false; + yycolumn += zzCharCount; + } + } + + if (zzR) { + // peek one character ahead if it is + // (if we have counted one line too much) + boolean zzPeek; + if (zzMarkedPosL < zzEndReadL) + zzPeek = zzBufferL[zzMarkedPosL] == '\n'; + else if (zzAtEOF) + zzPeek = false; + else { + boolean eof = zzRefill(); + zzEndReadL = zzEndRead; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + if (eof) + zzPeek = false; + else + zzPeek = zzBufferL[zzMarkedPosL] == '\n'; + } + if (zzPeek) yyline--; + } + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = ZZ_LEXSTATE[zzLexicalState]; + + // set up zzAction for empty match case: + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + } + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) { + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL); + zzCurrentPosL += Character.charCount(zzInput); + } + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL); + zzCurrentPosL += Character.charCount(zzInput); + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMap(zzInput) ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + { + return symbol(ChocoPyTokens.EOF); + } + } + else { + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 1: + { yypushback(1); + if(top() > currIndent) + { + pop(); + return symbol(ChocoPyTokens.DEDENT); + } + yystart(AFTER); + if(top()< currIndent) + { + push(currIndent); + return symbol(ChocoPyTokens.INDENT); + } + } + // fall through + case 65: break; + case 2: + { String space = yytext(); + if(space == "\t") + currIndent += 8; + else + currIndent ++; + } + // fall through + case 66: break; + case 3: + { currIndent = 0; + } + // fall through + case 67: break; + case 4: + { /* ignored */ + } + // fall through + case 68: break; + case 5: + { return symbol(ChocoPyTokens.UNRECOGNIZED); + } + // fall through + case 69: break; + case 6: + { /* ignore */ + } + // fall through + case 70: break; + case 7: + { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0; + } + // fall through + case 71: break; + case 8: + { return symbol(ChocoPyTokens.MOD); + } + // fall through + case 72: break; + case 9: + { return symbol(ChocoPyTokens.LPAR); + } + // fall through + case 73: break; + case 10: + { return symbol(ChocoPyTokens.RPAR); + } + // fall through + case 74: break; + case 11: + { return symbol(ChocoPyTokens.MUL); + } + // fall through + case 75: break; + case 12: + { return symbol(ChocoPyTokens.PLUS); + } + // fall through + case 76: break; + case 13: + { return symbol(ChocoPyTokens.COMMA); + } + // fall through + case 77: break; + case 14: + { return symbol(ChocoPyTokens.MINUS); + } + // fall through + case 78: break; + case 15: + { return symbol(ChocoPyTokens.DOT); + } + // fall through + case 79: break; + case 16: + { return symbol(ChocoPyTokens.DIV); + } + // fall through + case 80: break; + case 17: + { return symbol(ChocoPyTokens.NUMBER, + Integer.parseInt(yytext())); + } + // fall through + case 81: break; + case 18: + { return symbol(ChocoPyTokens.COLON); + } + // fall through + case 82: break; + case 19: + { return symbol(ChocoPyTokens.LT); + } + // fall through + case 83: break; + case 20: + { return symbol(ChocoPyTokens.ASSIGN); + } + // fall through + case 84: break; + case 21: + { return symbol(ChocoPyTokens.GT); + } + // fall through + case 85: break; + case 22: + { return symbol(ChocoPyTokens.NAMES, yytext()); + } + // fall through + case 86: break; + case 23: + { return symbol(ChocoPyTokens.LBR); + } + // fall through + case 87: break; + case 24: + { return symbol(ChocoPyTokens.RBR); + } + // fall through + case 88: break; + case 25: + { return symbol(ChocoPyTokens.NEQ); + } + // fall through + case 89: break; + case 26: + { return symbol(ChocoPyTokens.STRING, yytext()); + } + // fall through + case 90: break; + case 27: + { return symbol(ChocoPyTokens.ARROW); + } + // fall through + case 91: break; + case 28: + { return symbol(ChocoPyTokens.LEQ); + } + // fall through + case 92: break; + case 29: + { return symbol(ChocoPyTokens.EQUAL); + } + // fall through + case 93: break; + case 30: + { return symbol(ChocoPyTokens.GEQ); + } + // fall through + case 94: break; + case 31: + { return symbol(ChocoPyTokens.AS); + } + // fall through + case 95: break; + case 32: + { return symbol(ChocoPyTokens.IF); + } + // fall through + case 96: break; + case 33: + { return symbol(ChocoPyTokens.IN); + } + // fall through + case 97: break; + case 34: + { return symbol(ChocoPyTokens.IS); + } + // fall through + case 98: break; + case 35: + { return symbol(ChocoPyTokens.OR); + } + // fall through + case 99: break; + case 36: + { return symbol(ChocoPyTokens.AND); + } + // fall through + case 100: break; + case 37: + { return symbol(ChocoPyTokens.DEF); + } + // fall through + case 101: break; + case 38: + { return symbol(ChocoPyTokens.DEL); + } + // fall through + case 102: break; + case 39: + { return symbol(ChocoPyTokens.FOR); + } + // fall through + case 103: break; + case 40: + { return symbol(ChocoPyTokens.NOT); + } + // fall through + case 104: break; + case 41: + { return symbol(ChocoPyTokens.TRY); + } + // fall through + case 105: break; + case 42: + { return symbol(ChocoPyTokens.NONE); + } + // fall through + case 106: break; + case 43: + { return symbol(ChocoPyTokens.BOOL, true); + } + // fall through + case 107: break; + case 44: + { return symbol(ChocoPyTokens.ELIF); + } + // fall through + case 108: break; + case 45: + { return symbol(ChocoPyTokens.ELSE); + } + // fall through + case 109: break; + case 46: + { return symbol(ChocoPyTokens.FROM); + } + // fall through + case 110: break; + case 47: + { return symbol(ChocoPyTokens.PASS); + } + // fall through + case 111: break; + case 48: + { return symbol(ChocoPyTokens.WITH); + } + // fall through + case 112: break; + case 49: + { return symbol(ChocoPyTokens.BOOL, false); + } + // fall through + case 113: break; + case 50: + { return symbol(ChocoPyTokens.AWAIT); + } + // fall through + case 114: break; + case 51: + { return symbol(ChocoPyTokens.BREAK); + } + // fall through + case 115: break; + case 52: + { return symbol(ChocoPyTokens.CLASS); + } + // fall through + case 116: break; + case 53: + { return symbol(ChocoPyTokens.RAISE); + } + // fall through + case 117: break; + case 54: + { return symbol(ChocoPyTokens.WHILE); + } + // fall through + case 118: break; + case 55: + { return symbol(ChocoPyTokens.YIELD); + } + // fall through + case 119: break; + case 56: + { return symbol(ChocoPyTokens.ASSERT); + } + // fall through + case 120: break; + case 57: + { return symbol(ChocoPyTokens.EXCEPT); + } + // fall through + case 121: break; + case 58: + { return symbol(ChocoPyTokens.GLOBAL); + } + // fall through + case 122: break; + case 59: + { return symbol(ChocoPyTokens.IMPORT); + } + // fall through + case 123: break; + case 60: + { return symbol(ChocoPyTokens.LAMBDA); + } + // fall through + case 124: break; + case 61: + { return symbol(ChocoPyTokens.RETURN); + } + // fall through + case 125: break; + case 62: + { return symbol(ChocoPyTokens.FINALLY); + } + // fall through + case 126: break; + case 63: + { return symbol(ChocoPyTokens.CONTINUE); + } + // fall through + case 127: break; + case 64: + { return symbol(ChocoPyTokens.NONLOCAL); + } + // fall through + case 128: break; + default: + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + /** + * Converts an int token code into the name of the + * token by reflection on the cup symbol class/interface ChocoPyTokens + */ + private static String getTokenName(int token) { + try { + java.lang.reflect.Field [] classFields = ChocoPyTokens.class.getFields(); + for (int i = 0; i < classFields.length; i++) { + if (classFields[i].getInt(null) == token) { + return classFields[i].getName(); + } + } + } catch (Exception e) { + e.printStackTrace(System.err); + } + + return "UNKNOWN TOKEN"; + } + + /** + * Same as next_token but also prints the token to standard out + * for debugging. + */ + public java_cup.runtime.Symbol debug_next_token() throws java.io.IOException { + java_cup.runtime.Symbol s = next_token(); + System.out.println( "line:" + (yyline+1) + " col:" + (yycolumn+1) + " --"+ yytext() + "--" + getTokenName(s.sym) + "--"); + return s; + } + + /** + * Runs the scanner on input files. + * + * This main method is the debugging routine for the scanner. + * It prints debugging information about each returned token to + * System.out until the end of file is reached, or an error occured. + * + * @param argv the command line, contains the filenames to run + * the scanner on. + */ + public static void main(String[] argv) { + if (argv.length == 0) { + System.out.println("Usage : java ChocoPyLexer [ --encoding ] "); + } + else { + int firstFilePos = 0; + String encodingName = "UTF-8"; + if (argv[0].equals("--encoding")) { + firstFilePos = 2; + encodingName = argv[1]; + try { + // Side-effect: is encodingName valid? + java.nio.charset.Charset.forName(encodingName); + } catch (Exception e) { + System.out.println("Invalid encoding '" + encodingName + "'"); + return; + } + } + for (int i = firstFilePos; i < argv.length; i++) { + ChocoPyLexer scanner = null; + try { + java.io.FileInputStream stream = new java.io.FileInputStream(argv[i]); + java.io.Reader reader = new java.io.InputStreamReader(stream, encodingName); + scanner = new ChocoPyLexer(reader); + while ( !scanner.zzAtEOF ) scanner.debug_next_token(); + } + catch (java.io.FileNotFoundException e) { + System.out.println("File not found : \""+argv[i]+"\""); + } + catch (java.io.IOException e) { + System.out.println("IO error scanning file \""+argv[i]+"\""); + System.out.println(e); + } + catch (Exception e) { + System.out.println("Unexpected exception:"); + e.printStackTrace(); + } + } + } + } + + +} From 03c393beffece8981dd4658243d8998344cf518e Mon Sep 17 00:00:00 2001 From: bill Date: Wed, 17 Feb 2021 21:14:23 +0800 Subject: [PATCH 03/67] Changed how we deal w/ StringLiterals across multiple lines --- src/main/cup/chocopy/pa1/ChocoPy.cup | 4 ++-- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index 0bc9dd6..0585cf7 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -145,8 +145,8 @@ action code {: terminal NEWLINE; terminal String PLUS; terminal String MINUS; -terminal String MULTIPLY; -terminal String DIVIDE; +terminal String MUL; +terminal String DIV; terminal String NAMES; terminal Integer NUMBER; diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index e90072a..ebcec10 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -8,7 +8,7 @@ import java.util.ArrayList; %unicode %line %column -%states AFTER +%states AFTER, STR %class ChocoPyLexer %public @@ -33,6 +33,7 @@ import java.util.ArrayList; /** Producer of token-related values for the parser. */ final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); private int currIndent = 0; + private int currString = ""; private ArrayList stack = new ArrayList(20); /** Return a terminal symbol of syntactic category TYPE and no * semantic value at the current source location. */ @@ -67,7 +68,7 @@ WhiteSpace = [ \t] LineBreak = \r|\n|\r\n IntegerLiteral = 0|[1-9][0-9]* -StringLiteral = \"([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))*\" +StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))* Names = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z])* Comments = #[^\r\n]* %% @@ -112,7 +113,8 @@ Comments = #[^\r\n]* /* Literals. */ {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } - {StringLiteral} { return symbol(ChocoPyTokens.STRING, yytext());} +// {StringLiteral} { return symbol(ChocoPyTokens.STRING, yytext());} + "\"" {yystart(STR); currString = "";} "False" { return symbol(ChocoPyTokens.BOOL, false); } "True" { return symbol(ChocoPyTokens.BOOL, true); } "None" { return symbol(ChocoPyTokens.NONE); } @@ -180,7 +182,10 @@ Comments = #[^\r\n]* /* Comment. */ {Comments} { /* ignore */ } } - +{ + {StringLiteral} {currString+=yytext();} + "\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} +} <> { return symbol(ChocoPyTokens.EOF); } /* Error fallback. */ From b6f7943d483de31a800fb124118cc8b26f558a32 Mon Sep 17 00:00:00 2001 From: bill Date: Wed, 17 Feb 2021 21:22:28 +0800 Subject: [PATCH 04/67] Deal w/ multi-line String Literals. --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 1 + src/main/jflex/chocopy/pa1/ChocoPyLexer.java | 567 ++++++++++--------- 2 files changed, 298 insertions(+), 270 deletions(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index ebcec10..d7640a7 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -184,6 +184,7 @@ Comments = #[^\r\n]* } { {StringLiteral} {currString+=yytext();} + \\$ { /*'\' at the end of line, do nothing.*/ } "\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} } <> { return symbol(ChocoPyTokens.EOF); } diff --git a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java index 2045209..ac26ed7 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java +++ b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java @@ -19,6 +19,7 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { // Lexical states. public static final int YYINITIAL = 0; public static final int AFTER = 2; + public static final int STR = 4; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l @@ -27,7 +28,7 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { * l is of the form l = 2*k, k a non negative integer */ private static final int ZZ_LEXSTATE[] = { - 0, 0, 1, 1 + 0, 0, 1, 1, 2, 2 }; /** @@ -36,7 +37,7 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top(); private static final String ZZ_CMAP_TOP_PACKED_0 = - "\1\0\u10ff\u0100"; + "\1\0\37\u0100\1\u0200\u10df\u0100"; private static int [] zzUnpackcmap_top() { int [] result = new int[4352]; @@ -64,18 +65,19 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); private static final String ZZ_CMAP_BLOCKS_PACKED_0 = - "\11\0\1\1\1\2\2\0\1\3\22\0\1\1\1\4"+ - "\1\5\1\6\1\0\1\7\2\0\1\10\1\11\1\12"+ - "\1\13\1\14\1\15\1\16\1\17\1\20\11\21\1\22"+ - "\1\0\1\23\1\24\1\25\2\0\5\26\1\27\7\26"+ - "\1\30\5\26\1\31\6\26\1\32\1\33\1\34\1\0"+ - "\1\26\1\0\1\35\1\36\1\37\1\40\1\41\1\42"+ - "\1\43\1\44\1\45\1\26\1\46\1\47\1\50\1\51"+ - "\1\52\1\53\1\26\1\54\1\55\1\56\1\57\1\26"+ - "\1\60\1\61\1\62\1\26\u0185\0"; + "\11\0\1\1\1\2\2\3\1\4\22\0\1\1\1\5"+ + "\1\6\1\7\1\0\1\10\2\0\1\11\1\12\1\13"+ + "\1\14\1\15\1\16\1\17\1\20\1\21\11\22\1\23"+ + "\1\0\1\24\1\25\1\26\2\0\5\27\1\30\7\27"+ + "\1\31\5\27\1\32\6\27\1\33\1\34\1\35\1\0"+ + "\1\27\1\0\1\36\1\37\1\40\1\41\1\42\1\43"+ + "\1\44\1\45\1\46\1\27\1\47\1\50\1\51\1\52"+ + "\1\53\1\54\1\27\1\55\1\56\1\57\1\60\1\27"+ + "\1\61\1\62\1\63\1\27\12\0\1\3\u01a2\0\2\3"+ + "\326\0"; private static int [] zzUnpackcmap_blocks() { - int [] result = new int[512]; + int [] result = new int[768]; int offset = 0; offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result); return result; @@ -99,21 +101,22 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\2\0\1\1\1\2\2\3\1\4\1\5\1\6\2\7"+ - "\2\5\1\6\1\10\1\11\1\12\1\13\1\14\1\15"+ - "\1\16\1\17\1\20\2\21\1\22\1\23\1\24\1\25"+ - "\4\26\1\27\1\30\20\26\1\31\1\0\1\32\1\0"+ - "\1\33\1\20\1\34\1\35\1\36\4\26\1\37\13\26"+ - "\1\40\1\26\1\41\1\42\2\26\1\43\12\26\1\44"+ - "\5\26\1\45\1\46\4\26\1\47\5\26\1\50\3\26"+ - "\1\51\4\26\1\52\1\53\5\26\1\54\1\55\2\26"+ - "\1\56\4\26\1\57\3\26\1\60\1\26\1\61\1\26"+ - "\1\62\1\63\1\64\7\26\1\65\1\26\1\66\1\67"+ - "\1\70\1\26\1\71\1\26\1\72\1\73\1\74\1\26"+ - "\1\75\1\26\1\76\1\26\1\77\1\100"; + "\2\0\1\1\1\2\1\3\2\4\1\5\1\6\1\7"+ + "\2\10\1\6\1\11\1\7\1\12\1\13\1\14\1\15"+ + "\1\16\1\17\1\20\1\21\1\22\2\23\1\24\1\25"+ + "\1\26\1\27\4\30\1\31\1\32\20\30\1\1\1\33"+ + "\1\6\1\34\1\35\1\22\1\36\1\37\1\40\4\30"+ + "\1\41\13\30\1\42\1\30\1\43\1\44\2\30\1\45"+ + "\7\30\1\0\2\46\3\30\1\47\5\30\1\50\1\51"+ + "\4\30\1\52\5\30\1\53\3\30\1\54\4\30\1\55"+ + "\1\56\5\30\1\57\1\60\2\30\1\61\4\30\1\62"+ + "\3\30\1\63\1\30\1\64\1\30\1\65\1\66\1\67"+ + "\7\30\1\70\1\30\1\71\1\72\1\73\1\30\1\74"+ + "\1\30\1\75\1\76\1\77\1\30\1\100\1\30\1\101"+ + "\1\30\1\102\1\103"; private static int [] zzUnpackAction() { - int [] result = new int[172]; + int [] result = new int[176]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -138,31 +141,31 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\63\0\146\0\146\0\146\0\231\0\314\0\146"+ - "\0\146\0\146\0\377\0\u0132\0\u0165\0\u0198\0\146\0\146"+ - "\0\146\0\146\0\146\0\146\0\u01cb\0\146\0\u01fe\0\146"+ - "\0\u0231\0\146\0\u0264\0\u0297\0\u02ca\0\u02fd\0\u0330\0\u0363"+ - "\0\u0396\0\146\0\146\0\u03c9\0\u03fc\0\u042f\0\u0462\0\u0495"+ - "\0\u04c8\0\u04fb\0\u052e\0\u0561\0\u0594\0\u05c7\0\u05fa\0\u062d"+ - "\0\u0660\0\u0693\0\u06c6\0\146\0\u0165\0\146\0\u06f9\0\146"+ - "\0\146\0\146\0\146\0\146\0\u072c\0\u075f\0\u0792\0\u07c5"+ - "\0\u07f8\0\u082b\0\u085e\0\u0891\0\u08c4\0\u08f7\0\u092a\0\u095d"+ - "\0\u0990\0\u09c3\0\u09f6\0\u0a29\0\u02fd\0\u0a5c\0\u02fd\0\u02fd"+ - "\0\u0a8f\0\u0ac2\0\u02fd\0\u0af5\0\u0b28\0\u0b5b\0\u0b8e\0\u0bc1"+ - "\0\u0bf4\0\u0c27\0\u0c5a\0\u0c8d\0\u0cc0\0\u02fd\0\u0cf3\0\u0d26"+ - "\0\u0d59\0\u0d8c\0\u0dbf\0\u02fd\0\u02fd\0\u0df2\0\u0e25\0\u0e58"+ - "\0\u0e8b\0\u02fd\0\u0ebe\0\u0ef1\0\u0f24\0\u0f57\0\u0f8a\0\u02fd"+ - "\0\u0fbd\0\u0ff0\0\u1023\0\u02fd\0\u1056\0\u1089\0\u10bc\0\u10ef"+ - "\0\u02fd\0\u02fd\0\u1122\0\u1155\0\u1188\0\u11bb\0\u11ee\0\u02fd"+ - "\0\u02fd\0\u1221\0\u1254\0\u02fd\0\u1287\0\u12ba\0\u12ed\0\u1320"+ - "\0\u02fd\0\u1353\0\u1386\0\u13b9\0\u02fd\0\u13ec\0\u02fd\0\u141f"+ - "\0\u02fd\0\u02fd\0\u02fd\0\u1452\0\u1485\0\u14b8\0\u14eb\0\u151e"+ - "\0\u1551\0\u1584\0\u02fd\0\u15b7\0\u02fd\0\u02fd\0\u02fd\0\u15ea"+ - "\0\u02fd\0\u161d\0\u02fd\0\u02fd\0\u02fd\0\u1650\0\u02fd\0\u1683"+ - "\0\u02fd\0\u16b6\0\u02fd\0\u02fd"; + "\0\0\0\64\0\150\0\234\0\234\0\234\0\320\0\u0104"+ + "\0\234\0\234\0\234\0\u0138\0\u016c\0\234\0\u01a0\0\234"+ + "\0\234\0\234\0\234\0\234\0\234\0\u01d4\0\234\0\u0208"+ + "\0\234\0\u023c\0\234\0\u0270\0\u02a4\0\u02d8\0\u030c\0\u0340"+ + "\0\u0374\0\u03a8\0\234\0\234\0\u03dc\0\u0410\0\u0444\0\u0478"+ + "\0\u04ac\0\u04e0\0\u0514\0\u0548\0\u057c\0\u05b0\0\u05e4\0\u0618"+ + "\0\u064c\0\u0680\0\u06b4\0\u06e8\0\u071c\0\234\0\u0750\0\234"+ + "\0\234\0\234\0\234\0\234\0\234\0\u0784\0\u07b8\0\u07ec"+ + "\0\u0820\0\u0854\0\u0888\0\u08bc\0\u08f0\0\u0924\0\u0958\0\u098c"+ + "\0\u09c0\0\u09f4\0\u0a28\0\u0a5c\0\u0a90\0\u030c\0\u0ac4\0\u030c"+ + "\0\u030c\0\u0af8\0\u0b2c\0\u030c\0\u0b60\0\u0b94\0\u0bc8\0\u0bfc"+ + "\0\u0c30\0\u0c64\0\u0c98\0\u0ccc\0\234\0\u0d00\0\u0d34\0\u0d68"+ + "\0\u0d9c\0\u030c\0\u0dd0\0\u0e04\0\u0e38\0\u0e6c\0\u0ea0\0\u030c"+ + "\0\u030c\0\u0ed4\0\u0f08\0\u0f3c\0\u0f70\0\u030c\0\u0fa4\0\u0fd8"+ + "\0\u100c\0\u1040\0\u1074\0\u030c\0\u10a8\0\u10dc\0\u1110\0\u030c"+ + "\0\u1144\0\u1178\0\u11ac\0\u11e0\0\u030c\0\u030c\0\u1214\0\u1248"+ + "\0\u127c\0\u12b0\0\u12e4\0\u030c\0\u030c\0\u1318\0\u134c\0\u030c"+ + "\0\u1380\0\u13b4\0\u13e8\0\u141c\0\u030c\0\u1450\0\u1484\0\u14b8"+ + "\0\u030c\0\u14ec\0\u030c\0\u1520\0\u030c\0\u030c\0\u030c\0\u1554"+ + "\0\u1588\0\u15bc\0\u15f0\0\u1624\0\u1658\0\u168c\0\u030c\0\u16c0"+ + "\0\u030c\0\u030c\0\u030c\0\u16f4\0\u030c\0\u1728\0\u030c\0\u030c"+ + "\0\u030c\0\u175c\0\u030c\0\u1790\0\u030c\0\u17c4\0\u030c\0\u030c"; private static int [] zzUnpackRowMap() { - int [] result = new int[172]; + int [] result = new int[176]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -185,97 +188,101 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\1\3\1\4\1\5\1\6\2\3\1\7\54\3\1\10"+ - "\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1\20"+ - "\1\21\1\22\1\23\1\24\1\25\1\26\1\27\1\30"+ - "\1\31\1\32\1\33\1\34\1\35\1\36\1\37\1\40"+ - "\1\41\1\42\1\10\1\43\1\44\1\45\1\46\1\47"+ - "\1\50\1\51\1\52\1\36\1\53\1\36\1\54\1\36"+ - "\1\55\1\56\1\57\1\60\1\36\1\61\1\36\1\62"+ - "\1\36\1\63\65\0\1\5\60\0\2\7\2\0\57\7"+ - "\2\0\1\12\104\0\1\64\36\0\5\65\1\66\25\65"+ - "\1\67\27\65\2\16\2\0\57\16\25\0\1\70\54\0"+ - "\1\71\63\0\2\31\65\0\1\72\62\0\1\73\62\0"+ - "\1\74\64\0\4\36\3\0\26\36\26\0\4\36\3\0"+ - "\1\75\25\36\26\0\4\36\3\0\15\36\1\76\10\36"+ - "\26\0\4\36\3\0\17\36\1\77\6\36\26\0\4\36"+ - "\3\0\14\36\1\100\3\36\1\101\2\36\1\102\2\36"+ - "\26\0\4\36\3\0\17\36\1\103\6\36\26\0\4\36"+ - "\3\0\12\36\1\104\2\36\1\105\10\36\26\0\4\36"+ - "\3\0\4\36\1\106\21\36\26\0\4\36\3\0\12\36"+ - "\1\107\11\36\1\110\1\36\26\0\4\36\3\0\10\36"+ - "\1\111\4\36\1\112\1\36\1\113\6\36\26\0\4\36"+ - "\3\0\12\36\1\114\13\36\26\0\4\36\3\0\5\36"+ - "\1\115\5\36\1\116\1\117\3\36\1\120\5\36\26\0"+ - "\4\36\3\0\1\121\25\36\26\0\4\36\3\0\15\36"+ - "\1\122\10\36\26\0\4\36\3\0\17\36\1\123\6\36"+ - "\26\0\4\36\3\0\1\124\25\36\26\0\4\36\3\0"+ - "\1\125\3\36\1\126\21\36\26\0\4\36\3\0\17\36"+ - "\1\127\6\36\26\0\4\36\3\0\7\36\1\130\1\131"+ - "\15\36\26\0\4\36\3\0\10\36\1\132\15\36\5\0"+ - "\1\65\25\0\1\65\15\0\1\65\2\0\1\65\1\0"+ - "\1\65\32\0\4\36\3\0\12\36\1\133\13\36\26\0"+ - "\4\36\3\0\14\36\1\134\11\36\26\0\4\36\3\0"+ - "\22\36\1\135\3\36\26\0\4\36\3\0\3\36\1\136"+ - "\22\36\26\0\4\36\3\0\20\36\1\137\5\36\26\0"+ - "\4\36\3\0\1\140\25\36\26\0\4\36\3\0\4\36"+ - "\1\141\21\36\26\0\4\36\3\0\1\142\25\36\26\0"+ - "\4\36\3\0\14\36\1\143\11\36\26\0\4\36\3\0"+ - "\5\36\1\144\4\36\1\145\13\36\26\0\4\36\3\0"+ - "\10\36\1\146\7\36\1\147\5\36\26\0\4\36\3\0"+ - "\2\36\1\150\23\36\26\0\4\36\3\0\14\36\1\151"+ - "\11\36\26\0\4\36\3\0\17\36\1\152\6\36\26\0"+ - "\4\36\3\0\15\36\1\153\10\36\26\0\4\36\3\0"+ - "\15\36\1\154\10\36\26\0\4\36\3\0\16\36\1\155"+ - "\7\36\26\0\4\36\3\0\13\36\1\156\12\36\26\0"+ - "\4\36\3\0\14\36\1\157\4\36\1\160\4\36\26\0"+ - "\4\36\3\0\20\36\1\161\5\36\26\0\4\36\3\0"+ - "\10\36\1\162\15\36\26\0\4\36\3\0\21\36\1\163"+ - "\4\36\26\0\4\36\3\0\25\36\1\164\26\0\4\36"+ - "\3\0\10\36\1\165\15\36\26\0\4\36\3\0\21\36"+ - "\1\166\4\36\26\0\4\36\3\0\4\36\1\167\21\36"+ - "\26\0\4\36\3\0\20\36\1\170\5\36\26\0\4\36"+ - "\3\0\4\36\1\171\21\36\26\0\4\36\3\0\4\36"+ - "\1\172\21\36\26\0\4\36\3\0\4\36\1\173\21\36"+ - "\26\0\4\36\3\0\10\36\1\174\15\36\26\0\4\36"+ - "\3\0\1\175\25\36\26\0\4\36\3\0\20\36\1\176"+ - "\5\36\26\0\4\36\3\0\21\36\1\177\4\36\26\0"+ - "\4\36\3\0\5\36\1\200\20\36\26\0\4\36\3\0"+ - "\4\36\1\201\21\36\26\0\4\36\3\0\4\36\1\202"+ - "\21\36\26\0\4\36\3\0\1\203\25\36\26\0\4\36"+ - "\3\0\13\36\1\204\12\36\26\0\4\36\3\0\1\36"+ - "\1\205\24\36\26\0\4\36\3\0\15\36\1\206\10\36"+ - "\26\0\4\36\3\0\1\36\1\207\24\36\26\0\4\36"+ - "\3\0\12\36\1\210\13\36\26\0\4\36\3\0\20\36"+ - "\1\211\5\36\26\0\4\36\3\0\20\36\1\212\5\36"+ - "\26\0\4\36\3\0\22\36\1\213\3\36\26\0\4\36"+ - "\3\0\12\36\1\214\13\36\26\0\4\36\3\0\7\36"+ - "\1\215\16\36\26\0\4\36\3\0\12\36\1\216\13\36"+ - "\26\0\4\36\3\0\4\36\1\217\21\36\26\0\4\36"+ - "\3\0\17\36\1\220\6\36\26\0\4\36\3\0\21\36"+ - "\1\221\4\36\26\0\4\36\3\0\11\36\1\222\14\36"+ - "\26\0\4\36\3\0\20\36\1\223\5\36\26\0\4\36"+ - "\3\0\10\36\1\224\15\36\26\0\4\36\3\0\16\36"+ - "\1\225\7\36\26\0\4\36\3\0\12\36\1\226\13\36"+ - "\26\0\4\36\3\0\1\227\25\36\26\0\4\36\3\0"+ - "\17\36\1\230\6\36\26\0\4\36\3\0\3\36\1\231"+ - "\22\36\26\0\4\36\3\0\15\36\1\232\10\36\26\0"+ - "\4\36\3\0\4\36\1\233\21\36\26\0\4\36\3\0"+ - "\17\36\1\234\6\36\26\0\4\36\3\0\4\36\1\235"+ - "\21\36\26\0\4\36\3\0\3\36\1\236\22\36\26\0"+ - "\4\36\3\0\21\36\1\237\4\36\26\0\4\36\3\0"+ - "\14\36\1\240\11\36\26\0\4\36\3\0\21\36\1\241"+ - "\4\36\26\0\4\36\3\0\12\36\1\242\13\36\26\0"+ - "\4\36\3\0\12\36\1\243\13\36\26\0\4\36\3\0"+ - "\21\36\1\244\4\36\26\0\4\36\3\0\1\245\25\36"+ - "\26\0\4\36\3\0\2\36\1\246\23\36\26\0\4\36"+ - "\3\0\14\36\1\247\11\36\26\0\4\36\3\0\22\36"+ - "\1\250\3\36\26\0\4\36\3\0\25\36\1\251\26\0"+ - "\4\36\3\0\1\252\25\36\26\0\4\36\3\0\4\36"+ - "\1\253\21\36\26\0\4\36\3\0\12\36\1\254\13\36"; + "\1\4\1\5\1\6\1\4\1\7\2\4\1\10\54\4"+ + "\1\11\1\12\1\13\1\11\1\14\1\15\1\16\1\17"+ + "\1\20\1\21\1\22\1\23\1\24\1\25\1\26\1\27"+ + "\1\30\1\31\1\32\1\33\1\34\1\35\1\36\1\37"+ + "\1\40\1\41\1\42\1\43\1\11\1\44\1\45\1\46"+ + "\1\47\1\50\1\51\1\52\1\53\1\37\1\54\1\37"+ + "\1\55\1\37\1\56\1\57\1\60\1\61\1\37\1\62"+ + "\1\37\1\63\1\37\1\64\6\65\1\66\25\65\1\67"+ + "\27\65\66\0\1\6\61\0\2\10\1\0\1\10\1\0"+ + "\57\10\2\0\1\13\106\0\1\70\36\0\2\17\1\0"+ + "\1\17\1\0\57\17\26\0\1\71\55\0\1\72\64\0"+ + "\2\32\66\0\1\73\63\0\1\74\63\0\1\75\65\0"+ + "\4\37\3\0\26\37\27\0\4\37\3\0\1\76\25\37"+ + "\27\0\4\37\3\0\15\37\1\77\10\37\27\0\4\37"+ + "\3\0\17\37\1\100\6\37\27\0\4\37\3\0\14\37"+ + "\1\101\3\37\1\102\2\37\1\103\2\37\27\0\4\37"+ + "\3\0\17\37\1\104\6\37\27\0\4\37\3\0\12\37"+ + "\1\105\2\37\1\106\10\37\27\0\4\37\3\0\4\37"+ + "\1\107\21\37\27\0\4\37\3\0\12\37\1\110\11\37"+ + "\1\111\1\37\27\0\4\37\3\0\10\37\1\112\4\37"+ + "\1\113\1\37\1\114\6\37\27\0\4\37\3\0\12\37"+ + "\1\115\13\37\27\0\4\37\3\0\5\37\1\116\5\37"+ + "\1\117\1\120\3\37\1\121\5\37\27\0\4\37\3\0"+ + "\1\122\25\37\27\0\4\37\3\0\15\37\1\123\10\37"+ + "\27\0\4\37\3\0\17\37\1\124\6\37\27\0\4\37"+ + "\3\0\1\125\25\37\27\0\4\37\3\0\1\126\3\37"+ + "\1\127\21\37\27\0\4\37\3\0\17\37\1\130\6\37"+ + "\27\0\4\37\3\0\7\37\1\131\1\132\15\37\27\0"+ + "\4\37\3\0\10\37\1\133\15\37\6\65\1\0\25\65"+ + "\1\134\27\65\2\0\2\135\1\136\1\0\1\65\25\0"+ + "\1\65\15\0\1\65\2\0\1\65\1\0\1\65\33\0"+ + "\4\37\3\0\12\37\1\137\13\37\27\0\4\37\3\0"+ + "\14\37\1\140\11\37\27\0\4\37\3\0\22\37\1\141"+ + "\3\37\27\0\4\37\3\0\3\37\1\142\22\37\27\0"+ + "\4\37\3\0\20\37\1\143\5\37\27\0\4\37\3\0"+ + "\1\144\25\37\27\0\4\37\3\0\4\37\1\145\21\37"+ + "\27\0\4\37\3\0\1\146\25\37\27\0\4\37\3\0"+ + "\14\37\1\147\11\37\27\0\4\37\3\0\5\37\1\150"+ + "\4\37\1\151\13\37\27\0\4\37\3\0\10\37\1\152"+ + "\7\37\1\153\5\37\27\0\4\37\3\0\2\37\1\154"+ + "\23\37\27\0\4\37\3\0\14\37\1\155\11\37\27\0"+ + "\4\37\3\0\17\37\1\156\6\37\27\0\4\37\3\0"+ + "\15\37\1\157\10\37\27\0\4\37\3\0\15\37\1\160"+ + "\10\37\27\0\4\37\3\0\16\37\1\161\7\37\27\0"+ + "\4\37\3\0\13\37\1\162\12\37\27\0\4\37\3\0"+ + "\14\37\1\163\4\37\1\164\4\37\27\0\4\37\3\0"+ + "\20\37\1\165\5\37\27\0\4\37\3\0\10\37\1\166"+ + "\15\37\27\0\4\37\3\0\21\37\1\167\4\37\27\0"+ + "\4\37\3\0\25\37\1\170\27\0\4\37\3\0\10\37"+ + "\1\171\15\37\27\0\4\37\3\0\21\37\1\172\4\37"+ + "\27\0\4\37\3\0\4\37\1\173\21\37\6\0\1\65"+ + "\25\0\1\65\15\0\1\65\2\0\1\65\1\0\1\65"+ + "\6\0\1\135\110\0\4\37\3\0\20\37\1\174\5\37"+ + "\27\0\4\37\3\0\4\37\1\175\21\37\27\0\4\37"+ + "\3\0\4\37\1\176\21\37\27\0\4\37\3\0\4\37"+ + "\1\177\21\37\27\0\4\37\3\0\10\37\1\200\15\37"+ + "\27\0\4\37\3\0\1\201\25\37\27\0\4\37\3\0"+ + "\20\37\1\202\5\37\27\0\4\37\3\0\21\37\1\203"+ + "\4\37\27\0\4\37\3\0\5\37\1\204\20\37\27\0"+ + "\4\37\3\0\4\37\1\205\21\37\27\0\4\37\3\0"+ + "\4\37\1\206\21\37\27\0\4\37\3\0\1\207\25\37"+ + "\27\0\4\37\3\0\13\37\1\210\12\37\27\0\4\37"+ + "\3\0\1\37\1\211\24\37\27\0\4\37\3\0\15\37"+ + "\1\212\10\37\27\0\4\37\3\0\1\37\1\213\24\37"+ + "\27\0\4\37\3\0\12\37\1\214\13\37\27\0\4\37"+ + "\3\0\20\37\1\215\5\37\27\0\4\37\3\0\20\37"+ + "\1\216\5\37\27\0\4\37\3\0\22\37\1\217\3\37"+ + "\27\0\4\37\3\0\12\37\1\220\13\37\27\0\4\37"+ + "\3\0\7\37\1\221\16\37\27\0\4\37\3\0\12\37"+ + "\1\222\13\37\27\0\4\37\3\0\4\37\1\223\21\37"+ + "\27\0\4\37\3\0\17\37\1\224\6\37\27\0\4\37"+ + "\3\0\21\37\1\225\4\37\27\0\4\37\3\0\11\37"+ + "\1\226\14\37\27\0\4\37\3\0\20\37\1\227\5\37"+ + "\27\0\4\37\3\0\10\37\1\230\15\37\27\0\4\37"+ + "\3\0\16\37\1\231\7\37\27\0\4\37\3\0\12\37"+ + "\1\232\13\37\27\0\4\37\3\0\1\233\25\37\27\0"+ + "\4\37\3\0\17\37\1\234\6\37\27\0\4\37\3\0"+ + "\3\37\1\235\22\37\27\0\4\37\3\0\15\37\1\236"+ + "\10\37\27\0\4\37\3\0\4\37\1\237\21\37\27\0"+ + "\4\37\3\0\17\37\1\240\6\37\27\0\4\37\3\0"+ + "\4\37\1\241\21\37\27\0\4\37\3\0\3\37\1\242"+ + "\22\37\27\0\4\37\3\0\21\37\1\243\4\37\27\0"+ + "\4\37\3\0\14\37\1\244\11\37\27\0\4\37\3\0"+ + "\21\37\1\245\4\37\27\0\4\37\3\0\12\37\1\246"+ + "\13\37\27\0\4\37\3\0\12\37\1\247\13\37\27\0"+ + "\4\37\3\0\21\37\1\250\4\37\27\0\4\37\3\0"+ + "\1\251\25\37\27\0\4\37\3\0\2\37\1\252\23\37"+ + "\27\0\4\37\3\0\14\37\1\253\11\37\27\0\4\37"+ + "\3\0\22\37\1\254\3\37\27\0\4\37\3\0\25\37"+ + "\1\255\27\0\4\37\3\0\1\256\25\37\27\0\4\37"+ + "\3\0\4\37\1\257\21\37\27\0\4\37\3\0\12\37"+ + "\1\260\13\37"; private static int [] zzUnpackTrans() { - int [] result = new int[5865]; + int [] result = new int[6136]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -318,12 +325,13 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\2\0\3\11\2\1\3\11\4\1\6\11\1\1\1\11"+ - "\1\1\1\11\1\1\1\11\7\1\2\11\20\1\1\11"+ - "\1\0\1\11\1\0\5\11\160\1"; + "\2\0\1\1\3\11\2\1\3\11\2\1\1\11\1\1"+ + "\6\11\1\1\1\11\1\1\1\11\1\1\1\11\7\1"+ + "\2\11\21\1\1\11\1\1\6\11\36\1\1\0\1\11"+ + "\123\1"; private static int [] zzUnpackAttribute() { - int [] result = new int[172]; + int [] result = new int[176]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -411,6 +419,7 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { /** Producer of token-related values for the parser. */ final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); private int currIndent = 0; + private int currString = ""; private ArrayList stack = new ArrayList(20); /** Return a terminal symbol of syntactic category TYPE and no * semantic value at the current source location. */ @@ -834,6 +843,11 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { else { switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { case 1: + { currString+=yytext(); + } + // fall through + case 68: break; + case 2: { yypushback(1); if(top() > currIndent) { @@ -848,8 +862,8 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { } } // fall through - case 65: break; - case 2: + case 69: break; + case 3: { String space = yytext(); if(space == "\t") currIndent += 8; @@ -857,318 +871,331 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { currIndent ++; } // fall through - case 66: break; - case 3: + case 70: break; + case 4: { currIndent = 0; } // fall through - case 67: break; - case 4: + case 71: break; + case 5: { /* ignored */ } // fall through - case 68: break; - case 5: + case 72: break; + case 6: { return symbol(ChocoPyTokens.UNRECOGNIZED); } // fall through - case 69: break; - case 6: + case 73: break; + case 7: { /* ignore */ } // fall through - case 70: break; - case 7: + case 74: break; + case 8: { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0; } // fall through - case 71: break; - case 8: + case 75: break; + case 9: + { yystart(STR); currString = ""; + } + // fall through + case 76: break; + case 10: { return symbol(ChocoPyTokens.MOD); } // fall through - case 72: break; - case 9: + case 77: break; + case 11: { return symbol(ChocoPyTokens.LPAR); } // fall through - case 73: break; - case 10: + case 78: break; + case 12: { return symbol(ChocoPyTokens.RPAR); } // fall through - case 74: break; - case 11: + case 79: break; + case 13: { return symbol(ChocoPyTokens.MUL); } // fall through - case 75: break; - case 12: + case 80: break; + case 14: { return symbol(ChocoPyTokens.PLUS); } // fall through - case 76: break; - case 13: + case 81: break; + case 15: { return symbol(ChocoPyTokens.COMMA); } // fall through - case 77: break; - case 14: + case 82: break; + case 16: { return symbol(ChocoPyTokens.MINUS); } // fall through - case 78: break; - case 15: + case 83: break; + case 17: { return symbol(ChocoPyTokens.DOT); } // fall through - case 79: break; - case 16: + case 84: break; + case 18: { return symbol(ChocoPyTokens.DIV); } // fall through - case 80: break; - case 17: + case 85: break; + case 19: { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } // fall through - case 81: break; - case 18: + case 86: break; + case 20: { return symbol(ChocoPyTokens.COLON); } // fall through - case 82: break; - case 19: + case 87: break; + case 21: { return symbol(ChocoPyTokens.LT); } // fall through - case 83: break; - case 20: + case 88: break; + case 22: { return symbol(ChocoPyTokens.ASSIGN); } // fall through - case 84: break; - case 21: + case 89: break; + case 23: { return symbol(ChocoPyTokens.GT); } // fall through - case 85: break; - case 22: + case 90: break; + case 24: { return symbol(ChocoPyTokens.NAMES, yytext()); } // fall through - case 86: break; - case 23: + case 91: break; + case 25: { return symbol(ChocoPyTokens.LBR); } // fall through - case 87: break; - case 24: + case 92: break; + case 26: { return symbol(ChocoPyTokens.RBR); } // fall through - case 88: break; - case 25: - { return symbol(ChocoPyTokens.NEQ); + case 93: break; + case 27: + { yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString); } // fall through - case 89: break; - case 26: - { return symbol(ChocoPyTokens.STRING, yytext()); + case 94: break; + case 28: + { return symbol(ChocoPyTokens.NEQ); } // fall through - case 90: break; - case 27: + case 95: break; + case 29: { return symbol(ChocoPyTokens.ARROW); } // fall through - case 91: break; - case 28: + case 96: break; + case 30: { return symbol(ChocoPyTokens.LEQ); } // fall through - case 92: break; - case 29: + case 97: break; + case 31: { return symbol(ChocoPyTokens.EQUAL); } // fall through - case 93: break; - case 30: + case 98: break; + case 32: { return symbol(ChocoPyTokens.GEQ); } // fall through - case 94: break; - case 31: + case 99: break; + case 33: { return symbol(ChocoPyTokens.AS); } // fall through - case 95: break; - case 32: + case 100: break; + case 34: { return symbol(ChocoPyTokens.IF); } // fall through - case 96: break; - case 33: + case 101: break; + case 35: { return symbol(ChocoPyTokens.IN); } // fall through - case 97: break; - case 34: + case 102: break; + case 36: { return symbol(ChocoPyTokens.IS); } // fall through - case 98: break; - case 35: + case 103: break; + case 37: { return symbol(ChocoPyTokens.OR); } // fall through - case 99: break; - case 36: + case 104: break; + case 38: + // lookahead expression with fixed base length + zzMarkedPos = Character.offsetByCodePoints + (zzBufferL, zzStartRead, zzEndRead - zzStartRead, zzStartRead, 1); + { /*'\' at the end of line, do nothing.*/ + } + // fall through + case 105: break; + case 39: { return symbol(ChocoPyTokens.AND); } // fall through - case 100: break; - case 37: + case 106: break; + case 40: { return symbol(ChocoPyTokens.DEF); } // fall through - case 101: break; - case 38: + case 107: break; + case 41: { return symbol(ChocoPyTokens.DEL); } // fall through - case 102: break; - case 39: + case 108: break; + case 42: { return symbol(ChocoPyTokens.FOR); } // fall through - case 103: break; - case 40: + case 109: break; + case 43: { return symbol(ChocoPyTokens.NOT); } // fall through - case 104: break; - case 41: + case 110: break; + case 44: { return symbol(ChocoPyTokens.TRY); } // fall through - case 105: break; - case 42: + case 111: break; + case 45: { return symbol(ChocoPyTokens.NONE); } // fall through - case 106: break; - case 43: + case 112: break; + case 46: { return symbol(ChocoPyTokens.BOOL, true); } // fall through - case 107: break; - case 44: + case 113: break; + case 47: { return symbol(ChocoPyTokens.ELIF); } // fall through - case 108: break; - case 45: + case 114: break; + case 48: { return symbol(ChocoPyTokens.ELSE); } // fall through - case 109: break; - case 46: + case 115: break; + case 49: { return symbol(ChocoPyTokens.FROM); } // fall through - case 110: break; - case 47: + case 116: break; + case 50: { return symbol(ChocoPyTokens.PASS); } // fall through - case 111: break; - case 48: + case 117: break; + case 51: { return symbol(ChocoPyTokens.WITH); } // fall through - case 112: break; - case 49: + case 118: break; + case 52: { return symbol(ChocoPyTokens.BOOL, false); } // fall through - case 113: break; - case 50: + case 119: break; + case 53: { return symbol(ChocoPyTokens.AWAIT); } // fall through - case 114: break; - case 51: + case 120: break; + case 54: { return symbol(ChocoPyTokens.BREAK); } // fall through - case 115: break; - case 52: + case 121: break; + case 55: { return symbol(ChocoPyTokens.CLASS); } // fall through - case 116: break; - case 53: + case 122: break; + case 56: { return symbol(ChocoPyTokens.RAISE); } // fall through - case 117: break; - case 54: + case 123: break; + case 57: { return symbol(ChocoPyTokens.WHILE); } // fall through - case 118: break; - case 55: + case 124: break; + case 58: { return symbol(ChocoPyTokens.YIELD); } // fall through - case 119: break; - case 56: + case 125: break; + case 59: { return symbol(ChocoPyTokens.ASSERT); } // fall through - case 120: break; - case 57: + case 126: break; + case 60: { return symbol(ChocoPyTokens.EXCEPT); } // fall through - case 121: break; - case 58: + case 127: break; + case 61: { return symbol(ChocoPyTokens.GLOBAL); } // fall through - case 122: break; - case 59: + case 128: break; + case 62: { return symbol(ChocoPyTokens.IMPORT); } // fall through - case 123: break; - case 60: + case 129: break; + case 63: { return symbol(ChocoPyTokens.LAMBDA); } // fall through - case 124: break; - case 61: + case 130: break; + case 64: { return symbol(ChocoPyTokens.RETURN); } // fall through - case 125: break; - case 62: + case 131: break; + case 65: { return symbol(ChocoPyTokens.FINALLY); } // fall through - case 126: break; - case 63: + case 132: break; + case 66: { return symbol(ChocoPyTokens.CONTINUE); } // fall through - case 127: break; - case 64: + case 133: break; + case 67: { return symbol(ChocoPyTokens.NONLOCAL); } // fall through - case 128: break; + case 134: break; default: zzScanError(ZZ_NO_MATCH); } From 7409d7e19ff5a5db8ddc93cabda54476b1fb3057 Mon Sep 17 00:00:00 2001 From: bill Date: Wed, 17 Feb 2021 23:14:46 +0800 Subject: [PATCH 05/67] Revert "Deal w/ multi-line String Literals." This reverts commit b6f7943d483de31a800fb124118cc8b26f558a32. --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 1 - src/main/jflex/chocopy/pa1/ChocoPyLexer.java | 567 +++++++++---------- 2 files changed, 270 insertions(+), 298 deletions(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index d7640a7..ebcec10 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -184,7 +184,6 @@ Comments = #[^\r\n]* } { {StringLiteral} {currString+=yytext();} - \\$ { /*'\' at the end of line, do nothing.*/ } "\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} } <> { return symbol(ChocoPyTokens.EOF); } diff --git a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java index ac26ed7..2045209 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java +++ b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java @@ -19,7 +19,6 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { // Lexical states. public static final int YYINITIAL = 0; public static final int AFTER = 2; - public static final int STR = 4; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l @@ -28,7 +27,7 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { * l is of the form l = 2*k, k a non negative integer */ private static final int ZZ_LEXSTATE[] = { - 0, 0, 1, 1, 2, 2 + 0, 0, 1, 1 }; /** @@ -37,7 +36,7 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top(); private static final String ZZ_CMAP_TOP_PACKED_0 = - "\1\0\37\u0100\1\u0200\u10df\u0100"; + "\1\0\u10ff\u0100"; private static int [] zzUnpackcmap_top() { int [] result = new int[4352]; @@ -65,19 +64,18 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); private static final String ZZ_CMAP_BLOCKS_PACKED_0 = - "\11\0\1\1\1\2\2\3\1\4\22\0\1\1\1\5"+ - "\1\6\1\7\1\0\1\10\2\0\1\11\1\12\1\13"+ - "\1\14\1\15\1\16\1\17\1\20\1\21\11\22\1\23"+ - "\1\0\1\24\1\25\1\26\2\0\5\27\1\30\7\27"+ - "\1\31\5\27\1\32\6\27\1\33\1\34\1\35\1\0"+ - "\1\27\1\0\1\36\1\37\1\40\1\41\1\42\1\43"+ - "\1\44\1\45\1\46\1\27\1\47\1\50\1\51\1\52"+ - "\1\53\1\54\1\27\1\55\1\56\1\57\1\60\1\27"+ - "\1\61\1\62\1\63\1\27\12\0\1\3\u01a2\0\2\3"+ - "\326\0"; + "\11\0\1\1\1\2\2\0\1\3\22\0\1\1\1\4"+ + "\1\5\1\6\1\0\1\7\2\0\1\10\1\11\1\12"+ + "\1\13\1\14\1\15\1\16\1\17\1\20\11\21\1\22"+ + "\1\0\1\23\1\24\1\25\2\0\5\26\1\27\7\26"+ + "\1\30\5\26\1\31\6\26\1\32\1\33\1\34\1\0"+ + "\1\26\1\0\1\35\1\36\1\37\1\40\1\41\1\42"+ + "\1\43\1\44\1\45\1\26\1\46\1\47\1\50\1\51"+ + "\1\52\1\53\1\26\1\54\1\55\1\56\1\57\1\26"+ + "\1\60\1\61\1\62\1\26\u0185\0"; private static int [] zzUnpackcmap_blocks() { - int [] result = new int[768]; + int [] result = new int[512]; int offset = 0; offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result); return result; @@ -101,22 +99,21 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\2\0\1\1\1\2\1\3\2\4\1\5\1\6\1\7"+ - "\2\10\1\6\1\11\1\7\1\12\1\13\1\14\1\15"+ - "\1\16\1\17\1\20\1\21\1\22\2\23\1\24\1\25"+ - "\1\26\1\27\4\30\1\31\1\32\20\30\1\1\1\33"+ - "\1\6\1\34\1\35\1\22\1\36\1\37\1\40\4\30"+ - "\1\41\13\30\1\42\1\30\1\43\1\44\2\30\1\45"+ - "\7\30\1\0\2\46\3\30\1\47\5\30\1\50\1\51"+ - "\4\30\1\52\5\30\1\53\3\30\1\54\4\30\1\55"+ - "\1\56\5\30\1\57\1\60\2\30\1\61\4\30\1\62"+ - "\3\30\1\63\1\30\1\64\1\30\1\65\1\66\1\67"+ - "\7\30\1\70\1\30\1\71\1\72\1\73\1\30\1\74"+ - "\1\30\1\75\1\76\1\77\1\30\1\100\1\30\1\101"+ - "\1\30\1\102\1\103"; + "\2\0\1\1\1\2\2\3\1\4\1\5\1\6\2\7"+ + "\2\5\1\6\1\10\1\11\1\12\1\13\1\14\1\15"+ + "\1\16\1\17\1\20\2\21\1\22\1\23\1\24\1\25"+ + "\4\26\1\27\1\30\20\26\1\31\1\0\1\32\1\0"+ + "\1\33\1\20\1\34\1\35\1\36\4\26\1\37\13\26"+ + "\1\40\1\26\1\41\1\42\2\26\1\43\12\26\1\44"+ + "\5\26\1\45\1\46\4\26\1\47\5\26\1\50\3\26"+ + "\1\51\4\26\1\52\1\53\5\26\1\54\1\55\2\26"+ + "\1\56\4\26\1\57\3\26\1\60\1\26\1\61\1\26"+ + "\1\62\1\63\1\64\7\26\1\65\1\26\1\66\1\67"+ + "\1\70\1\26\1\71\1\26\1\72\1\73\1\74\1\26"+ + "\1\75\1\26\1\76\1\26\1\77\1\100"; private static int [] zzUnpackAction() { - int [] result = new int[176]; + int [] result = new int[172]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -141,31 +138,31 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\64\0\150\0\234\0\234\0\234\0\320\0\u0104"+ - "\0\234\0\234\0\234\0\u0138\0\u016c\0\234\0\u01a0\0\234"+ - "\0\234\0\234\0\234\0\234\0\234\0\u01d4\0\234\0\u0208"+ - "\0\234\0\u023c\0\234\0\u0270\0\u02a4\0\u02d8\0\u030c\0\u0340"+ - "\0\u0374\0\u03a8\0\234\0\234\0\u03dc\0\u0410\0\u0444\0\u0478"+ - "\0\u04ac\0\u04e0\0\u0514\0\u0548\0\u057c\0\u05b0\0\u05e4\0\u0618"+ - "\0\u064c\0\u0680\0\u06b4\0\u06e8\0\u071c\0\234\0\u0750\0\234"+ - "\0\234\0\234\0\234\0\234\0\234\0\u0784\0\u07b8\0\u07ec"+ - "\0\u0820\0\u0854\0\u0888\0\u08bc\0\u08f0\0\u0924\0\u0958\0\u098c"+ - "\0\u09c0\0\u09f4\0\u0a28\0\u0a5c\0\u0a90\0\u030c\0\u0ac4\0\u030c"+ - "\0\u030c\0\u0af8\0\u0b2c\0\u030c\0\u0b60\0\u0b94\0\u0bc8\0\u0bfc"+ - "\0\u0c30\0\u0c64\0\u0c98\0\u0ccc\0\234\0\u0d00\0\u0d34\0\u0d68"+ - "\0\u0d9c\0\u030c\0\u0dd0\0\u0e04\0\u0e38\0\u0e6c\0\u0ea0\0\u030c"+ - "\0\u030c\0\u0ed4\0\u0f08\0\u0f3c\0\u0f70\0\u030c\0\u0fa4\0\u0fd8"+ - "\0\u100c\0\u1040\0\u1074\0\u030c\0\u10a8\0\u10dc\0\u1110\0\u030c"+ - "\0\u1144\0\u1178\0\u11ac\0\u11e0\0\u030c\0\u030c\0\u1214\0\u1248"+ - "\0\u127c\0\u12b0\0\u12e4\0\u030c\0\u030c\0\u1318\0\u134c\0\u030c"+ - "\0\u1380\0\u13b4\0\u13e8\0\u141c\0\u030c\0\u1450\0\u1484\0\u14b8"+ - "\0\u030c\0\u14ec\0\u030c\0\u1520\0\u030c\0\u030c\0\u030c\0\u1554"+ - "\0\u1588\0\u15bc\0\u15f0\0\u1624\0\u1658\0\u168c\0\u030c\0\u16c0"+ - "\0\u030c\0\u030c\0\u030c\0\u16f4\0\u030c\0\u1728\0\u030c\0\u030c"+ - "\0\u030c\0\u175c\0\u030c\0\u1790\0\u030c\0\u17c4\0\u030c\0\u030c"; + "\0\0\0\63\0\146\0\146\0\146\0\231\0\314\0\146"+ + "\0\146\0\146\0\377\0\u0132\0\u0165\0\u0198\0\146\0\146"+ + "\0\146\0\146\0\146\0\146\0\u01cb\0\146\0\u01fe\0\146"+ + "\0\u0231\0\146\0\u0264\0\u0297\0\u02ca\0\u02fd\0\u0330\0\u0363"+ + "\0\u0396\0\146\0\146\0\u03c9\0\u03fc\0\u042f\0\u0462\0\u0495"+ + "\0\u04c8\0\u04fb\0\u052e\0\u0561\0\u0594\0\u05c7\0\u05fa\0\u062d"+ + "\0\u0660\0\u0693\0\u06c6\0\146\0\u0165\0\146\0\u06f9\0\146"+ + "\0\146\0\146\0\146\0\146\0\u072c\0\u075f\0\u0792\0\u07c5"+ + "\0\u07f8\0\u082b\0\u085e\0\u0891\0\u08c4\0\u08f7\0\u092a\0\u095d"+ + "\0\u0990\0\u09c3\0\u09f6\0\u0a29\0\u02fd\0\u0a5c\0\u02fd\0\u02fd"+ + "\0\u0a8f\0\u0ac2\0\u02fd\0\u0af5\0\u0b28\0\u0b5b\0\u0b8e\0\u0bc1"+ + "\0\u0bf4\0\u0c27\0\u0c5a\0\u0c8d\0\u0cc0\0\u02fd\0\u0cf3\0\u0d26"+ + "\0\u0d59\0\u0d8c\0\u0dbf\0\u02fd\0\u02fd\0\u0df2\0\u0e25\0\u0e58"+ + "\0\u0e8b\0\u02fd\0\u0ebe\0\u0ef1\0\u0f24\0\u0f57\0\u0f8a\0\u02fd"+ + "\0\u0fbd\0\u0ff0\0\u1023\0\u02fd\0\u1056\0\u1089\0\u10bc\0\u10ef"+ + "\0\u02fd\0\u02fd\0\u1122\0\u1155\0\u1188\0\u11bb\0\u11ee\0\u02fd"+ + "\0\u02fd\0\u1221\0\u1254\0\u02fd\0\u1287\0\u12ba\0\u12ed\0\u1320"+ + "\0\u02fd\0\u1353\0\u1386\0\u13b9\0\u02fd\0\u13ec\0\u02fd\0\u141f"+ + "\0\u02fd\0\u02fd\0\u02fd\0\u1452\0\u1485\0\u14b8\0\u14eb\0\u151e"+ + "\0\u1551\0\u1584\0\u02fd\0\u15b7\0\u02fd\0\u02fd\0\u02fd\0\u15ea"+ + "\0\u02fd\0\u161d\0\u02fd\0\u02fd\0\u02fd\0\u1650\0\u02fd\0\u1683"+ + "\0\u02fd\0\u16b6\0\u02fd\0\u02fd"; private static int [] zzUnpackRowMap() { - int [] result = new int[176]; + int [] result = new int[172]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -188,101 +185,97 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\1\4\1\5\1\6\1\4\1\7\2\4\1\10\54\4"+ - "\1\11\1\12\1\13\1\11\1\14\1\15\1\16\1\17"+ - "\1\20\1\21\1\22\1\23\1\24\1\25\1\26\1\27"+ - "\1\30\1\31\1\32\1\33\1\34\1\35\1\36\1\37"+ - "\1\40\1\41\1\42\1\43\1\11\1\44\1\45\1\46"+ - "\1\47\1\50\1\51\1\52\1\53\1\37\1\54\1\37"+ - "\1\55\1\37\1\56\1\57\1\60\1\61\1\37\1\62"+ - "\1\37\1\63\1\37\1\64\6\65\1\66\25\65\1\67"+ - "\27\65\66\0\1\6\61\0\2\10\1\0\1\10\1\0"+ - "\57\10\2\0\1\13\106\0\1\70\36\0\2\17\1\0"+ - "\1\17\1\0\57\17\26\0\1\71\55\0\1\72\64\0"+ - "\2\32\66\0\1\73\63\0\1\74\63\0\1\75\65\0"+ - "\4\37\3\0\26\37\27\0\4\37\3\0\1\76\25\37"+ - "\27\0\4\37\3\0\15\37\1\77\10\37\27\0\4\37"+ - "\3\0\17\37\1\100\6\37\27\0\4\37\3\0\14\37"+ - "\1\101\3\37\1\102\2\37\1\103\2\37\27\0\4\37"+ - "\3\0\17\37\1\104\6\37\27\0\4\37\3\0\12\37"+ - "\1\105\2\37\1\106\10\37\27\0\4\37\3\0\4\37"+ - "\1\107\21\37\27\0\4\37\3\0\12\37\1\110\11\37"+ - "\1\111\1\37\27\0\4\37\3\0\10\37\1\112\4\37"+ - "\1\113\1\37\1\114\6\37\27\0\4\37\3\0\12\37"+ - "\1\115\13\37\27\0\4\37\3\0\5\37\1\116\5\37"+ - "\1\117\1\120\3\37\1\121\5\37\27\0\4\37\3\0"+ - "\1\122\25\37\27\0\4\37\3\0\15\37\1\123\10\37"+ - "\27\0\4\37\3\0\17\37\1\124\6\37\27\0\4\37"+ - "\3\0\1\125\25\37\27\0\4\37\3\0\1\126\3\37"+ - "\1\127\21\37\27\0\4\37\3\0\17\37\1\130\6\37"+ - "\27\0\4\37\3\0\7\37\1\131\1\132\15\37\27\0"+ - "\4\37\3\0\10\37\1\133\15\37\6\65\1\0\25\65"+ - "\1\134\27\65\2\0\2\135\1\136\1\0\1\65\25\0"+ - "\1\65\15\0\1\65\2\0\1\65\1\0\1\65\33\0"+ - "\4\37\3\0\12\37\1\137\13\37\27\0\4\37\3\0"+ - "\14\37\1\140\11\37\27\0\4\37\3\0\22\37\1\141"+ - "\3\37\27\0\4\37\3\0\3\37\1\142\22\37\27\0"+ - "\4\37\3\0\20\37\1\143\5\37\27\0\4\37\3\0"+ - "\1\144\25\37\27\0\4\37\3\0\4\37\1\145\21\37"+ - "\27\0\4\37\3\0\1\146\25\37\27\0\4\37\3\0"+ - "\14\37\1\147\11\37\27\0\4\37\3\0\5\37\1\150"+ - "\4\37\1\151\13\37\27\0\4\37\3\0\10\37\1\152"+ - "\7\37\1\153\5\37\27\0\4\37\3\0\2\37\1\154"+ - "\23\37\27\0\4\37\3\0\14\37\1\155\11\37\27\0"+ - "\4\37\3\0\17\37\1\156\6\37\27\0\4\37\3\0"+ - "\15\37\1\157\10\37\27\0\4\37\3\0\15\37\1\160"+ - "\10\37\27\0\4\37\3\0\16\37\1\161\7\37\27\0"+ - "\4\37\3\0\13\37\1\162\12\37\27\0\4\37\3\0"+ - "\14\37\1\163\4\37\1\164\4\37\27\0\4\37\3\0"+ - "\20\37\1\165\5\37\27\0\4\37\3\0\10\37\1\166"+ - "\15\37\27\0\4\37\3\0\21\37\1\167\4\37\27\0"+ - "\4\37\3\0\25\37\1\170\27\0\4\37\3\0\10\37"+ - "\1\171\15\37\27\0\4\37\3\0\21\37\1\172\4\37"+ - "\27\0\4\37\3\0\4\37\1\173\21\37\6\0\1\65"+ - "\25\0\1\65\15\0\1\65\2\0\1\65\1\0\1\65"+ - "\6\0\1\135\110\0\4\37\3\0\20\37\1\174\5\37"+ - "\27\0\4\37\3\0\4\37\1\175\21\37\27\0\4\37"+ - "\3\0\4\37\1\176\21\37\27\0\4\37\3\0\4\37"+ - "\1\177\21\37\27\0\4\37\3\0\10\37\1\200\15\37"+ - "\27\0\4\37\3\0\1\201\25\37\27\0\4\37\3\0"+ - "\20\37\1\202\5\37\27\0\4\37\3\0\21\37\1\203"+ - "\4\37\27\0\4\37\3\0\5\37\1\204\20\37\27\0"+ - "\4\37\3\0\4\37\1\205\21\37\27\0\4\37\3\0"+ - "\4\37\1\206\21\37\27\0\4\37\3\0\1\207\25\37"+ - "\27\0\4\37\3\0\13\37\1\210\12\37\27\0\4\37"+ - "\3\0\1\37\1\211\24\37\27\0\4\37\3\0\15\37"+ - "\1\212\10\37\27\0\4\37\3\0\1\37\1\213\24\37"+ - "\27\0\4\37\3\0\12\37\1\214\13\37\27\0\4\37"+ - "\3\0\20\37\1\215\5\37\27\0\4\37\3\0\20\37"+ - "\1\216\5\37\27\0\4\37\3\0\22\37\1\217\3\37"+ - "\27\0\4\37\3\0\12\37\1\220\13\37\27\0\4\37"+ - "\3\0\7\37\1\221\16\37\27\0\4\37\3\0\12\37"+ - "\1\222\13\37\27\0\4\37\3\0\4\37\1\223\21\37"+ - "\27\0\4\37\3\0\17\37\1\224\6\37\27\0\4\37"+ - "\3\0\21\37\1\225\4\37\27\0\4\37\3\0\11\37"+ - "\1\226\14\37\27\0\4\37\3\0\20\37\1\227\5\37"+ - "\27\0\4\37\3\0\10\37\1\230\15\37\27\0\4\37"+ - "\3\0\16\37\1\231\7\37\27\0\4\37\3\0\12\37"+ - "\1\232\13\37\27\0\4\37\3\0\1\233\25\37\27\0"+ - "\4\37\3\0\17\37\1\234\6\37\27\0\4\37\3\0"+ - "\3\37\1\235\22\37\27\0\4\37\3\0\15\37\1\236"+ - "\10\37\27\0\4\37\3\0\4\37\1\237\21\37\27\0"+ - "\4\37\3\0\17\37\1\240\6\37\27\0\4\37\3\0"+ - "\4\37\1\241\21\37\27\0\4\37\3\0\3\37\1\242"+ - "\22\37\27\0\4\37\3\0\21\37\1\243\4\37\27\0"+ - "\4\37\3\0\14\37\1\244\11\37\27\0\4\37\3\0"+ - "\21\37\1\245\4\37\27\0\4\37\3\0\12\37\1\246"+ - "\13\37\27\0\4\37\3\0\12\37\1\247\13\37\27\0"+ - "\4\37\3\0\21\37\1\250\4\37\27\0\4\37\3\0"+ - "\1\251\25\37\27\0\4\37\3\0\2\37\1\252\23\37"+ - "\27\0\4\37\3\0\14\37\1\253\11\37\27\0\4\37"+ - "\3\0\22\37\1\254\3\37\27\0\4\37\3\0\25\37"+ - "\1\255\27\0\4\37\3\0\1\256\25\37\27\0\4\37"+ - "\3\0\4\37\1\257\21\37\27\0\4\37\3\0\12\37"+ - "\1\260\13\37"; + "\1\3\1\4\1\5\1\6\2\3\1\7\54\3\1\10"+ + "\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1\20"+ + "\1\21\1\22\1\23\1\24\1\25\1\26\1\27\1\30"+ + "\1\31\1\32\1\33\1\34\1\35\1\36\1\37\1\40"+ + "\1\41\1\42\1\10\1\43\1\44\1\45\1\46\1\47"+ + "\1\50\1\51\1\52\1\36\1\53\1\36\1\54\1\36"+ + "\1\55\1\56\1\57\1\60\1\36\1\61\1\36\1\62"+ + "\1\36\1\63\65\0\1\5\60\0\2\7\2\0\57\7"+ + "\2\0\1\12\104\0\1\64\36\0\5\65\1\66\25\65"+ + "\1\67\27\65\2\16\2\0\57\16\25\0\1\70\54\0"+ + "\1\71\63\0\2\31\65\0\1\72\62\0\1\73\62\0"+ + "\1\74\64\0\4\36\3\0\26\36\26\0\4\36\3\0"+ + "\1\75\25\36\26\0\4\36\3\0\15\36\1\76\10\36"+ + "\26\0\4\36\3\0\17\36\1\77\6\36\26\0\4\36"+ + "\3\0\14\36\1\100\3\36\1\101\2\36\1\102\2\36"+ + "\26\0\4\36\3\0\17\36\1\103\6\36\26\0\4\36"+ + "\3\0\12\36\1\104\2\36\1\105\10\36\26\0\4\36"+ + "\3\0\4\36\1\106\21\36\26\0\4\36\3\0\12\36"+ + "\1\107\11\36\1\110\1\36\26\0\4\36\3\0\10\36"+ + "\1\111\4\36\1\112\1\36\1\113\6\36\26\0\4\36"+ + "\3\0\12\36\1\114\13\36\26\0\4\36\3\0\5\36"+ + "\1\115\5\36\1\116\1\117\3\36\1\120\5\36\26\0"+ + "\4\36\3\0\1\121\25\36\26\0\4\36\3\0\15\36"+ + "\1\122\10\36\26\0\4\36\3\0\17\36\1\123\6\36"+ + "\26\0\4\36\3\0\1\124\25\36\26\0\4\36\3\0"+ + "\1\125\3\36\1\126\21\36\26\0\4\36\3\0\17\36"+ + "\1\127\6\36\26\0\4\36\3\0\7\36\1\130\1\131"+ + "\15\36\26\0\4\36\3\0\10\36\1\132\15\36\5\0"+ + "\1\65\25\0\1\65\15\0\1\65\2\0\1\65\1\0"+ + "\1\65\32\0\4\36\3\0\12\36\1\133\13\36\26\0"+ + "\4\36\3\0\14\36\1\134\11\36\26\0\4\36\3\0"+ + "\22\36\1\135\3\36\26\0\4\36\3\0\3\36\1\136"+ + "\22\36\26\0\4\36\3\0\20\36\1\137\5\36\26\0"+ + "\4\36\3\0\1\140\25\36\26\0\4\36\3\0\4\36"+ + "\1\141\21\36\26\0\4\36\3\0\1\142\25\36\26\0"+ + "\4\36\3\0\14\36\1\143\11\36\26\0\4\36\3\0"+ + "\5\36\1\144\4\36\1\145\13\36\26\0\4\36\3\0"+ + "\10\36\1\146\7\36\1\147\5\36\26\0\4\36\3\0"+ + "\2\36\1\150\23\36\26\0\4\36\3\0\14\36\1\151"+ + "\11\36\26\0\4\36\3\0\17\36\1\152\6\36\26\0"+ + "\4\36\3\0\15\36\1\153\10\36\26\0\4\36\3\0"+ + "\15\36\1\154\10\36\26\0\4\36\3\0\16\36\1\155"+ + "\7\36\26\0\4\36\3\0\13\36\1\156\12\36\26\0"+ + "\4\36\3\0\14\36\1\157\4\36\1\160\4\36\26\0"+ + "\4\36\3\0\20\36\1\161\5\36\26\0\4\36\3\0"+ + "\10\36\1\162\15\36\26\0\4\36\3\0\21\36\1\163"+ + "\4\36\26\0\4\36\3\0\25\36\1\164\26\0\4\36"+ + "\3\0\10\36\1\165\15\36\26\0\4\36\3\0\21\36"+ + "\1\166\4\36\26\0\4\36\3\0\4\36\1\167\21\36"+ + "\26\0\4\36\3\0\20\36\1\170\5\36\26\0\4\36"+ + "\3\0\4\36\1\171\21\36\26\0\4\36\3\0\4\36"+ + "\1\172\21\36\26\0\4\36\3\0\4\36\1\173\21\36"+ + "\26\0\4\36\3\0\10\36\1\174\15\36\26\0\4\36"+ + "\3\0\1\175\25\36\26\0\4\36\3\0\20\36\1\176"+ + "\5\36\26\0\4\36\3\0\21\36\1\177\4\36\26\0"+ + "\4\36\3\0\5\36\1\200\20\36\26\0\4\36\3\0"+ + "\4\36\1\201\21\36\26\0\4\36\3\0\4\36\1\202"+ + "\21\36\26\0\4\36\3\0\1\203\25\36\26\0\4\36"+ + "\3\0\13\36\1\204\12\36\26\0\4\36\3\0\1\36"+ + "\1\205\24\36\26\0\4\36\3\0\15\36\1\206\10\36"+ + "\26\0\4\36\3\0\1\36\1\207\24\36\26\0\4\36"+ + "\3\0\12\36\1\210\13\36\26\0\4\36\3\0\20\36"+ + "\1\211\5\36\26\0\4\36\3\0\20\36\1\212\5\36"+ + "\26\0\4\36\3\0\22\36\1\213\3\36\26\0\4\36"+ + "\3\0\12\36\1\214\13\36\26\0\4\36\3\0\7\36"+ + "\1\215\16\36\26\0\4\36\3\0\12\36\1\216\13\36"+ + "\26\0\4\36\3\0\4\36\1\217\21\36\26\0\4\36"+ + "\3\0\17\36\1\220\6\36\26\0\4\36\3\0\21\36"+ + "\1\221\4\36\26\0\4\36\3\0\11\36\1\222\14\36"+ + "\26\0\4\36\3\0\20\36\1\223\5\36\26\0\4\36"+ + "\3\0\10\36\1\224\15\36\26\0\4\36\3\0\16\36"+ + "\1\225\7\36\26\0\4\36\3\0\12\36\1\226\13\36"+ + "\26\0\4\36\3\0\1\227\25\36\26\0\4\36\3\0"+ + "\17\36\1\230\6\36\26\0\4\36\3\0\3\36\1\231"+ + "\22\36\26\0\4\36\3\0\15\36\1\232\10\36\26\0"+ + "\4\36\3\0\4\36\1\233\21\36\26\0\4\36\3\0"+ + "\17\36\1\234\6\36\26\0\4\36\3\0\4\36\1\235"+ + "\21\36\26\0\4\36\3\0\3\36\1\236\22\36\26\0"+ + "\4\36\3\0\21\36\1\237\4\36\26\0\4\36\3\0"+ + "\14\36\1\240\11\36\26\0\4\36\3\0\21\36\1\241"+ + "\4\36\26\0\4\36\3\0\12\36\1\242\13\36\26\0"+ + "\4\36\3\0\12\36\1\243\13\36\26\0\4\36\3\0"+ + "\21\36\1\244\4\36\26\0\4\36\3\0\1\245\25\36"+ + "\26\0\4\36\3\0\2\36\1\246\23\36\26\0\4\36"+ + "\3\0\14\36\1\247\11\36\26\0\4\36\3\0\22\36"+ + "\1\250\3\36\26\0\4\36\3\0\25\36\1\251\26\0"+ + "\4\36\3\0\1\252\25\36\26\0\4\36\3\0\4\36"+ + "\1\253\21\36\26\0\4\36\3\0\12\36\1\254\13\36"; private static int [] zzUnpackTrans() { - int [] result = new int[6136]; + int [] result = new int[5865]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -325,13 +318,12 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\2\0\1\1\3\11\2\1\3\11\2\1\1\11\1\1"+ - "\6\11\1\1\1\11\1\1\1\11\1\1\1\11\7\1"+ - "\2\11\21\1\1\11\1\1\6\11\36\1\1\0\1\11"+ - "\123\1"; + "\2\0\3\11\2\1\3\11\4\1\6\11\1\1\1\11"+ + "\1\1\1\11\1\1\1\11\7\1\2\11\20\1\1\11"+ + "\1\0\1\11\1\0\5\11\160\1"; private static int [] zzUnpackAttribute() { - int [] result = new int[176]; + int [] result = new int[172]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -419,7 +411,6 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { /** Producer of token-related values for the parser. */ final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); private int currIndent = 0; - private int currString = ""; private ArrayList stack = new ArrayList(20); /** Return a terminal symbol of syntactic category TYPE and no * semantic value at the current source location. */ @@ -843,11 +834,6 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { else { switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { case 1: - { currString+=yytext(); - } - // fall through - case 68: break; - case 2: { yypushback(1); if(top() > currIndent) { @@ -862,8 +848,8 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { } } // fall through - case 69: break; - case 3: + case 65: break; + case 2: { String space = yytext(); if(space == "\t") currIndent += 8; @@ -871,331 +857,318 @@ public class ChocoPyLexer implements java_cup.runtime.Scanner { currIndent ++; } // fall through - case 70: break; - case 4: + case 66: break; + case 3: { currIndent = 0; } // fall through - case 71: break; - case 5: + case 67: break; + case 4: { /* ignored */ } // fall through - case 72: break; - case 6: + case 68: break; + case 5: { return symbol(ChocoPyTokens.UNRECOGNIZED); } // fall through - case 73: break; - case 7: + case 69: break; + case 6: { /* ignore */ } // fall through - case 74: break; - case 8: + case 70: break; + case 7: { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0; } // fall through - case 75: break; - case 9: - { yystart(STR); currString = ""; - } - // fall through - case 76: break; - case 10: + case 71: break; + case 8: { return symbol(ChocoPyTokens.MOD); } // fall through - case 77: break; - case 11: + case 72: break; + case 9: { return symbol(ChocoPyTokens.LPAR); } // fall through - case 78: break; - case 12: + case 73: break; + case 10: { return symbol(ChocoPyTokens.RPAR); } // fall through - case 79: break; - case 13: + case 74: break; + case 11: { return symbol(ChocoPyTokens.MUL); } // fall through - case 80: break; - case 14: + case 75: break; + case 12: { return symbol(ChocoPyTokens.PLUS); } // fall through - case 81: break; - case 15: + case 76: break; + case 13: { return symbol(ChocoPyTokens.COMMA); } // fall through - case 82: break; - case 16: + case 77: break; + case 14: { return symbol(ChocoPyTokens.MINUS); } // fall through - case 83: break; - case 17: + case 78: break; + case 15: { return symbol(ChocoPyTokens.DOT); } // fall through - case 84: break; - case 18: + case 79: break; + case 16: { return symbol(ChocoPyTokens.DIV); } // fall through - case 85: break; - case 19: + case 80: break; + case 17: { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } // fall through - case 86: break; - case 20: + case 81: break; + case 18: { return symbol(ChocoPyTokens.COLON); } // fall through - case 87: break; - case 21: + case 82: break; + case 19: { return symbol(ChocoPyTokens.LT); } // fall through - case 88: break; - case 22: + case 83: break; + case 20: { return symbol(ChocoPyTokens.ASSIGN); } // fall through - case 89: break; - case 23: + case 84: break; + case 21: { return symbol(ChocoPyTokens.GT); } // fall through - case 90: break; - case 24: + case 85: break; + case 22: { return symbol(ChocoPyTokens.NAMES, yytext()); } // fall through - case 91: break; - case 25: + case 86: break; + case 23: { return symbol(ChocoPyTokens.LBR); } // fall through - case 92: break; - case 26: + case 87: break; + case 24: { return symbol(ChocoPyTokens.RBR); } // fall through - case 93: break; - case 27: - { yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString); + case 88: break; + case 25: + { return symbol(ChocoPyTokens.NEQ); } // fall through - case 94: break; - case 28: - { return symbol(ChocoPyTokens.NEQ); + case 89: break; + case 26: + { return symbol(ChocoPyTokens.STRING, yytext()); } // fall through - case 95: break; - case 29: + case 90: break; + case 27: { return symbol(ChocoPyTokens.ARROW); } // fall through - case 96: break; - case 30: + case 91: break; + case 28: { return symbol(ChocoPyTokens.LEQ); } // fall through - case 97: break; - case 31: + case 92: break; + case 29: { return symbol(ChocoPyTokens.EQUAL); } // fall through - case 98: break; - case 32: + case 93: break; + case 30: { return symbol(ChocoPyTokens.GEQ); } // fall through - case 99: break; - case 33: + case 94: break; + case 31: { return symbol(ChocoPyTokens.AS); } // fall through - case 100: break; - case 34: + case 95: break; + case 32: { return symbol(ChocoPyTokens.IF); } // fall through - case 101: break; - case 35: + case 96: break; + case 33: { return symbol(ChocoPyTokens.IN); } // fall through - case 102: break; - case 36: + case 97: break; + case 34: { return symbol(ChocoPyTokens.IS); } // fall through - case 103: break; - case 37: + case 98: break; + case 35: { return symbol(ChocoPyTokens.OR); } // fall through - case 104: break; - case 38: - // lookahead expression with fixed base length - zzMarkedPos = Character.offsetByCodePoints - (zzBufferL, zzStartRead, zzEndRead - zzStartRead, zzStartRead, 1); - { /*'\' at the end of line, do nothing.*/ - } - // fall through - case 105: break; - case 39: + case 99: break; + case 36: { return symbol(ChocoPyTokens.AND); } // fall through - case 106: break; - case 40: + case 100: break; + case 37: { return symbol(ChocoPyTokens.DEF); } // fall through - case 107: break; - case 41: + case 101: break; + case 38: { return symbol(ChocoPyTokens.DEL); } // fall through - case 108: break; - case 42: + case 102: break; + case 39: { return symbol(ChocoPyTokens.FOR); } // fall through - case 109: break; - case 43: + case 103: break; + case 40: { return symbol(ChocoPyTokens.NOT); } // fall through - case 110: break; - case 44: + case 104: break; + case 41: { return symbol(ChocoPyTokens.TRY); } // fall through - case 111: break; - case 45: + case 105: break; + case 42: { return symbol(ChocoPyTokens.NONE); } // fall through - case 112: break; - case 46: + case 106: break; + case 43: { return symbol(ChocoPyTokens.BOOL, true); } // fall through - case 113: break; - case 47: + case 107: break; + case 44: { return symbol(ChocoPyTokens.ELIF); } // fall through - case 114: break; - case 48: + case 108: break; + case 45: { return symbol(ChocoPyTokens.ELSE); } // fall through - case 115: break; - case 49: + case 109: break; + case 46: { return symbol(ChocoPyTokens.FROM); } // fall through - case 116: break; - case 50: + case 110: break; + case 47: { return symbol(ChocoPyTokens.PASS); } // fall through - case 117: break; - case 51: + case 111: break; + case 48: { return symbol(ChocoPyTokens.WITH); } // fall through - case 118: break; - case 52: + case 112: break; + case 49: { return symbol(ChocoPyTokens.BOOL, false); } // fall through - case 119: break; - case 53: + case 113: break; + case 50: { return symbol(ChocoPyTokens.AWAIT); } // fall through - case 120: break; - case 54: + case 114: break; + case 51: { return symbol(ChocoPyTokens.BREAK); } // fall through - case 121: break; - case 55: + case 115: break; + case 52: { return symbol(ChocoPyTokens.CLASS); } // fall through - case 122: break; - case 56: + case 116: break; + case 53: { return symbol(ChocoPyTokens.RAISE); } // fall through - case 123: break; - case 57: + case 117: break; + case 54: { return symbol(ChocoPyTokens.WHILE); } // fall through - case 124: break; - case 58: + case 118: break; + case 55: { return symbol(ChocoPyTokens.YIELD); } // fall through - case 125: break; - case 59: + case 119: break; + case 56: { return symbol(ChocoPyTokens.ASSERT); } // fall through - case 126: break; - case 60: + case 120: break; + case 57: { return symbol(ChocoPyTokens.EXCEPT); } // fall through - case 127: break; - case 61: + case 121: break; + case 58: { return symbol(ChocoPyTokens.GLOBAL); } // fall through - case 128: break; - case 62: + case 122: break; + case 59: { return symbol(ChocoPyTokens.IMPORT); } // fall through - case 129: break; - case 63: + case 123: break; + case 60: { return symbol(ChocoPyTokens.LAMBDA); } // fall through - case 130: break; - case 64: + case 124: break; + case 61: { return symbol(ChocoPyTokens.RETURN); } // fall through - case 131: break; - case 65: + case 125: break; + case 62: { return symbol(ChocoPyTokens.FINALLY); } // fall through - case 132: break; - case 66: + case 126: break; + case 63: { return symbol(ChocoPyTokens.CONTINUE); } // fall through - case 133: break; - case 67: + case 127: break; + case 64: { return symbol(ChocoPyTokens.NONLOCAL); } // fall through - case 134: break; + case 128: break; default: zzScanError(ZZ_NO_MATCH); } From 42628a34f785f373dac85e92c905594736cc3b8c Mon Sep 17 00:00:00 2001 From: bill Date: Wed, 17 Feb 2021 23:16:20 +0800 Subject: [PATCH 06/67] Revert "initial works on the lexer" This reverts commit 997178ba9cd1d191edcd01f1d896627a91f3e722. --- src/main/cup/chocopy/pa1/ChocoPy.cup | 5 - src/main/jflex/chocopy/pa1/ChocoPy.jflex | 136 +- src/main/jflex/chocopy/pa1/ChocoPyLexer.java | 1260 ------------------ 3 files changed, 13 insertions(+), 1388 deletions(-) delete mode 100644 src/main/jflex/chocopy/pa1/ChocoPyLexer.java diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index 0585cf7..d4ff444 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -144,11 +144,6 @@ action code {: */ terminal NEWLINE; terminal String PLUS; -terminal String MINUS; -terminal String MUL; -terminal String DIV; -terminal String NAMES; - terminal Integer NUMBER; /* Returned by the lexer for erroneous tokens. Since it does not appear in * the grammar, it indicates a syntax error. */ diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index ebcec10..9aafe7f 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -1,6 +1,6 @@ package chocopy.pa1; import java_cup.runtime.*; -import java.util.ArrayList; + %% /*** Do not change the flags below unless you know what you are doing. ***/ @@ -8,7 +8,7 @@ import java.util.ArrayList; %unicode %line %column -%states AFTER, STR + %class ChocoPyLexer %public @@ -32,13 +32,11 @@ import java.util.ArrayList; /** Producer of token-related values for the parser. */ final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); - private int currIndent = 0; - private int currString = ""; - private ArrayList stack = new ArrayList(20); + /** 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); + return symbol(type, yytext()); } /** Return a terminal symbol of syntactic category TYPE and semantic @@ -49,17 +47,7 @@ import java.util.ArrayList; new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), value); } - private void push(int indent){ - stack.add(indent); - } - private int pop(){ - if(stack.isEmpty()) return 0; - return stack.remove(stack.size() - 1); - } - private int top(){ - if(stack.isEmpty) return 0; - return stack.get(stack.size() - 1); - } + %} /* Macros (regexes used in rules below) */ @@ -67,125 +55,27 @@ import java.util.ArrayList; WhiteSpace = [ \t] LineBreak = \r|\n|\r\n -IntegerLiteral = 0|[1-9][0-9]* -StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))* -Names = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z])* -Comments = #[^\r\n]* +IntegerLiteral = 0 | [1-9][0-9]* + %% -{ - {WhiteSpace} - { - String space = yytext(); - if(space == "\t") - currIndent += 8; - else - currIndent ++; - } - {LineBreak} - { - currIndent = 0; - } - {Comments} { /* ignored */ } - [^ \t\r\n#] - { - yypushback(1); - if(top() > currIndent) - { - pop(); - return symbol(ChocoPyTokens.DEDENT); - } - yystart(AFTER); - if(top()< currIndent) - { - push(currIndent); - return symbol(ChocoPyTokens.INDENT); - } - } -} - { + + { /* Delimiters. */ - {LineBreak} { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0;} - ":" { return symbol(ChocoPyTokens.COLON); } - "," { return symbol(ChocoPyTokens.COMMA); } + {LineBreak} { return symbol(ChocoPyTokens.NEWLINE); } /* Literals. */ {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } -// {StringLiteral} { return symbol(ChocoPyTokens.STRING, yytext());} - "\"" {yystart(STR); currString = "";} - "False" { return symbol(ChocoPyTokens.BOOL, false); } - "True" { return symbol(ChocoPyTokens.BOOL, true); } - "None" { return symbol(ChocoPyTokens.NONE); } - - /*Keywords*/ - "if" {return symbol(ChocoPyTokens.IF);} - "else" {return symbol(ChocoPyTokens.ELSE);} - "elif" {return symbol(ChocoPyTokens.ELIF);} - "while" {return symbol(ChocoPyTokens.WHILE);} - "class" {return symbol(ChocoPyTokens.CLASS);} - "def" {return symbol(ChocoPyTokens.DEF);} - "lambda" {return symbol(ChocoPyTokens.LAMBDA);} - "as" { return symbol(ChocoPyTokens.AS); } - "for" { return symbol(ChocoPyTokens.FOR); } - "global" { return symbol(ChocoPyTokens.GLOBAL); } - "in" { return symbol(ChocoPyTokens.IN); } - "nonlocal" { return symbol(ChocoPyTokens.NONLOCAL); } - "pass" { return symbol(ChocoPyTokens.PASS); } - "return" { return symbol(ChocoPyTokens.RETURN); } - "assert" { return symbol(ChocoPyTokens.ASSERT); } - "await" { return symbol(ChocoPyTokens.AWAIT); } - "break" { return symbol(ChocoPyTokens.BREAK); } - "continue" { return symbol(ChocoPyTokens.CONTINUE); } - "del" { return symbol(ChocoPyTokens.DEL); } - "except" { return symbol(ChocoPyTokens.EXCEPT); } - "finally" { return symbol(ChocoPyTokens.FINALLY); } - "from" { return symbol(ChocoPyTokens.FROM); } - "import" { return symbol(ChocoPyTokens.IMPORT); } - "raise" { return symbol(ChocoPyTokens.RAISE); } - "try" { return symbol(ChocoPyTokens.TRY); } - "with" { return symbol(ChocoPyTokens.WITH); } - "yield" { return symbol(ChocoPyTokens.YIELD); } - /* Operators. */ - "+" { return symbol(ChocoPyTokens.PLUS); } - "-" { return symbol(ChocoPyTokens.MINUS); } - "*" { return symbol(ChocoPyTokens.MUL); } - "//" { return symbol(ChocoPyTokens.DIV); } - "/" { return symbol(ChocoPyTokens.DIV); } - "%" { return symbol(ChocoPyTokens.MOD); } - ">" { return symbol(ChocoPyTokens.GT); } - "<" { return symbol(ChocoPyTokens.LT); } - "==" { return symbol(ChocoPyTokens.EQUAL); } - "!=" { return symbol(ChocoPyTokens.NEQ); } - ">=" { return symbol(ChocoPyTokens.GEQ); } - "<=" { return symbol(ChocoPyTokens.LEQ); } - "=" { return symbol(ChocoPyTokens.ASSIGN); } - "and" { return symbol(ChocoPyTokens.AND); } - "or" { return symbol(ChocoPyTokens.OR); } - "not" { return symbol(ChocoPyTokens.NOT); } - "." { return symbol(ChocoPyTokens.DOT); } - "(" { return symbol(ChocoPyTokens.LPAR); } - ")" { return symbol(ChocoPyTokens.RPAR); } - "[" { return symbol(ChocoPyTokens.LBR); } - "]" { return symbol(ChocoPyTokens.RBR); } - "->" { return symbol(ChocoPyTokens.ARROW); } - "is" { return symbol(ChocoPyTokens.IS); } - - - /*Identifiers*/ - {Names} {return symbol(ChocoPyTokens.NAMES, yytext());} + "+" { return symbol(ChocoPyTokens.PLUS, yytext()); } + /* Whitespace. */ {WhiteSpace} { /* ignore */ } - /* Comment. */ - {Comments} { /* ignore */ } -} -{ - {StringLiteral} {currString+=yytext();} - "\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} } + <> { return symbol(ChocoPyTokens.EOF); } /* Error fallback. */ diff --git a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java deleted file mode 100644 index 2045209..0000000 --- a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java +++ /dev/null @@ -1,1260 +0,0 @@ -// DO NOT EDIT -// Generated by JFlex 1.8.2 http://jflex.de/ -// source: ChocoPy.jflex - -package chocopy.pa1; -import java_cup.runtime.*; -import java.util.ArrayList; - -// See https://github.com/jflex-de/jflex/issues/222 -@SuppressWarnings("FallThrough") -public class ChocoPyLexer implements java_cup.runtime.Scanner { - - /** This character denotes the end of file. */ - public static final int YYEOF = -1; - - /** Initial size of the lookahead buffer. */ - private static final int ZZ_BUFFERSIZE = 16384; - - // Lexical states. - public static final int YYINITIAL = 0; - public static final int AFTER = 2; - - /** - * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l - * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l - * at the beginning of a line - * l is of the form l = 2*k, k a non negative integer - */ - private static final int ZZ_LEXSTATE[] = { - 0, 0, 1, 1 - }; - - /** - * Top-level table for translating characters to character classes - */ - private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top(); - - private static final String ZZ_CMAP_TOP_PACKED_0 = - "\1\0\u10ff\u0100"; - - private static int [] zzUnpackcmap_top() { - int [] result = new int[4352]; - int offset = 0; - offset = zzUnpackcmap_top(ZZ_CMAP_TOP_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackcmap_top(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** - * Second-level tables for translating characters to character classes - */ - private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); - - private static final String ZZ_CMAP_BLOCKS_PACKED_0 = - "\11\0\1\1\1\2\2\0\1\3\22\0\1\1\1\4"+ - "\1\5\1\6\1\0\1\7\2\0\1\10\1\11\1\12"+ - "\1\13\1\14\1\15\1\16\1\17\1\20\11\21\1\22"+ - "\1\0\1\23\1\24\1\25\2\0\5\26\1\27\7\26"+ - "\1\30\5\26\1\31\6\26\1\32\1\33\1\34\1\0"+ - "\1\26\1\0\1\35\1\36\1\37\1\40\1\41\1\42"+ - "\1\43\1\44\1\45\1\26\1\46\1\47\1\50\1\51"+ - "\1\52\1\53\1\26\1\54\1\55\1\56\1\57\1\26"+ - "\1\60\1\61\1\62\1\26\u0185\0"; - - private static int [] zzUnpackcmap_blocks() { - int [] result = new int[512]; - int offset = 0; - offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - /** - * Translates DFA states to action switch labels. - */ - private static final int [] ZZ_ACTION = zzUnpackAction(); - - private static final String ZZ_ACTION_PACKED_0 = - "\2\0\1\1\1\2\2\3\1\4\1\5\1\6\2\7"+ - "\2\5\1\6\1\10\1\11\1\12\1\13\1\14\1\15"+ - "\1\16\1\17\1\20\2\21\1\22\1\23\1\24\1\25"+ - "\4\26\1\27\1\30\20\26\1\31\1\0\1\32\1\0"+ - "\1\33\1\20\1\34\1\35\1\36\4\26\1\37\13\26"+ - "\1\40\1\26\1\41\1\42\2\26\1\43\12\26\1\44"+ - "\5\26\1\45\1\46\4\26\1\47\5\26\1\50\3\26"+ - "\1\51\4\26\1\52\1\53\5\26\1\54\1\55\2\26"+ - "\1\56\4\26\1\57\3\26\1\60\1\26\1\61\1\26"+ - "\1\62\1\63\1\64\7\26\1\65\1\26\1\66\1\67"+ - "\1\70\1\26\1\71\1\26\1\72\1\73\1\74\1\26"+ - "\1\75\1\26\1\76\1\26\1\77\1\100"; - - private static int [] zzUnpackAction() { - int [] result = new int[172]; - int offset = 0; - offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAction(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** - * Translates a state to a row index in the transition table - */ - private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); - - private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\63\0\146\0\146\0\146\0\231\0\314\0\146"+ - "\0\146\0\146\0\377\0\u0132\0\u0165\0\u0198\0\146\0\146"+ - "\0\146\0\146\0\146\0\146\0\u01cb\0\146\0\u01fe\0\146"+ - "\0\u0231\0\146\0\u0264\0\u0297\0\u02ca\0\u02fd\0\u0330\0\u0363"+ - "\0\u0396\0\146\0\146\0\u03c9\0\u03fc\0\u042f\0\u0462\0\u0495"+ - "\0\u04c8\0\u04fb\0\u052e\0\u0561\0\u0594\0\u05c7\0\u05fa\0\u062d"+ - "\0\u0660\0\u0693\0\u06c6\0\146\0\u0165\0\146\0\u06f9\0\146"+ - "\0\146\0\146\0\146\0\146\0\u072c\0\u075f\0\u0792\0\u07c5"+ - "\0\u07f8\0\u082b\0\u085e\0\u0891\0\u08c4\0\u08f7\0\u092a\0\u095d"+ - "\0\u0990\0\u09c3\0\u09f6\0\u0a29\0\u02fd\0\u0a5c\0\u02fd\0\u02fd"+ - "\0\u0a8f\0\u0ac2\0\u02fd\0\u0af5\0\u0b28\0\u0b5b\0\u0b8e\0\u0bc1"+ - "\0\u0bf4\0\u0c27\0\u0c5a\0\u0c8d\0\u0cc0\0\u02fd\0\u0cf3\0\u0d26"+ - "\0\u0d59\0\u0d8c\0\u0dbf\0\u02fd\0\u02fd\0\u0df2\0\u0e25\0\u0e58"+ - "\0\u0e8b\0\u02fd\0\u0ebe\0\u0ef1\0\u0f24\0\u0f57\0\u0f8a\0\u02fd"+ - "\0\u0fbd\0\u0ff0\0\u1023\0\u02fd\0\u1056\0\u1089\0\u10bc\0\u10ef"+ - "\0\u02fd\0\u02fd\0\u1122\0\u1155\0\u1188\0\u11bb\0\u11ee\0\u02fd"+ - "\0\u02fd\0\u1221\0\u1254\0\u02fd\0\u1287\0\u12ba\0\u12ed\0\u1320"+ - "\0\u02fd\0\u1353\0\u1386\0\u13b9\0\u02fd\0\u13ec\0\u02fd\0\u141f"+ - "\0\u02fd\0\u02fd\0\u02fd\0\u1452\0\u1485\0\u14b8\0\u14eb\0\u151e"+ - "\0\u1551\0\u1584\0\u02fd\0\u15b7\0\u02fd\0\u02fd\0\u02fd\0\u15ea"+ - "\0\u02fd\0\u161d\0\u02fd\0\u02fd\0\u02fd\0\u1650\0\u02fd\0\u1683"+ - "\0\u02fd\0\u16b6\0\u02fd\0\u02fd"; - - private static int [] zzUnpackRowMap() { - int [] result = new int[172]; - int offset = 0; - offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackRowMap(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int high = packed.charAt(i++) << 16; - result[j++] = high | packed.charAt(i++); - } - return j; - } - - /** - * The transition table of the DFA - */ - private static final int [] ZZ_TRANS = zzUnpackTrans(); - - private static final String ZZ_TRANS_PACKED_0 = - "\1\3\1\4\1\5\1\6\2\3\1\7\54\3\1\10"+ - "\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1\20"+ - "\1\21\1\22\1\23\1\24\1\25\1\26\1\27\1\30"+ - "\1\31\1\32\1\33\1\34\1\35\1\36\1\37\1\40"+ - "\1\41\1\42\1\10\1\43\1\44\1\45\1\46\1\47"+ - "\1\50\1\51\1\52\1\36\1\53\1\36\1\54\1\36"+ - "\1\55\1\56\1\57\1\60\1\36\1\61\1\36\1\62"+ - "\1\36\1\63\65\0\1\5\60\0\2\7\2\0\57\7"+ - "\2\0\1\12\104\0\1\64\36\0\5\65\1\66\25\65"+ - "\1\67\27\65\2\16\2\0\57\16\25\0\1\70\54\0"+ - "\1\71\63\0\2\31\65\0\1\72\62\0\1\73\62\0"+ - "\1\74\64\0\4\36\3\0\26\36\26\0\4\36\3\0"+ - "\1\75\25\36\26\0\4\36\3\0\15\36\1\76\10\36"+ - "\26\0\4\36\3\0\17\36\1\77\6\36\26\0\4\36"+ - "\3\0\14\36\1\100\3\36\1\101\2\36\1\102\2\36"+ - "\26\0\4\36\3\0\17\36\1\103\6\36\26\0\4\36"+ - "\3\0\12\36\1\104\2\36\1\105\10\36\26\0\4\36"+ - "\3\0\4\36\1\106\21\36\26\0\4\36\3\0\12\36"+ - "\1\107\11\36\1\110\1\36\26\0\4\36\3\0\10\36"+ - "\1\111\4\36\1\112\1\36\1\113\6\36\26\0\4\36"+ - "\3\0\12\36\1\114\13\36\26\0\4\36\3\0\5\36"+ - "\1\115\5\36\1\116\1\117\3\36\1\120\5\36\26\0"+ - "\4\36\3\0\1\121\25\36\26\0\4\36\3\0\15\36"+ - "\1\122\10\36\26\0\4\36\3\0\17\36\1\123\6\36"+ - "\26\0\4\36\3\0\1\124\25\36\26\0\4\36\3\0"+ - "\1\125\3\36\1\126\21\36\26\0\4\36\3\0\17\36"+ - "\1\127\6\36\26\0\4\36\3\0\7\36\1\130\1\131"+ - "\15\36\26\0\4\36\3\0\10\36\1\132\15\36\5\0"+ - "\1\65\25\0\1\65\15\0\1\65\2\0\1\65\1\0"+ - "\1\65\32\0\4\36\3\0\12\36\1\133\13\36\26\0"+ - "\4\36\3\0\14\36\1\134\11\36\26\0\4\36\3\0"+ - "\22\36\1\135\3\36\26\0\4\36\3\0\3\36\1\136"+ - "\22\36\26\0\4\36\3\0\20\36\1\137\5\36\26\0"+ - "\4\36\3\0\1\140\25\36\26\0\4\36\3\0\4\36"+ - "\1\141\21\36\26\0\4\36\3\0\1\142\25\36\26\0"+ - "\4\36\3\0\14\36\1\143\11\36\26\0\4\36\3\0"+ - "\5\36\1\144\4\36\1\145\13\36\26\0\4\36\3\0"+ - "\10\36\1\146\7\36\1\147\5\36\26\0\4\36\3\0"+ - "\2\36\1\150\23\36\26\0\4\36\3\0\14\36\1\151"+ - "\11\36\26\0\4\36\3\0\17\36\1\152\6\36\26\0"+ - "\4\36\3\0\15\36\1\153\10\36\26\0\4\36\3\0"+ - "\15\36\1\154\10\36\26\0\4\36\3\0\16\36\1\155"+ - "\7\36\26\0\4\36\3\0\13\36\1\156\12\36\26\0"+ - "\4\36\3\0\14\36\1\157\4\36\1\160\4\36\26\0"+ - "\4\36\3\0\20\36\1\161\5\36\26\0\4\36\3\0"+ - "\10\36\1\162\15\36\26\0\4\36\3\0\21\36\1\163"+ - "\4\36\26\0\4\36\3\0\25\36\1\164\26\0\4\36"+ - "\3\0\10\36\1\165\15\36\26\0\4\36\3\0\21\36"+ - "\1\166\4\36\26\0\4\36\3\0\4\36\1\167\21\36"+ - "\26\0\4\36\3\0\20\36\1\170\5\36\26\0\4\36"+ - "\3\0\4\36\1\171\21\36\26\0\4\36\3\0\4\36"+ - "\1\172\21\36\26\0\4\36\3\0\4\36\1\173\21\36"+ - "\26\0\4\36\3\0\10\36\1\174\15\36\26\0\4\36"+ - "\3\0\1\175\25\36\26\0\4\36\3\0\20\36\1\176"+ - "\5\36\26\0\4\36\3\0\21\36\1\177\4\36\26\0"+ - "\4\36\3\0\5\36\1\200\20\36\26\0\4\36\3\0"+ - "\4\36\1\201\21\36\26\0\4\36\3\0\4\36\1\202"+ - "\21\36\26\0\4\36\3\0\1\203\25\36\26\0\4\36"+ - "\3\0\13\36\1\204\12\36\26\0\4\36\3\0\1\36"+ - "\1\205\24\36\26\0\4\36\3\0\15\36\1\206\10\36"+ - "\26\0\4\36\3\0\1\36\1\207\24\36\26\0\4\36"+ - "\3\0\12\36\1\210\13\36\26\0\4\36\3\0\20\36"+ - "\1\211\5\36\26\0\4\36\3\0\20\36\1\212\5\36"+ - "\26\0\4\36\3\0\22\36\1\213\3\36\26\0\4\36"+ - "\3\0\12\36\1\214\13\36\26\0\4\36\3\0\7\36"+ - "\1\215\16\36\26\0\4\36\3\0\12\36\1\216\13\36"+ - "\26\0\4\36\3\0\4\36\1\217\21\36\26\0\4\36"+ - "\3\0\17\36\1\220\6\36\26\0\4\36\3\0\21\36"+ - "\1\221\4\36\26\0\4\36\3\0\11\36\1\222\14\36"+ - "\26\0\4\36\3\0\20\36\1\223\5\36\26\0\4\36"+ - "\3\0\10\36\1\224\15\36\26\0\4\36\3\0\16\36"+ - "\1\225\7\36\26\0\4\36\3\0\12\36\1\226\13\36"+ - "\26\0\4\36\3\0\1\227\25\36\26\0\4\36\3\0"+ - "\17\36\1\230\6\36\26\0\4\36\3\0\3\36\1\231"+ - "\22\36\26\0\4\36\3\0\15\36\1\232\10\36\26\0"+ - "\4\36\3\0\4\36\1\233\21\36\26\0\4\36\3\0"+ - "\17\36\1\234\6\36\26\0\4\36\3\0\4\36\1\235"+ - "\21\36\26\0\4\36\3\0\3\36\1\236\22\36\26\0"+ - "\4\36\3\0\21\36\1\237\4\36\26\0\4\36\3\0"+ - "\14\36\1\240\11\36\26\0\4\36\3\0\21\36\1\241"+ - "\4\36\26\0\4\36\3\0\12\36\1\242\13\36\26\0"+ - "\4\36\3\0\12\36\1\243\13\36\26\0\4\36\3\0"+ - "\21\36\1\244\4\36\26\0\4\36\3\0\1\245\25\36"+ - "\26\0\4\36\3\0\2\36\1\246\23\36\26\0\4\36"+ - "\3\0\14\36\1\247\11\36\26\0\4\36\3\0\22\36"+ - "\1\250\3\36\26\0\4\36\3\0\25\36\1\251\26\0"+ - "\4\36\3\0\1\252\25\36\26\0\4\36\3\0\4\36"+ - "\1\253\21\36\26\0\4\36\3\0\12\36\1\254\13\36"; - - private static int [] zzUnpackTrans() { - int [] result = new int[5865]; - int offset = 0; - offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackTrans(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - value--; - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** Error code for "Unknown internal scanner error". */ - private static final int ZZ_UNKNOWN_ERROR = 0; - /** Error code for "could not match input". */ - private static final int ZZ_NO_MATCH = 1; - /** Error code for "pushback value was too large". */ - private static final int ZZ_PUSHBACK_2BIG = 2; - - /** - * Error messages for {@link #ZZ_UNKNOWN_ERROR}, {@link #ZZ_NO_MATCH}, and - * {@link #ZZ_PUSHBACK_2BIG} respectively. - */ - private static final String ZZ_ERROR_MSG[] = { - "Unknown internal scanner error", - "Error: could not match input", - "Error: pushback value was too large" - }; - - /** - * ZZ_ATTRIBUTE[aState] contains the attributes of state {@code aState} - */ - private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); - - private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\2\0\3\11\2\1\3\11\4\1\6\11\1\1\1\11"+ - "\1\1\1\11\1\1\1\11\7\1\2\11\20\1\1\11"+ - "\1\0\1\11\1\0\5\11\160\1"; - - private static int [] zzUnpackAttribute() { - int [] result = new int[172]; - int offset = 0; - offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAttribute(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - /** Input device. */ - private java.io.Reader zzReader; - - /** Current state of the DFA. */ - private int zzState; - - /** Current lexical state. */ - private int zzLexicalState = YYINITIAL; - - /** - * This buffer contains the current text to be matched and is the source of the {@link #yytext()} - * string. - */ - private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; - - /** Text position at the last accepting state. */ - private int zzMarkedPos; - - /** Current text position in the buffer. */ - private int zzCurrentPos; - - /** Marks the beginning of the {@link #yytext()} string in the buffer. */ - private int zzStartRead; - - /** Marks the last character in the buffer, that has been read from input. */ - private int zzEndRead; - - /** - * Whether the scanner is at the end of file. - * @see #yyatEOF - */ - private boolean zzAtEOF; - - /** - * The number of occupied positions in {@link #zzBuffer} beyond {@link #zzEndRead}. - * - *

When a lead/high surrogate has been read from the input stream into the final - * {@link #zzBuffer} position, this will have a value of 1; otherwise, it will have a value of 0. - */ - private int zzFinalHighSurrogate = 0; - - /** Number of newlines encountered up to the start of the matched text. */ - private int yyline; - - /** Number of characters from the last newline up to the start of the matched text. */ - private int yycolumn; - - /** Number of characters up to the start of the matched text. */ - @SuppressWarnings("unused") - private long yychar; - - /** Whether the scanner is currently at the beginning of a line. */ - @SuppressWarnings("unused") - private boolean zzAtBOL = true; - - /** Whether the user-EOF-code has already been executed. */ - @SuppressWarnings("unused") - private boolean zzEOFDone; - - /* user code: */ - /* 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(); - private int currIndent = 0; - private ArrayList stack = new ArrayList(20); - /** 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); - } - - /** 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); - } - private void push(int indent){ - stack.add(indent); - } - private int pop(){ - if(stack.isEmpty()) return 0; - return stack.remove(stack.size() - 1); - } - private int top(){ - if(stack.isEmpty) return 0; - return stack.get(stack.size() - 1); - } - - - /** - * Creates a new scanner - * - * @param in the java.io.Reader to read input from. - */ - public ChocoPyLexer(java.io.Reader in) { - this.zzReader = in; - } - - /** - * Translates raw input code points to DFA table row - */ - private static int zzCMap(int input) { - int offset = input & 255; - return offset == input ? ZZ_CMAP_BLOCKS[offset] : ZZ_CMAP_BLOCKS[ZZ_CMAP_TOP[input >> 8] | offset]; - } - - /** - * Refills the input buffer. - * - * @return {@code false} iff there was new input. - * @exception java.io.IOException if any I/O-Error occurs - */ - private boolean zzRefill() throws java.io.IOException { - - /* first: make room (if you can) */ - if (zzStartRead > 0) { - zzEndRead += zzFinalHighSurrogate; - zzFinalHighSurrogate = 0; - System.arraycopy(zzBuffer, zzStartRead, - zzBuffer, 0, - zzEndRead - zzStartRead); - - /* translate stored positions */ - zzEndRead -= zzStartRead; - zzCurrentPos -= zzStartRead; - zzMarkedPos -= zzStartRead; - zzStartRead = 0; - } - - /* is the buffer big enough? */ - if (zzCurrentPos >= zzBuffer.length - zzFinalHighSurrogate) { - /* if not: blow it up */ - char newBuffer[] = new char[zzBuffer.length * 2]; - System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); - zzBuffer = newBuffer; - zzEndRead += zzFinalHighSurrogate; - zzFinalHighSurrogate = 0; - } - - /* fill the buffer with new input */ - int requested = zzBuffer.length - zzEndRead; - int numRead = zzReader.read(zzBuffer, zzEndRead, requested); - - /* not supposed to occur according to specification of java.io.Reader */ - if (numRead == 0) { - throw new java.io.IOException( - "Reader returned 0 characters. See JFlex examples/zero-reader for a workaround."); - } - if (numRead > 0) { - zzEndRead += numRead; - if (Character.isHighSurrogate(zzBuffer[zzEndRead - 1])) { - if (numRead == requested) { // We requested too few chars to encode a full Unicode character - --zzEndRead; - zzFinalHighSurrogate = 1; - } else { // There is room in the buffer for at least one more char - int c = zzReader.read(); // Expecting to read a paired low surrogate char - if (c == -1) { - return true; - } else { - zzBuffer[zzEndRead++] = (char)c; - } - } - } - /* potentially more input available */ - return false; - } - - /* numRead < 0 ==> end of stream */ - return true; - } - - - /** - * Closes the input reader. - * - * @throws java.io.IOException if the reader could not be closed. - */ - public final void yyclose() throws java.io.IOException { - zzAtEOF = true; // indicate end of file - zzEndRead = zzStartRead; // invalidate buffer - - if (zzReader != null) { - zzReader.close(); - } - } - - - /** - * Resets the scanner to read from a new input stream. - * - *

Does not close the old reader. - * - *

All internal variables are reset, the old input stream cannot be reused (internal - * buffer is discarded and lost). Lexical state is set to {@code ZZ_INITIAL}. - * - *

Internal scan buffer is resized down to its initial length, if it has grown. - * - * @param reader The new input stream. - */ - public final void yyreset(java.io.Reader reader) { - zzReader = reader; - zzEOFDone = false; - yyResetPosition(); - zzLexicalState = YYINITIAL; - if (zzBuffer.length > ZZ_BUFFERSIZE) { - zzBuffer = new char[ZZ_BUFFERSIZE]; - } - } - - /** - * Resets the input position. - */ - private final void yyResetPosition() { - zzAtBOL = true; - zzAtEOF = false; - zzCurrentPos = 0; - zzMarkedPos = 0; - zzStartRead = 0; - zzEndRead = 0; - zzFinalHighSurrogate = 0; - yyline = 0; - yycolumn = 0; - yychar = 0L; - } - - - /** - * Returns whether the scanner has reached the end of the reader it reads from. - * - * @return whether the scanner has reached EOF. - */ - public final boolean yyatEOF() { - return zzAtEOF; - } - - - /** - * Returns the current lexical state. - * - * @return the current lexical state. - */ - public final int yystate() { - return zzLexicalState; - } - - - /** - * Enters a new lexical state. - * - * @param newState the new lexical state - */ - public final void yybegin(int newState) { - zzLexicalState = newState; - } - - - /** - * Returns the text matched by the current regular expression. - * - * @return the matched text. - */ - public final String yytext() { - return new String(zzBuffer, zzStartRead, zzMarkedPos-zzStartRead); - } - - - /** - * Returns the character at the given position from the matched text. - * - *

It is equivalent to {@code yytext().charAt(pos)}, but faster. - * - * @param position the position of the character to fetch. A value from 0 to {@code yylength()-1}. - * - * @return the character at {@code position}. - */ - public final char yycharat(int position) { - return zzBuffer[zzStartRead + position]; - } - - - /** - * How many characters were matched. - * - * @return the length of the matched text region. - */ - public final int yylength() { - return zzMarkedPos-zzStartRead; - } - - - /** - * Reports an error that occurred while scanning. - * - *

In a well-formed scanner (no or only correct usage of {@code yypushback(int)} and a - * match-all fallback rule) this method will only be called with things that - * "Can't Possibly Happen". - * - *

If this method is called, something is seriously wrong (e.g. a JFlex bug producing a faulty - * scanner etc.). - * - *

Usual syntax/scanner level error handling should be done in error fallback rules. - * - * @param errorCode the code of the error message to display. - */ - private static void zzScanError(int errorCode) { - String message; - try { - message = ZZ_ERROR_MSG[errorCode]; - } catch (ArrayIndexOutOfBoundsException e) { - message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; - } - - throw new Error(message); - } - - - /** - * Pushes the specified amount of characters back into the input stream. - * - *

They will be read again by then next call of the scanning method. - * - * @param number the number of characters to be read again. This number must not be greater than - * {@link #yylength()}. - */ - public void yypushback(int number) { - if ( number > yylength() ) - zzScanError(ZZ_PUSHBACK_2BIG); - - zzMarkedPos -= number; - } - - - - - /** - * Resumes scanning until the next regular expression is matched, the end of input is encountered - * or an I/O-Error occurs. - * - * @return the next token. - * @exception java.io.IOException if any I/O-Error occurs. - */ - @Override public java_cup.runtime.Symbol next_token() throws java.io.IOException { - int zzInput; - int zzAction; - - // cached fields: - int zzCurrentPosL; - int zzMarkedPosL; - int zzEndReadL = zzEndRead; - char[] zzBufferL = zzBuffer; - - int [] zzTransL = ZZ_TRANS; - int [] zzRowMapL = ZZ_ROWMAP; - int [] zzAttrL = ZZ_ATTRIBUTE; - - while (true) { - zzMarkedPosL = zzMarkedPos; - - boolean zzR = false; - int zzCh; - int zzCharCount; - for (zzCurrentPosL = zzStartRead ; - zzCurrentPosL < zzMarkedPosL ; - zzCurrentPosL += zzCharCount ) { - zzCh = Character.codePointAt(zzBufferL, zzCurrentPosL, zzMarkedPosL); - zzCharCount = Character.charCount(zzCh); - switch (zzCh) { - case '\u000B': // fall through - case '\u000C': // fall through - case '\u0085': // fall through - case '\u2028': // fall through - case '\u2029': - yyline++; - yycolumn = 0; - zzR = false; - break; - case '\r': - yyline++; - yycolumn = 0; - zzR = true; - break; - case '\n': - if (zzR) - zzR = false; - else { - yyline++; - yycolumn = 0; - } - break; - default: - zzR = false; - yycolumn += zzCharCount; - } - } - - if (zzR) { - // peek one character ahead if it is - // (if we have counted one line too much) - boolean zzPeek; - if (zzMarkedPosL < zzEndReadL) - zzPeek = zzBufferL[zzMarkedPosL] == '\n'; - else if (zzAtEOF) - zzPeek = false; - else { - boolean eof = zzRefill(); - zzEndReadL = zzEndRead; - zzMarkedPosL = zzMarkedPos; - zzBufferL = zzBuffer; - if (eof) - zzPeek = false; - else - zzPeek = zzBufferL[zzMarkedPosL] == '\n'; - } - if (zzPeek) yyline--; - } - zzAction = -1; - - zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; - - zzState = ZZ_LEXSTATE[zzLexicalState]; - - // set up zzAction for empty match case: - int zzAttributes = zzAttrL[zzState]; - if ( (zzAttributes & 1) == 1 ) { - zzAction = zzState; - } - - - zzForAction: { - while (true) { - - if (zzCurrentPosL < zzEndReadL) { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL); - zzCurrentPosL += Character.charCount(zzInput); - } - else if (zzAtEOF) { - zzInput = YYEOF; - break zzForAction; - } - else { - // store back cached positions - zzCurrentPos = zzCurrentPosL; - zzMarkedPos = zzMarkedPosL; - boolean eof = zzRefill(); - // get translated positions and possibly new buffer - zzCurrentPosL = zzCurrentPos; - zzMarkedPosL = zzMarkedPos; - zzBufferL = zzBuffer; - zzEndReadL = zzEndRead; - if (eof) { - zzInput = YYEOF; - break zzForAction; - } - else { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL); - zzCurrentPosL += Character.charCount(zzInput); - } - } - int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMap(zzInput) ]; - if (zzNext == -1) break zzForAction; - zzState = zzNext; - - zzAttributes = zzAttrL[zzState]; - if ( (zzAttributes & 1) == 1 ) { - zzAction = zzState; - zzMarkedPosL = zzCurrentPosL; - if ( (zzAttributes & 8) == 8 ) break zzForAction; - } - - } - } - - // store back cached position - zzMarkedPos = zzMarkedPosL; - - if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { - zzAtEOF = true; - { - return symbol(ChocoPyTokens.EOF); - } - } - else { - switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 1: - { yypushback(1); - if(top() > currIndent) - { - pop(); - return symbol(ChocoPyTokens.DEDENT); - } - yystart(AFTER); - if(top()< currIndent) - { - push(currIndent); - return symbol(ChocoPyTokens.INDENT); - } - } - // fall through - case 65: break; - case 2: - { String space = yytext(); - if(space == "\t") - currIndent += 8; - else - currIndent ++; - } - // fall through - case 66: break; - case 3: - { currIndent = 0; - } - // fall through - case 67: break; - case 4: - { /* ignored */ - } - // fall through - case 68: break; - case 5: - { return symbol(ChocoPyTokens.UNRECOGNIZED); - } - // fall through - case 69: break; - case 6: - { /* ignore */ - } - // fall through - case 70: break; - case 7: - { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0; - } - // fall through - case 71: break; - case 8: - { return symbol(ChocoPyTokens.MOD); - } - // fall through - case 72: break; - case 9: - { return symbol(ChocoPyTokens.LPAR); - } - // fall through - case 73: break; - case 10: - { return symbol(ChocoPyTokens.RPAR); - } - // fall through - case 74: break; - case 11: - { return symbol(ChocoPyTokens.MUL); - } - // fall through - case 75: break; - case 12: - { return symbol(ChocoPyTokens.PLUS); - } - // fall through - case 76: break; - case 13: - { return symbol(ChocoPyTokens.COMMA); - } - // fall through - case 77: break; - case 14: - { return symbol(ChocoPyTokens.MINUS); - } - // fall through - case 78: break; - case 15: - { return symbol(ChocoPyTokens.DOT); - } - // fall through - case 79: break; - case 16: - { return symbol(ChocoPyTokens.DIV); - } - // fall through - case 80: break; - case 17: - { return symbol(ChocoPyTokens.NUMBER, - Integer.parseInt(yytext())); - } - // fall through - case 81: break; - case 18: - { return symbol(ChocoPyTokens.COLON); - } - // fall through - case 82: break; - case 19: - { return symbol(ChocoPyTokens.LT); - } - // fall through - case 83: break; - case 20: - { return symbol(ChocoPyTokens.ASSIGN); - } - // fall through - case 84: break; - case 21: - { return symbol(ChocoPyTokens.GT); - } - // fall through - case 85: break; - case 22: - { return symbol(ChocoPyTokens.NAMES, yytext()); - } - // fall through - case 86: break; - case 23: - { return symbol(ChocoPyTokens.LBR); - } - // fall through - case 87: break; - case 24: - { return symbol(ChocoPyTokens.RBR); - } - // fall through - case 88: break; - case 25: - { return symbol(ChocoPyTokens.NEQ); - } - // fall through - case 89: break; - case 26: - { return symbol(ChocoPyTokens.STRING, yytext()); - } - // fall through - case 90: break; - case 27: - { return symbol(ChocoPyTokens.ARROW); - } - // fall through - case 91: break; - case 28: - { return symbol(ChocoPyTokens.LEQ); - } - // fall through - case 92: break; - case 29: - { return symbol(ChocoPyTokens.EQUAL); - } - // fall through - case 93: break; - case 30: - { return symbol(ChocoPyTokens.GEQ); - } - // fall through - case 94: break; - case 31: - { return symbol(ChocoPyTokens.AS); - } - // fall through - case 95: break; - case 32: - { return symbol(ChocoPyTokens.IF); - } - // fall through - case 96: break; - case 33: - { return symbol(ChocoPyTokens.IN); - } - // fall through - case 97: break; - case 34: - { return symbol(ChocoPyTokens.IS); - } - // fall through - case 98: break; - case 35: - { return symbol(ChocoPyTokens.OR); - } - // fall through - case 99: break; - case 36: - { return symbol(ChocoPyTokens.AND); - } - // fall through - case 100: break; - case 37: - { return symbol(ChocoPyTokens.DEF); - } - // fall through - case 101: break; - case 38: - { return symbol(ChocoPyTokens.DEL); - } - // fall through - case 102: break; - case 39: - { return symbol(ChocoPyTokens.FOR); - } - // fall through - case 103: break; - case 40: - { return symbol(ChocoPyTokens.NOT); - } - // fall through - case 104: break; - case 41: - { return symbol(ChocoPyTokens.TRY); - } - // fall through - case 105: break; - case 42: - { return symbol(ChocoPyTokens.NONE); - } - // fall through - case 106: break; - case 43: - { return symbol(ChocoPyTokens.BOOL, true); - } - // fall through - case 107: break; - case 44: - { return symbol(ChocoPyTokens.ELIF); - } - // fall through - case 108: break; - case 45: - { return symbol(ChocoPyTokens.ELSE); - } - // fall through - case 109: break; - case 46: - { return symbol(ChocoPyTokens.FROM); - } - // fall through - case 110: break; - case 47: - { return symbol(ChocoPyTokens.PASS); - } - // fall through - case 111: break; - case 48: - { return symbol(ChocoPyTokens.WITH); - } - // fall through - case 112: break; - case 49: - { return symbol(ChocoPyTokens.BOOL, false); - } - // fall through - case 113: break; - case 50: - { return symbol(ChocoPyTokens.AWAIT); - } - // fall through - case 114: break; - case 51: - { return symbol(ChocoPyTokens.BREAK); - } - // fall through - case 115: break; - case 52: - { return symbol(ChocoPyTokens.CLASS); - } - // fall through - case 116: break; - case 53: - { return symbol(ChocoPyTokens.RAISE); - } - // fall through - case 117: break; - case 54: - { return symbol(ChocoPyTokens.WHILE); - } - // fall through - case 118: break; - case 55: - { return symbol(ChocoPyTokens.YIELD); - } - // fall through - case 119: break; - case 56: - { return symbol(ChocoPyTokens.ASSERT); - } - // fall through - case 120: break; - case 57: - { return symbol(ChocoPyTokens.EXCEPT); - } - // fall through - case 121: break; - case 58: - { return symbol(ChocoPyTokens.GLOBAL); - } - // fall through - case 122: break; - case 59: - { return symbol(ChocoPyTokens.IMPORT); - } - // fall through - case 123: break; - case 60: - { return symbol(ChocoPyTokens.LAMBDA); - } - // fall through - case 124: break; - case 61: - { return symbol(ChocoPyTokens.RETURN); - } - // fall through - case 125: break; - case 62: - { return symbol(ChocoPyTokens.FINALLY); - } - // fall through - case 126: break; - case 63: - { return symbol(ChocoPyTokens.CONTINUE); - } - // fall through - case 127: break; - case 64: - { return symbol(ChocoPyTokens.NONLOCAL); - } - // fall through - case 128: break; - default: - zzScanError(ZZ_NO_MATCH); - } - } - } - } - - /** - * Converts an int token code into the name of the - * token by reflection on the cup symbol class/interface ChocoPyTokens - */ - private static String getTokenName(int token) { - try { - java.lang.reflect.Field [] classFields = ChocoPyTokens.class.getFields(); - for (int i = 0; i < classFields.length; i++) { - if (classFields[i].getInt(null) == token) { - return classFields[i].getName(); - } - } - } catch (Exception e) { - e.printStackTrace(System.err); - } - - return "UNKNOWN TOKEN"; - } - - /** - * Same as next_token but also prints the token to standard out - * for debugging. - */ - public java_cup.runtime.Symbol debug_next_token() throws java.io.IOException { - java_cup.runtime.Symbol s = next_token(); - System.out.println( "line:" + (yyline+1) + " col:" + (yycolumn+1) + " --"+ yytext() + "--" + getTokenName(s.sym) + "--"); - return s; - } - - /** - * Runs the scanner on input files. - * - * This main method is the debugging routine for the scanner. - * It prints debugging information about each returned token to - * System.out until the end of file is reached, or an error occured. - * - * @param argv the command line, contains the filenames to run - * the scanner on. - */ - public static void main(String[] argv) { - if (argv.length == 0) { - System.out.println("Usage : java ChocoPyLexer [ --encoding ] "); - } - else { - int firstFilePos = 0; - String encodingName = "UTF-8"; - if (argv[0].equals("--encoding")) { - firstFilePos = 2; - encodingName = argv[1]; - try { - // Side-effect: is encodingName valid? - java.nio.charset.Charset.forName(encodingName); - } catch (Exception e) { - System.out.println("Invalid encoding '" + encodingName + "'"); - return; - } - } - for (int i = firstFilePos; i < argv.length; i++) { - ChocoPyLexer scanner = null; - try { - java.io.FileInputStream stream = new java.io.FileInputStream(argv[i]); - java.io.Reader reader = new java.io.InputStreamReader(stream, encodingName); - scanner = new ChocoPyLexer(reader); - while ( !scanner.zzAtEOF ) scanner.debug_next_token(); - } - catch (java.io.FileNotFoundException e) { - System.out.println("File not found : \""+argv[i]+"\""); - } - catch (java.io.IOException e) { - System.out.println("IO error scanning file \""+argv[i]+"\""); - System.out.println(e); - } - catch (Exception e) { - System.out.println("Unexpected exception:"); - e.printStackTrace(); - } - } - } - } - - -} From 62330bd2370d572325a28b06f9b53b838e659371 Mon Sep 17 00:00:00 2001 From: bill Date: Thu, 18 Feb 2021 00:07:18 +0800 Subject: [PATCH 07/67] Fixed some typos, added comments. --- .gitignore | 3 + src/main/jflex/chocopy/pa1/ChocoPy.jflex | 79 +++++++++++++++++------- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 21cc758..987fe16 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,6 @@ tramp Session.vim .netrwhist *~ + +# JFlex +src/main/jflex/chocopy/pa1/ChocoPyLexer.java diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index d7640a7..24c0328 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -32,9 +32,10 @@ import java.util.ArrayList; /** Producer of token-related values for the parser. */ final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); - private int currIndent = 0; + private int currIndent = 0; //Current Indentation Level private int currString = ""; - private ArrayList stack = new ArrayList(20); + /*A stack that keeps track of the spaces in each Indentation Level*/ + private ArrayList stack = new ArrayList(20); /** Return a terminal symbol of syntactic category TYPE and no * semantic value at the current source location. */ private Symbol symbol(int type) { @@ -57,7 +58,7 @@ import java.util.ArrayList; return stack.remove(stack.size() - 1); } private int top(){ - if(stack.isEmpty) return 0; + if(stack.isEmpty()) return 0; return stack.get(stack.size() - 1); } %} @@ -67,39 +68,74 @@ import java.util.ArrayList; WhiteSpace = [ \t] LineBreak = \r|\n|\r\n -IntegerLiteral = 0|[1-9][0-9]* -StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))* -Names = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z])* +IntegerLiteral = 0|[1-9][0-9]* // Accroding to the manual, 00+ is illeagal +StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))* // \n, \r, \t, \\, \" and Anything except \ and " +Identifiers = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z][0-9])* Comments = #[^\r\n]* %% { {WhiteSpace} { - String space = yytext(); - if(space == "\t") - currIndent += 8; + /*Add indentation */ + if(yytext() == "\t") + currIndent += 8; //'\t' = 8 spaces else currIndent ++; } - {LineBreak} +/* +# This python code will test if '\t' is 8 spaces +# It will run and print '1\n2' +# Please tell me if your Python reports an error +# Or you find documentations that says otherwise + +if True: + print(1) # \t + print(2) # 8 spaces +*/ + + {LineBreak} { + /* + If this is a blank line, start over on the next line. + An empty line should just be ignored, therefore we don't + pass a NEWLINE to Cup. + */ currIndent = 0; } - {Comments} { /* ignored */ } - [^ \t\r\n#] + {Comments} { /* ignored */ } //Ignore blank lines + + /*If it's not a blank line (Current character isn't a + Whitespace/linebreak/comment), deal with indentation here and + start accepting whatever is on this line in `AFTER' state*/ + [^ \t\r\n#] { + //rewind the current character. yypushback(1); if(top() > currIndent) - { + { + /* + If the indentation of the line < indents current level should have, + keep dedenting until it reaches the right level. + It's like a loop, because we're not changing the state + and we rewinded the current character. So it will keep + going until top()<= currIndent and it will switch to + AFTER state. + */ pop(); - return symbol(ChocoPyTokens.DEDENT); + return symbol(ChocoPyTokens.DEDENT, currIndent); } + /*Otherwise, we will start dealing with the rest + of the line after indentation in from the next token.*/ yystart(AFTER); if(top()< currIndent) - { + { + /* + If current indentation > indents current level should have, + start a new level which will have `currIndent' spaces. + */ push(currIndent); - return symbol(ChocoPyTokens.INDENT); + return symbol(ChocoPyTokens.INDENT, currIndent); } } } @@ -113,8 +149,7 @@ Comments = #[^\r\n]* /* Literals. */ {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } -// {StringLiteral} { return symbol(ChocoPyTokens.STRING, yytext());} - "\"" {yystart(STR); currString = "";} + "\"" {yystart(STR); currString = "";} //Start taking a string when see a " "False" { return symbol(ChocoPyTokens.BOOL, false); } "True" { return symbol(ChocoPyTokens.BOOL, true); } "None" { return symbol(ChocoPyTokens.NONE); } @@ -154,7 +189,7 @@ Comments = #[^\r\n]* "-" { return symbol(ChocoPyTokens.MINUS); } "*" { return symbol(ChocoPyTokens.MUL); } "//" { return symbol(ChocoPyTokens.DIV); } - "/" { return symbol(ChocoPyTokens.DIV); } + "/" { return symbol(ChocoPyTokens.DIV); } //Accroding to manual, chocopy don't have fp division, '/', '//' should be integr division "%" { return symbol(ChocoPyTokens.MOD); } ">" { return symbol(ChocoPyTokens.GT); } "<" { return symbol(ChocoPyTokens.LT); } @@ -176,16 +211,16 @@ Comments = #[^\r\n]* /*Identifiers*/ - {Names} {return symbol(ChocoPyTokens.NAMES, yytext());} + {Identifiers} {return symbol(ChocoPyTokens.ID, yytext());} /* Whitespace. */ {WhiteSpace} { /* ignore */ } /* Comment. */ {Comments} { /* ignore */ } } { - {StringLiteral} {currString+=yytext();} + {StringLiteral} {currString += yytext();} \\$ { /*'\' at the end of line, do nothing.*/ } - "\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} + "\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} // accepted a ", return to AFTER state } <> { return symbol(ChocoPyTokens.EOF); } From d5097498b7b103865f919305ba4a32f651d7e594 Mon Sep 17 00:00:00 2001 From: bill Date: Thu, 18 Feb 2021 00:27:21 +0800 Subject: [PATCH 08/67] more comments --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index 24c0328..dc0677f 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -50,6 +50,7 @@ import java.util.ArrayList; new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), value); } + private void push(int indent){ stack.add(indent); } @@ -73,7 +74,15 @@ StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))* // \n, \r, \t, \\, \" Identifiers = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z][0-9])* Comments = #[^\r\n]* %% - +//YYINITIAL state is where we're dealing with indentations. +//We will set the state to YYINITIAL when starting a +//new line unless this line is within a string, e.g.: +/* +"this is \ +a string across \ +multiple lines\ +" +*/ { {WhiteSpace} { @@ -115,8 +124,10 @@ if True: if(top() > currIndent) { /* - If the indentation of the line < indents current level should have, - keep dedenting until it reaches the right level. + If the indentation of the line is less than number of + indents current level should have, + keep dedenting until it reaches the level with the same + number of indents. It's like a loop, because we're not changing the state and we rewinded the current character. So it will keep going until top()<= currIndent and it will switch to @@ -126,12 +137,12 @@ if True: return symbol(ChocoPyTokens.DEDENT, currIndent); } /*Otherwise, we will start dealing with the rest - of the line after indentation in from the next token.*/ + of the line after indentation in AFTER state. */ yystart(AFTER); if(top()< currIndent) { /* - If current indentation > indents current level should have, + If current indentation is more than indents current level should have, start a new level which will have `currIndent' spaces. */ push(currIndent); From ecb8d23418dd389b5160205022981e36b2c54425 Mon Sep 17 00:00:00 2001 From: bill Date: Thu, 18 Feb 2021 00:36:30 +0800 Subject: [PATCH 09/67] bug fixes --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 8 +- src/main/jflex/chocopy/pa1/ChocoPyLexer.java | 1287 ------------------ 2 files changed, 4 insertions(+), 1291 deletions(-) delete mode 100644 src/main/jflex/chocopy/pa1/ChocoPyLexer.java diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index dc0677f..ccb7187 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -33,7 +33,7 @@ import java.util.ArrayList; /** Producer of token-related values for the parser. */ final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); private int currIndent = 0; //Current Indentation Level - private int currString = ""; + private String currString = ""; /*A stack that keeps track of the spaces in each Indentation Level*/ private ArrayList stack = new ArrayList(20); /** Return a terminal symbol of syntactic category TYPE and no @@ -70,7 +70,7 @@ WhiteSpace = [ \t] LineBreak = \r|\n|\r\n IntegerLiteral = 0|[1-9][0-9]* // Accroding to the manual, 00+ is illeagal -StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))* // \n, \r, \t, \\, \" and Anything except \ and " +StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))+ // \n, \r, \t, \\, \" and Anything except \ and " Identifiers = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z][0-9])* Comments = #[^\r\n]* %% @@ -138,7 +138,7 @@ if True: } /*Otherwise, we will start dealing with the rest of the line after indentation in AFTER state. */ - yystart(AFTER); + yybegin(AFTER); if(top()< currIndent) { /* @@ -160,7 +160,7 @@ if True: /* Literals. */ {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } - "\"" {yystart(STR); currString = "";} //Start taking a string when see a " + "\"" {yybegin(STR); currString = "";} //Start taking a string when see a " "False" { return symbol(ChocoPyTokens.BOOL, false); } "True" { return symbol(ChocoPyTokens.BOOL, true); } "None" { return symbol(ChocoPyTokens.NONE); } diff --git a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java b/src/main/jflex/chocopy/pa1/ChocoPyLexer.java deleted file mode 100644 index ac26ed7..0000000 --- a/src/main/jflex/chocopy/pa1/ChocoPyLexer.java +++ /dev/null @@ -1,1287 +0,0 @@ -// DO NOT EDIT -// Generated by JFlex 1.8.2 http://jflex.de/ -// source: ChocoPy.jflex - -package chocopy.pa1; -import java_cup.runtime.*; -import java.util.ArrayList; - -// See https://github.com/jflex-de/jflex/issues/222 -@SuppressWarnings("FallThrough") -public class ChocoPyLexer implements java_cup.runtime.Scanner { - - /** This character denotes the end of file. */ - public static final int YYEOF = -1; - - /** Initial size of the lookahead buffer. */ - private static final int ZZ_BUFFERSIZE = 16384; - - // Lexical states. - public static final int YYINITIAL = 0; - public static final int AFTER = 2; - public static final int STR = 4; - - /** - * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l - * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l - * at the beginning of a line - * l is of the form l = 2*k, k a non negative integer - */ - private static final int ZZ_LEXSTATE[] = { - 0, 0, 1, 1, 2, 2 - }; - - /** - * Top-level table for translating characters to character classes - */ - private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top(); - - private static final String ZZ_CMAP_TOP_PACKED_0 = - "\1\0\37\u0100\1\u0200\u10df\u0100"; - - private static int [] zzUnpackcmap_top() { - int [] result = new int[4352]; - int offset = 0; - offset = zzUnpackcmap_top(ZZ_CMAP_TOP_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackcmap_top(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** - * Second-level tables for translating characters to character classes - */ - private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); - - private static final String ZZ_CMAP_BLOCKS_PACKED_0 = - "\11\0\1\1\1\2\2\3\1\4\22\0\1\1\1\5"+ - "\1\6\1\7\1\0\1\10\2\0\1\11\1\12\1\13"+ - "\1\14\1\15\1\16\1\17\1\20\1\21\11\22\1\23"+ - "\1\0\1\24\1\25\1\26\2\0\5\27\1\30\7\27"+ - "\1\31\5\27\1\32\6\27\1\33\1\34\1\35\1\0"+ - "\1\27\1\0\1\36\1\37\1\40\1\41\1\42\1\43"+ - "\1\44\1\45\1\46\1\27\1\47\1\50\1\51\1\52"+ - "\1\53\1\54\1\27\1\55\1\56\1\57\1\60\1\27"+ - "\1\61\1\62\1\63\1\27\12\0\1\3\u01a2\0\2\3"+ - "\326\0"; - - private static int [] zzUnpackcmap_blocks() { - int [] result = new int[768]; - int offset = 0; - offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - /** - * Translates DFA states to action switch labels. - */ - private static final int [] ZZ_ACTION = zzUnpackAction(); - - private static final String ZZ_ACTION_PACKED_0 = - "\2\0\1\1\1\2\1\3\2\4\1\5\1\6\1\7"+ - "\2\10\1\6\1\11\1\7\1\12\1\13\1\14\1\15"+ - "\1\16\1\17\1\20\1\21\1\22\2\23\1\24\1\25"+ - "\1\26\1\27\4\30\1\31\1\32\20\30\1\1\1\33"+ - "\1\6\1\34\1\35\1\22\1\36\1\37\1\40\4\30"+ - "\1\41\13\30\1\42\1\30\1\43\1\44\2\30\1\45"+ - "\7\30\1\0\2\46\3\30\1\47\5\30\1\50\1\51"+ - "\4\30\1\52\5\30\1\53\3\30\1\54\4\30\1\55"+ - "\1\56\5\30\1\57\1\60\2\30\1\61\4\30\1\62"+ - "\3\30\1\63\1\30\1\64\1\30\1\65\1\66\1\67"+ - "\7\30\1\70\1\30\1\71\1\72\1\73\1\30\1\74"+ - "\1\30\1\75\1\76\1\77\1\30\1\100\1\30\1\101"+ - "\1\30\1\102\1\103"; - - private static int [] zzUnpackAction() { - int [] result = new int[176]; - int offset = 0; - offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAction(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** - * Translates a state to a row index in the transition table - */ - private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); - - private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\64\0\150\0\234\0\234\0\234\0\320\0\u0104"+ - "\0\234\0\234\0\234\0\u0138\0\u016c\0\234\0\u01a0\0\234"+ - "\0\234\0\234\0\234\0\234\0\234\0\u01d4\0\234\0\u0208"+ - "\0\234\0\u023c\0\234\0\u0270\0\u02a4\0\u02d8\0\u030c\0\u0340"+ - "\0\u0374\0\u03a8\0\234\0\234\0\u03dc\0\u0410\0\u0444\0\u0478"+ - "\0\u04ac\0\u04e0\0\u0514\0\u0548\0\u057c\0\u05b0\0\u05e4\0\u0618"+ - "\0\u064c\0\u0680\0\u06b4\0\u06e8\0\u071c\0\234\0\u0750\0\234"+ - "\0\234\0\234\0\234\0\234\0\234\0\u0784\0\u07b8\0\u07ec"+ - "\0\u0820\0\u0854\0\u0888\0\u08bc\0\u08f0\0\u0924\0\u0958\0\u098c"+ - "\0\u09c0\0\u09f4\0\u0a28\0\u0a5c\0\u0a90\0\u030c\0\u0ac4\0\u030c"+ - "\0\u030c\0\u0af8\0\u0b2c\0\u030c\0\u0b60\0\u0b94\0\u0bc8\0\u0bfc"+ - "\0\u0c30\0\u0c64\0\u0c98\0\u0ccc\0\234\0\u0d00\0\u0d34\0\u0d68"+ - "\0\u0d9c\0\u030c\0\u0dd0\0\u0e04\0\u0e38\0\u0e6c\0\u0ea0\0\u030c"+ - "\0\u030c\0\u0ed4\0\u0f08\0\u0f3c\0\u0f70\0\u030c\0\u0fa4\0\u0fd8"+ - "\0\u100c\0\u1040\0\u1074\0\u030c\0\u10a8\0\u10dc\0\u1110\0\u030c"+ - "\0\u1144\0\u1178\0\u11ac\0\u11e0\0\u030c\0\u030c\0\u1214\0\u1248"+ - "\0\u127c\0\u12b0\0\u12e4\0\u030c\0\u030c\0\u1318\0\u134c\0\u030c"+ - "\0\u1380\0\u13b4\0\u13e8\0\u141c\0\u030c\0\u1450\0\u1484\0\u14b8"+ - "\0\u030c\0\u14ec\0\u030c\0\u1520\0\u030c\0\u030c\0\u030c\0\u1554"+ - "\0\u1588\0\u15bc\0\u15f0\0\u1624\0\u1658\0\u168c\0\u030c\0\u16c0"+ - "\0\u030c\0\u030c\0\u030c\0\u16f4\0\u030c\0\u1728\0\u030c\0\u030c"+ - "\0\u030c\0\u175c\0\u030c\0\u1790\0\u030c\0\u17c4\0\u030c\0\u030c"; - - private static int [] zzUnpackRowMap() { - int [] result = new int[176]; - int offset = 0; - offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackRowMap(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int high = packed.charAt(i++) << 16; - result[j++] = high | packed.charAt(i++); - } - return j; - } - - /** - * The transition table of the DFA - */ - private static final int [] ZZ_TRANS = zzUnpackTrans(); - - private static final String ZZ_TRANS_PACKED_0 = - "\1\4\1\5\1\6\1\4\1\7\2\4\1\10\54\4"+ - "\1\11\1\12\1\13\1\11\1\14\1\15\1\16\1\17"+ - "\1\20\1\21\1\22\1\23\1\24\1\25\1\26\1\27"+ - "\1\30\1\31\1\32\1\33\1\34\1\35\1\36\1\37"+ - "\1\40\1\41\1\42\1\43\1\11\1\44\1\45\1\46"+ - "\1\47\1\50\1\51\1\52\1\53\1\37\1\54\1\37"+ - "\1\55\1\37\1\56\1\57\1\60\1\61\1\37\1\62"+ - "\1\37\1\63\1\37\1\64\6\65\1\66\25\65\1\67"+ - "\27\65\66\0\1\6\61\0\2\10\1\0\1\10\1\0"+ - "\57\10\2\0\1\13\106\0\1\70\36\0\2\17\1\0"+ - "\1\17\1\0\57\17\26\0\1\71\55\0\1\72\64\0"+ - "\2\32\66\0\1\73\63\0\1\74\63\0\1\75\65\0"+ - "\4\37\3\0\26\37\27\0\4\37\3\0\1\76\25\37"+ - "\27\0\4\37\3\0\15\37\1\77\10\37\27\0\4\37"+ - "\3\0\17\37\1\100\6\37\27\0\4\37\3\0\14\37"+ - "\1\101\3\37\1\102\2\37\1\103\2\37\27\0\4\37"+ - "\3\0\17\37\1\104\6\37\27\0\4\37\3\0\12\37"+ - "\1\105\2\37\1\106\10\37\27\0\4\37\3\0\4\37"+ - "\1\107\21\37\27\0\4\37\3\0\12\37\1\110\11\37"+ - "\1\111\1\37\27\0\4\37\3\0\10\37\1\112\4\37"+ - "\1\113\1\37\1\114\6\37\27\0\4\37\3\0\12\37"+ - "\1\115\13\37\27\0\4\37\3\0\5\37\1\116\5\37"+ - "\1\117\1\120\3\37\1\121\5\37\27\0\4\37\3\0"+ - "\1\122\25\37\27\0\4\37\3\0\15\37\1\123\10\37"+ - "\27\0\4\37\3\0\17\37\1\124\6\37\27\0\4\37"+ - "\3\0\1\125\25\37\27\0\4\37\3\0\1\126\3\37"+ - "\1\127\21\37\27\0\4\37\3\0\17\37\1\130\6\37"+ - "\27\0\4\37\3\0\7\37\1\131\1\132\15\37\27\0"+ - "\4\37\3\0\10\37\1\133\15\37\6\65\1\0\25\65"+ - "\1\134\27\65\2\0\2\135\1\136\1\0\1\65\25\0"+ - "\1\65\15\0\1\65\2\0\1\65\1\0\1\65\33\0"+ - "\4\37\3\0\12\37\1\137\13\37\27\0\4\37\3\0"+ - "\14\37\1\140\11\37\27\0\4\37\3\0\22\37\1\141"+ - "\3\37\27\0\4\37\3\0\3\37\1\142\22\37\27\0"+ - "\4\37\3\0\20\37\1\143\5\37\27\0\4\37\3\0"+ - "\1\144\25\37\27\0\4\37\3\0\4\37\1\145\21\37"+ - "\27\0\4\37\3\0\1\146\25\37\27\0\4\37\3\0"+ - "\14\37\1\147\11\37\27\0\4\37\3\0\5\37\1\150"+ - "\4\37\1\151\13\37\27\0\4\37\3\0\10\37\1\152"+ - "\7\37\1\153\5\37\27\0\4\37\3\0\2\37\1\154"+ - "\23\37\27\0\4\37\3\0\14\37\1\155\11\37\27\0"+ - "\4\37\3\0\17\37\1\156\6\37\27\0\4\37\3\0"+ - "\15\37\1\157\10\37\27\0\4\37\3\0\15\37\1\160"+ - "\10\37\27\0\4\37\3\0\16\37\1\161\7\37\27\0"+ - "\4\37\3\0\13\37\1\162\12\37\27\0\4\37\3\0"+ - "\14\37\1\163\4\37\1\164\4\37\27\0\4\37\3\0"+ - "\20\37\1\165\5\37\27\0\4\37\3\0\10\37\1\166"+ - "\15\37\27\0\4\37\3\0\21\37\1\167\4\37\27\0"+ - "\4\37\3\0\25\37\1\170\27\0\4\37\3\0\10\37"+ - "\1\171\15\37\27\0\4\37\3\0\21\37\1\172\4\37"+ - "\27\0\4\37\3\0\4\37\1\173\21\37\6\0\1\65"+ - "\25\0\1\65\15\0\1\65\2\0\1\65\1\0\1\65"+ - "\6\0\1\135\110\0\4\37\3\0\20\37\1\174\5\37"+ - "\27\0\4\37\3\0\4\37\1\175\21\37\27\0\4\37"+ - "\3\0\4\37\1\176\21\37\27\0\4\37\3\0\4\37"+ - "\1\177\21\37\27\0\4\37\3\0\10\37\1\200\15\37"+ - "\27\0\4\37\3\0\1\201\25\37\27\0\4\37\3\0"+ - "\20\37\1\202\5\37\27\0\4\37\3\0\21\37\1\203"+ - "\4\37\27\0\4\37\3\0\5\37\1\204\20\37\27\0"+ - "\4\37\3\0\4\37\1\205\21\37\27\0\4\37\3\0"+ - "\4\37\1\206\21\37\27\0\4\37\3\0\1\207\25\37"+ - "\27\0\4\37\3\0\13\37\1\210\12\37\27\0\4\37"+ - "\3\0\1\37\1\211\24\37\27\0\4\37\3\0\15\37"+ - "\1\212\10\37\27\0\4\37\3\0\1\37\1\213\24\37"+ - "\27\0\4\37\3\0\12\37\1\214\13\37\27\0\4\37"+ - "\3\0\20\37\1\215\5\37\27\0\4\37\3\0\20\37"+ - "\1\216\5\37\27\0\4\37\3\0\22\37\1\217\3\37"+ - "\27\0\4\37\3\0\12\37\1\220\13\37\27\0\4\37"+ - "\3\0\7\37\1\221\16\37\27\0\4\37\3\0\12\37"+ - "\1\222\13\37\27\0\4\37\3\0\4\37\1\223\21\37"+ - "\27\0\4\37\3\0\17\37\1\224\6\37\27\0\4\37"+ - "\3\0\21\37\1\225\4\37\27\0\4\37\3\0\11\37"+ - "\1\226\14\37\27\0\4\37\3\0\20\37\1\227\5\37"+ - "\27\0\4\37\3\0\10\37\1\230\15\37\27\0\4\37"+ - "\3\0\16\37\1\231\7\37\27\0\4\37\3\0\12\37"+ - "\1\232\13\37\27\0\4\37\3\0\1\233\25\37\27\0"+ - "\4\37\3\0\17\37\1\234\6\37\27\0\4\37\3\0"+ - "\3\37\1\235\22\37\27\0\4\37\3\0\15\37\1\236"+ - "\10\37\27\0\4\37\3\0\4\37\1\237\21\37\27\0"+ - "\4\37\3\0\17\37\1\240\6\37\27\0\4\37\3\0"+ - "\4\37\1\241\21\37\27\0\4\37\3\0\3\37\1\242"+ - "\22\37\27\0\4\37\3\0\21\37\1\243\4\37\27\0"+ - "\4\37\3\0\14\37\1\244\11\37\27\0\4\37\3\0"+ - "\21\37\1\245\4\37\27\0\4\37\3\0\12\37\1\246"+ - "\13\37\27\0\4\37\3\0\12\37\1\247\13\37\27\0"+ - "\4\37\3\0\21\37\1\250\4\37\27\0\4\37\3\0"+ - "\1\251\25\37\27\0\4\37\3\0\2\37\1\252\23\37"+ - "\27\0\4\37\3\0\14\37\1\253\11\37\27\0\4\37"+ - "\3\0\22\37\1\254\3\37\27\0\4\37\3\0\25\37"+ - "\1\255\27\0\4\37\3\0\1\256\25\37\27\0\4\37"+ - "\3\0\4\37\1\257\21\37\27\0\4\37\3\0\12\37"+ - "\1\260\13\37"; - - private static int [] zzUnpackTrans() { - int [] result = new int[6136]; - int offset = 0; - offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackTrans(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - value--; - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** Error code for "Unknown internal scanner error". */ - private static final int ZZ_UNKNOWN_ERROR = 0; - /** Error code for "could not match input". */ - private static final int ZZ_NO_MATCH = 1; - /** Error code for "pushback value was too large". */ - private static final int ZZ_PUSHBACK_2BIG = 2; - - /** - * Error messages for {@link #ZZ_UNKNOWN_ERROR}, {@link #ZZ_NO_MATCH}, and - * {@link #ZZ_PUSHBACK_2BIG} respectively. - */ - private static final String ZZ_ERROR_MSG[] = { - "Unknown internal scanner error", - "Error: could not match input", - "Error: pushback value was too large" - }; - - /** - * ZZ_ATTRIBUTE[aState] contains the attributes of state {@code aState} - */ - private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); - - private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\2\0\1\1\3\11\2\1\3\11\2\1\1\11\1\1"+ - "\6\11\1\1\1\11\1\1\1\11\1\1\1\11\7\1"+ - "\2\11\21\1\1\11\1\1\6\11\36\1\1\0\1\11"+ - "\123\1"; - - private static int [] zzUnpackAttribute() { - int [] result = new int[176]; - int offset = 0; - offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAttribute(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - /** Input device. */ - private java.io.Reader zzReader; - - /** Current state of the DFA. */ - private int zzState; - - /** Current lexical state. */ - private int zzLexicalState = YYINITIAL; - - /** - * This buffer contains the current text to be matched and is the source of the {@link #yytext()} - * string. - */ - private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; - - /** Text position at the last accepting state. */ - private int zzMarkedPos; - - /** Current text position in the buffer. */ - private int zzCurrentPos; - - /** Marks the beginning of the {@link #yytext()} string in the buffer. */ - private int zzStartRead; - - /** Marks the last character in the buffer, that has been read from input. */ - private int zzEndRead; - - /** - * Whether the scanner is at the end of file. - * @see #yyatEOF - */ - private boolean zzAtEOF; - - /** - * The number of occupied positions in {@link #zzBuffer} beyond {@link #zzEndRead}. - * - *

When a lead/high surrogate has been read from the input stream into the final - * {@link #zzBuffer} position, this will have a value of 1; otherwise, it will have a value of 0. - */ - private int zzFinalHighSurrogate = 0; - - /** Number of newlines encountered up to the start of the matched text. */ - private int yyline; - - /** Number of characters from the last newline up to the start of the matched text. */ - private int yycolumn; - - /** Number of characters up to the start of the matched text. */ - @SuppressWarnings("unused") - private long yychar; - - /** Whether the scanner is currently at the beginning of a line. */ - @SuppressWarnings("unused") - private boolean zzAtBOL = true; - - /** Whether the user-EOF-code has already been executed. */ - @SuppressWarnings("unused") - private boolean zzEOFDone; - - /* user code: */ - /* 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(); - private int currIndent = 0; - private int currString = ""; - private ArrayList stack = new ArrayList(20); - /** 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); - } - - /** 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); - } - private void push(int indent){ - stack.add(indent); - } - private int pop(){ - if(stack.isEmpty()) return 0; - return stack.remove(stack.size() - 1); - } - private int top(){ - if(stack.isEmpty) return 0; - return stack.get(stack.size() - 1); - } - - - /** - * Creates a new scanner - * - * @param in the java.io.Reader to read input from. - */ - public ChocoPyLexer(java.io.Reader in) { - this.zzReader = in; - } - - /** - * Translates raw input code points to DFA table row - */ - private static int zzCMap(int input) { - int offset = input & 255; - return offset == input ? ZZ_CMAP_BLOCKS[offset] : ZZ_CMAP_BLOCKS[ZZ_CMAP_TOP[input >> 8] | offset]; - } - - /** - * Refills the input buffer. - * - * @return {@code false} iff there was new input. - * @exception java.io.IOException if any I/O-Error occurs - */ - private boolean zzRefill() throws java.io.IOException { - - /* first: make room (if you can) */ - if (zzStartRead > 0) { - zzEndRead += zzFinalHighSurrogate; - zzFinalHighSurrogate = 0; - System.arraycopy(zzBuffer, zzStartRead, - zzBuffer, 0, - zzEndRead - zzStartRead); - - /* translate stored positions */ - zzEndRead -= zzStartRead; - zzCurrentPos -= zzStartRead; - zzMarkedPos -= zzStartRead; - zzStartRead = 0; - } - - /* is the buffer big enough? */ - if (zzCurrentPos >= zzBuffer.length - zzFinalHighSurrogate) { - /* if not: blow it up */ - char newBuffer[] = new char[zzBuffer.length * 2]; - System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); - zzBuffer = newBuffer; - zzEndRead += zzFinalHighSurrogate; - zzFinalHighSurrogate = 0; - } - - /* fill the buffer with new input */ - int requested = zzBuffer.length - zzEndRead; - int numRead = zzReader.read(zzBuffer, zzEndRead, requested); - - /* not supposed to occur according to specification of java.io.Reader */ - if (numRead == 0) { - throw new java.io.IOException( - "Reader returned 0 characters. See JFlex examples/zero-reader for a workaround."); - } - if (numRead > 0) { - zzEndRead += numRead; - if (Character.isHighSurrogate(zzBuffer[zzEndRead - 1])) { - if (numRead == requested) { // We requested too few chars to encode a full Unicode character - --zzEndRead; - zzFinalHighSurrogate = 1; - } else { // There is room in the buffer for at least one more char - int c = zzReader.read(); // Expecting to read a paired low surrogate char - if (c == -1) { - return true; - } else { - zzBuffer[zzEndRead++] = (char)c; - } - } - } - /* potentially more input available */ - return false; - } - - /* numRead < 0 ==> end of stream */ - return true; - } - - - /** - * Closes the input reader. - * - * @throws java.io.IOException if the reader could not be closed. - */ - public final void yyclose() throws java.io.IOException { - zzAtEOF = true; // indicate end of file - zzEndRead = zzStartRead; // invalidate buffer - - if (zzReader != null) { - zzReader.close(); - } - } - - - /** - * Resets the scanner to read from a new input stream. - * - *

Does not close the old reader. - * - *

All internal variables are reset, the old input stream cannot be reused (internal - * buffer is discarded and lost). Lexical state is set to {@code ZZ_INITIAL}. - * - *

Internal scan buffer is resized down to its initial length, if it has grown. - * - * @param reader The new input stream. - */ - public final void yyreset(java.io.Reader reader) { - zzReader = reader; - zzEOFDone = false; - yyResetPosition(); - zzLexicalState = YYINITIAL; - if (zzBuffer.length > ZZ_BUFFERSIZE) { - zzBuffer = new char[ZZ_BUFFERSIZE]; - } - } - - /** - * Resets the input position. - */ - private final void yyResetPosition() { - zzAtBOL = true; - zzAtEOF = false; - zzCurrentPos = 0; - zzMarkedPos = 0; - zzStartRead = 0; - zzEndRead = 0; - zzFinalHighSurrogate = 0; - yyline = 0; - yycolumn = 0; - yychar = 0L; - } - - - /** - * Returns whether the scanner has reached the end of the reader it reads from. - * - * @return whether the scanner has reached EOF. - */ - public final boolean yyatEOF() { - return zzAtEOF; - } - - - /** - * Returns the current lexical state. - * - * @return the current lexical state. - */ - public final int yystate() { - return zzLexicalState; - } - - - /** - * Enters a new lexical state. - * - * @param newState the new lexical state - */ - public final void yybegin(int newState) { - zzLexicalState = newState; - } - - - /** - * Returns the text matched by the current regular expression. - * - * @return the matched text. - */ - public final String yytext() { - return new String(zzBuffer, zzStartRead, zzMarkedPos-zzStartRead); - } - - - /** - * Returns the character at the given position from the matched text. - * - *

It is equivalent to {@code yytext().charAt(pos)}, but faster. - * - * @param position the position of the character to fetch. A value from 0 to {@code yylength()-1}. - * - * @return the character at {@code position}. - */ - public final char yycharat(int position) { - return zzBuffer[zzStartRead + position]; - } - - - /** - * How many characters were matched. - * - * @return the length of the matched text region. - */ - public final int yylength() { - return zzMarkedPos-zzStartRead; - } - - - /** - * Reports an error that occurred while scanning. - * - *

In a well-formed scanner (no or only correct usage of {@code yypushback(int)} and a - * match-all fallback rule) this method will only be called with things that - * "Can't Possibly Happen". - * - *

If this method is called, something is seriously wrong (e.g. a JFlex bug producing a faulty - * scanner etc.). - * - *

Usual syntax/scanner level error handling should be done in error fallback rules. - * - * @param errorCode the code of the error message to display. - */ - private static void zzScanError(int errorCode) { - String message; - try { - message = ZZ_ERROR_MSG[errorCode]; - } catch (ArrayIndexOutOfBoundsException e) { - message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; - } - - throw new Error(message); - } - - - /** - * Pushes the specified amount of characters back into the input stream. - * - *

They will be read again by then next call of the scanning method. - * - * @param number the number of characters to be read again. This number must not be greater than - * {@link #yylength()}. - */ - public void yypushback(int number) { - if ( number > yylength() ) - zzScanError(ZZ_PUSHBACK_2BIG); - - zzMarkedPos -= number; - } - - - - - /** - * Resumes scanning until the next regular expression is matched, the end of input is encountered - * or an I/O-Error occurs. - * - * @return the next token. - * @exception java.io.IOException if any I/O-Error occurs. - */ - @Override public java_cup.runtime.Symbol next_token() throws java.io.IOException { - int zzInput; - int zzAction; - - // cached fields: - int zzCurrentPosL; - int zzMarkedPosL; - int zzEndReadL = zzEndRead; - char[] zzBufferL = zzBuffer; - - int [] zzTransL = ZZ_TRANS; - int [] zzRowMapL = ZZ_ROWMAP; - int [] zzAttrL = ZZ_ATTRIBUTE; - - while (true) { - zzMarkedPosL = zzMarkedPos; - - boolean zzR = false; - int zzCh; - int zzCharCount; - for (zzCurrentPosL = zzStartRead ; - zzCurrentPosL < zzMarkedPosL ; - zzCurrentPosL += zzCharCount ) { - zzCh = Character.codePointAt(zzBufferL, zzCurrentPosL, zzMarkedPosL); - zzCharCount = Character.charCount(zzCh); - switch (zzCh) { - case '\u000B': // fall through - case '\u000C': // fall through - case '\u0085': // fall through - case '\u2028': // fall through - case '\u2029': - yyline++; - yycolumn = 0; - zzR = false; - break; - case '\r': - yyline++; - yycolumn = 0; - zzR = true; - break; - case '\n': - if (zzR) - zzR = false; - else { - yyline++; - yycolumn = 0; - } - break; - default: - zzR = false; - yycolumn += zzCharCount; - } - } - - if (zzR) { - // peek one character ahead if it is - // (if we have counted one line too much) - boolean zzPeek; - if (zzMarkedPosL < zzEndReadL) - zzPeek = zzBufferL[zzMarkedPosL] == '\n'; - else if (zzAtEOF) - zzPeek = false; - else { - boolean eof = zzRefill(); - zzEndReadL = zzEndRead; - zzMarkedPosL = zzMarkedPos; - zzBufferL = zzBuffer; - if (eof) - zzPeek = false; - else - zzPeek = zzBufferL[zzMarkedPosL] == '\n'; - } - if (zzPeek) yyline--; - } - zzAction = -1; - - zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; - - zzState = ZZ_LEXSTATE[zzLexicalState]; - - // set up zzAction for empty match case: - int zzAttributes = zzAttrL[zzState]; - if ( (zzAttributes & 1) == 1 ) { - zzAction = zzState; - } - - - zzForAction: { - while (true) { - - if (zzCurrentPosL < zzEndReadL) { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL); - zzCurrentPosL += Character.charCount(zzInput); - } - else if (zzAtEOF) { - zzInput = YYEOF; - break zzForAction; - } - else { - // store back cached positions - zzCurrentPos = zzCurrentPosL; - zzMarkedPos = zzMarkedPosL; - boolean eof = zzRefill(); - // get translated positions and possibly new buffer - zzCurrentPosL = zzCurrentPos; - zzMarkedPosL = zzMarkedPos; - zzBufferL = zzBuffer; - zzEndReadL = zzEndRead; - if (eof) { - zzInput = YYEOF; - break zzForAction; - } - else { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL); - zzCurrentPosL += Character.charCount(zzInput); - } - } - int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMap(zzInput) ]; - if (zzNext == -1) break zzForAction; - zzState = zzNext; - - zzAttributes = zzAttrL[zzState]; - if ( (zzAttributes & 1) == 1 ) { - zzAction = zzState; - zzMarkedPosL = zzCurrentPosL; - if ( (zzAttributes & 8) == 8 ) break zzForAction; - } - - } - } - - // store back cached position - zzMarkedPos = zzMarkedPosL; - - if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { - zzAtEOF = true; - { - return symbol(ChocoPyTokens.EOF); - } - } - else { - switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 1: - { currString+=yytext(); - } - // fall through - case 68: break; - case 2: - { yypushback(1); - if(top() > currIndent) - { - pop(); - return symbol(ChocoPyTokens.DEDENT); - } - yystart(AFTER); - if(top()< currIndent) - { - push(currIndent); - return symbol(ChocoPyTokens.INDENT); - } - } - // fall through - case 69: break; - case 3: - { String space = yytext(); - if(space == "\t") - currIndent += 8; - else - currIndent ++; - } - // fall through - case 70: break; - case 4: - { currIndent = 0; - } - // fall through - case 71: break; - case 5: - { /* ignored */ - } - // fall through - case 72: break; - case 6: - { return symbol(ChocoPyTokens.UNRECOGNIZED); - } - // fall through - case 73: break; - case 7: - { /* ignore */ - } - // fall through - case 74: break; - case 8: - { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0; - } - // fall through - case 75: break; - case 9: - { yystart(STR); currString = ""; - } - // fall through - case 76: break; - case 10: - { return symbol(ChocoPyTokens.MOD); - } - // fall through - case 77: break; - case 11: - { return symbol(ChocoPyTokens.LPAR); - } - // fall through - case 78: break; - case 12: - { return symbol(ChocoPyTokens.RPAR); - } - // fall through - case 79: break; - case 13: - { return symbol(ChocoPyTokens.MUL); - } - // fall through - case 80: break; - case 14: - { return symbol(ChocoPyTokens.PLUS); - } - // fall through - case 81: break; - case 15: - { return symbol(ChocoPyTokens.COMMA); - } - // fall through - case 82: break; - case 16: - { return symbol(ChocoPyTokens.MINUS); - } - // fall through - case 83: break; - case 17: - { return symbol(ChocoPyTokens.DOT); - } - // fall through - case 84: break; - case 18: - { return symbol(ChocoPyTokens.DIV); - } - // fall through - case 85: break; - case 19: - { return symbol(ChocoPyTokens.NUMBER, - Integer.parseInt(yytext())); - } - // fall through - case 86: break; - case 20: - { return symbol(ChocoPyTokens.COLON); - } - // fall through - case 87: break; - case 21: - { return symbol(ChocoPyTokens.LT); - } - // fall through - case 88: break; - case 22: - { return symbol(ChocoPyTokens.ASSIGN); - } - // fall through - case 89: break; - case 23: - { return symbol(ChocoPyTokens.GT); - } - // fall through - case 90: break; - case 24: - { return symbol(ChocoPyTokens.NAMES, yytext()); - } - // fall through - case 91: break; - case 25: - { return symbol(ChocoPyTokens.LBR); - } - // fall through - case 92: break; - case 26: - { return symbol(ChocoPyTokens.RBR); - } - // fall through - case 93: break; - case 27: - { yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString); - } - // fall through - case 94: break; - case 28: - { return symbol(ChocoPyTokens.NEQ); - } - // fall through - case 95: break; - case 29: - { return symbol(ChocoPyTokens.ARROW); - } - // fall through - case 96: break; - case 30: - { return symbol(ChocoPyTokens.LEQ); - } - // fall through - case 97: break; - case 31: - { return symbol(ChocoPyTokens.EQUAL); - } - // fall through - case 98: break; - case 32: - { return symbol(ChocoPyTokens.GEQ); - } - // fall through - case 99: break; - case 33: - { return symbol(ChocoPyTokens.AS); - } - // fall through - case 100: break; - case 34: - { return symbol(ChocoPyTokens.IF); - } - // fall through - case 101: break; - case 35: - { return symbol(ChocoPyTokens.IN); - } - // fall through - case 102: break; - case 36: - { return symbol(ChocoPyTokens.IS); - } - // fall through - case 103: break; - case 37: - { return symbol(ChocoPyTokens.OR); - } - // fall through - case 104: break; - case 38: - // lookahead expression with fixed base length - zzMarkedPos = Character.offsetByCodePoints - (zzBufferL, zzStartRead, zzEndRead - zzStartRead, zzStartRead, 1); - { /*'\' at the end of line, do nothing.*/ - } - // fall through - case 105: break; - case 39: - { return symbol(ChocoPyTokens.AND); - } - // fall through - case 106: break; - case 40: - { return symbol(ChocoPyTokens.DEF); - } - // fall through - case 107: break; - case 41: - { return symbol(ChocoPyTokens.DEL); - } - // fall through - case 108: break; - case 42: - { return symbol(ChocoPyTokens.FOR); - } - // fall through - case 109: break; - case 43: - { return symbol(ChocoPyTokens.NOT); - } - // fall through - case 110: break; - case 44: - { return symbol(ChocoPyTokens.TRY); - } - // fall through - case 111: break; - case 45: - { return symbol(ChocoPyTokens.NONE); - } - // fall through - case 112: break; - case 46: - { return symbol(ChocoPyTokens.BOOL, true); - } - // fall through - case 113: break; - case 47: - { return symbol(ChocoPyTokens.ELIF); - } - // fall through - case 114: break; - case 48: - { return symbol(ChocoPyTokens.ELSE); - } - // fall through - case 115: break; - case 49: - { return symbol(ChocoPyTokens.FROM); - } - // fall through - case 116: break; - case 50: - { return symbol(ChocoPyTokens.PASS); - } - // fall through - case 117: break; - case 51: - { return symbol(ChocoPyTokens.WITH); - } - // fall through - case 118: break; - case 52: - { return symbol(ChocoPyTokens.BOOL, false); - } - // fall through - case 119: break; - case 53: - { return symbol(ChocoPyTokens.AWAIT); - } - // fall through - case 120: break; - case 54: - { return symbol(ChocoPyTokens.BREAK); - } - // fall through - case 121: break; - case 55: - { return symbol(ChocoPyTokens.CLASS); - } - // fall through - case 122: break; - case 56: - { return symbol(ChocoPyTokens.RAISE); - } - // fall through - case 123: break; - case 57: - { return symbol(ChocoPyTokens.WHILE); - } - // fall through - case 124: break; - case 58: - { return symbol(ChocoPyTokens.YIELD); - } - // fall through - case 125: break; - case 59: - { return symbol(ChocoPyTokens.ASSERT); - } - // fall through - case 126: break; - case 60: - { return symbol(ChocoPyTokens.EXCEPT); - } - // fall through - case 127: break; - case 61: - { return symbol(ChocoPyTokens.GLOBAL); - } - // fall through - case 128: break; - case 62: - { return symbol(ChocoPyTokens.IMPORT); - } - // fall through - case 129: break; - case 63: - { return symbol(ChocoPyTokens.LAMBDA); - } - // fall through - case 130: break; - case 64: - { return symbol(ChocoPyTokens.RETURN); - } - // fall through - case 131: break; - case 65: - { return symbol(ChocoPyTokens.FINALLY); - } - // fall through - case 132: break; - case 66: - { return symbol(ChocoPyTokens.CONTINUE); - } - // fall through - case 133: break; - case 67: - { return symbol(ChocoPyTokens.NONLOCAL); - } - // fall through - case 134: break; - default: - zzScanError(ZZ_NO_MATCH); - } - } - } - } - - /** - * Converts an int token code into the name of the - * token by reflection on the cup symbol class/interface ChocoPyTokens - */ - private static String getTokenName(int token) { - try { - java.lang.reflect.Field [] classFields = ChocoPyTokens.class.getFields(); - for (int i = 0; i < classFields.length; i++) { - if (classFields[i].getInt(null) == token) { - return classFields[i].getName(); - } - } - } catch (Exception e) { - e.printStackTrace(System.err); - } - - return "UNKNOWN TOKEN"; - } - - /** - * Same as next_token but also prints the token to standard out - * for debugging. - */ - public java_cup.runtime.Symbol debug_next_token() throws java.io.IOException { - java_cup.runtime.Symbol s = next_token(); - System.out.println( "line:" + (yyline+1) + " col:" + (yycolumn+1) + " --"+ yytext() + "--" + getTokenName(s.sym) + "--"); - return s; - } - - /** - * Runs the scanner on input files. - * - * This main method is the debugging routine for the scanner. - * It prints debugging information about each returned token to - * System.out until the end of file is reached, or an error occured. - * - * @param argv the command line, contains the filenames to run - * the scanner on. - */ - public static void main(String[] argv) { - if (argv.length == 0) { - System.out.println("Usage : java ChocoPyLexer [ --encoding ] "); - } - else { - int firstFilePos = 0; - String encodingName = "UTF-8"; - if (argv[0].equals("--encoding")) { - firstFilePos = 2; - encodingName = argv[1]; - try { - // Side-effect: is encodingName valid? - java.nio.charset.Charset.forName(encodingName); - } catch (Exception e) { - System.out.println("Invalid encoding '" + encodingName + "'"); - return; - } - } - for (int i = firstFilePos; i < argv.length; i++) { - ChocoPyLexer scanner = null; - try { - java.io.FileInputStream stream = new java.io.FileInputStream(argv[i]); - java.io.Reader reader = new java.io.InputStreamReader(stream, encodingName); - scanner = new ChocoPyLexer(reader); - while ( !scanner.zzAtEOF ) scanner.debug_next_token(); - } - catch (java.io.FileNotFoundException e) { - System.out.println("File not found : \""+argv[i]+"\""); - } - catch (java.io.IOException e) { - System.out.println("IO error scanning file \""+argv[i]+"\""); - System.out.println(e); - } - catch (Exception e) { - System.out.println("Unexpected exception:"); - e.printStackTrace(); - } - } - } - } - - -} From e844793c0292c3713b021b741b34d46e2f8968a4 Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Wed, 17 Feb 2021 13:34:39 -0500 Subject: [PATCH 10/67] Added terminals to parser --- src/main/cup/chocopy/pa1/ChocoPy.cup | 73 +++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index d4ff444..c1b8605 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -142,9 +142,78 @@ action code {: * semantic value of type for these symbols that may be referenced * in actions ( {: ... :} ). */ +terminal INDENT; +terminal DEDENT; +terminal String ID; +terminal String STRING; + + + +/* Terminal Delimiters */ terminal NEWLINE; -terminal String PLUS; -terminal Integer NUMBER; +terminal String COLON; +terminal String COMMA; + +/* Terminal Literals */ +terminal Integer NUMBER; +terminal Boolean BOOL; +terminal String NONE; + +/* Terminal Keywords */ +terminal String IF; +terminal String ELSE; +terminal String ELIF; +terminal String WHILE; +terminal String CLASS; +terminal String DEF; +terminal String LAMBDA; +terminal String AS; +terminal String FOR; +terminal String GLOBAL; +terminal String IN; +terminal String NONLOCAL; +terminal String PASS; +terminal String RETURN; +terminal String ASSERT; +terminal String AWAIT; +terminal String BREAK; +terminal String CONTINUE; +terminal String DEL; +terminal String EXCEPT; +terminal String FINALLY; +terminal String FROM; +terminal String IMPORT; +terminal String RAISE; +terminal String TRY; +terminal String WITH; +terminal String YIELD; + + +/* Terminal Operators */ +terminal String PLUS; +terminal String MINUS; +terminal String MUL; +terminal String DIV; +terminal String MOD; +terminal String GT; +terminal String LT; +terminal String EQUAL; +terminal String NEQ; +terminal String GEQ; +terminal String LEQ; +terminal String ASSIGN; +terminal String AND; +terminal String OR; +terminal String NOT; +terminal String DOT; +terminal String LPAR; +terminal String RPAR; +terminal String LBR; +terminal String RBR; +terminal String ARROW; +terminal String IS; + + /* Returned by the lexer for erroneous tokens. Since it does not appear in * the grammar, it indicates a syntax error. */ terminal UNRECOGNIZED; From 4cd3062255ea9e6376a554cdcf4d152112177b96 Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Wed, 17 Feb 2021 14:44:11 -0500 Subject: [PATCH 11/67] Added precedences --- src/main/cup/chocopy/pa1/ChocoPy.cup | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index c1b8605..f6abdda 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -213,7 +213,6 @@ terminal String RBR; terminal String ARROW; terminal String IS; - /* Returned by the lexer for erroneous tokens. Since it does not appear in * the grammar, it indicates a syntax error. */ terminal UNRECOGNIZED; @@ -231,7 +230,13 @@ 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; +precedence left OR; +precedence left AND; +precedence left NOT; +precedence nonassoc EQUAL, NEQ, LT, GT, LEQ, GEQ, IS; +precedence left PLUS, MINUS; +precedence left MUL, DIV, MOD; +precedence left DOT, COMMA, LBR, RBR; /* The start symbol. */ start with program; From 2ab3fddc66a086be21df37951b1c72a1c0964b5f Mon Sep 17 00:00:00 2001 From: bill Date: Thu, 18 Feb 2021 20:38:43 +0800 Subject: [PATCH 12/67] Bug fixed: unreachable code; symbol(value) not implemented. --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index ccb7187..9cc41de 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -39,7 +39,7 @@ import java.util.ArrayList; /** 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); + return symbol(type, null); } /** Return a terminal symbol of syntactic category TYPE and semantic @@ -142,8 +142,9 @@ if True: if(top()< currIndent) { /* - If current indentation is more than indents current level should have, - start a new level which will have `currIndent' spaces. + If current indentation is more than the number of indents + current level should have, start a new level which will have + `currIndent' indents. */ push(currIndent); return symbol(ChocoPyTokens.INDENT, currIndent); @@ -153,7 +154,7 @@ if True: { /* Delimiters. */ - {LineBreak} { return symbol(ChocoPyTokens.NEWLINE); yybegin(YYINITIAL); currIndent = 0;} + {LineBreak} { yybegin(YYINITIAL); currIndent = 0;return symbol(ChocoPyTokens.NEWLINE);} ":" { return symbol(ChocoPyTokens.COLON); } "," { return symbol(ChocoPyTokens.COMMA); } From d247243be145771d4d5df624a3ec67a00acf151b Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Thu, 18 Feb 2021 15:26:14 -0500 Subject: [PATCH 13/67] Added first 10 (till var_def) rules of grammer from lauguage reference --- src/main/cup/chocopy/pa1/ChocoPy.cup | 118 ++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index f6abdda..fb1f495 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -130,6 +130,18 @@ action code {: return new ComplexSymbolFactory.Location(first.getLocation()[0], first.getLocation()[1]); } + + /** Return the rightmost 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 getRight(List nodes) { + if (nodes.isEmpty()) { + return null; + } + Node last = nodes.get(nodes.size()-1); + return new ComplexSymbolFactory.Location(last.getLocation()[2], + last.getLocation()[3]); + } :} @@ -213,6 +225,7 @@ terminal String RBR; terminal String ARROW; terminal String IS; + /* Returned by the lexer for erroneous tokens. Since it does not appear in * the grammar, it indicates a syntax error. */ terminal UNRECOGNIZED; @@ -223,10 +236,22 @@ terminal UNRECOGNIZED; * defines the listed nonterminal identifier symbols to have semantic values * of type . */ non terminal Program program; -non terminal List program_head; +non terminal List program_head, class_body, class_body_defs, fun_body_decs; non terminal List stmt_list, opt_stmt_list; non terminal Stmt stmt, expr_stmt; non terminal Expr expr, binary_expr; +non terminal VarDef var_def; +non terminal ClassDef class_def; +non terminal FuncDef fun_def; +non terminal Literal literal; +non terminal TypedVar typed_var; +non terminal TypeAnnotation type, ret_type; +non terminal Identifier identifier; +non terminal List typed_vars; +non terminal GlobalDecl global_decl; +non terminal NonLocalDecl nonlocal_decl; + + /* Precedences (lowest to highest) for resolving what would otherwise be * ambiguities in the form of shift/reduce conflicts.. */ @@ -244,16 +269,97 @@ start with program; /***** GRAMMAR RULES *****/ +/* Rules are defined in the order given by the language reference */ + +/* program */ 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(); :} +program_head ::= program_head:d var_def:vd {: RESULT = combine(d, vd); :} + | program_head:d class_def:cd {: RESULT = combine(d, cd); :} + | program_head:d fun_def:fd {: RESULT = combine(d, fd); :} + | program_head:d error:e {: RESULT = d; :} + | {: RESULT = empty(); :} + ; + + +/* class_def */ +class_def ::= CLASS:c identifier:id LPAR identifier:parentId RPAR COLON NEWLINE INDENT class_body:cb DEDENT {: RESULT = new ClassDef(cxleft, getRight(cb), id, parentId, cb); :}; + + +/* class_body */ +class_body ::= PASS NEWLINE {: RESULT = empty(); :} + | class_body_defs:defs {: RESULT = defs; :} + ; + +class_body_defs ::= class_body_defs:defs var_def:vd {: RESULT = combine(defs, vd); :} + | class_body_defs:defs fun_def:fd {: RESULT = combine(defs, fd); :} + | class_body_defs:defs error {: RESULT = defs; :} + | var_def:vd {: RESULT = single(vd); :} + | fun_def:fd {: RESULT = single(fd); :} + ; + + +/* fun_def */ +fun_def ::= DEF:def identifier:id LPAR typed_vars:params RPAR ret_type:rt COLON NEWLINE INDENT fun_body_decs:fbd stmt_list:sl DEDENT + {: RESULT = new FuncDef(defxleft, getRight(sl), id, params, rt, fbd, sl); :} + ; + +ret_type ::= ARROW type:t {: RESULT= t; :} + | {: RESULT= null; :} + ; + +typed_vars ::= typed_var:tv {: RESULT= single(tv); :} + | typed_vars:tvs COMMA typed_var:tv {: RESULT= combine(tvs, tv); :} + | typed_vars:tvs COMMA error {: RESULT= tvs; :} + | {: RESULT= empty(); :} + ; + + + +/* fun_body */ +fun_body_decs ::= fun_body_decs:fbd global_decl:gd {: RESULT= combine(fbd, gd); :} + | fun_body_decs:fbd nonlocal_decl:nd {: RESULT= combine(fbd, nd); :} + | fun_body_decs:fbd var_def:vd {: RESULT= combine(fbd, vd); :} + | fun_body_decs:fbd fun_def:fd {: RESULT= combine(fbd, fd); :} + | fun_body_decs:fbd error {: RESULT= fbd; :} + | {: RESULT= empty(); :} ; + + +/* typed_var */ +typed_var ::= identifier:id COLON type:t {: RESULT = new TypedVar(idxleft, txright, id, t); :}; + + +/* type */ +type ::= identifier:id {: RESULT = new ClassType(idxleft, idxright, id.name); :} + | STRING:str {: RESULT = new ClassType(strxleft, strxright, str); :} + | LBR:lbr type:t RBR:rbr {: RESULT = new ListType(lbrxleft, rbrxright, t); :} + ; + + +/* global_decl */ +global_decl ::= GLOBAL:g identifier:id NEWLINE {: RESULT = new GlobalDecl(gxleft, idxright, id); :}; + + +/* nonlocal_decl */ +nonlocal_decl ::= NONLOCAL:n identifier:id NEWLINE {: RESULT = new NonLocalDecl(nxleft, idxright, id); :}; + + +/* var_def */ +var_def ::= typed_var:t ASSIGN literal:l NEWLINE {: RESULT = new VarDef(txleft, lxright, t, l); :}; + + +/* literal */ +literal ::= NONE:n {: RESULT = new NoneLiteral(nxleft, nxright); :} + | BOOL:b {: RESULT = new BooleanLiteral(bxleft, bxright, b); :} + | NUMBER:n {: RESULT = new IntegerLiteral(nxleft, nxright, n); :} + | STRING:s {: RESULT = new StringLiteral(sxleft, sxright, s); :} + ; + opt_stmt_list ::= {: RESULT = empty(); :} | stmt_list:s {: RESULT = s; :} @@ -286,3 +392,7 @@ binary_expr ::= expr:e1 PLUS:op expr:e2 {: RESULT = new BinaryExpr(e1xleft, e2xright, e1, op, e2); :} ; + + +/* Extras - rules below have not been given in language reference, we have them to ease implementation */ +identifier ::= ID:idStr {: RESULT = new Identifier(idStrxleft, idStrxright, idStr); :}; From 27b46f386d1bee3457d4c93fca9f208e399d7939 Mon Sep 17 00:00:00 2001 From: bill Date: Sat, 20 Feb 2021 04:04:06 +0800 Subject: [PATCH 14/67] Lexer will pass the original tokens even if it can be inferred to match the type of terminal defined in .cup file. --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index 9cc41de..8ecbb02 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -39,7 +39,7 @@ import java.util.ArrayList; /** 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, null); + return symbol(type, yytext()); } /** Return a terminal symbol of syntactic category TYPE and semantic From cf3bd4d7457356b3f53056652943fa9beebfbfe8 Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Fri, 19 Feb 2021 18:44:22 -0500 Subject: [PATCH 15/67] Finished all grammar - passes 24 test cases --- src/main/cup/chocopy/pa1/ChocoPy.cup | 150 ++++++++++++++++++++++----- 1 file changed, 122 insertions(+), 28 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index fb1f495..40f819a 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -237,19 +237,25 @@ terminal UNRECOGNIZED; * of type . */ non terminal Program program; non terminal List program_head, class_body, class_body_defs, fun_body_decs; -non terminal List stmt_list, opt_stmt_list; -non terminal Stmt stmt, expr_stmt; -non terminal Expr expr, binary_expr; +non terminal List stmt_list, opt_stmt_list, block, else_body; +non terminal Stmt stmt, simple_stmt; +non terminal Expr expr, binary_expr, pexpr, cexpr, cmp_pexpr; non terminal VarDef var_def; non terminal ClassDef class_def; non terminal FuncDef fun_def; non terminal Literal literal; +non terminal StringLiteral bin_op, comp_op; non terminal TypedVar typed_var; non terminal TypeAnnotation type, ret_type; non terminal Identifier identifier; non terminal List typed_vars; non terminal GlobalDecl global_decl; non terminal NonLocalDecl nonlocal_decl; +non terminal List opt_target, expr_list; +non terminal Expr target; +non terminal MemberExpr member_expr; +non terminal IndexExpr index_expr; + @@ -262,6 +268,7 @@ precedence nonassoc EQUAL, NEQ, LT, GT, LEQ, GEQ, IS; precedence left PLUS, MINUS; precedence left MUL, DIV, MOD; precedence left DOT, COMMA, LBR, RBR; +precedence left IF, ELSE; /* The start symbol. */ start with program; @@ -284,6 +291,10 @@ program_head ::= program_head:d var_def:vd {: RESULT = combine(d, v | program_head:d error:e {: RESULT = d; :} | {: RESULT = empty(); :} ; + +opt_stmt_list ::= {: RESULT = empty(); :} + | stmt_list:s {: RESULT = s; :} + ; /* class_def */ @@ -318,8 +329,7 @@ typed_vars ::= typed_var:tv {: RESULT= single(tv | {: RESULT= empty(); :} ; - - + /* fun_body */ fun_body_decs ::= fun_body_decs:fbd global_decl:gd {: RESULT= combine(fbd, gd); :} | fun_body_decs:fbd nonlocal_decl:nd {: RESULT= combine(fbd, nd); :} @@ -353,46 +363,130 @@ nonlocal_decl ::= NONLOCAL:n identifier:id NEWLINE {: RESULT = new NonLoc var_def ::= typed_var:t ASSIGN literal:l NEWLINE {: RESULT = new VarDef(txleft, lxright, t, l); :}; +/* stmt */ +stmt ::= simple_stmt:s NEWLINE {: RESULT = s; :} + | IF:i expr:cond COLON block:b else_body:elb {: RESULT = new IfStmt(ixleft, getRight(elb), cond, b, elb); :} + | WHILE:wh expr:cond COLON block:b {: RESULT = new WhileStmt(whxleft, getRight(b), cond, b); :} + | FOR:f identifier:id IN expr:e COLON block:b {: RESULT = new ForStmt(fxleft, getRight(b), id, e, b); :} + ; + + +else_body ::= ELSE:el COLON block:b {: RESULT = b; :} + | ELIF:el expr:cond COLON block:b else_body:elb {: RESULT = single(new IfStmt(elxleft, getRight(elb), cond, b, elb)); :} + | {: RESULT = empty(); :} + ; + +/* simple_stmt */ +simple_stmt ::= PASS:p {: RESULT = null; :} + | expr:e {: RESULT = new ExprStmt(exleft, exright, e); :} + | RETURN:r expr:e {: RESULT = new ReturnStmt(rxleft, exright, e); :} + | RETURN {: RESULT = null; :} + | opt_target:ot expr:e {: RESULT = new AssignStmt(getLeft(ot), exright, ot, e); :} + ; + + +opt_target ::= opt_target:ot target:t ASSIGN {: RESULT = combine(ot, t); :} + | target:t ASSIGN {: RESULT = single(t); :} + ; + + +/* block */ +block ::= NEWLINE INDENT stmt_list:sl DEDENT {: RESULT = sl; :}; + + /* literal */ literal ::= NONE:n {: RESULT = new NoneLiteral(nxleft, nxright); :} | BOOL:b {: RESULT = new BooleanLiteral(bxleft, bxright, b); :} | NUMBER:n {: RESULT = new IntegerLiteral(nxleft, nxright, n); :} | STRING:s {: RESULT = new StringLiteral(sxleft, sxright, s); :} ; + + +/* expr */ +expr ::= pexpr:ce {: RESULT = ce; :} + | NOT:n expr:exp {: RESULT = new UnaryExpr(nxleft, expxright, n, exp); :} + | expr:e1 AND:a expr:e2 {: RESULT = new BinaryExpr(e1xleft, e2xright, e1, a, e2); :} + | expr:e1 OR:o expr:e2 {: RESULT = new BinaryExpr(e1xleft, e2xright, e1, o, e2); :} + | expr:e1 IF expr:e2 ELSE expr:e3 {: RESULT = new IfExpr(e1xleft, e3xright, e2, e1, e3); :} + ; -opt_stmt_list ::= {: RESULT = empty(); :} - | stmt_list:s {: RESULT = s; :} - ; +/* cexpr */ +/* +cexpr ::= pexpr:pe {: RESULT = new Expr(pexleft, pexright); :} + | cmp_pexpr:cp {: RESULT = new Expr(cpxleft, cpxright); :} + ; -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. */ + +cmp_pexpr ::= pexpr:p comp_op:co cmp_pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, co, p2); :} + | pexpr:p {: RESULT = new Expr(pxleft, pxright); :} + ; +*/ + +/* pexpr */ +pexpr ::= identifier:id {: RESULT = id; :} + | literal:l {: RESULT = l; :} + | LBR:lbr expr_list:l RBR:rbr {: RESULT = new ListExpr(lbrxleft, rbrxright, l); :} + | LPAR:lpar expr:e RPAR:rpar {: RESULT = e; :} + | member_expr:m {: RESULT = m; :} + | index_expr:i {: RESULT = i; :} + | member_expr:m LPAR expr_list:l RPAR:rpar {: RESULT = new MethodCallExpr(mxleft, rparxright, m, l); :} + | identifier:id LPAR expr_list:l RPAR:rpar {: RESULT = new CallExpr(idxleft, rparxright, id, l); :} + | pexpr:p1 bin_op:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo.value, p2); :} + | MINUS:m pexpr:p {: RESULT = new UnaryExpr(mxleft, pxright, m, p); :} + | pexpr:p1 comp_op:co pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, co.value, p2); :} + ; + +expr_list ::= expr:e {: RESULT = single(e); :} + | expr_list:el COMMA expr:e {: RESULT = combine(el, e); :} + | {: RESULT = null; :} ; -stmt ::= expr_stmt:s NEWLINE {: RESULT = s; :} - ; -expr_stmt ::= expr:e {: RESULT = new ExprStmt(exleft, exright, e); :} - ; +/* bin_op */ +bin_op ::= PLUS:a {: RESULT = new StringLiteral(axleft, axright, "+"); :} + | MINUS:a {: RESULT = new StringLiteral(axleft, axright, "-"); :} + | MUL:a {: RESULT = new StringLiteral(axleft, axright, "*"); :} + | DIV:a {: RESULT = new StringLiteral(axleft, axright, "/"); :} + | MOD:a {: RESULT = new StringLiteral(axleft, axright, "%"); :} + ; -expr ::= binary_expr:e {: RESULT = e; :} - | NUMBER:n {: RESULT = new IntegerLiteral(nxleft, nxright, n); :} - ; +/* comp_op */ +comp_op ::= EQUAL:a {: RESULT = new StringLiteral(axleft, axright, "=="); :} + | NEQ:a {: RESULT = new StringLiteral(axleft, axright, "!="); :} + | LEQ:a {: RESULT = new StringLiteral(axleft, axright, "<="); :} + | GEQ:a {: RESULT = new StringLiteral(axleft, axright, ">="); :} + | LT:a {: RESULT = new StringLiteral(axleft, axright, "<"); :} + | GT:a {: RESULT = new StringLiteral(axleft, axright, ">"); :} + | IS:a {: RESULT = new StringLiteral(axleft, axright, "is"); :} + ; + +/* member_expr */ +member_expr ::= pexpr:p DOT identifier:id {: RESULT = new MemberExpr(pxleft, idxright, p, id); :} + ; -/* 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); :} +/* index_expr */ +index_expr ::= pexpr:p LBR expr:e RBR:rbr {: RESULT = new IndexExpr(pxleft, rbrxright, p, e); :} ; + +/* target */ +target ::= identifier:id {: RESULT = id; :} + | member_expr:m {: RESULT = m; :} + | index_expr:i {: RESULT = i; :} + ; /* Extras - rules below have not been given in language reference, we have them to ease implementation */ identifier ::= ID:idStr {: RESULT = new Identifier(idStrxleft, idStrxright, idStr); :}; + + +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. */ + ; \ No newline at end of file From 7b2e1dab3f8dcd16642ad514011b43275a5baf03 Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Fri, 19 Feb 2021 18:45:13 -0500 Subject: [PATCH 16/67] Added test scripts to ease testing --- build.sh | 3 +++ full_test.sh | 3 +++ test.sh | 12 ++++++++++++ 3 files changed, 18 insertions(+) create mode 100755 build.sh create mode 100755 full_test.sh create mode 100755 test.sh diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..f4e6621 --- /dev/null +++ b/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +mvn clean package -e diff --git a/full_test.sh b/full_test.sh new file mode 100755 index 0000000..19504c9 --- /dev/null +++ b/full_test.sh @@ -0,0 +1,3 @@ +#!/bin/bash +./build.sh +./test.sh diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..7060f44 --- /dev/null +++ b/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +FILENAME=$1 + +if [ -z "$1" ] ; then + echo "Running all test cases. Usage for individual test cases: test.sh FILENAME (inside src/test/data/pa1/sample/ folder)" + java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy --pass=s --test --dir src/test/data/pa1/sample/ + exit 1 +fi + +java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \ + --pass=s --test src/test/data/pa1/sample/${FILENAME} From 1c02aa84d85b4382e8d97332bf83fb98e1b65d0f Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Fri, 19 Feb 2021 19:03:02 -0500 Subject: [PATCH 17/67] Added cexpr --- src/main/cup/chocopy/pa1/ChocoPy.cup | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index 40f819a..e4004ff 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -403,7 +403,7 @@ literal ::= NONE:n {: RESULT = new NoneLi /* expr */ -expr ::= pexpr:ce {: RESULT = ce; :} +expr ::= cexpr:ce {: RESULT = ce; :} | NOT:n expr:exp {: RESULT = new UnaryExpr(nxleft, expxright, n, exp); :} | expr:e1 AND:a expr:e2 {: RESULT = new BinaryExpr(e1xleft, e2xright, e1, a, e2); :} | expr:e1 OR:o expr:e2 {: RESULT = new BinaryExpr(e1xleft, e2xright, e1, o, e2); :} @@ -412,29 +412,23 @@ expr ::= pexpr:ce {: RESULT = ce; :} /* cexpr */ -/* -cexpr ::= pexpr:pe {: RESULT = new Expr(pexleft, pexright); :} - | cmp_pexpr:cp {: RESULT = new Expr(cpxleft, cpxright); :} +cexpr ::= pexpr:pe {: RESULT = pe; :} + | pexpr:p1 comp_op:co cexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, co.value, p2); :} ; -cmp_pexpr ::= pexpr:p comp_op:co cmp_pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, co, p2); :} - | pexpr:p {: RESULT = new Expr(pxleft, pxright); :} - ; -*/ /* pexpr */ pexpr ::= identifier:id {: RESULT = id; :} | literal:l {: RESULT = l; :} | LBR:lbr expr_list:l RBR:rbr {: RESULT = new ListExpr(lbrxleft, rbrxright, l); :} - | LPAR:lpar expr:e RPAR:rpar {: RESULT = e; :} + | LPAR:lpar expr:e RPAR:rpar {: RESULT = e; :} | member_expr:m {: RESULT = m; :} | index_expr:i {: RESULT = i; :} | member_expr:m LPAR expr_list:l RPAR:rpar {: RESULT = new MethodCallExpr(mxleft, rparxright, m, l); :} | identifier:id LPAR expr_list:l RPAR:rpar {: RESULT = new CallExpr(idxleft, rparxright, id, l); :} | pexpr:p1 bin_op:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo.value, p2); :} | MINUS:m pexpr:p {: RESULT = new UnaryExpr(mxleft, pxright, m, p); :} - | pexpr:p1 comp_op:co pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, co.value, p2); :} ; expr_list ::= expr:e {: RESULT = single(e); :} From 0672838265f037bbe321007d84c961370e2804fc Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Fri, 19 Feb 2021 19:06:13 -0500 Subject: [PATCH 18/67] Cleanup --- src/main/cup/chocopy/pa1/ChocoPy.cup | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index e4004ff..13e324c 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -239,7 +239,7 @@ non terminal Program program; non terminal List program_head, class_body, class_body_defs, fun_body_decs; non terminal List stmt_list, opt_stmt_list, block, else_body; non terminal Stmt stmt, simple_stmt; -non terminal Expr expr, binary_expr, pexpr, cexpr, cmp_pexpr; +non terminal Expr expr, pexpr, cexpr; non terminal VarDef var_def; non terminal ClassDef class_def; non terminal FuncDef fun_def; @@ -376,6 +376,7 @@ else_body ::= ELSE:el COLON block:b {: RES | {: RESULT = empty(); :} ; + /* simple_stmt */ simple_stmt ::= PASS:p {: RESULT = null; :} | expr:e {: RESULT = new ExprStmt(exleft, exright, e); :} @@ -417,7 +418,6 @@ cexpr ::= pexpr:pe {: RESULT = pe; :} ; - /* pexpr */ pexpr ::= identifier:id {: RESULT = id; :} | literal:l {: RESULT = l; :} @@ -456,14 +456,17 @@ comp_op ::= EQUAL:a {: RESULT = new Stri | IS:a {: RESULT = new StringLiteral(axleft, axright, "is"); :} ; + /* member_expr */ member_expr ::= pexpr:p DOT identifier:id {: RESULT = new MemberExpr(pxleft, idxright, p, id); :} ; + /* index_expr */ index_expr ::= pexpr:p LBR expr:e RBR:rbr {: RESULT = new IndexExpr(pxleft, rbrxright, p, e); :} ; + /* target */ target ::= identifier:id {: RESULT = id; :} | member_expr:m {: RESULT = m; :} From c5c9bb2f0d177dc9a983d7fa5bd3e2529117ee54 Mon Sep 17 00:00:00 2001 From: bill Date: Sat, 20 Feb 2021 19:46:30 +0800 Subject: [PATCH 19/67] Changes made on Flex to adapt for merging. --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index 8ecbb02..8699d5c 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -34,6 +34,7 @@ import java.util.ArrayList; final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory(); private int currIndent = 0; //Current Indentation Level private String currString = ""; + private int str_l = 0, str_c = 0; //Start location of a string. /*A stack that keeps track of the spaces in each Indentation Level*/ private ArrayList stack = new ArrayList(20); /** Return a terminal symbol of syntactic category TYPE and no @@ -45,6 +46,7 @@ import java.util.ArrayList; /** Return a terminal symbol of syntactic category TYPE and semantic * value VALUE at the current source location. */ private Symbol symbol(int type, Object value) { + //System.out.println(yytext() + ChocoPyTokens.terminalNames[type]); return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[type], type, new ComplexSymbolFactory.Location(yyline + 1, yycolumn + 1), new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), @@ -134,6 +136,7 @@ if True: AFTER state. */ pop(); + //System.out.println("dedent"); return symbol(ChocoPyTokens.DEDENT, currIndent); } /*Otherwise, we will start dealing with the rest @@ -146,6 +149,8 @@ if True: current level should have, start a new level which will have `currIndent' indents. */ + //System.out.println("indent"); + push(currIndent); return symbol(ChocoPyTokens.INDENT, currIndent); } @@ -161,7 +166,7 @@ if True: /* Literals. */ {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } - "\"" {yybegin(STR); currString = "";} //Start taking a string when see a " + "\"" {yybegin(STR); str_l = yyline + 1; str_c = yycolumn + 1; currString = "";} //Start taking a string when see a " "False" { return symbol(ChocoPyTokens.BOOL, false); } "True" { return symbol(ChocoPyTokens.BOOL, true); } "None" { return symbol(ChocoPyTokens.NONE); } @@ -223,7 +228,7 @@ if True: /*Identifiers*/ - {Identifiers} {return symbol(ChocoPyTokens.ID, yytext());} + {Identifiers} {return symbol(ChocoPyTokens.ID, yytext());} /* Whitespace. */ {WhiteSpace} { /* ignore */ } /* Comment. */ @@ -232,9 +237,12 @@ if True: { {StringLiteral} {currString += yytext();} \\$ { /*'\' at the end of line, do nothing.*/ } - "\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} // accepted a ", return to AFTER state + "\"" {yybegin(AFTER); return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[ChocoPyTokens.STRING], ChocoPyTokens.STRING, + new ComplexSymbolFactory.Location(str_l, str_c), + new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), + currString);} // accepted a ", return to AFTER state } -<> { return symbol(ChocoPyTokens.EOF); } +<> { if(!stack.isEmpty()){ return symbol(ChocoPyTokens.DEDENT, pop());} return symbol(ChocoPyTokens.EOF);} /* Error fallback. */ [^] { return symbol(ChocoPyTokens.UNRECOGNIZED); } From ab6c72e690319326465a4ad63629ff47b0ff8da0 Mon Sep 17 00:00:00 2001 From: bill Date: Sat, 20 Feb 2021 21:42:01 +0800 Subject: [PATCH 20/67] Simple fixes for the errors. --- src/main/cup/chocopy/pa1/ChocoPy.cup | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index 13e324c..bb26a36 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -268,7 +268,7 @@ precedence nonassoc EQUAL, NEQ, LT, GT, LEQ, GEQ, IS; precedence left PLUS, MINUS; precedence left MUL, DIV, MOD; precedence left DOT, COMMA, LBR, RBR; -precedence left IF, ELSE; +precedence right IF, ELSE; /* The start symbol. */ start with program; @@ -315,12 +315,12 @@ class_body_defs ::= class_body_defs:defs var_def:vd {: RESULT = combine(de /* fun_def */ -fun_def ::= DEF:def identifier:id LPAR typed_vars:params RPAR ret_type:rt COLON NEWLINE INDENT fun_body_decs:fbd stmt_list:sl DEDENT - {: RESULT = new FuncDef(defxleft, getRight(sl), id, params, rt, fbd, sl); :} +fun_def ::= DEF:def identifier:id LPAR typed_vars:params RPAR ret_type:rt COLON:col NEWLINE INDENT fun_body_decs:fbd stmt_list:sl DEDENT + {: TypeAnnotation _rt = rt;if(rt.getLocation()[0] == -2) _rt = new ClassType( colxright, colxright, "");RESULT = new FuncDef(defxleft, getRight(sl), id, params, _rt, fbd, sl); :} ; ret_type ::= ARROW type:t {: RESULT= t; :} - | {: RESULT= null; :} + | {: RESULT= new ClassType(new ComplexSymbolFactory.Location(-2,-1), new ComplexSymbolFactory.Location(-1,-1),""); :} ; typed_vars ::= typed_var:tv {: RESULT= single(tv); :} @@ -427,13 +427,17 @@ pexpr ::= identifier:id {: RESULT = id; :} | index_expr:i {: RESULT = i; :} | member_expr:m LPAR expr_list:l RPAR:rpar {: RESULT = new MethodCallExpr(mxleft, rparxright, m, l); :} | identifier:id LPAR expr_list:l RPAR:rpar {: RESULT = new CallExpr(idxleft, rparxright, id, l); :} - | pexpr:p1 bin_op:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo.value, p2); :} + | pexpr:p1 PLUS:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 MINUS:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 MUL:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 DIV:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 MOD:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} | MINUS:m pexpr:p {: RESULT = new UnaryExpr(mxleft, pxright, m, p); :} ; expr_list ::= expr:e {: RESULT = single(e); :} | expr_list:el COMMA expr:e {: RESULT = combine(el, e); :} - | {: RESULT = null; :} + | {: RESULT = new ArrayList(); :} ; From b2536564bcdb65b25b40ce99e644f391c507a64d Mon Sep 17 00:00:00 2001 From: bill Date: Sat, 20 Feb 2021 23:24:11 +0800 Subject: [PATCH 21/67] Cleanup --- src/main/cup/chocopy/pa1/ChocoPy.cup | 21 ++++++++++----------- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 3 --- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index bb26a36..15340a3 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -316,11 +316,11 @@ class_body_defs ::= class_body_defs:defs var_def:vd {: RESULT = combine(de /* fun_def */ fun_def ::= DEF:def identifier:id LPAR typed_vars:params RPAR ret_type:rt COLON:col NEWLINE INDENT fun_body_decs:fbd stmt_list:sl DEDENT - {: TypeAnnotation _rt = rt;if(rt.getLocation()[0] == -2) _rt = new ClassType( colxright, colxright, "");RESULT = new FuncDef(defxleft, getRight(sl), id, params, _rt, fbd, sl); :} + {: TypeAnnotation _rt = rt;if((rt instanceof ClassType) && ((ClassType)rt).className == "") _rt = new ClassType( colxright, colxright, "");RESULT = new FuncDef(defxleft, getRight(sl), id, params, _rt, fbd, sl); :} ; ret_type ::= ARROW type:t {: RESULT= t; :} - | {: RESULT= new ClassType(new ComplexSymbolFactory.Location(-2,-1), new ComplexSymbolFactory.Location(-1,-1),""); :} + | {: RESULT= new ClassType(null, null,""); :} ; typed_vars ::= typed_var:tv {: RESULT= single(tv); :} @@ -427,11 +427,11 @@ pexpr ::= identifier:id {: RESULT = id; :} | index_expr:i {: RESULT = i; :} | member_expr:m LPAR expr_list:l RPAR:rpar {: RESULT = new MethodCallExpr(mxleft, rparxright, m, l); :} | identifier:id LPAR expr_list:l RPAR:rpar {: RESULT = new CallExpr(idxleft, rparxright, id, l); :} - | pexpr:p1 PLUS:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} - | pexpr:p1 MINUS:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} - | pexpr:p1 MUL:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} - | pexpr:p1 DIV:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} - | pexpr:p1 MOD:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 PLUS:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 MINUS:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 MUL:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 DIV:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} + | pexpr:p1 MOD:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} | MINUS:m pexpr:p {: RESULT = new UnaryExpr(mxleft, pxright, m, p); :} ; @@ -440,17 +440,16 @@ expr_list ::= expr:e {: RESULT = single(e); | {: RESULT = new ArrayList(); :} ; - -/* bin_op */ +/* bin_op */ //We may still be able to use bin_op, so I left it here. bin_op ::= PLUS:a {: RESULT = new StringLiteral(axleft, axright, "+"); :} | MINUS:a {: RESULT = new StringLiteral(axleft, axright, "-"); :} | MUL:a {: RESULT = new StringLiteral(axleft, axright, "*"); :} - | DIV:a {: RESULT = new StringLiteral(axleft, axright, "/"); :} + | DIV:a {: RESULT = new StringLiteral(axleft, axright, "//"); :} //Section 2.6.3 in chocopy language reference | MOD:a {: RESULT = new StringLiteral(axleft, axright, "%"); :} ; -/* comp_op */ +/* comp_op */ //this might also need some change in order not to break left associativity comp_op ::= EQUAL:a {: RESULT = new StringLiteral(axleft, axright, "=="); :} | NEQ:a {: RESULT = new StringLiteral(axleft, axright, "!="); :} | LEQ:a {: RESULT = new StringLiteral(axleft, axright, "<="); :} diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index 8699d5c..43a7f03 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -46,7 +46,6 @@ import java.util.ArrayList; /** Return a terminal symbol of syntactic category TYPE and semantic * value VALUE at the current source location. */ private Symbol symbol(int type, Object value) { - //System.out.println(yytext() + ChocoPyTokens.terminalNames[type]); return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[type], type, new ComplexSymbolFactory.Location(yyline + 1, yycolumn + 1), new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), @@ -136,7 +135,6 @@ if True: AFTER state. */ pop(); - //System.out.println("dedent"); return symbol(ChocoPyTokens.DEDENT, currIndent); } /*Otherwise, we will start dealing with the rest @@ -149,7 +147,6 @@ if True: current level should have, start a new level which will have `currIndent' indents. */ - //System.out.println("indent"); push(currIndent); return symbol(ChocoPyTokens.INDENT, currIndent); From ca13d4c461509ea07cb08a6f253108424bf0ef79 Mon Sep 17 00:00:00 2001 From: bill Date: Sun, 21 Feb 2021 17:55:07 +0800 Subject: [PATCH 22/67] Fixed failure on test bad_indentation.py --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index 43a7f03..55446aa 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -149,7 +149,10 @@ if True: */ push(currIndent); - return symbol(ChocoPyTokens.INDENT, currIndent); + return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[ChocoPyTokens.INDENT], ChocoPyTokens.INDENT, + new ComplexSymbolFactory.Location(yyline + 1, yycolumn - 1), + new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), + currIndent); } } } From 0c5f9b6d8b7ef216c23dffe592036e4e202e1b3e Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Mon, 22 Feb 2021 10:18:59 +0530 Subject: [PATCH 23/67] Adding tests --- src/test/data/pa1/student_contributed/bad.py | 30 ++++++++ src/test/data/pa1/student_contributed/good.py | 69 ++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/test/data/pa1/student_contributed/bad.py b/src/test/data/pa1/student_contributed/bad.py index b85905e..56f38a7 100644 --- a/src/test/data/pa1/student_contributed/bad.py +++ b/src/test/data/pa1/student_contributed/bad.py @@ -1 +1,31 @@ 1 2 3 + +def fun5(): + c = 6 + def fun6(): + print("Hello") + c = 4 + 5 + +if True: + if True: + print("Hello") + if True: + print("Maybe") + else: + print("World") +else: + print("Again") +else: + print("And Again") + +class Thor(object): + y:int = 0 + print("Right place?") + +class Stones(object): + y:int = 0 + def fun(x:int): + print("Right place?") + def bar(): + return 2+3 + print("Wrong Place") diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py index 8138b36..6d27ff6 100644 --- a/src/test/data/pa1/student_contributed/good.py +++ b/src/test/data/pa1/student_contributed/good.py @@ -1 +1,68 @@ -1 + 2 + 3 + +print("Hi") +def fun1(): + def fun2(): + print("Hello") + +print("World") + +def fun3(): + def fun4(): + print("Hello") + c = 4 + 5 + +def fun5(): + c = 6 + def fun6(): + print("Hello") + c = 4 + 5 + + +if True: + if True: + if True: + print("Hello") +print("World") + +if True: + if True: + if True: + print("Hello") + print("World") + +if True: + if True: + if True: + print("Hello") + print("World") + +if True: + if True: + if True: + print("Hello") + else: + print("World") + +if True: + if True: + if True: + print("Hello") +else: + print("World") + +class Foo(object): + x:int = 0 + + def __init__(self:"Foo", x:int): + self.x = x + + def bar(y:int)->None: + print("Hello World!",self.x+y) + y = 10 + +f = Foo(1) +print(f.x) +f.bar(4) + +a=[[[1],[2]][[3],[4]]] +print(a[0][0][1]*a[1][1][0]) \ No newline at end of file From f6091d744f9ab13fa24088aea881aeec751a9259 Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Mon, 22 Feb 2021 10:39:50 +0530 Subject: [PATCH 24/67] Create WORKLOG.md --- WORKLOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 WORKLOG.md diff --git a/WORKLOG.md b/WORKLOG.md new file mode 100644 index 0000000..612c819 --- /dev/null +++ b/WORKLOG.md @@ -0,0 +1,17 @@ +Compiler Construction PA1 Worklog +
+
Team: +
Apoorva Ranade(ar6496) +
Sanjar Ahmadov(sa5640) +
Yinqi Sun(ys3540) +
+
Acknowledgments: Provide attribution to any collaborations, external resources, or out-side help. +
+
Indentation: Describe your strategy for handling INDENT and DEDENT tokens. Point to the relevant source files and line numbers. +
A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. +
+
Challenges: Describe any challenges (besides indentation) you encountered and the way you solved them. Mention the approaches that did not work, if any. +
+
+
Improvements: Describe any improvements you introduced that were not strictly necessary to pass the tests, such as implementing additional functionality, adding new tests, or enabling static analysis. +
Added more tests to rigorously check program flow and indentation. From 609903851d29089cf143810f28bb5e95e0c9fa22 Mon Sep 17 00:00:00 2001 From: bill Date: Mon, 22 Feb 2021 16:42:06 +0800 Subject: [PATCH 25/67] Bug fixes: Catching Indentation Errors. A typo on regex of Identifiers Potential fixes on allowing function body with only definations. (not applied) TODO: Allowing a program to have interleaving definations and statements? --- src/main/cup/chocopy/pa1/ChocoPy.cup | 31 +++++++++++++++++++----- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 28 ++++++++++++++++++--- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index 15340a3..20db76b 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -1,4 +1,5 @@ import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java_cup.runtime.*; @@ -113,12 +114,26 @@ action code {: } return list; } - + List combine(List list, List item) { + if (item != null) { + Iterator it = item.iterator(); + while(it.hasNext()) + list.add(it.next()); + } + return list; + } /** Return a mutable empty list. */ List empty() { return new ArrayList(); } - + class FuncBody { + public List fbd; + public List sl; + public FuncBody(List fbd, List sl){ + this.fbd = fbd; + this.sl = sl; + } + } /** 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. */ @@ -228,7 +243,7 @@ terminal String IS; /* Returned by the lexer for erroneous tokens. Since it does not appear in * the grammar, it indicates a syntax error. */ -terminal UNRECOGNIZED; +terminal String UNRECOGNIZED; /* Nonterminal symbols (defined in production rules below). * As for terminal symbols, @@ -236,7 +251,7 @@ terminal UNRECOGNIZED; * defines the listed nonterminal identifier symbols to have semantic values * of type . */ non terminal Program program; -non terminal List program_head, class_body, class_body_defs, fun_body_decs; +non terminal List defs, program_head, opt_program_head, class_body, class_body_defs, fun_body_decs; non terminal List stmt_list, opt_stmt_list, block, else_body; non terminal Stmt stmt, simple_stmt; non terminal Expr expr, pexpr, cexpr; @@ -255,7 +270,7 @@ non terminal List opt_target, expr_list; non terminal Expr target; non terminal MemberExpr member_expr; non terminal IndexExpr index_expr; - +non terminal FuncBody fun_body; @@ -330,7 +345,11 @@ typed_vars ::= typed_var:tv {: RESULT= single(tv ; -/* fun_body */ +/* fun_body */ +fun_body ::= fun_body_decs:fbd stmt_list:sl {: RESULT = new FuncBody(fbd, sl);:} + | fun_body_decs:fbd {: RESULT = new FuncBody(fbd, new ArrayList());:} + ; + fun_body_decs ::= fun_body_decs:fbd global_decl:gd {: RESULT= combine(fbd, gd); :} | fun_body_decs:fbd nonlocal_decl:nd {: RESULT= combine(fbd, nd); :} | fun_body_decs:fbd var_def:vd {: RESULT= combine(fbd, vd); :} diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index 55446aa..de6ec6c 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -1,6 +1,7 @@ package chocopy.pa1; import java_cup.runtime.*; import java.util.ArrayList; +import java.util.Iterator; %% /*** Do not change the flags below unless you know what you are doing. ***/ @@ -37,6 +38,7 @@ import java.util.ArrayList; private int str_l = 0, str_c = 0; //Start location of a string. /*A stack that keeps track of the spaces in each Indentation Level*/ private ArrayList stack = new ArrayList(20); + private boolean indentErrorUnchecked = true; /** Return a terminal symbol of syntactic category TYPE and no * semantic value at the current source location. */ private Symbol symbol(int type) { @@ -63,6 +65,15 @@ import java.util.ArrayList; if(stack.isEmpty()) return 0; return stack.get(stack.size() - 1); } + private boolean find(int indent){ + if(indent == 0) return true; + Iterator it = stack.iterator(); + while(it.hasNext()){ + if(it.next() == indent) + return true; + } + return false; + } %} /* Macros (regexes used in rules below) */ @@ -72,7 +83,7 @@ LineBreak = \r|\n|\r\n IntegerLiteral = 0|[1-9][0-9]* // Accroding to the manual, 00+ is illeagal StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))+ // \n, \r, \t, \\, \" and Anything except \ and " -Identifiers = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z][0-9])* +Identifiers = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z]|[0-9])* Comments = #[^\r\n]* %% //YYINITIAL state is where we're dealing with indentations. @@ -135,7 +146,18 @@ if True: AFTER state. */ pop(); - return symbol(ChocoPyTokens.DEDENT, currIndent); + if(top() < currIndent) + { + currIndent = top(); + return symbolFactory.newSymbol("", ChocoPyTokens.UNRECOGNIZED, + new ComplexSymbolFactory.Location(yyline + 1, yycolumn - 1), + new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), + currIndent); + } + return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[ChocoPyTokens.DEDENT], ChocoPyTokens.DEDENT, + new ComplexSymbolFactory.Location(yyline + 1, yycolumn - 1), + new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), + currIndent); } /*Otherwise, we will start dealing with the rest of the line after indentation in AFTER state. */ @@ -159,7 +181,7 @@ if True: { /* Delimiters. */ - {LineBreak} { yybegin(YYINITIAL); currIndent = 0;return symbol(ChocoPyTokens.NEWLINE);} + {LineBreak} { yybegin(YYINITIAL); currIndent = 0;indentErrorUnchecked = true; return symbol(ChocoPyTokens.NEWLINE);} ":" { return symbol(ChocoPyTokens.COLON); } "," { return symbol(ChocoPyTokens.COMMA); } From 6bcd40cbf9e2c1160ee57f291063c0dafc4ab392 Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Mon, 22 Feb 2021 19:32:37 +0530 Subject: [PATCH 26/67] Updating tests --- src/test/data/pa1/student_contributed/bad.py | 4 ++++ src/test/data/pa1/student_contributed/good.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/test/data/pa1/student_contributed/bad.py b/src/test/data/pa1/student_contributed/bad.py index 56f38a7..68e3773 100644 --- a/src/test/data/pa1/student_contributed/bad.py +++ b/src/test/data/pa1/student_contributed/bad.py @@ -29,3 +29,7 @@ class Stones(object): def bar(): return 2+3 print("Wrong Place") + +def fun1(): + def fun2(): + print("Hello") diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py index 6d27ff6..b0812da 100644 --- a/src/test/data/pa1/student_contributed/good.py +++ b/src/test/data/pa1/student_contributed/good.py @@ -3,7 +3,8 @@ print("Hi") def fun1(): def fun2(): print("Hello") - + fun2() + print("World") def fun3(): From 534b043c62d1b0d6ff38dea2fed42a9cd233d2be Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Mon, 22 Feb 2021 20:02:16 +0530 Subject: [PATCH 27/67] Update WORKLOG.md --- WORKLOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/WORKLOG.md b/WORKLOG.md index 612c819..72ea5a9 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -11,7 +11,10 @@ Compiler Construction PA1 Worklog
A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack.

Challenges: Describe any challenges (besides indentation) you encountered and the way you solved them. Mention the approaches that did not work, if any. -
+
Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. +
Handling errors was another challenge. This required debugging and small changes to program flow. +
Understanding the giving code was a small challenge and took some time before we could start coding.

Improvements: Describe any improvements you introduced that were not strictly necessary to pass the tests, such as implementing additional functionality, adding new tests, or enabling static analysis.
Added more tests to rigorously check program flow and indentation. +
Function body must have atleast oone statement which is not a part of a nested function. From 53aaa5c140ca319fe8efe16c901b8a878861ad5f Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Mon, 22 Feb 2021 20:13:27 +0530 Subject: [PATCH 28/67] Updating tests for multi-line strings --- src/test/data/pa1/student_contributed/good.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py index b0812da..4c01c88 100644 --- a/src/test/data/pa1/student_contributed/good.py +++ b/src/test/data/pa1/student_contributed/good.py @@ -66,4 +66,12 @@ print(f.x) f.bar(4) a=[[[1],[2]][[3],[4]]] -print(a[0][0][1]*a[1][1][0]) \ No newline at end of file +print(a[0][0][1]*a[1][1][0]) + +multiline_string="Hi World, +Here I am" + +""" +This is a +multi-line comment. +""" \ No newline at end of file From c21b761c55fff456c8aaa3f3454bc788a28548cd Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Wed, 24 Feb 2021 10:48:45 +0530 Subject: [PATCH 29/67] Updating tests yet again --- src/test/data/pa1/student_contributed/good.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py index 4c01c88..88f20ca 100644 --- a/src/test/data/pa1/student_contributed/good.py +++ b/src/test/data/pa1/student_contributed/good.py @@ -74,4 +74,15 @@ Here I am" """ This is a multi-line comment. -""" \ No newline at end of file +""" + + +def get_stones(name:str)->str: + color=['Red','Blue'] + stones=['Mind','Soul'] + def map_name(nm:str)->str: + return stones[color.index(nm)] + return map_name(name) + +stone="Blue" +print(get_stones(stone)) \ No newline at end of file From 9f6d969d2dbb0e8d1f579fab246ec76163fc3e64 Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Wed, 24 Feb 2021 18:59:14 +0530 Subject: [PATCH 30/67] Update WORKLOG.md --- WORKLOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/WORKLOG.md b/WORKLOG.md index 72ea5a9..7b7b13f 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -18,3 +18,4 @@ Compiler Construction PA1 Worklog
Improvements: Describe any improvements you introduced that were not strictly necessary to pass the tests, such as implementing additional functionality, adding new tests, or enabling static analysis.
Added more tests to rigorously check program flow and indentation.
Function body must have atleast oone statement which is not a part of a nested function. +
Support for multi-line strings. From 0a0b308dcc60a21f880beafdf293208151ce8e87 Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Fri, 26 Feb 2021 19:10:23 +0530 Subject: [PATCH 31/67] Modifying Tests --- src/test/data/pa1/student_contributed/good.py | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py index 88f20ca..000fffe 100644 --- a/src/test/data/pa1/student_contributed/good.py +++ b/src/test/data/pa1/student_contributed/good.py @@ -1,11 +1,24 @@ +class Foo(object): + x:int = 0 + + def __init__(self:"Foo", x:int): + self.x = x + + def bar(y:int): + print("Hello World!",self.x+y) + y = 10 + +def get_stones(name:str)->str: + color=["Red","Blue"] + stones=["Mind","Soul"] + def map_name(nm:str)->str: + return stones[color.index(nm)] + return map_name(name) -print("Hi") def fun1(): def fun2(): print("Hello") fun2() - -print("World") def fun3(): def fun4(): @@ -51,38 +64,17 @@ if True: else: print("World") -class Foo(object): - x:int = 0 - def __init__(self:"Foo", x:int): - self.x = x - - def bar(y:int)->None: - print("Hello World!",self.x+y) - y = 10 f = Foo(1) print(f.x) f.bar(4) -a=[[[1],[2]][[3],[4]]] +a=[[[1],[2]],[[3],[4]]] print(a[0][0][1]*a[1][1][0]) multiline_string="Hi World, Here I am" -""" -This is a -multi-line comment. -""" - - -def get_stones(name:str)->str: - color=['Red','Blue'] - stones=['Mind','Soul'] - def map_name(nm:str)->str: - return stones[color.index(nm)] - return map_name(name) - stone="Blue" print(get_stones(stone)) \ No newline at end of file From d7a9aab8a47eb6177d0a00bf532e7af7e3c5fb43 Mon Sep 17 00:00:00 2001 From: Apoorva Ranade Date: Fri, 26 Feb 2021 19:14:42 +0530 Subject: [PATCH 32/67] Working tests --- src/test/data/pa1/student_contributed/good.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py index 000fffe..093076f 100644 --- a/src/test/data/pa1/student_contributed/good.py +++ b/src/test/data/pa1/student_contributed/good.py @@ -9,26 +9,26 @@ class Foo(object): y = 10 def get_stones(name:str)->str: - color=["Red","Blue"] - stones=["Mind","Soul"] def map_name(nm:str)->str: return stones[color.index(nm)] + color=["Red","Blue"] + stones=["Mind","Soul"] return map_name(name) -def fun1(): - def fun2(): +def funa(): + def funb(): print("Hello") - fun2() + funb() -def fun3(): - def fun4(): +def fund(): + def fune(): print("Hello") c = 4 + 5 -def fun5(): - c = 6 - def fun6(): +def funf(): + def fung(): print("Hello") + c = 6 c = 4 + 5 From a80842e6563483472a43ee8b7386c7d080f84e38 Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Fri, 26 Feb 2021 19:44:37 +0530 Subject: [PATCH 33/67] Update WORKLOG.md --- WORKLOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index 7b7b13f..6824dcd 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -5,17 +5,16 @@ Compiler Construction PA1 Worklog
Sanjar Ahmadov(sa5640)
Yinqi Sun(ys3540)
-
Acknowledgments: Provide attribution to any collaborations, external resources, or out-side help.
-
Indentation: Describe your strategy for handling INDENT and DEDENT tokens. Point to the relevant source files and line numbers. +
Indentation:
A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack.
-
Challenges: Describe any challenges (besides indentation) you encountered and the way you solved them. Mention the approaches that did not work, if any. +
Challenges:
Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else.
Handling errors was another challenge. This required debugging and small changes to program flow.
Understanding the giving code was a small challenge and took some time before we could start coding.
-
Improvements: Describe any improvements you introduced that were not strictly necessary to pass the tests, such as implementing additional functionality, adding new tests, or enabling static analysis. +
Improvements:
Added more tests to rigorously check program flow and indentation.
Function body must have atleast oone statement which is not a part of a nested function.
Support for multi-line strings. From c8f40451c02b9d253e858d2e0b01dcab071f246c Mon Sep 17 00:00:00 2001 From: Sanjar Date: Fri, 26 Feb 2021 09:15:40 -0500 Subject: [PATCH 34/67] Update WORKLOG.md --- WORKLOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index 6824dcd..28c3037 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -10,11 +10,11 @@ Compiler Construction PA1 Worklog
A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack.

Challenges: -
Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. -
Handling errors was another challenge. This required debugging and small changes to program flow. -
Understanding the giving code was a small challenge and took some time before we could start coding. +
- Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. +
- Handling errors was another challenge. This required debugging and small changes to program flow. +
- Understanding the giving code was a small challenge and took some time before we could start coding.

Improvements: -
Added more tests to rigorously check program flow and indentation. -
Function body must have atleast oone statement which is not a part of a nested function. -
Support for multi-line strings. +
- Added more tests to rigorously check program flow and indentation. +
- Function body must have atleast oone statement which is not a part of a nested function. +
- Support for multi-line strings. From b95bc53e66b39b180e4a7ab7f84d16ee14d7f3d0 Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Fri, 26 Feb 2021 19:47:01 +0530 Subject: [PATCH 35/67] Update WORKLOG.md --- WORKLOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/WORKLOG.md b/WORKLOG.md index 28c3037..3386e5e 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -16,5 +16,4 @@ Compiler Construction PA1 Worklog

Improvements:
- Added more tests to rigorously check program flow and indentation. -
- Function body must have atleast oone statement which is not a part of a nested function.
- Support for multi-line strings. From c011c1b819c62230b10daf63f326ba3a6adc18e0 Mon Sep 17 00:00:00 2001 From: sunyinqi0508 Date: Fri, 26 Feb 2021 22:20:27 +0800 Subject: [PATCH 36/67] Update WORKLOG.md --- WORKLOG.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index 3386e5e..34839e8 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -1,19 +1,19 @@ -Compiler Construction PA1 Worklog +# Compiler Construction PA1 Worklog
-
Team: +## Team:
Apoorva Ranade(ar6496)
Sanjar Ahmadov(sa5640)
Yinqi Sun(ys3540)

-
Indentation: -
A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. +## Indentation: + - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack.
-
Challenges: -
- Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. -
- Handling errors was another challenge. This required debugging and small changes to program flow. -
- Understanding the giving code was a small challenge and took some time before we could start coding. -
-
Improvements: -
- Added more tests to rigorously check program flow and indentation. -
- Support for multi-line strings. +## Challenges: + - Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. + - Handling errors was another challenge. This required debugging and small changes to program flow. + - Understanding the giving code was a small challenge and took some time before we could start coding. + +## Improvements: + - Added more tests to rigorously check program flow and indentation. + - Support for multi-line strings. From 75f46461615a0597b1ead24bf706a93472dd2418 Mon Sep 17 00:00:00 2001 From: sunyinqi0508 Date: Fri, 26 Feb 2021 22:20:51 +0800 Subject: [PATCH 37/67] Update WORKLOG.md --- WORKLOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index 34839e8..2c62e57 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -1,5 +1,5 @@ # Compiler Construction PA1 Worklog -
+ ## Team:
Apoorva Ranade(ar6496)
Sanjar Ahmadov(sa5640) @@ -8,7 +8,7 @@
## Indentation: - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. -
+ ## Challenges: - Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. - Handling errors was another challenge. This required debugging and small changes to program flow. From 2bba267990454c09448c30e8d109619551b57710 Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Fri, 26 Feb 2021 20:02:24 +0530 Subject: [PATCH 38/67] Update WORKLOG.md --- WORKLOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WORKLOG.md b/WORKLOG.md index 2c62e57..deaf23f 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -7,7 +7,7 @@

## Indentation: - - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. + - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. The file: src/main/jflex/chocopy/pa1/ChocoPy.jflex, lines from 100 to 182, contain the code for the same. Line 270 of the same file deals with additional dedents in case the input ends in an indented state. ## Challenges: - Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. From 016e8c76b8c03676299097ac4fdc50f8da49b47a Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Fri, 26 Feb 2021 20:03:53 +0530 Subject: [PATCH 39/67] Update WORKLOG.md --- WORKLOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WORKLOG.md b/WORKLOG.md index deaf23f..79a3ee8 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -7,7 +7,8 @@

## Indentation: - - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. The file: src/main/jflex/chocopy/pa1/ChocoPy.jflex, lines from 100 to 182, contain the code for the same. Line 270 of the same file deals with additional dedents in case the input ends in an indented state. + - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. + - The file: src/main/jflex/chocopy/pa1/ChocoPy.jflex, lines from 100 to 182, contain the code for the same. Line 270 of the same file deals with additional dedents in case the input ends in an indented state. ## Challenges: - Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. From e3bc6a32da0c82e0a5f1b0960ffa9d8781f6d50f Mon Sep 17 00:00:00 2001 From: ar6496 <78793916+ar6496@users.noreply.github.com> Date: Fri, 26 Feb 2021 20:04:13 +0530 Subject: [PATCH 40/67] Update WORKLOG.md --- WORKLOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WORKLOG.md b/WORKLOG.md index 79a3ee8..5d30c78 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -8,7 +8,8 @@
## Indentation: - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. - - The file: src/main/jflex/chocopy/pa1/ChocoPy.jflex, lines from 100 to 182, contain the code for the same. Line 270 of the same file deals with additional dedents in case the input ends in an indented state. + - The file: src/main/jflex/chocopy/pa1/ChocoPy.jflex, lines from 100 to 182, contain the code for the stack. + - Line 270 of the same file deals with additional dedents in case the input ends in an indented state. ## Challenges: - Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. From 776e6001fd00793e0f177d56428490b00b42d35c Mon Sep 17 00:00:00 2001 From: Sanjar Ahmadov Date: Fri, 26 Feb 2021 09:42:15 -0500 Subject: [PATCH 41/67] Update styles --- src/main/jflex/chocopy/pa1/ChocoPy.jflex | 94 +++++++++++++----------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/main/jflex/chocopy/pa1/ChocoPy.jflex b/src/main/jflex/chocopy/pa1/ChocoPy.jflex index c297fab..cbfb668 100644 --- a/src/main/jflex/chocopy/pa1/ChocoPy.jflex +++ b/src/main/jflex/chocopy/pa1/ChocoPy.jflex @@ -180,30 +180,32 @@ if True: } } } + + { /* Delimiters. */ - {LineBreak} { yybegin(YYINITIAL); currIndent = 0;indentErrorUnchecked = true; return symbol(ChocoPyTokens.NEWLINE);} - ":" { return symbol(ChocoPyTokens.COLON); } - "," { return symbol(ChocoPyTokens.COMMA); } + {LineBreak} { yybegin(YYINITIAL); currIndent = 0;indentErrorUnchecked = true; return symbol(ChocoPyTokens.NEWLINE);} + ":" { return symbol(ChocoPyTokens.COLON); } + "," { return symbol(ChocoPyTokens.COMMA); } /* Literals. */ - {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, + {IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER, Integer.parseInt(yytext())); } - "\"" {yybegin(STR); str_l = yyline + 1; str_c = yycolumn + 1; currString = "";} //Start taking a string when see a " + "\"" { yybegin(STR); str_l = yyline + 1; str_c = yycolumn + 1; currString = ""; } //Start taking a string when see a " "False" { return symbol(ChocoPyTokens.BOOL, false); } "True" { return symbol(ChocoPyTokens.BOOL, true); } "None" { return symbol(ChocoPyTokens.NONE); } /*Keywords*/ - "if" {return symbol(ChocoPyTokens.IF);} - "else" {return symbol(ChocoPyTokens.ELSE);} - "elif" {return symbol(ChocoPyTokens.ELIF);} - "while" {return symbol(ChocoPyTokens.WHILE);} - "class" {return symbol(ChocoPyTokens.CLASS);} - "def" {return symbol(ChocoPyTokens.DEF);} - "lambda" {return symbol(ChocoPyTokens.LAMBDA);} + "if" { return symbol(ChocoPyTokens.IF); } + "else" { return symbol(ChocoPyTokens.ELSE); } + "elif" { return symbol(ChocoPyTokens.ELIF); } + "while" { return symbol(ChocoPyTokens.WHILE); } + "class" { return symbol(ChocoPyTokens.CLASS); } + "def" { return symbol(ChocoPyTokens.DEF); } + "lambda" { return symbol(ChocoPyTokens.LAMBDA); } "as" { return symbol(ChocoPyTokens.AS); } "for" { return symbol(ChocoPyTokens.FOR); } "global" { return symbol(ChocoPyTokens.GLOBAL); } @@ -227,47 +229,51 @@ if True: /* Operators. */ - "+" { return symbol(ChocoPyTokens.PLUS); } - "-" { return symbol(ChocoPyTokens.MINUS); } - "*" { return symbol(ChocoPyTokens.MUL); } - "//" { return symbol(ChocoPyTokens.DIV); } - "/" { return symbol(ChocoPyTokens.DIV); } //Accroding to manual, chocopy don't have fp division, '/', '//' should be integr division - "%" { return symbol(ChocoPyTokens.MOD); } - ">" { return symbol(ChocoPyTokens.GT); } - "<" { return symbol(ChocoPyTokens.LT); } - "==" { return symbol(ChocoPyTokens.EQUAL); } - "!=" { return symbol(ChocoPyTokens.NEQ); } - ">=" { return symbol(ChocoPyTokens.GEQ); } - "<=" { return symbol(ChocoPyTokens.LEQ); } - "=" { return symbol(ChocoPyTokens.ASSIGN); } - "and" { return symbol(ChocoPyTokens.AND); } - "or" { return symbol(ChocoPyTokens.OR); } - "not" { return symbol(ChocoPyTokens.NOT); } - "." { return symbol(ChocoPyTokens.DOT); } - "(" { return symbol(ChocoPyTokens.LPAR); } - ")" { return symbol(ChocoPyTokens.RPAR); } - "[" { return symbol(ChocoPyTokens.LBR); } - "]" { return symbol(ChocoPyTokens.RBR); } + "+" { return symbol(ChocoPyTokens.PLUS); } + "-" { return symbol(ChocoPyTokens.MINUS); } + "*" { return symbol(ChocoPyTokens.MUL); } + "//" { return symbol(ChocoPyTokens.DIV); } + "/" { return symbol(ChocoPyTokens.DIV); } //Accroding to manual, chocopy don't have fp division, '/', '//' should be integr division + "%" { return symbol(ChocoPyTokens.MOD); } + ">" { return symbol(ChocoPyTokens.GT); } + "<" { return symbol(ChocoPyTokens.LT); } + "==" { return symbol(ChocoPyTokens.EQUAL); } + "!=" { return symbol(ChocoPyTokens.NEQ); } + ">=" { return symbol(ChocoPyTokens.GEQ); } + "<=" { return symbol(ChocoPyTokens.LEQ); } + "=" { return symbol(ChocoPyTokens.ASSIGN); } + "and" { return symbol(ChocoPyTokens.AND); } + "or" { return symbol(ChocoPyTokens.OR); } + "not" { return symbol(ChocoPyTokens.NOT); } + "." { return symbol(ChocoPyTokens.DOT); } + "(" { return symbol(ChocoPyTokens.LPAR); } + ")" { return symbol(ChocoPyTokens.RPAR); } + "[" { return symbol(ChocoPyTokens.LBR); } + "]" { return symbol(ChocoPyTokens.RBR); } "->" { return symbol(ChocoPyTokens.ARROW); } "is" { return symbol(ChocoPyTokens.IS); } /*Identifiers*/ - {Identifiers} {return symbol(ChocoPyTokens.ID, yytext());} + {Identifiers} { return symbol(ChocoPyTokens.ID, yytext()); } + /* Whitespace. */ - {WhiteSpace} { /* ignore */ } + {WhiteSpace} { /* ignore */ } + /* Comment. */ - {Comments} { /* ignore */ } + {Comments} { /* ignore */ } } { - {StringLiteral} {currString += yytext();} - \\$ { /*'\' at the end of line, do nothing.*/ } - "\"" {yybegin(AFTER); return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[ChocoPyTokens.STRING], ChocoPyTokens.STRING, - new ComplexSymbolFactory.Location(str_l, str_c), - new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), - currString);} // accepted a ", return to AFTER state + {StringLiteral} { currString += yytext(); } + + \\$ { /*'\' at the end of line, do nothing.*/ } + + "\"" { yybegin(AFTER); return symbolFactory.newSymbol(ChocoPyTokens.terminalNames[ChocoPyTokens.STRING], ChocoPyTokens.STRING, + new ComplexSymbolFactory.Location(str_l, str_c), + new ComplexSymbolFactory.Location(yyline + 1,yycolumn + yylength()), + currString); } // accepted a ", return to AFTER state } -<> { if(!stack.isEmpty()){ return symbol(ChocoPyTokens.DEDENT, pop());} return symbol(ChocoPyTokens.EOF);} +<> { if(!stack.isEmpty()){ return symbol(ChocoPyTokens.DEDENT, pop());} return symbol(ChocoPyTokens.EOF); } /* Error fallback. */ -[^] { return symbol(ChocoPyTokens.UNRECOGNIZED); } +[^] { return symbol(ChocoPyTokens.UNRECOGNIZED); } From 1efee5e539631d384a15c54c3ac4780f48a54e8a Mon Sep 17 00:00:00 2001 From: bill Date: Mon, 1 Mar 2021 17:54:09 +0800 Subject: [PATCH 42/67] Fixed precedence on '-'. Passed additional tests. Comments on bad.py. Updated worklog. --- WORKLOG.md | 13 +++++++------ src/main/cup/chocopy/pa1/ChocoPy.cup | 13 +++++++++---- src/test/data/pa1/student_contributed/bad.py | 10 +++++++--- src/test/data/pa1/student_contributed/good.py | 4 +++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index 5d30c78..68007bb 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -1,11 +1,9 @@ # Compiler Construction PA1 Worklog ## Team: -
Apoorva Ranade(ar6496) -
Sanjar Ahmadov(sa5640) -
Yinqi Sun(ys3540) -
+**Apoorva Ranade**(ar6496)   **Sanjar Ahmadov**(sa5640)   **Yinqi Sun**(ys3540)
+ ## Indentation: - A stack is maintained by the lexer to keep track of indentations. A count is accumulated for the number of whitespace characters before the first token. If the count changes from the previous line count, a stack operation is performed. If count increases, another value is added to the stack. If count decreases, the topmost value is popped from the stack. - The file: src/main/jflex/chocopy/pa1/ChocoPy.jflex, lines from 100 to 182, contain the code for the stack. @@ -13,8 +11,11 @@ ## Challenges: - Shift-reduce errors while parsing the grammar. One approach to fix is to change the grammar. We chose to fix this issue by adding a precedence as in the case of expr by adding right precedence for if and else. - - Handling errors was another challenge. This required debugging and small changes to program flow. - - Understanding the giving code was a small challenge and took some time before we could start coding. + - '-' can either be a minus operator or a negative sign, and these two have different precedence. We solved this by assigning '-' the correct precedence at the production rule where we know whether it is a minus operator or a negative sign. + - File: src/main/jflex/chocopy/pa1/ChocoPy.cup Line: 459 + - Handling errors was another challenge. This required debugging and small changes to program flow. It's also a collaborative effort between group members that completed different part of the project. + - Understanding the giving code was a small challenge since some parts are compiled into binary and it become harder for us to debug through the source code, therefore it took us some time before we could start coding. + - Differences between ChocoPy and Python sometimes get us confused. For example, ChocoPy doesn't allow a function body without any statements and global (unscoped) statements in between (class/function/variable) definitions. This made us fail tests that we didn't thought we should. We then thoroughly read the reference manual and make our implementation conform to the manual whenever we can. ## Improvements: - Added more tests to rigorously check program flow and indentation. diff --git a/src/main/cup/chocopy/pa1/ChocoPy.cup b/src/main/cup/chocopy/pa1/ChocoPy.cup index 1bcb484..44d7cfe 100644 --- a/src/main/cup/chocopy/pa1/ChocoPy.cup +++ b/src/main/cup/chocopy/pa1/ChocoPy.cup @@ -239,6 +239,7 @@ terminal String LBR; terminal String RBR; terminal String ARROW; terminal String IS; +terminal String UMINUS; /* Returned by the lexer for erroneous tokens. Since it does not appear in @@ -282,6 +283,7 @@ precedence left NOT; precedence nonassoc EQUAL, NEQ, LT, GT, LEQ, GEQ, IS; precedence left PLUS, MINUS; precedence left MUL, DIV, MOD; +precedence left UMINUS; precedence left DOT, COMMA, LBR, RBR; precedence right IF, ELSE; @@ -295,8 +297,11 @@ start with program; /* program */ program ::= program_head:d opt_stmt_list:s - {: RESULT = new Program(d.isEmpty() ? getLeft(s) : getLeft(d), - sxright, d, s, errors); + {: + ComplexSymbolFactory.Location left = d.isEmpty() ? getLeft(s) : getLeft(d); + if(left == null) + left = new ComplexSymbolFactory.Location(1,1); + RESULT = new Program(left, sxright, d, s, errors); :} ; @@ -400,7 +405,7 @@ else_body ::= ELSE:el COLON block:b {: RES simple_stmt ::= PASS:p {: RESULT = null; :} | expr:e {: RESULT = new ExprStmt(exleft, exright, e); :} | RETURN:r expr:e {: RESULT = new ReturnStmt(rxleft, exright, e); :} - | RETURN {: RESULT = null; :} + | RETURN:r {: RESULT = new ReturnStmt(rxleft, rxright, null); :} | opt_target:ot expr:e {: RESULT = new AssignStmt(getLeft(ot), exright, ot, e); :} ; @@ -451,7 +456,7 @@ pexpr ::= identifier:id {: RESULT = id; :} | pexpr:p1 MUL:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} | pexpr:p1 DIV:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} | pexpr:p1 MOD:bo pexpr:p2 {: RESULT = new BinaryExpr(p1xleft, p2xright, p1, bo, p2); :} - | MINUS:m pexpr:p {: RESULT = new UnaryExpr(mxleft, pxright, m, p); :} + | MINUS:m pexpr:p {: RESULT = new UnaryExpr(mxleft, pxright, m, p); :} %prec UMINUS ; expr_list ::= expr:e {: RESULT = single(e); :} diff --git a/src/test/data/pa1/student_contributed/bad.py b/src/test/data/pa1/student_contributed/bad.py index 68e3773..95bf0f0 100644 --- a/src/test/data/pa1/student_contributed/bad.py +++ b/src/test/data/pa1/student_contributed/bad.py @@ -4,8 +4,10 @@ def fun5(): c = 6 def fun6(): print("Hello") - c = 4 + 5 + c = 4 + 5 # Indentation error +# Global statements in between definitions +# (not allowed in the language manual) if True: if True: print("Hello") @@ -16,11 +18,11 @@ if True: else: print("Again") else: - print("And Again") + print("And Again") # Unmatched Else class Thor(object): y:int = 0 - print("Right place?") + print("Right place?") # Statement in class class Stones(object): y:int = 0 @@ -30,6 +32,8 @@ class Stones(object): return 2+3 print("Wrong Place") +# Functions without `statements' +# (not allowed in the language manual) def fun1(): def fun2(): print("Hello") diff --git a/src/test/data/pa1/student_contributed/good.py b/src/test/data/pa1/student_contributed/good.py index 093076f..874fa40 100644 --- a/src/test/data/pa1/student_contributed/good.py +++ b/src/test/data/pa1/student_contributed/good.py @@ -73,8 +73,10 @@ f.bar(4) a=[[[1],[2]],[[3],[4]]] print(a[0][0][1]*a[1][1][0]) -multiline_string="Hi World, +multiline_string="Hi World,\ Here I am" +expr_precedence = -a + b * (c + d) + stone="Blue" print(get_stones(stone)) \ No newline at end of file From b758a071dc0208960495f7a5ce305d3241ddf3af Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Wed, 3 Mar 2021 14:08:57 +0000 Subject: [PATCH 43/67] Initial commit --- .gitignore | 149 +++ LICENSE | 26 + README.md | 35 + chocopy-ref.jar | Bin 0 -> 144775 bytes pom.xml | 330 ++++++ src/main/java/chocopy/common/Utils.java | 54 + .../common/analysis/AbstractNodeAnalyzer.java | 174 ++++ .../chocopy/common/analysis/NodeAnalyzer.java | 93 ++ .../chocopy/common/analysis/SymbolTable.java | 62 ++ .../common/analysis/types/ClassValueType.java | 53 + .../common/analysis/types/FuncType.java | 45 + .../common/analysis/types/ListValueType.java | 57 ++ .../chocopy/common/analysis/types/Type.java | 68 ++ .../common/analysis/types/ValueType.java | 29 + .../chocopy/common/astnodes/AssignStmt.java | 25 + .../chocopy/common/astnodes/BinaryExpr.java | 31 + .../common/astnodes/BooleanLiteral.java | 21 + .../chocopy/common/astnodes/CallExpr.java | 26 + .../chocopy/common/astnodes/ClassDef.java | 39 + .../chocopy/common/astnodes/ClassType.java | 21 + .../common/astnodes/CompilerError.java | 56 ++ .../chocopy/common/astnodes/Declaration.java | 17 + .../java/chocopy/common/astnodes/Errors.java | 71 ++ .../java/chocopy/common/astnodes/Expr.java | 43 + .../chocopy/common/astnodes/ExprStmt.java | 21 + .../java/chocopy/common/astnodes/ForStmt.java | 29 + .../java/chocopy/common/astnodes/FuncDef.java | 50 + .../chocopy/common/astnodes/GlobalDecl.java | 26 + .../chocopy/common/astnodes/Identifier.java | 24 + .../java/chocopy/common/astnodes/IfExpr.java | 26 + .../java/chocopy/common/astnodes/IfStmt.java | 35 + .../chocopy/common/astnodes/IndexExpr.java | 24 + .../common/astnodes/IntegerLiteral.java | 21 + .../chocopy/common/astnodes/ListExpr.java | 23 + .../chocopy/common/astnodes/ListType.java | 21 + .../java/chocopy/common/astnodes/Literal.java | 16 + .../chocopy/common/astnodes/MemberExpr.java | 24 + .../common/astnodes/MethodCallExpr.java | 26 + .../java/chocopy/common/astnodes/Node.java | 176 ++++ .../chocopy/common/astnodes/NonLocalDecl.java | 26 + .../chocopy/common/astnodes/NoneLiteral.java | 17 + .../java/chocopy/common/astnodes/Program.java | 56 ++ .../chocopy/common/astnodes/ReturnStmt.java | 21 + .../java/chocopy/common/astnodes/Stmt.java | 18 + .../common/astnodes/StringLiteral.java | 21 + .../common/astnodes/TypeAnnotation.java | 11 + .../chocopy/common/astnodes/TypedVar.java | 24 + .../chocopy/common/astnodes/UnaryExpr.java | 24 + .../java/chocopy/common/astnodes/VarDef.java | 32 + .../chocopy/common/astnodes/WhileStmt.java | 25 + .../java/chocopy/pa2/DeclarationAnalyzer.java | 55 + .../java/chocopy/pa2/StudentAnalysis.java | 30 + src/main/java/chocopy/pa2/TypeChecker.java | 94 ++ src/test/data/pa2/sample/ast_coverage.py | 38 + src/test/data/pa2/sample/ast_coverage.py.ast | 627 ++++++++++++ .../data/pa2/sample/ast_coverage.py.ast.typed | 952 ++++++++++++++++++ src/test/data/pa2/sample/bad_assign_expr.py | 11 + .../data/pa2/sample/bad_assign_expr.py.ast | 177 ++++ .../pa2/sample/bad_assign_expr.py.ast.typed | 301 ++++++ src/test/data/pa2/sample/bad_class_attr.py | 13 + .../data/pa2/sample/bad_class_attr.py.ast | 155 +++ .../pa2/sample/bad_class_attr.py.ast.typed | 165 +++ .../data/pa2/sample/bad_class_attr_type.py | 4 + .../pa2/sample/bad_class_attr_type.py.ast | 60 ++ .../sample/bad_class_attr_type.py.ast.typed | 73 ++ .../pa2/sample/bad_class_init_override.py | 8 + .../pa2/sample/bad_class_init_override.py.ast | 106 ++ .../bad_class_init_override.py.ast.typed | 111 ++ .../data/pa2/sample/bad_class_init_return.py | 5 + .../pa2/sample/bad_class_init_return.py.ast | 75 ++ .../sample/bad_class_init_return.py.ast.typed | 88 ++ .../data/pa2/sample/bad_class_member_expr.py | 6 + .../pa2/sample/bad_class_member_expr.py.ast | 110 ++ .../sample/bad_class_member_expr.py.ast.typed | 161 +++ src/test/data/pa2/sample/bad_class_method.py | 14 + .../data/pa2/sample/bad_class_method.py.ast | 158 +++ .../pa2/sample/bad_class_method.py.ast.typed | 168 ++++ .../pa2/sample/bad_class_method_invoke.py | 30 + .../pa2/sample/bad_class_method_invoke.py.ast | 474 +++++++++ .../bad_class_method_invoke.py.ast.typed | 668 ++++++++++++ .../pa2/sample/bad_class_method_override.py | 33 + .../sample/bad_class_method_override.py.ast | 439 ++++++++ .../bad_class_method_override.py.ast.typed | 454 +++++++++ .../sample/bad_class_method_override_attr.py | 8 + .../bad_class_method_override_attr.py.ast | 111 ++ ...ad_class_method_override_attr.py.ast.typed | 116 +++ src/test/data/pa2/sample/bad_class_super.py | 15 + .../data/pa2/sample/bad_class_super.py.ast | 154 +++ .../pa2/sample/bad_class_super.py.ast.typed | 169 ++++ src/test/data/pa2/sample/bad_concat.py | 3 + src/test/data/pa2/sample/bad_concat.py.ast | 77 ++ .../data/pa2/sample/bad_concat.py.ast.typed | 149 +++ .../data/pa2/sample/bad_duplicate_class.py | 18 + .../pa2/sample/bad_duplicate_class.py.ast | 190 ++++ .../sample/bad_duplicate_class.py.ast.typed | 205 ++++ .../pa2/sample/bad_duplicate_class_member.py | 12 + .../sample/bad_duplicate_class_member.py.ast | 156 +++ .../bad_duplicate_class_member.py.ast.typed | 166 +++ .../data/pa2/sample/bad_duplicate_global.py | 18 + .../pa2/sample/bad_duplicate_global.py.ast | 129 +++ .../sample/bad_duplicate_global.py.ast.typed | 144 +++ .../data/pa2/sample/bad_duplicate_global_2.py | 6 + .../pa2/sample/bad_duplicate_global_2.py.ast | 47 + .../bad_duplicate_global_2.py.ast.typed | 52 + .../data/pa2/sample/bad_duplicate_local.py | 21 + .../pa2/sample/bad_duplicate_local.py.ast | 257 +++++ .../sample/bad_duplicate_local.py.ast.typed | 277 +++++ src/test/data/pa2/sample/bad_expr_binary.py | 13 + .../data/pa2/sample/bad_expr_binary.py.ast | 239 +++++ .../pa2/sample/bad_expr_binary.py.ast.typed | 455 +++++++++ src/test/data/pa2/sample/bad_expr_if.py | 2 + src/test/data/pa2/sample/bad_expr_if.py.ast | 70 ++ .../data/pa2/sample/bad_expr_if.py.ast.typed | 107 ++ src/test/data/pa2/sample/bad_expr_unary.py | 4 + .../data/pa2/sample/bad_expr_unary.py.ast | 62 ++ .../pa2/sample/bad_expr_unary.py.ast.typed | 114 +++ src/test/data/pa2/sample/bad_func_def_call.py | 13 + .../data/pa2/sample/bad_func_def_call.py.ast | 187 ++++ .../pa2/sample/bad_func_def_call.py.ast.typed | 336 +++++++ .../data/pa2/sample/bad_func_def_return.py | 10 + .../pa2/sample/bad_func_def_return.py.ast | 125 +++ .../sample/bad_func_def_return.py.ast.typed | 174 ++++ src/test/data/pa2/sample/bad_list_assign.py | 6 + .../data/pa2/sample/bad_list_assign.py.ast | 116 +++ .../pa2/sample/bad_list_assign.py.ast.typed | 192 ++++ src/test/data/pa2/sample/bad_list_index.py | 7 + .../data/pa2/sample/bad_list_index.py.ast | 147 +++ .../pa2/sample/bad_list_index.py.ast.typed | 275 +++++ src/test/data/pa2/sample/bad_local_assign.py | 23 + .../data/pa2/sample/bad_local_assign.py.ast | 253 +++++ .../pa2/sample/bad_local_assign.py.ast.typed | 330 ++++++ src/test/data/pa2/sample/bad_none_assign.py | 14 + .../data/pa2/sample/bad_none_assign.py.ast | 187 ++++ .../pa2/sample/bad_none_assign.py.ast.typed | 265 +++++ .../data/pa2/sample/bad_nonlocal_global.py | 25 + .../pa2/sample/bad_nonlocal_global.py.ast | 229 +++++ .../sample/bad_nonlocal_global.py.ast.typed | 259 +++++ .../data/pa2/sample/bad_return_missing.py | 6 + .../data/pa2/sample/bad_return_missing.py.ast | 58 ++ .../sample/bad_return_missing.py.ast.typed | 63 ++ src/test/data/pa2/sample/bad_return_top.py | 3 + .../data/pa2/sample/bad_return_top.py.ast | 41 + .../pa2/sample/bad_return_top.py.ast.typed | 50 + src/test/data/pa2/sample/bad_shadow_local.py | 14 + .../data/pa2/sample/bad_shadow_local.py.ast | 179 ++++ .../pa2/sample/bad_shadow_local.py.ast.typed | 199 ++++ .../data/pa2/sample/bad_shadow_local_2.py | 8 + .../data/pa2/sample/bad_shadow_local_2.py.ast | 98 ++ .../sample/bad_shadow_local_2.py.ast.typed | 103 ++ src/test/data/pa2/sample/bad_strings.py | 10 + src/test/data/pa2/sample/bad_strings.py.ast | 183 ++++ .../data/pa2/sample/bad_strings.py.ast.typed | 301 ++++++ .../data/pa2/sample/bad_type_annotation.py | 7 + .../pa2/sample/bad_type_annotation.py.ast | 86 ++ .../sample/bad_type_annotation.py.ast.typed | 106 ++ src/test/data/pa2/sample/bad_type_id.py | 1 + src/test/data/pa2/sample/bad_type_id.py.ast | 29 + .../data/pa2/sample/bad_type_id.py.ast.typed | 51 + src/test/data/pa2/sample/bad_var_assign.py | 8 + .../data/pa2/sample/bad_var_assign.py.ast | 127 +++ .../pa2/sample/bad_var_assign.py.ast.typed | 213 ++++ src/test/data/pa2/sample/class_def_assign.py | 18 + .../data/pa2/sample/class_def_assign.py.ast | 263 +++++ .../pa2/sample/class_def_assign.py.ast.typed | 323 ++++++ src/test/data/pa2/sample/class_def_attr.py | 22 + .../data/pa2/sample/class_def_attr.py.ast | 346 +++++++ .../pa2/sample/class_def_attr.py.ast.typed | 446 ++++++++ src/test/data/pa2/sample/class_def_init.py | 17 + .../data/pa2/sample/class_def_init.py.ast | 243 +++++ .../pa2/sample/class_def_init.py.ast.typed | 287 ++++++ src/test/data/pa2/sample/class_def_methods.py | 28 + .../data/pa2/sample/class_def_methods.py.ast | 451 +++++++++ .../pa2/sample/class_def_methods.py.ast.typed | 595 +++++++++++ .../data/pa2/sample/decl_global_forward.py | 9 + .../pa2/sample/decl_global_forward.py.ast | 108 ++ .../sample/decl_global_forward.py.ast.typed | 155 +++ .../data/pa2/sample/decl_nonlocal_forward.py | 10 + .../pa2/sample/decl_nonlocal_forward.py.ast | 137 +++ .../sample/decl_nonlocal_forward.py.ast.typed | 196 ++++ src/test/data/pa2/sample/expr_binary.py | 2 + src/test/data/pa2/sample/expr_binary.py.ast | 109 ++ .../data/pa2/sample/expr_binary.py.ast.typed | 185 ++++ src/test/data/pa2/sample/expr_concat.py | 3 + src/test/data/pa2/sample/expr_concat.py.ast | 93 ++ .../data/pa2/sample/expr_concat.py.ast.typed | 175 ++++ src/test/data/pa2/sample/expr_id.py | 3 + src/test/data/pa2/sample/expr_id.py.ast | 51 + src/test/data/pa2/sample/expr_id.py.ast.typed | 67 ++ src/test/data/pa2/sample/expr_if.py | 1 + src/test/data/pa2/sample/expr_if.py.ast | 43 + src/test/data/pa2/sample/expr_if.py.ast.typed | 67 ++ src/test/data/pa2/sample/expr_int.py | 1 + src/test/data/pa2/sample/expr_int.py.ast | 29 + .../data/pa2/sample/expr_int.py.ast.typed | 41 + src/test/data/pa2/sample/expr_list_index.py | 12 + .../data/pa2/sample/expr_list_index.py.ast | 247 +++++ .../pa2/sample/expr_list_index.py.ast.typed | 398 ++++++++ src/test/data/pa2/sample/expr_lists.py | 12 + src/test/data/pa2/sample/expr_lists.py.ast | 233 +++++ .../data/pa2/sample/expr_lists.py.ast.typed | 374 +++++++ src/test/data/pa2/sample/expr_unary.py | 2 + src/test/data/pa2/sample/expr_unary.py.ast | 37 + .../data/pa2/sample/expr_unary.py.ast.typed | 53 + src/test/data/pa2/sample/expr_var_assign.py | 4 + .../data/pa2/sample/expr_var_assign.py.ast | 71 ++ .../pa2/sample/expr_var_assign.py.ast.typed | 91 ++ src/test/data/pa2/sample/func_def_call.py | 7 + src/test/data/pa2/sample/func_def_call.py.ast | 111 ++ .../pa2/sample/func_def_call.py.ast.typed | 153 +++ src/test/data/pa2/sample/stmt_for_lists.py | 4 + .../data/pa2/sample/stmt_for_lists.py.ast | 77 ++ .../pa2/sample/stmt_for_lists.py.ast.typed | 116 +++ src/test/data/pa2/sample/stmt_for_strings.py | 4 + .../data/pa2/sample/stmt_for_strings.py.ast | 64 ++ .../pa2/sample/stmt_for_strings.py.ast.typed | 88 ++ src/test/data/pa2/sample/stmt_if.py | 7 + src/test/data/pa2/sample/stmt_if.py.ast | 51 + src/test/data/pa2/sample/stmt_if.py.ast.typed | 71 ++ src/test/data/pa2/sample/stmt_list_assign.py | 7 + .../data/pa2/sample/stmt_list_assign.py.ast | 155 +++ .../pa2/sample/stmt_list_assign.py.ast.typed | 256 +++++ src/test/data/pa2/sample/stmt_var_assign.py | 9 + .../data/pa2/sample/stmt_var_assign.py.ast | 150 +++ .../pa2/sample/stmt_var_assign.py.ast.typed | 198 ++++ src/test/data/pa2/sample/stmt_while.py | 3 + src/test/data/pa2/sample/stmt_while.py.ast | 75 ++ .../data/pa2/sample/stmt_while.py.ast.typed | 107 ++ src/test/data/pa2/sample/strings.py | 8 + src/test/data/pa2/sample/strings.py.ast | 139 +++ src/test/data/pa2/sample/strings.py.ast.typed | 195 ++++ .../pa2/student_contributed/bad_semantic.py | 4 + .../data/pa2/student_contributed/bad_types.py | 2 + src/test/data/pa2/student_contributed/good.py | 2 + 233 files changed, 25009 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/java/chocopy/common/Utils.java create mode 100644 src/main/java/chocopy/common/analysis/AbstractNodeAnalyzer.java create mode 100644 src/main/java/chocopy/common/analysis/NodeAnalyzer.java create mode 100644 src/main/java/chocopy/common/analysis/SymbolTable.java create mode 100644 src/main/java/chocopy/common/analysis/types/ClassValueType.java create mode 100644 src/main/java/chocopy/common/analysis/types/FuncType.java create mode 100644 src/main/java/chocopy/common/analysis/types/ListValueType.java create mode 100644 src/main/java/chocopy/common/analysis/types/Type.java create mode 100644 src/main/java/chocopy/common/analysis/types/ValueType.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/pa2/DeclarationAnalyzer.java create mode 100644 src/main/java/chocopy/pa2/StudentAnalysis.java create mode 100644 src/main/java/chocopy/pa2/TypeChecker.java create mode 100644 src/test/data/pa2/sample/ast_coverage.py create mode 100644 src/test/data/pa2/sample/ast_coverage.py.ast create mode 100644 src/test/data/pa2/sample/ast_coverage.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_assign_expr.py create mode 100644 src/test/data/pa2/sample/bad_assign_expr.py.ast create mode 100644 src/test/data/pa2/sample/bad_assign_expr.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_attr.py create mode 100644 src/test/data/pa2/sample/bad_class_attr.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_attr.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_attr_type.py create mode 100644 src/test/data/pa2/sample/bad_class_attr_type.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_attr_type.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_init_override.py create mode 100644 src/test/data/pa2/sample/bad_class_init_override.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_init_override.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_init_return.py create mode 100644 src/test/data/pa2/sample/bad_class_init_return.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_init_return.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_member_expr.py create mode 100644 src/test/data/pa2/sample/bad_class_member_expr.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_member_expr.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_method.py create mode 100644 src/test/data/pa2/sample/bad_class_method.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_method.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_method_invoke.py create mode 100644 src/test/data/pa2/sample/bad_class_method_invoke.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_method_invoke.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_method_override.py create mode 100644 src/test/data/pa2/sample/bad_class_method_override.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_method_override.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_method_override_attr.py create mode 100644 src/test/data/pa2/sample/bad_class_method_override_attr.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_method_override_attr.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_class_super.py create mode 100644 src/test/data/pa2/sample/bad_class_super.py.ast create mode 100644 src/test/data/pa2/sample/bad_class_super.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_concat.py create mode 100644 src/test/data/pa2/sample/bad_concat.py.ast create mode 100644 src/test/data/pa2/sample/bad_concat.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_duplicate_class.py create mode 100644 src/test/data/pa2/sample/bad_duplicate_class.py.ast create mode 100644 src/test/data/pa2/sample/bad_duplicate_class.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_duplicate_class_member.py create mode 100644 src/test/data/pa2/sample/bad_duplicate_class_member.py.ast create mode 100644 src/test/data/pa2/sample/bad_duplicate_class_member.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_duplicate_global.py create mode 100644 src/test/data/pa2/sample/bad_duplicate_global.py.ast create mode 100644 src/test/data/pa2/sample/bad_duplicate_global.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_duplicate_global_2.py create mode 100644 src/test/data/pa2/sample/bad_duplicate_global_2.py.ast create mode 100644 src/test/data/pa2/sample/bad_duplicate_global_2.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_duplicate_local.py create mode 100644 src/test/data/pa2/sample/bad_duplicate_local.py.ast create mode 100644 src/test/data/pa2/sample/bad_duplicate_local.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_expr_binary.py create mode 100644 src/test/data/pa2/sample/bad_expr_binary.py.ast create mode 100644 src/test/data/pa2/sample/bad_expr_binary.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_expr_if.py create mode 100644 src/test/data/pa2/sample/bad_expr_if.py.ast create mode 100644 src/test/data/pa2/sample/bad_expr_if.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_expr_unary.py create mode 100644 src/test/data/pa2/sample/bad_expr_unary.py.ast create mode 100644 src/test/data/pa2/sample/bad_expr_unary.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_func_def_call.py create mode 100644 src/test/data/pa2/sample/bad_func_def_call.py.ast create mode 100644 src/test/data/pa2/sample/bad_func_def_call.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_func_def_return.py create mode 100644 src/test/data/pa2/sample/bad_func_def_return.py.ast create mode 100644 src/test/data/pa2/sample/bad_func_def_return.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_list_assign.py create mode 100644 src/test/data/pa2/sample/bad_list_assign.py.ast create mode 100644 src/test/data/pa2/sample/bad_list_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_list_index.py create mode 100644 src/test/data/pa2/sample/bad_list_index.py.ast create mode 100644 src/test/data/pa2/sample/bad_list_index.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_local_assign.py create mode 100644 src/test/data/pa2/sample/bad_local_assign.py.ast create mode 100644 src/test/data/pa2/sample/bad_local_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_none_assign.py create mode 100644 src/test/data/pa2/sample/bad_none_assign.py.ast create mode 100644 src/test/data/pa2/sample/bad_none_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_nonlocal_global.py create mode 100644 src/test/data/pa2/sample/bad_nonlocal_global.py.ast create mode 100644 src/test/data/pa2/sample/bad_nonlocal_global.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_return_missing.py create mode 100644 src/test/data/pa2/sample/bad_return_missing.py.ast create mode 100644 src/test/data/pa2/sample/bad_return_missing.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_return_top.py create mode 100644 src/test/data/pa2/sample/bad_return_top.py.ast create mode 100644 src/test/data/pa2/sample/bad_return_top.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_shadow_local.py create mode 100644 src/test/data/pa2/sample/bad_shadow_local.py.ast create mode 100644 src/test/data/pa2/sample/bad_shadow_local.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_shadow_local_2.py create mode 100644 src/test/data/pa2/sample/bad_shadow_local_2.py.ast create mode 100644 src/test/data/pa2/sample/bad_shadow_local_2.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_strings.py create mode 100644 src/test/data/pa2/sample/bad_strings.py.ast create mode 100644 src/test/data/pa2/sample/bad_strings.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_type_annotation.py create mode 100644 src/test/data/pa2/sample/bad_type_annotation.py.ast create mode 100644 src/test/data/pa2/sample/bad_type_annotation.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_type_id.py create mode 100644 src/test/data/pa2/sample/bad_type_id.py.ast create mode 100644 src/test/data/pa2/sample/bad_type_id.py.ast.typed create mode 100644 src/test/data/pa2/sample/bad_var_assign.py create mode 100644 src/test/data/pa2/sample/bad_var_assign.py.ast create mode 100644 src/test/data/pa2/sample/bad_var_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/class_def_assign.py create mode 100644 src/test/data/pa2/sample/class_def_assign.py.ast create mode 100644 src/test/data/pa2/sample/class_def_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/class_def_attr.py create mode 100644 src/test/data/pa2/sample/class_def_attr.py.ast create mode 100644 src/test/data/pa2/sample/class_def_attr.py.ast.typed create mode 100644 src/test/data/pa2/sample/class_def_init.py create mode 100644 src/test/data/pa2/sample/class_def_init.py.ast create mode 100644 src/test/data/pa2/sample/class_def_init.py.ast.typed create mode 100644 src/test/data/pa2/sample/class_def_methods.py create mode 100644 src/test/data/pa2/sample/class_def_methods.py.ast create mode 100644 src/test/data/pa2/sample/class_def_methods.py.ast.typed create mode 100644 src/test/data/pa2/sample/decl_global_forward.py create mode 100644 src/test/data/pa2/sample/decl_global_forward.py.ast create mode 100644 src/test/data/pa2/sample/decl_global_forward.py.ast.typed create mode 100644 src/test/data/pa2/sample/decl_nonlocal_forward.py create mode 100644 src/test/data/pa2/sample/decl_nonlocal_forward.py.ast create mode 100644 src/test/data/pa2/sample/decl_nonlocal_forward.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_binary.py create mode 100644 src/test/data/pa2/sample/expr_binary.py.ast create mode 100644 src/test/data/pa2/sample/expr_binary.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_concat.py create mode 100644 src/test/data/pa2/sample/expr_concat.py.ast create mode 100644 src/test/data/pa2/sample/expr_concat.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_id.py create mode 100644 src/test/data/pa2/sample/expr_id.py.ast create mode 100644 src/test/data/pa2/sample/expr_id.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_if.py create mode 100644 src/test/data/pa2/sample/expr_if.py.ast create mode 100644 src/test/data/pa2/sample/expr_if.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_int.py create mode 100644 src/test/data/pa2/sample/expr_int.py.ast create mode 100644 src/test/data/pa2/sample/expr_int.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_list_index.py create mode 100644 src/test/data/pa2/sample/expr_list_index.py.ast create mode 100644 src/test/data/pa2/sample/expr_list_index.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_lists.py create mode 100644 src/test/data/pa2/sample/expr_lists.py.ast create mode 100644 src/test/data/pa2/sample/expr_lists.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_unary.py create mode 100644 src/test/data/pa2/sample/expr_unary.py.ast create mode 100644 src/test/data/pa2/sample/expr_unary.py.ast.typed create mode 100644 src/test/data/pa2/sample/expr_var_assign.py create mode 100644 src/test/data/pa2/sample/expr_var_assign.py.ast create mode 100644 src/test/data/pa2/sample/expr_var_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/func_def_call.py create mode 100644 src/test/data/pa2/sample/func_def_call.py.ast create mode 100644 src/test/data/pa2/sample/func_def_call.py.ast.typed create mode 100644 src/test/data/pa2/sample/stmt_for_lists.py create mode 100644 src/test/data/pa2/sample/stmt_for_lists.py.ast create mode 100644 src/test/data/pa2/sample/stmt_for_lists.py.ast.typed create mode 100644 src/test/data/pa2/sample/stmt_for_strings.py create mode 100644 src/test/data/pa2/sample/stmt_for_strings.py.ast create mode 100644 src/test/data/pa2/sample/stmt_for_strings.py.ast.typed create mode 100644 src/test/data/pa2/sample/stmt_if.py create mode 100644 src/test/data/pa2/sample/stmt_if.py.ast create mode 100644 src/test/data/pa2/sample/stmt_if.py.ast.typed create mode 100644 src/test/data/pa2/sample/stmt_list_assign.py create mode 100644 src/test/data/pa2/sample/stmt_list_assign.py.ast create mode 100644 src/test/data/pa2/sample/stmt_list_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/stmt_var_assign.py create mode 100644 src/test/data/pa2/sample/stmt_var_assign.py.ast create mode 100644 src/test/data/pa2/sample/stmt_var_assign.py.ast.typed create mode 100644 src/test/data/pa2/sample/stmt_while.py create mode 100644 src/test/data/pa2/sample/stmt_while.py.ast create mode 100644 src/test/data/pa2/sample/stmt_while.py.ast.typed create mode 100644 src/test/data/pa2/sample/strings.py create mode 100644 src/test/data/pa2/sample/strings.py.ast create mode 100644 src/test/data/pa2/sample/strings.py.ast.typed create mode 100644 src/test/data/pa2/student_contributed/bad_semantic.py create mode 100644 src/test/data/pa2/student_contributed/bad_types.py create mode 100644 src/test/data/pa2/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..6716c27 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# NYU Compiler Construction CSCI-GA.2130/Spring 2021: Programming Assignment 2 + +This assignment is adapted from https://github.com/cs164berkeley/pa2-chocopy-semantic-analysis with the authors' permission. + +See the PA2 document on Piazza for a detailed specification. + +## Quickstart + +Run the following commands to compile your analyzer and run the tests: +``` +mvn clean package +java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \ + --pass=.s --test --dir src/test/data/pa2/sample/ +``` + +The dot in `--pass` makes the compiler skip parsing and go straight to semantic analysis. +`--pass=.s` uses your (`s` for `student`) analyzer to perform semantic analysis on a preparsed input (in this case, the `.ast` files under `src/test/data/pa2/sample/`). +With the starter code, only two tests should pass. +Your main objective is to build an analyzer that passes all the provided tests. + +`--pass=.r` uses the reference (`r` for `reference`) analyzer, 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) analyzer with: +``` +java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \ + --pass=.s src/test/data/pa2/sample/expr_unary.py.ast +``` + +You can also run both passes on the original `.py` file: +``` +java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \ + --pass=rr src/test/data/pa2/sample/expr_unary.py +``` + +Once you merge your parser code from assignment 1, you should be able to use `--pass=ss`. diff --git a/chocopy-ref.jar b/chocopy-ref.jar new file mode 100644 index 0000000000000000000000000000000000000000..a497f250c0918754ad6e49ccd25efddcf20f9036 GIT binary patch literal 144775 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