commit
9f1681bb23
@ -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
|
||||||
|
*~
|
@ -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.
|
@ -0,0 +1,52 @@
|
|||||||
|
# NYU Compiler Construction CSCI-GA.2130/Spring 2021: Programming Assignment 3
|
||||||
|
|
||||||
|
This assignment is adapted from https://github.com/cs164berkeley/pa3-chocopy-code-generation with the authors' permission.
|
||||||
|
|
||||||
|
See the PA3 document on Piazza for a detailed specification.
|
||||||
|
|
||||||
|
## Quickstart
|
||||||
|
|
||||||
|
Run the following commands to compile your code generator and run the tests:
|
||||||
|
```
|
||||||
|
mvn clean package
|
||||||
|
java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
|
||||||
|
--pass=..s --test --run --dir src/test/data/pa3/sample/
|
||||||
|
```
|
||||||
|
|
||||||
|
The dots in `--pass` make the compiler skip parsing and semantic analysis and go straight to code generation.
|
||||||
|
`--pass=..s` uses your (`s` for `student`) generator to generate code from an annotated AST (the `.ast.typed` files under `src/test/data/pa3/sample/`).
|
||||||
|
With the starter code, only one test should pass.
|
||||||
|
Your main objective is to build a code generator that passes all the provided tests.
|
||||||
|
|
||||||
|
`--pass=..r` uses the reference (`r` for `reference`) generator, 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) generator with:
|
||||||
|
```
|
||||||
|
java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
|
||||||
|
--pass=..s src/test/data/pa3/sample/op_add.py.ast.typed
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also run all passes on the original `.py` file:
|
||||||
|
```
|
||||||
|
java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
|
||||||
|
--pass=rrr src/test/data/pa3/sample/op_add.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you merge your semantic analysis code from assignment 2, you should be able to use `--pass=sss`.
|
||||||
|
|
||||||
|
## Generating vs Running
|
||||||
|
|
||||||
|
The above should be familiar from previous assignments.
|
||||||
|
A new aspect of PA3 is the distinction between generating and running the code.
|
||||||
|
|
||||||
|
The following outputs the generated RISC-V assembly (with the usual option to save to a file with `--out`):
|
||||||
|
```
|
||||||
|
java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
|
||||||
|
--pass=rrr src/test/data/pa3/sample/op_add.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The following (note the `--run` option) generates the assembly and then _runs it on the bundled RISC-V emulator_:
|
||||||
|
```
|
||||||
|
java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy \
|
||||||
|
--pass=rrr --run src/test/data/pa3/sample/op_add.py
|
||||||
|
```
|
Binary file not shown.
@ -0,0 +1,330 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>chocopy</groupId>
|
||||||
|
<artifactId>chocopy</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>2.2-SNAPSHOT</version>
|
||||||
|
<name>chocopy</name>
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
|
||||||
|
<!-- Set this property to true on the command-line for very verbose output -->
|
||||||
|
<properties>
|
||||||
|
<chocopy.debug>false</chocopy.debug>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<!-- Specify JFlex and CUP plugins here; execute in profiles -->
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>de.jflex</groupId>
|
||||||
|
<artifactId>jflex-maven-plugin</artifactId>
|
||||||
|
<version>1.6.1</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.vbmacher</groupId>
|
||||||
|
<artifactId>cup-maven-plugin</artifactId>
|
||||||
|
<version>11b-20160615</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-site-plugin</artifactId>
|
||||||
|
<version>3.7.1</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<finalName>assignment</finalName>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase> <!-- bind to the packaging phase -->
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<configuration>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
<parameters>true</parameters>
|
||||||
|
<debug>true</debug>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/asm</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**/*.s</include>
|
||||||
|
<include>**/*.os</include>
|
||||||
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/reference/*.s</exclude>
|
||||||
|
</excludes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>reference</id>
|
||||||
|
<activation>
|
||||||
|
<!-- This profile is activated whenever we have the reference sources available -->
|
||||||
|
<file>
|
||||||
|
<exists>src/main/java/chocopy/reference/</exists>
|
||||||
|
</file>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Do not include student skeletons in the reference JAR -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/pa1/*</exclude>
|
||||||
|
<exclude>**/pa2/*</exclude>
|
||||||
|
<exclude>**/pa3/*</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- Name the generated JAR differently so that it is different from the student version -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<finalName>chocopy-ref</finalName>
|
||||||
|
<appendAssemblyId>false</appendAssemblyId>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- Run JFlex to generate reference lexer -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>de.jflex</groupId>
|
||||||
|
<artifactId>jflex-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>jflex-reference</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<lexDefinitions>
|
||||||
|
<lexDefinition>src/main/jflex/chocopy/reference/ChocoPy.jflex</lexDefinition>
|
||||||
|
</lexDefinitions>
|
||||||
|
<dump>${chocopy.debug}</dump>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- Run CUP to generate reference parser -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.vbmacher</groupId>
|
||||||
|
<artifactId>cup-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>cup-reference</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<cupDefinition>src/main/cup/chocopy/reference/ChocoPy.cup</cupDefinition>
|
||||||
|
<packageName>chocopy.reference</packageName>
|
||||||
|
<className>ChocoPyParser</className>
|
||||||
|
<symbolsName>ChocoPyTokens</symbolsName>
|
||||||
|
<dumpTables>${chocopy.debug}</dumpTables>
|
||||||
|
<dumpStates>${chocopy.debug}</dumpStates>
|
||||||
|
<dumpGrammar>${chocopy.debug}</dumpGrammar>
|
||||||
|
<locations>true</locations>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- No debug -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<debug>true</debug>
|
||||||
|
<debuglevel>none</debuglevel>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- Copy dependencies to target/ -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-dependencies</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>pa1</id>
|
||||||
|
<activation>
|
||||||
|
<!-- This profile is activated whenever we are in a PA1 distribution -->
|
||||||
|
<file>
|
||||||
|
<exists>src/main/java/chocopy/pa1</exists>
|
||||||
|
</file>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Run JFlex on the student version -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>de.jflex</groupId>
|
||||||
|
<artifactId>jflex-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>jflex-pa1</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<lexDefinitions>
|
||||||
|
<lexDefinition>src/main/jflex/chocopy/pa1/ChocoPy.jflex</lexDefinition>
|
||||||
|
</lexDefinitions>
|
||||||
|
<dump>${chocopy.debug}</dump>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- Run CUP on the student version -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.vbmacher</groupId>
|
||||||
|
<artifactId>cup-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>cup-pa1</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<cupDefinition>src/main/cup/chocopy/pa1/ChocoPy.cup</cupDefinition>
|
||||||
|
<packageName>chocopy.pa1</packageName>
|
||||||
|
<className>ChocoPyParser</className>
|
||||||
|
<symbolsName>ChocoPyTokens</symbolsName>
|
||||||
|
<dumpTables>${chocopy.debug}</dumpTables>
|
||||||
|
<dumpStates>${chocopy.debug}</dumpStates>
|
||||||
|
<dumpGrammar>${chocopy.debug}</dumpGrammar>
|
||||||
|
<locations>true</locations>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>pa2</id>
|
||||||
|
<activation>
|
||||||
|
<!-- This profile is activated whenever we are in a PA2 distribution -->
|
||||||
|
<file>
|
||||||
|
<exists>src/main/java/chocopy/pa2</exists>
|
||||||
|
</file>
|
||||||
|
</activation>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>pa3</id>
|
||||||
|
<activation>
|
||||||
|
<!-- This profile is activated whenever we are in a PA3 distribution -->
|
||||||
|
<file>
|
||||||
|
<exists>src/main/java/chocopy/pa3</exists>
|
||||||
|
</file>
|
||||||
|
</activation>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>venus164-repo</id>
|
||||||
|
<name>Repository for Venus164</name>
|
||||||
|
<url>https://raw.githubusercontent.com/chocopy/venus/maven-repository/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.argparse4j</groupId>
|
||||||
|
<artifactId>argparse4j</artifactId>
|
||||||
|
<version>0.8.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.9.10</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.module</groupId>
|
||||||
|
<artifactId>jackson-module-parameter-names</artifactId>
|
||||||
|
<version>2.9.10</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.vbmacher</groupId>
|
||||||
|
<artifactId>java-cup-runtime</artifactId>
|
||||||
|
<version>11b-20160615</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/de.jflex/jflex -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.jflex</groupId>
|
||||||
|
<artifactId>jflex</artifactId>
|
||||||
|
<version>1.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
<version>1.2.71</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>edu.berkeley.eecs.venus164</groupId>
|
||||||
|
<artifactId>venus164</artifactId>
|
||||||
|
<version>0.2.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.proguard</groupId>
|
||||||
|
<artifactId>proguard-base</artifactId>
|
||||||
|
<version>6.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,12 @@
|
|||||||
|
# Runtime support function abort (does not return).
|
||||||
|
mv t0, a0 # Save exit code in temp
|
||||||
|
li a0, @print_string # Code for print_string ecall
|
||||||
|
ecall # Print error message in a1
|
||||||
|
li a1, 10 # Load newline character
|
||||||
|
li a0, @print_char # Code for print_char ecall
|
||||||
|
ecall # Print newline
|
||||||
|
mv a1, t0 # Move exit code to a1
|
||||||
|
li a0, @exit2 # Code for exit2 ecall
|
||||||
|
ecall # Exit with code
|
||||||
|
abort_17: # Infinite loop
|
||||||
|
j abort_17 # Prevent fallthrough
|
@ -0,0 +1,4 @@
|
|||||||
|
# Runtime support function alloc.
|
||||||
|
# Prototype address is in a0.
|
||||||
|
lw a1, 4(a0) # Get size of object in words
|
||||||
|
j alloc2 # Allocate object with exact size
|
@ -0,0 +1,27 @@
|
|||||||
|
# Runtime support function alloc2 (realloc).
|
||||||
|
# Prototype address is in a0.
|
||||||
|
# Number of words to allocate is in a1.
|
||||||
|
li a2, 4 # Word size in bytes
|
||||||
|
mul a2, a1, a2 # Calculate number of bytes to allocate
|
||||||
|
add a2, gp, a2 # Estimate where GP will move
|
||||||
|
bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
|
||||||
|
lw t0, @.__obj_size__(a0) # Get size of object in words
|
||||||
|
mv t2, a0 # Initialize src ptr
|
||||||
|
mv t3, gp # Initialize dest ptr
|
||||||
|
alloc2_16: # Copy-loop header
|
||||||
|
lw t1, 0(t2) # Load next word from src
|
||||||
|
sw t1, 0(t3) # Store next word to dest
|
||||||
|
addi t2, t2, 4 # Increment src
|
||||||
|
addi t3, t3, 4 # Increment dest
|
||||||
|
addi t0, t0, -1 # Decrement counter
|
||||||
|
bne t0, zero, alloc2_16 # Loop if more words left to copy
|
||||||
|
mv a0, gp # Save new object's address to return
|
||||||
|
sw a1, @.__obj_size__(a0) # Set size of new object in words
|
||||||
|
# (same as requested size)
|
||||||
|
mv gp, a2 # Set next free slot in the heap
|
||||||
|
jr ra # Return to caller
|
||||||
|
alloc2_15: # OOM handler
|
||||||
|
li a0, @error_oom # Exit code for: Out of memory
|
||||||
|
la a1, STRING["Out of memory"] # Load error message as str
|
||||||
|
addi a1, a1, @.__str__ # Load address of attribute __str__
|
||||||
|
j abort # Abort
|
@ -0,0 +1,5 @@
|
|||||||
|
# Runtime support function heap.init.
|
||||||
|
mv a1, a0 # Move requested size to A1
|
||||||
|
li a0, @sbrk # Code for ecall: sbrk
|
||||||
|
ecall # Request A1 bytes
|
||||||
|
jr ra # Return to caller
|
@ -0,0 +1,40 @@
|
|||||||
|
# Function input
|
||||||
|
addi sp, sp, -16 # Reserve stack
|
||||||
|
sw ra, 12(sp) # Save registers
|
||||||
|
sw fp, 8(sp)
|
||||||
|
sw s1, 4(sp)
|
||||||
|
addi fp, sp, 16 # Set fp
|
||||||
|
|
||||||
|
li a0, @fill_line_buffer # Fill the internal line buffer.
|
||||||
|
ecall
|
||||||
|
bgez a0, input_nonempty # More input found
|
||||||
|
la a0, $str$prototype # EOF: Return empty string.
|
||||||
|
j input_done
|
||||||
|
|
||||||
|
input_nonempty:
|
||||||
|
mv s1, a0
|
||||||
|
addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
|
||||||
|
addi t0, t0, @.__str__ # Including header.
|
||||||
|
srli a1, t0, 2 # Convert to words.
|
||||||
|
la a0, $str$prototype # Load address of string prototype.
|
||||||
|
jal ra, alloc2 # Allocate string.
|
||||||
|
sw s1, @.__len__(a0) # Store string length.
|
||||||
|
mv a2, s1 # Pass length.
|
||||||
|
mv s1, a0 # Save string object address.
|
||||||
|
addi a1, a0, @.__str__ # Pass address of string data.
|
||||||
|
li a0, @read_string # ecall to read from internal buffer.
|
||||||
|
ecall
|
||||||
|
addi a0, a0, 1 # Actual length (including NL).
|
||||||
|
sw a0, @.__len__(s1) # Store actual length.
|
||||||
|
add t0, a0, s1
|
||||||
|
li t1, 10 # Store newline and null byte
|
||||||
|
sb t1, @.__str__-1(t0)
|
||||||
|
sb zero, @.__str__(t0) # Store null byte at end.
|
||||||
|
mv a0, s1 # Return string object.
|
||||||
|
|
||||||
|
input_done:
|
||||||
|
lw s1, -12(fp)
|
||||||
|
lw ra, -4(fp)
|
||||||
|
lw fp, -8(fp)
|
||||||
|
addi sp, sp, 16
|
||||||
|
jr ra
|
@ -0,0 +1,20 @@
|
|||||||
|
# Function len
|
||||||
|
# We do not save/restore fp/ra for this function
|
||||||
|
# because we know that it does not use the stack or does not
|
||||||
|
# call other functions.
|
||||||
|
|
||||||
|
lw a0, 0(sp) # Load arg
|
||||||
|
beq a0, zero, len_12 # None is an illegal argument
|
||||||
|
lw t0, 0(a0) # Get type tag of arg
|
||||||
|
li t1, 3 # Load type tag of `str`
|
||||||
|
beq t0, t1, len_13 # Go to len(str)
|
||||||
|
li t1, -1 # Load type tag for list objects
|
||||||
|
beq t0, t1, len_13 # Go to len(list)
|
||||||
|
len_12: # Invalid argument
|
||||||
|
li a0, @error_arg # Exit code for: Invalid argument
|
||||||
|
la a1, STRING["Invalid argument"] # Load error message as str
|
||||||
|
addi a1, a1, @.__str__ # Load address of attribute __str__
|
||||||
|
j abort # Abort
|
||||||
|
len_13: # Get length of string
|
||||||
|
lw a0, @.__len__(a0) # Load attribute: __len__
|
||||||
|
jr ra # Return to caller
|
@ -0,0 +1,3 @@
|
|||||||
|
# Init method for type object.
|
||||||
|
mv a0, zero # `None` constant
|
||||||
|
jr ra # Return
|
@ -0,0 +1,52 @@
|
|||||||
|
# Function print
|
||||||
|
lw a0, 0(sp) # Load arg
|
||||||
|
beq a0, zero, print_6 # None is an illegal argument
|
||||||
|
lw t0, 0(a0) # Get type tag of arg
|
||||||
|
li t1, 1 # Load type tag of `int`
|
||||||
|
beq t0, t1, print_7 # Go to print(int)
|
||||||
|
li t1, 3 # Load type tag of `str`
|
||||||
|
beq t0, t1, print_8 # Go to print(str)
|
||||||
|
li t1, 2 # Load type tag of `bool`
|
||||||
|
beq t0, t1, print_9 # Go to print(bool)
|
||||||
|
print_6: # Invalid argument
|
||||||
|
li a0, 1 # Exit code for: Invalid argument
|
||||||
|
la a1, STRING["Invalid argument"] # Load error message as str
|
||||||
|
addi a1, a1, @.__str__ # Load address of attribute __str__
|
||||||
|
j abort # Abort
|
||||||
|
|
||||||
|
# Printing bools
|
||||||
|
print_9: # Print bool object in A0
|
||||||
|
lw a0, @.__bool__(a0) # Load attribute __bool__
|
||||||
|
beq a0, zero, print_10 # Go to: print(False)
|
||||||
|
la a0, STRING["True"] # String representation: True
|
||||||
|
j print_8 # Go to: print(str)
|
||||||
|
print_10: # Print False object in A0
|
||||||
|
la a0, STRING["False"] # String representation: False
|
||||||
|
j print_8 # Go to: print(str)
|
||||||
|
|
||||||
|
# Printing strs.
|
||||||
|
print_8: # Print str object in A0
|
||||||
|
addi a1, a0, @.__str__ # Load address of attribute __str__
|
||||||
|
j print_11 # Print the null-terminated string is now in A1
|
||||||
|
mv a0, zero # Load None
|
||||||
|
j print_5 # Go to return
|
||||||
|
print_11: # Print null-terminated string in A1
|
||||||
|
li a0, @print_string # Code for ecall: print_string
|
||||||
|
ecall # Print string
|
||||||
|
li a1, 10 # Load newline character
|
||||||
|
li a0, @print_char # Code for ecall: print_char
|
||||||
|
ecall # Print character
|
||||||
|
j print_5 # Go to return
|
||||||
|
|
||||||
|
# Printing ints.
|
||||||
|
print_7: # Print int object in A0
|
||||||
|
lw a1, @.__int__(a0) # Load attribute __int__
|
||||||
|
li a0, @print_int # Code for ecall: print_int
|
||||||
|
ecall # Print integer
|
||||||
|
li a1, 10 # Load newline character
|
||||||
|
li a0, 11 # Code for ecall: print_char
|
||||||
|
ecall # Print character
|
||||||
|
|
||||||
|
print_5: # End of function
|
||||||
|
mv a0, zero # Load None
|
||||||
|
jr ra # Return to caller
|
@ -0,0 +1,54 @@
|
|||||||
|
package chocopy.common;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>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, Charset.forName("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();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,174 @@
|
|||||||
|
package chocopy.common.analysis;
|
||||||
|
|
||||||
|
import chocopy.common.astnodes.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An empty implementation of the {@link NodeAnalyzer} that simply returns does nothing and returns
|
||||||
|
* null for every AST node type.
|
||||||
|
*
|
||||||
|
* <p>T is the type of analysis result.
|
||||||
|
*/
|
||||||
|
public class AbstractNodeAnalyzer<T> implements NodeAnalyzer<T> {
|
||||||
|
@Override
|
||||||
|
public T analyze(AssignStmt node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(BinaryExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(BooleanLiteral node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(CallExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(ClassDef node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(ClassType node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(CompilerError node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(Errors node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(ExprStmt node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(ForStmt node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(FuncDef node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(GlobalDecl node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(Identifier node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(IfExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(IfStmt node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(IndexExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(IntegerLiteral node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(ListExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(ListType node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(MemberExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(MethodCallExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(NoneLiteral node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(NonLocalDecl node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(Program node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(ReturnStmt node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(StringLiteral node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(TypedVar node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(UnaryExpr node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(VarDef node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T analyze(WhileStmt node) {
|
||||||
|
return defaultAction(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault(T value) {
|
||||||
|
defaultValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T defaultAction(Node node) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Default value for non-overridden methods. */
|
||||||
|
private T defaultValue = null;
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>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<T> 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.
|
||||||
|
*
|
||||||
|
* <p>The class AbstractNodeAnalyzer provides empty default implementations for these methods.
|
||||||
|
*
|
||||||
|
* <p>The type T is the type of result returned by the encapsulated analysis.
|
||||||
|
*/
|
||||||
|
public interface NodeAnalyzer<T> {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package chocopy.common.analysis;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block-structured symbol table a mapping identifiers to information about them of type T in a
|
||||||
|
* given declarative region.
|
||||||
|
*/
|
||||||
|
public class SymbolTable<T> {
|
||||||
|
|
||||||
|
/** Contents of the current (innermost) region. */
|
||||||
|
private final Map<String, T> tab = new HashMap<>();
|
||||||
|
/** Enclosing block. */
|
||||||
|
private final SymbolTable<T> parent;
|
||||||
|
|
||||||
|
/** A table representing a region nested in that represented by PARENT0. */
|
||||||
|
public SymbolTable(SymbolTable<T> parent0) {
|
||||||
|
parent = parent0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A top-level symbol table. */
|
||||||
|
public SymbolTable() {
|
||||||
|
this.parent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the mapping of NAME in the innermost nested region containing this one. */
|
||||||
|
public T get(String name) {
|
||||||
|
if (tab.containsKey(name)) {
|
||||||
|
return tab.get(name);
|
||||||
|
} else if (parent != null) {
|
||||||
|
return parent.get(name);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new mapping of NAME -> VALUE to the current region, possibly shadowing mappings in the
|
||||||
|
* enclosing parent. Returns modified table.
|
||||||
|
*/
|
||||||
|
public SymbolTable<T> put(String name, T value) {
|
||||||
|
tab.put(name, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether NAME has a mapping in this region (ignoring enclosing regions. */
|
||||||
|
public boolean declares(String name) {
|
||||||
|
return tab.containsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns all the names declared this region (ignoring enclosing regions). */
|
||||||
|
public Set<String> getDeclaredSymbols() {
|
||||||
|
return tab.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the parent, or null if this is the top level. */
|
||||||
|
public SymbolTable<T> getParent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package chocopy.common.analysis.types;
|
||||||
|
|
||||||
|
import chocopy.common.astnodes.ClassType;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/** Represents the semantic value of a simple class reference. */
|
||||||
|
public class ClassValueType extends ValueType {
|
||||||
|
|
||||||
|
/** The name of the class. */
|
||||||
|
private final String className;
|
||||||
|
|
||||||
|
/** A class type for the class named CLASSNAME. */
|
||||||
|
@JsonCreator
|
||||||
|
public ClassValueType(@JsonProperty String className) {
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A class type for the class referenced by CLASSTYPEANNOTATION. */
|
||||||
|
public ClassValueType(ClassType classTypeAnnotation) {
|
||||||
|
this.className = classTypeAnnotation.className;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonProperty
|
||||||
|
public String className() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ClassValueType classType = (ClassValueType) o;
|
||||||
|
return Objects.equals(className, classType.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package chocopy.common.analysis.types;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Semantic information for a function or method. */
|
||||||
|
public class FuncType extends Type {
|
||||||
|
|
||||||
|
/** Types of parameters. */
|
||||||
|
public final List<ValueType> parameters;
|
||||||
|
/** Function's return type. */
|
||||||
|
public final ValueType returnType;
|
||||||
|
|
||||||
|
/** Create a FuncType returning RETURNTYPE0, initially parameterless. */
|
||||||
|
public FuncType(ValueType returnType0) {
|
||||||
|
this(new ArrayList<>(), returnType0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a FuncType for NAME0 with formal parameter types PARAMETERS0, returning type
|
||||||
|
* RETURNTYPE0.
|
||||||
|
*/
|
||||||
|
@JsonCreator
|
||||||
|
public FuncType(List<ValueType> parameters0, ValueType returnType0) {
|
||||||
|
this.parameters = parameters0;
|
||||||
|
this.returnType = returnType0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFuncType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the type of the K-th parameter. */
|
||||||
|
public ValueType getParamType(int k) {
|
||||||
|
return parameters.get(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "<function>";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package chocopy.common.analysis.types;
|
||||||
|
|
||||||
|
import chocopy.common.astnodes.ListType;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/** Represents a semantic value of a list type denotation. */
|
||||||
|
public class ListValueType extends ValueType {
|
||||||
|
|
||||||
|
/** This ListValueType represents [ELEMENTTYPE]. */
|
||||||
|
public final ValueType elementType;
|
||||||
|
|
||||||
|
/** Represents [ELEMENTTYPE]. */
|
||||||
|
@JsonCreator
|
||||||
|
public ListValueType(Type elementType) {
|
||||||
|
this.elementType = (ValueType) elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents [<type>], where <type> is that denoted in TYPEANNOTATION. */
|
||||||
|
public ListValueType(ListType typeAnnotation) {
|
||||||
|
elementType = ValueType.annotationToValueType(typeAnnotation.elementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ListValueType listType = (ListValueType) o;
|
||||||
|
return Objects.equals(elementType, listType.elementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(elementType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[" + elementType.toString() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true iff I represent [T]. */
|
||||||
|
@Override
|
||||||
|
public boolean isListType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueType elementType() {
|
||||||
|
return elementType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package chocopy.common.analysis.types;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation for the static type of symbols and expressions during type-checking.
|
||||||
|
*
|
||||||
|
* <p>Symbols such as variables and attributes will typically map to a {@link ValueType}.
|
||||||
|
*
|
||||||
|
* <p>Symbols such as classes will typically map to a more complex Type.
|
||||||
|
*/
|
||||||
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "kind")
|
||||||
|
@JsonSubTypes({
|
||||||
|
@JsonSubTypes.Type(FuncType.class),
|
||||||
|
@JsonSubTypes.Type(ClassValueType.class),
|
||||||
|
@JsonSubTypes.Type(ListValueType.class)
|
||||||
|
})
|
||||||
|
public abstract class Type {
|
||||||
|
|
||||||
|
/** The type object. */
|
||||||
|
public static final ClassValueType OBJECT_TYPE = new ClassValueType("object");
|
||||||
|
/** The type int. */
|
||||||
|
public static final ClassValueType INT_TYPE = new ClassValueType("int");
|
||||||
|
/** The type str. */
|
||||||
|
public static final ClassValueType STR_TYPE = new ClassValueType("str");
|
||||||
|
/** The type bool. */
|
||||||
|
public static final ClassValueType BOOL_TYPE = new ClassValueType("bool");
|
||||||
|
|
||||||
|
/** The type of None. */
|
||||||
|
public static final ClassValueType NONE_TYPE = new ClassValueType("<None>");
|
||||||
|
/** The type of []. */
|
||||||
|
public static final ClassValueType EMPTY_TYPE = new ClassValueType("<Empty>");
|
||||||
|
|
||||||
|
/** Returns the name of the class, if this is a class type, Otherwise null. */
|
||||||
|
public String className() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return true iff this is a type that does not include the value None. */
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isSpecialType() {
|
||||||
|
return equals(INT_TYPE) || equals(BOOL_TYPE) || equals(STR_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isListType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isFuncType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return true iff this type represents a kind of assignable value. */
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isValueType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** For list types, return the type of the elements; otherwise null. */
|
||||||
|
@JsonIgnore
|
||||||
|
public ValueType elementType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package chocopy.common.analysis.types;
|
||||||
|
|
||||||
|
import chocopy.common.astnodes.ClassType;
|
||||||
|
import chocopy.common.astnodes.ListType;
|
||||||
|
import chocopy.common.astnodes.TypeAnnotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ValueType references types that are assigned to variables and expressions.
|
||||||
|
*
|
||||||
|
* <p>In particular, ValueType can be a {@link ClassValueType} (e.g. "int") or a {@link
|
||||||
|
* ListValueType} (e.g. "[int]").
|
||||||
|
*/
|
||||||
|
public abstract class ValueType extends Type {
|
||||||
|
|
||||||
|
/** Returns the type corresponding to ANNOTATION. */
|
||||||
|
public static ValueType annotationToValueType(TypeAnnotation annotation) {
|
||||||
|
if (annotation instanceof ClassType) {
|
||||||
|
return new ClassValueType((ClassType) annotation);
|
||||||
|
} else {
|
||||||
|
assert annotation instanceof ListType;
|
||||||
|
return new ListValueType((ListType) annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValueType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
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<Expr> 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<Expr> targets, Expr value) {
|
||||||
|
super(left, right);
|
||||||
|
this.targets = targets;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package chocopy.common.astnodes;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.NodeAnalyzer;
|
||||||
|
import java_cup.runtime.ComplexSymbolFactory.Location;
|
||||||
|
|
||||||
|
/** <operand> <operator> <operand>. */
|
||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
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<Expr> args;
|
||||||
|
|
||||||
|
/** AST for FUNCTION(ARGS) at [LEFT..RIGHT]. */
|
||||||
|
public CallExpr(Location left, Location right, Identifier function, List<Expr> args) {
|
||||||
|
super(left, right);
|
||||||
|
this.function = function;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
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<Declaration> declarations;
|
||||||
|
|
||||||
|
/** An AST for class NAME(SUPERCLASS): DECLARATIONS. spanning source locations [LEFT..RIGHT]. */
|
||||||
|
public ClassDef(
|
||||||
|
Location left,
|
||||||
|
Location right,
|
||||||
|
Identifier name,
|
||||||
|
Identifier superClass,
|
||||||
|
List<Declaration> declarations) {
|
||||||
|
super(left, right);
|
||||||
|
this.name = name;
|
||||||
|
this.superClass = superClass;
|
||||||
|
this.declarations = declarations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getIdentifier() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The error message. */
|
||||||
|
public final String message;
|
||||||
|
/** True if this is a syntax error. */
|
||||||
|
private final boolean syntax;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
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();
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
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<CompilerError> 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<CompilerError> 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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package chocopy.common.astnodes;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.types.Type;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import java_cup.runtime.ComplexSymbolFactory.Location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base of all AST nodes representing expressions.
|
||||||
|
*
|
||||||
|
* <p>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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the value that this expression evaluates to.
|
||||||
|
*
|
||||||
|
* <p>This field is always <tt>null</tt> after the parsing stage, but is populated by the
|
||||||
|
* typechecker in the semantic analysis stage.
|
||||||
|
*
|
||||||
|
* <p>After typechecking this field may be <tt>null</tt> only for expressions that cannot be
|
||||||
|
* assigned a type. In particular, {@link NoneLiteral} expressions will not have a typed
|
||||||
|
* assigned to them.
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
private Type inferredType;
|
||||||
|
|
||||||
|
/** Set getInferredType() to TYPE, returning TYPE. */
|
||||||
|
public Type setInferredType(Type type) {
|
||||||
|
inferredType = type;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getInferredType() {
|
||||||
|
return inferredType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
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<Stmt> 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<Stmt> body) {
|
||||||
|
super(left, right);
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.iterable = iterable;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
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<TypedVar> params;
|
||||||
|
/** Return type annotation. */
|
||||||
|
public final TypeAnnotation returnType;
|
||||||
|
/** Local-variable,inner-function, global, and nonlocal declarations. */
|
||||||
|
public final List<Declaration> declarations;
|
||||||
|
/** Other statements. */
|
||||||
|
public final List<Stmt> statements;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AST for def NAME(PARAMS) -> RETURNTYPE: DECLARATIONS STATEMENTS spanning source locations
|
||||||
|
* [LEFT..RIGHT].
|
||||||
|
*/
|
||||||
|
public FuncDef(
|
||||||
|
Location left,
|
||||||
|
Location right,
|
||||||
|
Identifier name,
|
||||||
|
List<TypedVar> params,
|
||||||
|
TypeAnnotation returnType,
|
||||||
|
List<Declaration> declarations,
|
||||||
|
List<Stmt> statements) {
|
||||||
|
super(left, right);
|
||||||
|
this.name = name;
|
||||||
|
this.params = params;
|
||||||
|
this.returnType = returnType;
|
||||||
|
this.declarations = declarations;
|
||||||
|
this.statements = statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getIdentifier() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getIdentifier() {
|
||||||
|
return this.variable;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
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<Stmt> thenBody;
|
||||||
|
/** "False" branch. */
|
||||||
|
public final List<Stmt> elseBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AST for if CONDITION: THENBODY else: ELSEBODY spanning source locations [LEFT..RIGHT].
|
||||||
|
*/
|
||||||
|
public IfStmt(
|
||||||
|
Location left,
|
||||||
|
Location right,
|
||||||
|
Expr condition,
|
||||||
|
List<Stmt> thenBody,
|
||||||
|
List<Stmt> elseBody) {
|
||||||
|
super(left, right);
|
||||||
|
this.condition = condition;
|
||||||
|
this.thenBody = thenBody;
|
||||||
|
this.elseBody = elseBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
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<Expr> elements;
|
||||||
|
|
||||||
|
/** The AST for [ ELEMENTS ]. spanning source locations [LEFT..RIGHT]. */
|
||||||
|
public ListExpr(Location left, Location right, List<Expr> elements) {
|
||||||
|
super(left, right);
|
||||||
|
this.elements = elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package chocopy.common.astnodes;
|
||||||
|
|
||||||
|
import java_cup.runtime.ComplexSymbolFactory.Location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base of all the literal nodes.
|
||||||
|
*
|
||||||
|
* <p>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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
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<Expr> args;
|
||||||
|
|
||||||
|
/** The AST for METHOD(ARGS). spanning source locations [LEFT..RIGHT]. */
|
||||||
|
public MethodCallExpr(Location left, Location right, MemberExpr method, List<Expr> args) {
|
||||||
|
super(left, right);
|
||||||
|
this.method = method;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,176 @@
|
|||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>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 { <first line>, <first column>, <last line>, <last column> }.
|
||||||
|
* 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> T dispatch(NodeAnalyzer<T> 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> T fromJSON(String json, Class<T> 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> T fromJSON(JsonNode tree, Class<T> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getIdentifier() {
|
||||||
|
return this.variable;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
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<Declaration> declarations;
|
||||||
|
/** Trailing statements. */
|
||||||
|
public final List<Stmt> statements;
|
||||||
|
/** Accumulated errors. */
|
||||||
|
public final Errors errors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AST for the program DECLARATIONS STATEMENTS spanning source locations [LEFT..RIGHT].
|
||||||
|
*
|
||||||
|
* <p>ERRORS is the container for all error messages applying to the program.
|
||||||
|
*/
|
||||||
|
public Program(
|
||||||
|
Location left,
|
||||||
|
Location right,
|
||||||
|
List<Declaration> declarations,
|
||||||
|
List<Stmt> 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> T dispatch(NodeAnalyzer<T> 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<CompilerError> getErrorList() {
|
||||||
|
return errors.errors;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package chocopy.common.astnodes;
|
||||||
|
|
||||||
|
import java_cup.runtime.ComplexSymbolFactory.Location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base of all AST nodes representing statements.
|
||||||
|
*
|
||||||
|
* <p>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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
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> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The identifier defined by this declaration. */
|
||||||
|
@Override
|
||||||
|
public Identifier getIdentifier() {
|
||||||
|
return this.var.identifier;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
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<Stmt> body;
|
||||||
|
|
||||||
|
/** The AST for while CONDITION: BODY spanning source locations [LEFT..RIGHT]. */
|
||||||
|
public WhileStmt(Location left, Location right, Expr condition, List<Stmt> body) {
|
||||||
|
super(left, right);
|
||||||
|
this.condition = condition;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T dispatch(NodeAnalyzer<T> analyzer) {
|
||||||
|
return analyzer.analyze(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.types.ValueType;
|
||||||
|
import chocopy.common.astnodes.Literal;
|
||||||
|
|
||||||
|
/** Information concerning an instance variable. */
|
||||||
|
public class AttrInfo extends VarInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptor for an attribute named ATTRNAME of type VARTYPE whose initial value, if any, is
|
||||||
|
* a constant specified by INITIALVALUE (it is otherwise null).
|
||||||
|
*/
|
||||||
|
public AttrInfo(String attrName, ValueType varType, Literal initialValue) {
|
||||||
|
super(attrName, varType, initialValue);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Information for code generation a class. */
|
||||||
|
public class ClassInfo extends SymbolInfo {
|
||||||
|
|
||||||
|
/** Name of class. */
|
||||||
|
protected final String className;
|
||||||
|
|
||||||
|
/** Information about instance variables of the class. */
|
||||||
|
public final List<AttrInfo> attributes;
|
||||||
|
/** Information about methods of the class. */
|
||||||
|
public final List<FuncInfo> methods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag indicating type of value: 0: (reserved) 1: int 2: bool 3: str -1: [T] for any T >3:
|
||||||
|
* User-defined types.
|
||||||
|
*/
|
||||||
|
protected final int typeTag;
|
||||||
|
/** Label of area containing initial instance values. */
|
||||||
|
protected final Label prototypeLabel;
|
||||||
|
/** Label of area containing method-dispatching table. */
|
||||||
|
protected Label dispatchTableLabel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptor for a class named CLASSNAME identified by runtime tag TYPETAG, and having the
|
||||||
|
* class denoted by SUPERCLASSINFO as its superclass. The latter is null iff the class is
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
public ClassInfo(String className, int typeTag, ClassInfo superClassInfo) {
|
||||||
|
this.className = className;
|
||||||
|
this.typeTag = typeTag;
|
||||||
|
prototypeLabel = new Label(String.format("$%s$%s", className, "prototype"));
|
||||||
|
dispatchTableLabel = new Label(String.format("$%s$%s", className, "dispatchTable"));
|
||||||
|
attributes = new ArrayList<>();
|
||||||
|
methods = new ArrayList<>();
|
||||||
|
if (superClassInfo != null) {
|
||||||
|
attributes.addAll(superClassInfo.attributes);
|
||||||
|
methods.addAll(superClassInfo.methods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add an attribute described by ATTRINFO. */
|
||||||
|
public void addAttribute(AttrInfo attrInfo) {
|
||||||
|
this.attributes.add(attrInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a method described by FUNCINFO, overriding any inherited method of that name if
|
||||||
|
* necessary.
|
||||||
|
*/
|
||||||
|
public void addMethod(FuncInfo funcInfo) {
|
||||||
|
String methodName = funcInfo.getBaseName();
|
||||||
|
int idx = this.getMethodIndex(methodName);
|
||||||
|
if (idx >= 0) {
|
||||||
|
this.methods.set(idx, funcInfo);
|
||||||
|
} else {
|
||||||
|
this.methods.add(funcInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return my type tag. */
|
||||||
|
public int getTypeTag() {
|
||||||
|
return typeTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the address of this class's prototype object (a label). */
|
||||||
|
public Label getPrototypeLabel() {
|
||||||
|
return prototypeLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the address of this class's dispatch table (a label). */
|
||||||
|
public Label getDispatchTableLabel() {
|
||||||
|
return dispatchTableLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the attribute named ATTRNAME in order of definition.
|
||||||
|
*
|
||||||
|
* <p>This index takes into account inherited attribute and returns the index of an attribute as
|
||||||
|
* a slot index in its object layout (excluding the object header). Attributes are numbered from
|
||||||
|
* 0; the result is an index, and not a byte offset.
|
||||||
|
*/
|
||||||
|
public int getAttributeIndex(String attrName) {
|
||||||
|
for (int i = 0; i < attributes.size(); i++) {
|
||||||
|
if (attributes.get(i).getVarName().equals(attrName)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the method named METHODNAME in order of definition.
|
||||||
|
*
|
||||||
|
* <p>This index takes into account inherited and overridden methods and returns the index of
|
||||||
|
* the method as a slot number (not a byte offset) in the dispatch table.
|
||||||
|
*/
|
||||||
|
public int getMethodIndex(String methodName) {
|
||||||
|
for (int i = 0; i < methods.size(); i++) {
|
||||||
|
if (methods.get(i).getBaseName().equals(methodName)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the list of attributes of this class, in order of the object's layout. */
|
||||||
|
public List<AttrInfo> getAttributes() {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the list of methods of this class, in order of the object's dispatch table. */
|
||||||
|
public List<FuncInfo> getMethods() {
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,880 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.AbstractNodeAnalyzer;
|
||||||
|
import chocopy.common.analysis.SymbolTable;
|
||||||
|
import chocopy.common.analysis.types.Type;
|
||||||
|
import chocopy.common.analysis.types.ValueType;
|
||||||
|
import chocopy.common.astnodes.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static chocopy.common.Utils.*;
|
||||||
|
import static chocopy.common.codegen.RiscVBackend.Register.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The code generator for a ChocoPy program.
|
||||||
|
*
|
||||||
|
* <p>This class implements logic to analyze all declarations in a program and create descriptors
|
||||||
|
* for classes, functions, methods, variables (global and local), and attributes. This logic also
|
||||||
|
* builds symbol tables for globals and individual functions.
|
||||||
|
*
|
||||||
|
* <p>This class also implements logic to emit global variables, object prototypes and dispatch
|
||||||
|
* tables, as well as int/str/bool constants.
|
||||||
|
*
|
||||||
|
* <p>However, this class is abstract because it does not implement logic for emitting executable
|
||||||
|
* code in bodies of user-defined functions as well as in top-level statements. This class should be
|
||||||
|
* extended with implementations for such logic.
|
||||||
|
*
|
||||||
|
* <p>All non-public members of this class are `protected`, and can be overridden by sub-classes to
|
||||||
|
* extend change functionality.
|
||||||
|
*
|
||||||
|
* <p>The SymbolInfo classes can also be overridden. If say you want to use your own extended
|
||||||
|
* FuncInfo called MyFuncInfo (that extends FuncInfo), then override the makeFuncInfo() method of
|
||||||
|
* this class to `return new MyFuncInfo(...)` instead. This is probably not needed, though.
|
||||||
|
*/
|
||||||
|
public abstract class CodeGenBase {
|
||||||
|
|
||||||
|
/** The location of the text resources containing common library code. */
|
||||||
|
protected static final String LIBRARY_CODE_DIR = "chocopy/common/";
|
||||||
|
|
||||||
|
/** The backend that emits assembly. */
|
||||||
|
protected final RiscVBackend backend;
|
||||||
|
|
||||||
|
/** Convenience variable: the word size for the current back end. */
|
||||||
|
protected final int wordSize;
|
||||||
|
|
||||||
|
/** A counter for generating unique class type tags. */
|
||||||
|
protected int nextTypeTag = 0;
|
||||||
|
|
||||||
|
/** A counter used to generate unique local label names. */
|
||||||
|
protected int nextLabelSuffix = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined classes. The list "class" is a fake class; we use it only to emit a prototype
|
||||||
|
* object for empty lists.
|
||||||
|
*/
|
||||||
|
protected ClassInfo objectClass, intClass, boolClass, strClass, listClass;
|
||||||
|
|
||||||
|
/** Predefined functions. */
|
||||||
|
protected FuncInfo printFunc, lenFunc, inputFunc;
|
||||||
|
|
||||||
|
/** A list of global variables, whose initial values are emitted in the backend. */
|
||||||
|
protected final List<GlobalVarInfo> globalVars = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of program classes, whose prototype objects and dispatch tables are emitted in the
|
||||||
|
* backend.
|
||||||
|
*/
|
||||||
|
protected final List<ClassInfo> classes = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of functions (including methods and nested functions) whose bodies are emitted in the
|
||||||
|
* backend.
|
||||||
|
*/
|
||||||
|
protected final List<FuncInfo> functions = new ArrayList<>();
|
||||||
|
|
||||||
|
/** Label for built-in routine: alloc. */
|
||||||
|
protected final Label objectAllocLabel = new Label("alloc");
|
||||||
|
|
||||||
|
/** Label for built-in routine: alloc2. */
|
||||||
|
protected final Label objectAllocResizeLabel = new Label("alloc2");
|
||||||
|
|
||||||
|
/** Label for built-in routine: abort. */
|
||||||
|
protected final Label abortLabel = new Label("abort");
|
||||||
|
|
||||||
|
/** Label for built-in routine: heap.init. */
|
||||||
|
protected final Label heapInitLabel = new Label("heap.init");
|
||||||
|
|
||||||
|
/** Error codes. */
|
||||||
|
protected final int ERROR_ARG = 1,
|
||||||
|
ERROR_DIV_ZERO = 2,
|
||||||
|
ERROR_OOB = 3,
|
||||||
|
ERROR_NONE = 4,
|
||||||
|
ERROR_OOM = 5,
|
||||||
|
ERROR_NYI = 6;
|
||||||
|
|
||||||
|
/** Size of heap memory. */
|
||||||
|
protected final int HEAP_SIZE_BYTES = 1024 * 1024 * 32;
|
||||||
|
|
||||||
|
/** Ecall numbers for intrinsic routines. */
|
||||||
|
protected final int EXIT_ECALL = 10,
|
||||||
|
EXIT2_ECALL = 17,
|
||||||
|
PRINT_STRING_ECALL = 4,
|
||||||
|
PRINT_CHAR_ECALL = 11,
|
||||||
|
PRINT_INT_ECALL = 1,
|
||||||
|
READ_STRING_ECALL = 8,
|
||||||
|
FILL_LINE_BUFFER__ECALL = 18,
|
||||||
|
SBRK_ECALL = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The symbol table that maps global names to information about the bound global variables,
|
||||||
|
* global functions, or classes.
|
||||||
|
*/
|
||||||
|
protected final SymbolTable<SymbolInfo> globalSymbols = new SymbolTable<>();
|
||||||
|
|
||||||
|
/** A utility for caching constants and generating labels for constants. */
|
||||||
|
protected final Constants constants = new Constants();
|
||||||
|
|
||||||
|
/** The object header size, in words (includes type tag, size, and dispatch table pointer). */
|
||||||
|
public static final int HEADER_SIZE = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a code generator for ChocoPy that uses BACKEND to emit assembly code.
|
||||||
|
*
|
||||||
|
* <p>The constructor creates Info objects for predefined functions, classes, methods, and
|
||||||
|
* built-in routines.
|
||||||
|
*/
|
||||||
|
public CodeGenBase(RiscVBackend backend) {
|
||||||
|
this.backend = backend;
|
||||||
|
wordSize = backend.getWordSize();
|
||||||
|
|
||||||
|
initClasses();
|
||||||
|
initFunctions();
|
||||||
|
initAsmConstants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a fresh type tag. */
|
||||||
|
protected int getNextTypeTag() {
|
||||||
|
return nextTypeTag++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the next unique label suffix. */
|
||||||
|
protected int getNextLabelSuffix() {
|
||||||
|
return nextLabelSuffix++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a fresh label.
|
||||||
|
*
|
||||||
|
* <p>This label is guaranteed to be unique amongst labels generated by invoking this method.
|
||||||
|
* All such labels have a prefix of `label_`.
|
||||||
|
*
|
||||||
|
* <p>This is useful to generate local labels in function bodies (e.g. for targets of jumps),
|
||||||
|
* where the name does not matter in general.
|
||||||
|
*/
|
||||||
|
protected Label generateLocalLabel() {
|
||||||
|
return new Label(String.format("label_%d", getNextLabelSuffix()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates assembly code for PROGRAM.
|
||||||
|
*
|
||||||
|
* <p>This is the main driver that calls internal methods for emitting DATA section (globals,
|
||||||
|
* constants, prototypes, etc) as well as the the CODE section (predefined functions, built-in
|
||||||
|
* routines, and user-defined functions).
|
||||||
|
*/
|
||||||
|
public void generate(Program program) {
|
||||||
|
analyzeProgram(program);
|
||||||
|
|
||||||
|
backend.startData();
|
||||||
|
|
||||||
|
for (ClassInfo classInfo : this.classes) {
|
||||||
|
emitPrototype(classInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ClassInfo classInfo : this.classes) {
|
||||||
|
emitDispatchTable(classInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (GlobalVarInfo global : this.globalVars) {
|
||||||
|
backend.emitGlobalLabel(global.getLabel());
|
||||||
|
emitConstant(
|
||||||
|
global.getInitialValue(),
|
||||||
|
global.getVarType(),
|
||||||
|
String.format("Initial value of global var: %s", global.getVarName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.startCode();
|
||||||
|
|
||||||
|
Label mainLabel = new Label("main");
|
||||||
|
backend.emitGlobalLabel(mainLabel);
|
||||||
|
backend.emitLUI(A0, HEAP_SIZE_BYTES >> 12, "Initialize heap size (in multiples of 4KB)");
|
||||||
|
backend.emitADD(S11, S11, A0, "Save heap size");
|
||||||
|
backend.emitJAL(heapInitLabel, "Call heap.init routine");
|
||||||
|
backend.emitMV(GP, A0, "Initialize heap pointer");
|
||||||
|
backend.emitMV(S10, GP, "Set beginning of heap");
|
||||||
|
backend.emitADD(S11, S10, S11, "Set end of heap (= start of heap + heap size)");
|
||||||
|
backend.emitMV(RA, ZERO, "No normal return from main program.");
|
||||||
|
backend.emitMV(FP, ZERO, "No preceding frame.");
|
||||||
|
|
||||||
|
emitTopLevel(program.statements);
|
||||||
|
|
||||||
|
for (FuncInfo funcInfo : this.functions) {
|
||||||
|
funcInfo.emitBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
emitStdFunc("alloc");
|
||||||
|
emitStdFunc("alloc2");
|
||||||
|
emitStdFunc("abort");
|
||||||
|
emitStdFunc("heap.init");
|
||||||
|
|
||||||
|
emitCustomCode();
|
||||||
|
|
||||||
|
backend.startData();
|
||||||
|
emitConstants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create descriptors and symbols for builtin classes and methods. */
|
||||||
|
protected void initClasses() {
|
||||||
|
FuncInfo objectInit =
|
||||||
|
makeFuncInfo(
|
||||||
|
"object.__init__",
|
||||||
|
0,
|
||||||
|
Type.NONE_TYPE,
|
||||||
|
globalSymbols,
|
||||||
|
null,
|
||||||
|
this::emitStdFunc);
|
||||||
|
objectInit.addParam(makeStackVarInfo("self", Type.OBJECT_TYPE, null, objectInit));
|
||||||
|
functions.add(objectInit);
|
||||||
|
|
||||||
|
objectClass = makeClassInfo("object", getNextTypeTag(), null);
|
||||||
|
objectClass.addMethod(objectInit);
|
||||||
|
classes.add(objectClass);
|
||||||
|
globalSymbols.put(objectClass.getClassName(), objectClass);
|
||||||
|
|
||||||
|
intClass = makeClassInfo("int", getNextTypeTag(), objectClass);
|
||||||
|
intClass.addAttribute(makeAttrInfo("__int__", null, null));
|
||||||
|
classes.add(intClass);
|
||||||
|
globalSymbols.put(intClass.getClassName(), intClass);
|
||||||
|
|
||||||
|
boolClass = makeClassInfo("bool", getNextTypeTag(), objectClass);
|
||||||
|
boolClass.addAttribute(makeAttrInfo("__bool__", null, null));
|
||||||
|
classes.add(boolClass);
|
||||||
|
globalSymbols.put(boolClass.getClassName(), boolClass);
|
||||||
|
|
||||||
|
strClass = makeClassInfo("str", getNextTypeTag(), objectClass);
|
||||||
|
strClass.addAttribute(
|
||||||
|
makeAttrInfo("__len__", Type.INT_TYPE, new IntegerLiteral(null, null, 0)));
|
||||||
|
strClass.addAttribute(makeAttrInfo("__str__", null, null));
|
||||||
|
classes.add(strClass);
|
||||||
|
globalSymbols.put(strClass.getClassName(), strClass);
|
||||||
|
|
||||||
|
listClass = makeClassInfo(".list", -1, objectClass);
|
||||||
|
listClass.addAttribute(
|
||||||
|
makeAttrInfo("__len__", Type.INT_TYPE, new IntegerLiteral(null, null, 0)));
|
||||||
|
classes.add(listClass);
|
||||||
|
listClass.dispatchTableLabel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create descriptors and symbols for builtin functions. */
|
||||||
|
protected void initFunctions() {
|
||||||
|
printFunc =
|
||||||
|
makeFuncInfo("print", 0, Type.NONE_TYPE, globalSymbols, null, this::emitStdFunc);
|
||||||
|
printFunc.addParam(makeStackVarInfo("arg", Type.OBJECT_TYPE, null, printFunc));
|
||||||
|
functions.add(printFunc);
|
||||||
|
globalSymbols.put(printFunc.getBaseName(), printFunc);
|
||||||
|
|
||||||
|
lenFunc = makeFuncInfo("len", 0, Type.INT_TYPE, globalSymbols, null, this::emitStdFunc);
|
||||||
|
lenFunc.addParam(makeStackVarInfo("arg", Type.OBJECT_TYPE, null, lenFunc));
|
||||||
|
functions.add(lenFunc);
|
||||||
|
globalSymbols.put(lenFunc.getBaseName(), lenFunc);
|
||||||
|
|
||||||
|
inputFunc = makeFuncInfo("input", 0, Type.STR_TYPE, globalSymbols, null, this::emitStdFunc);
|
||||||
|
functions.add(inputFunc);
|
||||||
|
globalSymbols.put(inputFunc.getBaseName(), inputFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Symbolic assembler constants defined here (to add others, override
|
||||||
|
* initAsmConstants in an extension of CodeGenBase):
|
||||||
|
* ecalls:
|
||||||
|
* @sbrk
|
||||||
|
* @fill_line_buffer
|
||||||
|
* @read_string
|
||||||
|
* @print_string
|
||||||
|
* @print_char
|
||||||
|
* @print_int
|
||||||
|
* @exit2
|
||||||
|
* Exit codes:
|
||||||
|
* @error_div_zero: Division by 0.
|
||||||
|
* @error_arg: Bad argument.
|
||||||
|
* @error_oob: Out of bounds.
|
||||||
|
* @error_none: Attempt to access attribute of None.
|
||||||
|
* @error_oom: Out of memory.
|
||||||
|
* @error_nyi: Unimplemented operation.
|
||||||
|
* Data-structure byte offsets:
|
||||||
|
* @.__obj_size__: Offset of size of object.
|
||||||
|
* @.__len__: Offset of length in chars or words.
|
||||||
|
* @.__str__: Offset of string data.
|
||||||
|
* @.__elts__: Offset of first list item.
|
||||||
|
* @.__int__: Offset of integer value.
|
||||||
|
* @.__bool__: Offset of boolean (1/0) value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Define @-constants to be used in assembly code. */
|
||||||
|
protected void initAsmConstants() {
|
||||||
|
backend.defineSym("sbrk", SBRK_ECALL);
|
||||||
|
backend.defineSym("print_string", PRINT_STRING_ECALL);
|
||||||
|
backend.defineSym("print_char", PRINT_CHAR_ECALL);
|
||||||
|
backend.defineSym("print_int", PRINT_INT_ECALL);
|
||||||
|
backend.defineSym("exit2", EXIT2_ECALL);
|
||||||
|
backend.defineSym("read_string", READ_STRING_ECALL);
|
||||||
|
backend.defineSym("fill_line_buffer", FILL_LINE_BUFFER__ECALL);
|
||||||
|
|
||||||
|
backend.defineSym(".__obj_size__", 4);
|
||||||
|
backend.defineSym(".__len__", 12);
|
||||||
|
backend.defineSym(".__int__", 12);
|
||||||
|
backend.defineSym(".__bool__", 12);
|
||||||
|
backend.defineSym(".__str__", 16);
|
||||||
|
backend.defineSym(".__elts__", 16);
|
||||||
|
|
||||||
|
backend.defineSym("error_div_zero", ERROR_DIV_ZERO);
|
||||||
|
backend.defineSym("error_arg", ERROR_ARG);
|
||||||
|
backend.defineSym("error_oob", ERROR_OOB);
|
||||||
|
backend.defineSym("error_none", ERROR_NONE);
|
||||||
|
backend.defineSym("error_oom", ERROR_OOM);
|
||||||
|
backend.defineSym("error_nyi", ERROR_NYI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
/* */
|
||||||
|
/* FACTORY METHODS TO CREATE INFO OBJECTS */
|
||||||
|
/* */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory method that returns a descriptor for function or method FUNCNAME returning type
|
||||||
|
* RETURNTYPE at nesting level DEPTH in the region corresponding to PARENTSYMBOLTABLE.
|
||||||
|
*
|
||||||
|
* <p>PARENTFUNCINFO is a descriptor of the enclosing function and is null for global functions
|
||||||
|
* and methods.
|
||||||
|
*
|
||||||
|
* <p>EMITTER is a method that emits the function's body (usually a generic emitter for
|
||||||
|
* user-defined functions/methods, and a special emitter for pre-defined functions/methods).
|
||||||
|
*
|
||||||
|
* <p>Sub-classes of CodeGenBase can override this method if they wish to use a sub-class of
|
||||||
|
* FuncInfo with more functionality.
|
||||||
|
*/
|
||||||
|
protected FuncInfo makeFuncInfo(
|
||||||
|
String funcName,
|
||||||
|
int depth,
|
||||||
|
ValueType returnType,
|
||||||
|
SymbolTable<SymbolInfo> parentSymbolTable,
|
||||||
|
FuncInfo parentFuncInfo,
|
||||||
|
Consumer<FuncInfo> emitter) {
|
||||||
|
return new FuncInfo(
|
||||||
|
funcName, depth, returnType, parentSymbolTable, parentFuncInfo, emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a descriptor for a class named CLASSNAME having type tag TYPETAG and superclass
|
||||||
|
* SUPERCLASSINFO (null for `object' only).
|
||||||
|
*
|
||||||
|
* <p>Sub-classes of CodeGenBase can override this method if they wish to use a sub-class of
|
||||||
|
* ClassInfo with more functionality.
|
||||||
|
*/
|
||||||
|
public ClassInfo makeClassInfo(String className, int typeTag, ClassInfo superClassInfo) {
|
||||||
|
return new ClassInfo(className, typeTag, superClassInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory method that returns a descriptor for an attribute named ATTRNAME of type ATTRTYPE
|
||||||
|
* and with an initial value specified by INITIALVALUE, which may be null to indicate a default
|
||||||
|
* initialization.
|
||||||
|
*
|
||||||
|
* <p>Sub-classes of CodeGenBase can override this method if they wish to use a sub-class of
|
||||||
|
* AttrInfo with more functionality.
|
||||||
|
*/
|
||||||
|
public AttrInfo makeAttrInfo(String attrName, ValueType attrType, Literal initialValue) {
|
||||||
|
return new AttrInfo(attrName, attrType, initialValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory method that returns a descriptor for a local variable or parameter named VARNAME of
|
||||||
|
* type VARTYPE, whose initial value is specified by INITIALVALUE (if non-null) and which is
|
||||||
|
* defined immediately within the function given by FUNCINFO.
|
||||||
|
*
|
||||||
|
* <p>These variables are allocated on the stack in activation frames.
|
||||||
|
*
|
||||||
|
* <p>Sub-classes of CodeGenBase can override this method if they wish to use a sub-class of
|
||||||
|
* StackVarInfo with more functionality.
|
||||||
|
*/
|
||||||
|
public StackVarInfo makeStackVarInfo(
|
||||||
|
String varName, ValueType varType, Literal initialValue, FuncInfo funcInfo) {
|
||||||
|
return new StackVarInfo(varName, varType, initialValue, funcInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory method that returns a descriptor for a global variable with name VARNAME and type
|
||||||
|
* VARTYPE, whose initial value is specified by INITIALVALUE (if non-null).
|
||||||
|
*
|
||||||
|
* <p>Sub-classes of CodeGenBase can override this method if they wish to use a sub-class of
|
||||||
|
* GlobalVarInfo with more functionality.
|
||||||
|
*/
|
||||||
|
public GlobalVarInfo makeGlobalVarInfo(
|
||||||
|
String varName, ValueType varType, Literal initialValue) {
|
||||||
|
return new GlobalVarInfo(varName, varType, initialValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------*
|
||||||
|
* *
|
||||||
|
* ANALYSIS OF AST INTO INFO OBJECTS *
|
||||||
|
* (Students can ignore these methods as all the work has *
|
||||||
|
* been done and does not need to be modified/extended) *
|
||||||
|
* *
|
||||||
|
*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/** Analyze PROGRAM, creating Info objects for all symbols. Populate the global symbol table. */
|
||||||
|
protected void analyzeProgram(Program program) {
|
||||||
|
/* Proceed in phases:
|
||||||
|
* 1. Analyze all global variable declarations.
|
||||||
|
* Do this first so that global variables are in the symbol
|
||||||
|
* table before we encounter `global x` declarations.
|
||||||
|
* 2. Analyze classes and global functions now that global variables
|
||||||
|
* are in the symbol table.
|
||||||
|
*/
|
||||||
|
for (Declaration decl : program.declarations) {
|
||||||
|
if (decl instanceof VarDef) {
|
||||||
|
VarDef varDef = (VarDef) decl;
|
||||||
|
ValueType varType = ValueType.annotationToValueType(varDef.var.type);
|
||||||
|
GlobalVarInfo globalVar =
|
||||||
|
makeGlobalVarInfo(varDef.var.identifier.name, varType, varDef.value);
|
||||||
|
|
||||||
|
this.globalVars.add(globalVar);
|
||||||
|
|
||||||
|
this.globalSymbols.put(globalVar.getVarName(), globalVar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Declaration decl : program.declarations) {
|
||||||
|
if (decl instanceof ClassDef) {
|
||||||
|
ClassDef classDef = (ClassDef) decl;
|
||||||
|
ClassInfo classInfo = analyzeClass(classDef);
|
||||||
|
|
||||||
|
this.classes.add(classInfo);
|
||||||
|
|
||||||
|
this.globalSymbols.put(classInfo.getClassName(), classInfo);
|
||||||
|
} else if (decl instanceof FuncDef) {
|
||||||
|
FuncDef funcDef = (FuncDef) decl;
|
||||||
|
FuncInfo funcInfo = analyzeFunction(null, funcDef, 0, globalSymbols, null);
|
||||||
|
|
||||||
|
this.functions.add(funcInfo);
|
||||||
|
|
||||||
|
this.globalSymbols.put(funcInfo.getBaseName(), funcInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyze a class definition CLASSDEF and return the resulting Info object. Also creates Info
|
||||||
|
* objects for attributes/methods and stores them in the ClassInfo. Methods are recursively
|
||||||
|
* analyzed using analyzeFunction().
|
||||||
|
*/
|
||||||
|
protected ClassInfo analyzeClass(ClassDef classDef) {
|
||||||
|
String className = classDef.name.name;
|
||||||
|
String superClassName = classDef.superClass.name;
|
||||||
|
SymbolInfo superSymbolInfo = globalSymbols.get(superClassName);
|
||||||
|
assert superSymbolInfo instanceof ClassInfo
|
||||||
|
: "Semantic analysis should ensure that super-class is defined";
|
||||||
|
ClassInfo superClassInfo = (ClassInfo) superSymbolInfo;
|
||||||
|
ClassInfo classInfo = makeClassInfo(className, getNextTypeTag(), superClassInfo);
|
||||||
|
|
||||||
|
for (Declaration decl : classDef.declarations) {
|
||||||
|
if (decl instanceof VarDef) {
|
||||||
|
VarDef attrDef = (VarDef) decl;
|
||||||
|
ValueType attrType = ValueType.annotationToValueType(attrDef.var.type);
|
||||||
|
AttrInfo attrInfo =
|
||||||
|
makeAttrInfo(attrDef.var.identifier.name, attrType, attrDef.value);
|
||||||
|
|
||||||
|
classInfo.addAttribute(attrInfo);
|
||||||
|
} else if (decl instanceof FuncDef) {
|
||||||
|
FuncDef funcDef = (FuncDef) decl;
|
||||||
|
FuncInfo methodInfo = analyzeFunction(className, funcDef, 0, globalSymbols, null);
|
||||||
|
|
||||||
|
this.functions.add(methodInfo);
|
||||||
|
|
||||||
|
classInfo.addMethod(methodInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return classInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyze a function or method definition FUNCDEF at nesting depth DEPTH and return the
|
||||||
|
* resulting Info object. Analyze any nested functions recursively. The FuncInfo's symbol table
|
||||||
|
* is completely populated by analyzing all the params, local vars, global and nonlocal var
|
||||||
|
* declarations.
|
||||||
|
*
|
||||||
|
* <p>CONTAINER is the fully qualified name of the containing function/class, or null for global
|
||||||
|
* functions. PARENTSYMBOLTABLE symbol table contains symbols inherited from outer regions (that
|
||||||
|
* of the containing function/method for nested function definitions, and the global symbol
|
||||||
|
* table for global function / method definitions). PARENTFUNCINFO is the Info object for the
|
||||||
|
* parent function/method if this definition is nested, and otherwise null.
|
||||||
|
*/
|
||||||
|
protected FuncInfo analyzeFunction(
|
||||||
|
String container,
|
||||||
|
FuncDef funcDef,
|
||||||
|
int depth,
|
||||||
|
SymbolTable<SymbolInfo> parentSymbolTable,
|
||||||
|
FuncInfo parentFuncInfo) {
|
||||||
|
/* We proceed in three steps.
|
||||||
|
* 1. Create the FuncInfo object to be returned.
|
||||||
|
* 2. Populate it by analyzing all the parameters and local var
|
||||||
|
* definitions.
|
||||||
|
* 3. Now that the function's symbol table is built up, analyze
|
||||||
|
* nested function definitions.
|
||||||
|
* 4. Add the body to the function descriptor for code gen.
|
||||||
|
*/
|
||||||
|
|
||||||
|
String funcBaseName = funcDef.name.name;
|
||||||
|
String funcQualifiedName =
|
||||||
|
container != null ? String.format("%s.%s", container, funcBaseName) : funcBaseName;
|
||||||
|
|
||||||
|
FuncInfo funcInfo =
|
||||||
|
makeFuncInfo(
|
||||||
|
funcQualifiedName,
|
||||||
|
depth,
|
||||||
|
ValueType.annotationToValueType(funcDef.returnType),
|
||||||
|
parentSymbolTable,
|
||||||
|
parentFuncInfo,
|
||||||
|
this::emitUserDefinedFunction);
|
||||||
|
|
||||||
|
for (TypedVar param : funcDef.params) {
|
||||||
|
ValueType paramType = ValueType.annotationToValueType(param.type);
|
||||||
|
|
||||||
|
StackVarInfo paramInfo =
|
||||||
|
makeStackVarInfo(param.identifier.name, paramType, null, funcInfo);
|
||||||
|
|
||||||
|
funcInfo.addParam(paramInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDeclAnalyzer localDefs = new LocalDeclAnalyzer(funcInfo);
|
||||||
|
|
||||||
|
for (Declaration decl : funcDef.declarations) {
|
||||||
|
decl.dispatch(localDefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
NestedFuncAnalyzer nestedFuncs = new NestedFuncAnalyzer(funcInfo);
|
||||||
|
|
||||||
|
for (Declaration decl : funcDef.declarations) {
|
||||||
|
decl.dispatch(nestedFuncs);
|
||||||
|
}
|
||||||
|
|
||||||
|
funcInfo.addBody(funcDef.statements);
|
||||||
|
return funcInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Analyzer for local variable declarations in a function. */
|
||||||
|
protected class LocalDeclAnalyzer extends AbstractNodeAnalyzer<Void> {
|
||||||
|
/** The descriptor for the function being analyzed. */
|
||||||
|
private final FuncInfo funcInfo;
|
||||||
|
|
||||||
|
/** A new analyzer for a function with descriptor FUNCINFO0. */
|
||||||
|
protected LocalDeclAnalyzer(FuncInfo funcInfo0) {
|
||||||
|
funcInfo = funcInfo0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void analyze(VarDef localVarDef) {
|
||||||
|
ValueType localVarType = ValueType.annotationToValueType(localVarDef.var.type);
|
||||||
|
StackVarInfo localVar =
|
||||||
|
makeStackVarInfo(
|
||||||
|
localVarDef.var.identifier.name,
|
||||||
|
localVarType,
|
||||||
|
localVarDef.value,
|
||||||
|
funcInfo);
|
||||||
|
funcInfo.addLocal(localVar);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void analyze(GlobalDecl decl) {
|
||||||
|
SymbolInfo symInfo = globalSymbols.get(decl.getIdentifier().name);
|
||||||
|
assert symInfo instanceof GlobalVarInfo
|
||||||
|
: "Semantic analysis should ensure that global var exists";
|
||||||
|
GlobalVarInfo globalVar = (GlobalVarInfo) symInfo;
|
||||||
|
funcInfo.getSymbolTable().put(globalVar.getVarName(), globalVar);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void analyze(NonLocalDecl decl) {
|
||||||
|
assert funcInfo.getSymbolTable().get(decl.getIdentifier().name) instanceof StackVarInfo
|
||||||
|
: "Semantic analysis should ensure nonlocal var exists";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Analyzer for nested function declarations in a function. */
|
||||||
|
protected class NestedFuncAnalyzer extends AbstractNodeAnalyzer<Void> {
|
||||||
|
/** Descriptor for the function being analyzed. */
|
||||||
|
private final FuncInfo funcInfo;
|
||||||
|
|
||||||
|
/** A new analyzer for a function with descriptor FUNCINFO0. */
|
||||||
|
protected NestedFuncAnalyzer(FuncInfo funcInfo0) {
|
||||||
|
funcInfo = funcInfo0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void analyze(FuncDef nestedFuncDef) {
|
||||||
|
FuncInfo nestedFuncInfo =
|
||||||
|
analyzeFunction(
|
||||||
|
funcInfo.getFuncName(),
|
||||||
|
nestedFuncDef,
|
||||||
|
funcInfo.getDepth() + 1,
|
||||||
|
funcInfo.getSymbolTable(),
|
||||||
|
funcInfo);
|
||||||
|
|
||||||
|
functions.add(nestedFuncInfo);
|
||||||
|
|
||||||
|
funcInfo.getSymbolTable().put(nestedFuncInfo.getBaseName(), nestedFuncInfo);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------*
|
||||||
|
* *
|
||||||
|
* EMITING DATA SECTION FOR GLOBALS+PROTOTYPES+CONSTANTS *
|
||||||
|
* (Students can ignore these methods as all the work has *
|
||||||
|
* been done and does not need to be modified/extended) *
|
||||||
|
* *
|
||||||
|
*------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/** Emit code to align next data item to word boundary. */
|
||||||
|
protected void alignObject() {
|
||||||
|
int wordSizeLog2 = 31 - Integer.numberOfLeadingZeros(wordSize);
|
||||||
|
backend.alignNext(wordSizeLog2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit the constant section containing the prototype FOR the class defined by CLASSINFO. */
|
||||||
|
protected void emitPrototype(ClassInfo classInfo) {
|
||||||
|
backend.emitGlobalLabel(classInfo.getPrototypeLabel());
|
||||||
|
backend.emitWordLiteral(
|
||||||
|
classInfo.getTypeTag(),
|
||||||
|
String.format("Type tag for class: %s", classInfo.getClassName()));
|
||||||
|
backend.emitWordLiteral(classInfo.attributes.size() + HEADER_SIZE, "Object size");
|
||||||
|
backend.emitWordAddress(classInfo.getDispatchTableLabel(), "Pointer to dispatch table");
|
||||||
|
for (VarInfo attr : classInfo.attributes) {
|
||||||
|
String cmnt = String.format("Initial value of attribute: %s", attr.getVarName());
|
||||||
|
emitConstant(attr.getInitialValue(), attr.getVarType(), cmnt);
|
||||||
|
}
|
||||||
|
alignObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit a word containing a constant int representing VALUE */
|
||||||
|
protected void emitConstantInt(int value, String comment) {
|
||||||
|
backend.emitWordLiteral(value, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit a word containing a constant bool representing VALUE */
|
||||||
|
protected void emitConstantBool(boolean value, String comment) {
|
||||||
|
backend.emitWordLiteral(value ? 1 : 0, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a word containing a constant representing VALUE, assuming that it will be interpreted as
|
||||||
|
* a value of static type TYPE. VALUE may be null, indicating None. TYPE may be null, indicating
|
||||||
|
* object. COMMENT is an optional comment.
|
||||||
|
*/
|
||||||
|
protected void emitConstant(Literal value, ValueType type, String comment) {
|
||||||
|
if (type != null && type.equals(Type.INT_TYPE)) {
|
||||||
|
this.emitConstantInt(((IntegerLiteral) value).value, comment);
|
||||||
|
} else if (type != null && type.equals(Type.BOOL_TYPE)) {
|
||||||
|
this.emitConstantBool(((BooleanLiteral) value).value, comment);
|
||||||
|
} else {
|
||||||
|
backend.emitWordAddress(constants.fromLiteral(value), comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit code for all constants. */
|
||||||
|
protected void emitConstants() {
|
||||||
|
backend.emitGlobalLabel(constants.falseConstant);
|
||||||
|
backend.emitWordLiteral(boolClass.getTypeTag(), "Type tag for class: bool");
|
||||||
|
backend.emitWordLiteral(boolClass.attributes.size() + HEADER_SIZE, "Object size");
|
||||||
|
backend.emitWordAddress(boolClass.getDispatchTableLabel(), "Pointer to dispatch table");
|
||||||
|
backend.emitWordLiteral(0, "Constant value of attribute: __bool__");
|
||||||
|
alignObject();
|
||||||
|
|
||||||
|
backend.emitGlobalLabel(constants.trueConstant);
|
||||||
|
backend.emitWordLiteral(boolClass.getTypeTag(), "Type tag for class: bool");
|
||||||
|
backend.emitWordLiteral(boolClass.attributes.size() + HEADER_SIZE, "Object size");
|
||||||
|
backend.emitWordAddress(boolClass.getDispatchTableLabel(), "Pointer to dispatch table");
|
||||||
|
backend.emitWordLiteral(1, "Constant value of attribute: __bool__");
|
||||||
|
alignObject();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Label> e : constants.strConstants.entrySet()) {
|
||||||
|
String value = e.getKey();
|
||||||
|
Label label = e.getValue();
|
||||||
|
int numWordsForCharacters = value.length() / wordSize + 1;
|
||||||
|
backend.emitGlobalLabel(label);
|
||||||
|
backend.emitWordLiteral(strClass.getTypeTag(), "Type tag for class: str");
|
||||||
|
backend.emitWordLiteral(3 + 1 + numWordsForCharacters, "Object size");
|
||||||
|
backend.emitWordAddress(strClass.getDispatchTableLabel(), "Pointer to dispatch table");
|
||||||
|
this.emitConstantInt(value.length(), "Constant value of attribute: __len__");
|
||||||
|
backend.emitString(value, "Constant value of attribute: __str__");
|
||||||
|
alignObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, Label> e : constants.intConstants.entrySet()) {
|
||||||
|
Integer value = e.getKey();
|
||||||
|
Label label = e.getValue();
|
||||||
|
backend.emitGlobalLabel(label);
|
||||||
|
backend.emitWordLiteral(intClass.getTypeTag(), "Type tag for class: int");
|
||||||
|
backend.emitWordLiteral(intClass.attributes.size() + HEADER_SIZE, "Object size");
|
||||||
|
backend.emitWordAddress(intClass.getDispatchTableLabel(), "Pointer to dispatch table");
|
||||||
|
backend.emitWordLiteral(value, "Constant value of attribute: __int__");
|
||||||
|
alignObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit the method dispatching table for CLASSINFO. */
|
||||||
|
protected void emitDispatchTable(ClassInfo classInfo) {
|
||||||
|
Label dispatchTableLabel = classInfo.getDispatchTableLabel();
|
||||||
|
if (dispatchTableLabel == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backend.emitGlobalLabel(dispatchTableLabel);
|
||||||
|
for (FuncInfo method : classInfo.methods) {
|
||||||
|
String cmnt =
|
||||||
|
String.format(
|
||||||
|
"Implementation for method: %s.%s",
|
||||||
|
classInfo.getClassName(), method.getBaseName());
|
||||||
|
backend.emitWordAddress(method.getCodeLabel(), cmnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------*
|
||||||
|
* *
|
||||||
|
* UTILITY METHODS TO GET BYTE OFFSETS IN OBJECT LAYOUT *
|
||||||
|
* (Students will find these methods helpful to use in *
|
||||||
|
* their sub-class when generating code for expressions) *
|
||||||
|
* *
|
||||||
|
*------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/** Return offset of the type-tag field in an object. */
|
||||||
|
protected int getTypeTagOffset() {
|
||||||
|
return 0 * wordSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return offset of the size field in an object. */
|
||||||
|
protected int getObjectSizeOffset() {
|
||||||
|
return 1 * wordSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return offset of the start of the pointer to the method-dispatching table in an object. */
|
||||||
|
protected int getDispatchTableOffset() {
|
||||||
|
return 2 * wordSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the offset of the ATTRNAME attribute of an object of type described by CLASSINFO. */
|
||||||
|
protected int getAttrOffset(ClassInfo classInfo, String attrName) {
|
||||||
|
int attrIndex = classInfo.getAttributeIndex(attrName);
|
||||||
|
assert attrIndex >= 0 : "Type checker ensures that attributes are valid";
|
||||||
|
return wordSize * (HEADER_SIZE + attrIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the offset of the method named METHODNAME in the method-dispatching table for the
|
||||||
|
* class described by CLASSINFO.
|
||||||
|
*/
|
||||||
|
protected int getMethodOffset(ClassInfo classInfo, String methodName) {
|
||||||
|
int methodIndex = classInfo.getMethodIndex(methodName);
|
||||||
|
assert methodIndex >= 0 : "Type checker ensures that attributes are valid";
|
||||||
|
return wordSize * methodIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------*
|
||||||
|
* *
|
||||||
|
* UNIMPLEMENTED METHODS (should be extended) *
|
||||||
|
* *
|
||||||
|
*------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/** Emits code for STATEMENTS, assumed to be at the top level. */
|
||||||
|
protected abstract void emitTopLevel(List<Stmt> statements);
|
||||||
|
|
||||||
|
/** Emits code for the body of user-defined function FUNCINFO. */
|
||||||
|
protected abstract void emitUserDefinedFunction(FuncInfo funcInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits code outside the ChocoPy program.
|
||||||
|
*
|
||||||
|
* <p>Custom assembly routines (that may be jumpable from program statements) can be emitted
|
||||||
|
* here.
|
||||||
|
*/
|
||||||
|
protected abstract void emitCustomCode();
|
||||||
|
|
||||||
|
/*------------------------------------------------------------*
|
||||||
|
* *
|
||||||
|
* PREDEFINED FUNCTIONS AND ROUTINES *
|
||||||
|
* (Students may find a cursory read of these methods to *
|
||||||
|
* be useful to get an idea for how code can be emitted) *
|
||||||
|
* *
|
||||||
|
*------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return Risc V assembler code for function NAME from directory LIB, or null if it does not
|
||||||
|
* exist. LIB must end in '/'.
|
||||||
|
*/
|
||||||
|
protected String getStandardLibraryCode(String name, String lib) {
|
||||||
|
String simpleName = name.replace("$", "") + ".s";
|
||||||
|
return getResourceFileAsString(lib + simpleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit label and body for the function LABEL, taking the source from directory LIB (must end in
|
||||||
|
* '/').
|
||||||
|
*/
|
||||||
|
protected void emitStdFunc(Label label, String lib) {
|
||||||
|
emitStdFunc(label, label.toString(), lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit label and body for the function LABEL, taking the source from SOURCEFILE.s in directory
|
||||||
|
* LIB (must end in '/').
|
||||||
|
*/
|
||||||
|
protected void emitStdFunc(Label label, String sourceFile, String lib) {
|
||||||
|
String source = getStandardLibraryCode(sourceFile, lib);
|
||||||
|
if (source == null) {
|
||||||
|
throw fatal("Code for %s is missing.", sourceFile);
|
||||||
|
}
|
||||||
|
backend.emitGlobalLabel(label);
|
||||||
|
backend.emit(convertLiterals(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit label and body for the function LABEL, taking the source from from the default library
|
||||||
|
* directory.
|
||||||
|
*/
|
||||||
|
protected void emitStdFunc(Label label) {
|
||||||
|
emitStdFunc(label, LIBRARY_CODE_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit label and body for the function NAME, taking the source from from the default library
|
||||||
|
* directory.
|
||||||
|
*/
|
||||||
|
protected void emitStdFunc(String name) {
|
||||||
|
emitStdFunc(new Label(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit label and body for the function described by FUNCINFO, taking the source from from the
|
||||||
|
* default library directory.
|
||||||
|
*/
|
||||||
|
protected void emitStdFunc(FuncInfo funcInfo) {
|
||||||
|
emitStdFunc(funcInfo.getCodeLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Pattern matching STRING["..."]. */
|
||||||
|
private static final Pattern STRING_LITERAL_PATN = Pattern.compile("STRING\\[\"(.*?)\"\\]");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return result of converting STRING["..."] notations in SOURCE to labels of string constants,
|
||||||
|
* adding those constants to the pool.
|
||||||
|
*/
|
||||||
|
private String convertLiterals(String source) {
|
||||||
|
Matcher matcher = STRING_LITERAL_PATN.matcher(source);
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
while (matcher.find()) {
|
||||||
|
String r = constants.getStrConstant(matcher.group(1)).toString();
|
||||||
|
matcher.appendReplacement(
|
||||||
|
result, pad(r, ' ', matcher.end(0) - matcher.start(0), false));
|
||||||
|
}
|
||||||
|
return matcher.appendTail(result).toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import chocopy.common.astnodes.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A store for caching and re-using program constants that are represented as immutable objects.
|
||||||
|
*
|
||||||
|
* <p>Constants are emitted in assembly in the DATA section, and therefore are represented by their
|
||||||
|
* labels.
|
||||||
|
*/
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
/** A counter used to generate unique label names for constants. */
|
||||||
|
protected int nextLabelSuffix = 0;
|
||||||
|
|
||||||
|
/** The constant representing the boolean `False`. */
|
||||||
|
final Label falseConstant = generateConstantLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constant representing the boolean `True`. This immediately follows falseConstant in
|
||||||
|
* static memory.
|
||||||
|
*/
|
||||||
|
final Label trueConstant = generateConstantLabel();
|
||||||
|
|
||||||
|
/** A cache for integer-valued constants. */
|
||||||
|
final Map<Integer, Label> intConstants = new HashMap<>();
|
||||||
|
|
||||||
|
/** A cache for string-valued constants. */
|
||||||
|
final Map<String, Label> strConstants = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next unique label suffix for constants.
|
||||||
|
*
|
||||||
|
* @return the next unique label suffix for constants
|
||||||
|
*/
|
||||||
|
protected int getNextLabelSuffix() {
|
||||||
|
return nextLabelSuffix++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a fresh label for constants.
|
||||||
|
*
|
||||||
|
* <p>This label is guaranteed to be unique amongst labels generated by invoking this method.
|
||||||
|
* All such labels have a prefix of `const_`.
|
||||||
|
*
|
||||||
|
* @return a fresh label
|
||||||
|
*/
|
||||||
|
public Label generateConstantLabel() {
|
||||||
|
return new Label(String.format("const_%d", getNextLabelSuffix()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label for a `bool` constant.
|
||||||
|
*
|
||||||
|
* @param value the boolean value
|
||||||
|
* @return the label for the boolean value
|
||||||
|
*/
|
||||||
|
public Label getBoolConstant(boolean value) {
|
||||||
|
return value ? trueConstant : falseConstant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label for am `int` constant.
|
||||||
|
*
|
||||||
|
* @param value the integer value
|
||||||
|
* @return the label for the integer value
|
||||||
|
*/
|
||||||
|
public Label getIntConstant(int value) {
|
||||||
|
if (intConstants.containsKey(value)) {
|
||||||
|
return intConstants.get(value);
|
||||||
|
} else {
|
||||||
|
Label newLabel = generateConstantLabel();
|
||||||
|
intConstants.put(value, newLabel);
|
||||||
|
return newLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label for a `str` constant.
|
||||||
|
*
|
||||||
|
* @param value the string value
|
||||||
|
* @return the label for the string value
|
||||||
|
*/
|
||||||
|
public Label getStrConstant(String value) {
|
||||||
|
if (strConstants.containsKey(value)) {
|
||||||
|
return strConstants.get(value);
|
||||||
|
} else {
|
||||||
|
Label newLabel = generateConstantLabel();
|
||||||
|
strConstants.put(value, newLabel);
|
||||||
|
return newLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a constant literal in the AST to a constant for code generation.
|
||||||
|
*
|
||||||
|
* @param literal the literal expression in the AST
|
||||||
|
* @return a {@link Label} representing a constant int/str/bool, or `null` representing the None
|
||||||
|
* literal
|
||||||
|
*/
|
||||||
|
public Label fromLiteral(Literal literal) {
|
||||||
|
if (literal instanceof IntegerLiteral) {
|
||||||
|
return getIntConstant(((IntegerLiteral) literal).value);
|
||||||
|
} else if (literal instanceof StringLiteral) {
|
||||||
|
return getStrConstant(((StringLiteral) literal).value);
|
||||||
|
} else if (literal instanceof BooleanLiteral) {
|
||||||
|
return getBoolConstant(((BooleanLiteral) literal).value);
|
||||||
|
} else {
|
||||||
|
assert literal == null || literal instanceof NoneLiteral;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,206 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.SymbolTable;
|
||||||
|
import chocopy.common.analysis.types.ValueType;
|
||||||
|
import chocopy.common.astnodes.Stmt;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptor for function and method definitions.
|
||||||
|
*
|
||||||
|
* <p>This class stores information required for code generation such as the information about a
|
||||||
|
* function's parameters, local variables, the local symbol table, the function body, and the label
|
||||||
|
* where the code for the body is generated.
|
||||||
|
*/
|
||||||
|
public class FuncInfo extends SymbolInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fully-qualified name of the function.
|
||||||
|
*
|
||||||
|
* <p>All functions in a ChocoPy program have a unique fully-qualified name. Global functions
|
||||||
|
* defined with name `f` have fully-qualified name `f`. Methods `m` in a class `C` have
|
||||||
|
* fully-qualified name `C.m`. Functions `f` nested inside another function with fully-qualified
|
||||||
|
* name `F` have a fully-qualified name of `F.f`.
|
||||||
|
*/
|
||||||
|
protected final String funcName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The static depth of a function.
|
||||||
|
*
|
||||||
|
* <p>Global functions and class methods have a static depth of 0. Nested functions that are
|
||||||
|
* defined in the body of a function with static depth `D` have a static depth of `D+1`.
|
||||||
|
*/
|
||||||
|
protected final int depth;
|
||||||
|
|
||||||
|
/** This function's return type. */
|
||||||
|
protected final ValueType returnType;
|
||||||
|
|
||||||
|
/** A list of parameter names. */
|
||||||
|
protected final List<String> params = new ArrayList<>();
|
||||||
|
|
||||||
|
/** A list of local variable descriptors. */
|
||||||
|
protected final List<StackVarInfo> locals = new ArrayList<>();
|
||||||
|
|
||||||
|
/** The function body. */
|
||||||
|
protected final List<Stmt> statements = new ArrayList<>();
|
||||||
|
|
||||||
|
/** The local symbol table that binds identifiers seen in the function's body. */
|
||||||
|
protected final SymbolTable<SymbolInfo> symbolTable;
|
||||||
|
|
||||||
|
/** The label of the generated code for the function's body. */
|
||||||
|
protected final Label codeLabel;
|
||||||
|
|
||||||
|
/** The descriptor of the enclosing function (this is only non-null for nested functions). */
|
||||||
|
protected final FuncInfo parentFuncInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that is invoked to emit the function's body.
|
||||||
|
*
|
||||||
|
* <p>The method should accept one parameter of type `FuncInfo`.
|
||||||
|
*/
|
||||||
|
protected final Consumer<FuncInfo> emitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a descriptor for a function or method with fully qualified name FUNCNAME returning
|
||||||
|
* type RETURNTYPE that is at nesting depth DEPTH. The code label is formed from FUNCNAME by
|
||||||
|
* prepending a $ sign to prevent collisions. PARENTSYMBOLTABLE is the symbol table of the
|
||||||
|
* containing region. PARENTFUNCINFO is the descriptor of the enclosing function (null for
|
||||||
|
* global functions and methods). EMITTER encapsulates a method that emits the function's body
|
||||||
|
* (this is usually a generic emitter for user-defined functions/methods, and a special emitter
|
||||||
|
* for pre-defined functions/methods).
|
||||||
|
*/
|
||||||
|
public FuncInfo(
|
||||||
|
String funcName,
|
||||||
|
int depth,
|
||||||
|
ValueType returnType,
|
||||||
|
SymbolTable<SymbolInfo> parentSymbolTable,
|
||||||
|
FuncInfo parentFuncInfo,
|
||||||
|
Consumer<FuncInfo> emitter) {
|
||||||
|
this.funcName = funcName;
|
||||||
|
this.codeLabel = new Label(String.format("$%s", funcName));
|
||||||
|
this.depth = depth;
|
||||||
|
this.returnType = returnType;
|
||||||
|
this.symbolTable = new SymbolTable<>(parentSymbolTable);
|
||||||
|
this.parentFuncInfo = parentFuncInfo;
|
||||||
|
this.emitter = emitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds parameter with descriptor PARAMINFO to this function. */
|
||||||
|
public void addParam(StackVarInfo paramInfo) {
|
||||||
|
this.params.add(paramInfo.getVarName());
|
||||||
|
this.symbolTable.put(paramInfo.getVarName(), paramInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds a local variable with descriptor STACKVARINFO to this function. */
|
||||||
|
public void addLocal(StackVarInfo stackVarInfo) {
|
||||||
|
this.locals.add(stackVarInfo);
|
||||||
|
this.symbolTable.put(stackVarInfo.getVarName(), stackVarInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds STMTS to the function's body. */
|
||||||
|
public void addBody(List<Stmt> stmts) {
|
||||||
|
statements.addAll(stmts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of parameter or local variable NAME in the function's activation record.
|
||||||
|
*
|
||||||
|
* <p>The convention is that for a function with N params and K local vars, the i`th param is at
|
||||||
|
* index `i` and the j`th local var is at index `N+j+2`. In all, a function stores N+K+2
|
||||||
|
* variables contiguously in its activation record, where the N+1st is the frame pointer and the
|
||||||
|
* N+2nd is the return address.
|
||||||
|
*
|
||||||
|
* <p>Caution: this is an index (starting at 0), and not an offset in number of bytes.
|
||||||
|
*/
|
||||||
|
public int getVarIndex(String name) {
|
||||||
|
int idx = params.indexOf(name);
|
||||||
|
if (idx >= 0) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < locals.size(); i++) {
|
||||||
|
if (locals.get(i).getVarName().equals(name)) {
|
||||||
|
return i + params.size() + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String msg = String.format("%s is not a var defined in function %s", name, funcName);
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the label corresponding to the function's body in assembly. */
|
||||||
|
public Label getCodeLabel() {
|
||||||
|
return codeLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the function's defined name in the program. This is the last component of the
|
||||||
|
* dot-separated fully-qualified name.
|
||||||
|
*/
|
||||||
|
public String getBaseName() {
|
||||||
|
int rightmostDotIndex = funcName.lastIndexOf('.');
|
||||||
|
if (rightmostDotIndex == -1) {
|
||||||
|
return funcName;
|
||||||
|
} else {
|
||||||
|
return funcName.substring(rightmostDotIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the function's fully-qualified name. */
|
||||||
|
public String getFuncName() {
|
||||||
|
return funcName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the function's static nesting depth. */
|
||||||
|
public int getDepth() {
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the function's parameters in order of definition. */
|
||||||
|
public List<String> getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the return type of this function. */
|
||||||
|
public ValueType getReturnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the function's explicitly defined local variables, excluding parameters.
|
||||||
|
*
|
||||||
|
* <p>This list is mainly used in generating code for initializing local variables that are not
|
||||||
|
* parameters.
|
||||||
|
*/
|
||||||
|
public List<StackVarInfo> getLocals() {
|
||||||
|
return locals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the list of statements in the function's body. */
|
||||||
|
public List<Stmt> getStatements() {
|
||||||
|
return statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the function's local symbol table.
|
||||||
|
*
|
||||||
|
* @return the function's local symbol table
|
||||||
|
*/
|
||||||
|
public SymbolTable<SymbolInfo> getSymbolTable() {
|
||||||
|
return symbolTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parent function's descriptor for nested functions, and null if this function is
|
||||||
|
* not nested.
|
||||||
|
*/
|
||||||
|
public FuncInfo getParentFuncInfo() {
|
||||||
|
return parentFuncInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emits the function's body. */
|
||||||
|
public void emitBody() {
|
||||||
|
emitter.accept(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.types.ValueType;
|
||||||
|
import chocopy.common.astnodes.Literal;
|
||||||
|
|
||||||
|
/** Code-generation related information about a global variable. */
|
||||||
|
public class GlobalVarInfo extends VarInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable resides in static storage tagged with LABEL. The label is prepended with "$" to
|
||||||
|
* prevent name clashes.
|
||||||
|
*/
|
||||||
|
protected final Label label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptor for a global variable named VARNAME of type VARTYPE whose initial value is
|
||||||
|
* labeled with INITIALVALUE (null if no initialization value).
|
||||||
|
*/
|
||||||
|
public GlobalVarInfo(String varName, ValueType varType, Literal initialValue) {
|
||||||
|
super(varName, varType, initialValue);
|
||||||
|
this.label = new Label(String.format("$%s", varName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the code location of this variable. */
|
||||||
|
public Label getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/** A label in assembly. */
|
||||||
|
public class Label {
|
||||||
|
|
||||||
|
/** The name of the label. */
|
||||||
|
public final String labelName;
|
||||||
|
|
||||||
|
/** A new label with name LABELNAME. */
|
||||||
|
public Label(String labelName) {
|
||||||
|
this.labelName = labelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Label label = (Label) o;
|
||||||
|
return Objects.equals(labelName, label.labelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(labelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return labelName;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,606 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
/** RISC V assembly-language generation utilities. */
|
||||||
|
public class RiscVBackend {
|
||||||
|
|
||||||
|
/** Accumulator for assembly code output. */
|
||||||
|
protected final StringWriter asmText = new StringWriter();
|
||||||
|
|
||||||
|
/** Allows print, println, and printf of assembly code. */
|
||||||
|
private final PrintWriter out = new PrintWriter(asmText);
|
||||||
|
|
||||||
|
/** The word size in bytes for RISC-V 32-bit. */
|
||||||
|
protected static final int WORD_SIZE = 4;
|
||||||
|
|
||||||
|
/** The RISC-V registers. */
|
||||||
|
public enum Register {
|
||||||
|
A0("a0"),
|
||||||
|
A1("a1"),
|
||||||
|
A2("a2"),
|
||||||
|
A3("a3"),
|
||||||
|
A4("a4"),
|
||||||
|
A5("a5"),
|
||||||
|
A6("a6"),
|
||||||
|
A7("a7"),
|
||||||
|
T0("t0"),
|
||||||
|
T1("t1"),
|
||||||
|
T2("t2"),
|
||||||
|
T3("t3"),
|
||||||
|
T4("t4"),
|
||||||
|
T5("t5"),
|
||||||
|
T6("t6"),
|
||||||
|
S1("s1"),
|
||||||
|
S2("s2"),
|
||||||
|
S3("s3"),
|
||||||
|
S4("s4"),
|
||||||
|
S5("s5"),
|
||||||
|
S6("s6"),
|
||||||
|
S7("s7"),
|
||||||
|
S8("s8"),
|
||||||
|
S9("s9"),
|
||||||
|
S10("s10"),
|
||||||
|
S11("s11"),
|
||||||
|
FP("fp"),
|
||||||
|
SP("sp"),
|
||||||
|
GP("gp"),
|
||||||
|
RA("ra"),
|
||||||
|
ZERO("zero");
|
||||||
|
|
||||||
|
/** The name of the register used in assembly. */
|
||||||
|
protected final String name;
|
||||||
|
|
||||||
|
/** This register's code representation is NAME. */
|
||||||
|
Register(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return asmText.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define @NAME to have the value VALUE. Here, NAME is assumed to be an identifier consisting of
|
||||||
|
* letters, digits, underscores, and any of the characters '$' or '.', and that does not start
|
||||||
|
* with a digit. Value may be a numeral or another symbol.
|
||||||
|
*/
|
||||||
|
public void defineSym(String name, String value) {
|
||||||
|
if (name.startsWith("@")) {
|
||||||
|
emitInsn(String.format(".equiv %s, %s", name, value), null);
|
||||||
|
} else {
|
||||||
|
emitInsn(String.format(".equiv @%s, %s", name, value), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define @NAME to have the value VALUE, where value is converted to a string. See {@link
|
||||||
|
* #defineSym(java.lang.String, java.lang.String)}.
|
||||||
|
*/
|
||||||
|
public void defineSym(String name, int value) {
|
||||||
|
defineSym(name, Integer.toString(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the word size in bytes.
|
||||||
|
*
|
||||||
|
* <p>This method is used instead of directly accessing the static field {@link #WORD_SIZE}, so
|
||||||
|
* that this class may be extended with alternate word sizes.
|
||||||
|
*/
|
||||||
|
public int getWordSize() {
|
||||||
|
return WORD_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit the text STR to the output stream verbatim. STR should have no trailing newline. */
|
||||||
|
protected void emit(String str) {
|
||||||
|
out.println(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit instruction or directive INSN along with COMMENT as a one-line comment, if non-null. */
|
||||||
|
public void emitInsn(String insn, String comment) {
|
||||||
|
if (comment != null) {
|
||||||
|
emit(String.format(" %-40s # %s", insn, comment));
|
||||||
|
} else {
|
||||||
|
emitInsn(insn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit instruction or directive INSN without a comment. */
|
||||||
|
protected void emitInsn(String insn) {
|
||||||
|
emit(String.format(" %s", insn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a local label marker for LABEL with one-line comment COMMENT (null if missing). Invoke
|
||||||
|
* only once per unique label.
|
||||||
|
*/
|
||||||
|
public void emitLocalLabel(Label label, String comment) {
|
||||||
|
if (comment != null) {
|
||||||
|
emit(String.format("%-42s # %s", label + ":", comment));
|
||||||
|
} else {
|
||||||
|
emit(String.format("%s:", label + ":"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit a global label marker for LABEL. Invoke only once per unique label. */
|
||||||
|
public void emitGlobalLabel(Label label) {
|
||||||
|
emit(String.format("\n.globl %s", label));
|
||||||
|
emit(String.format("%s:", label));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a data word containing VALUE as an integer value. COMMENT is a emitted as a one-line
|
||||||
|
* comment, if non-null.
|
||||||
|
*/
|
||||||
|
public void emitWordLiteral(Integer value, String comment) {
|
||||||
|
emitInsn(String.format(".word %s", value), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a data word containing the address ADDR, or 0 if LABEL is null. COMMENT is a emitted as
|
||||||
|
* a one-line comment, if non-null.
|
||||||
|
*/
|
||||||
|
public void emitWordAddress(Label addr, String comment) {
|
||||||
|
if (addr == null) {
|
||||||
|
emitWordLiteral(0, comment);
|
||||||
|
} else {
|
||||||
|
emitInsn(String.format(".word %s", addr), comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit VALUE as an ASCII null-terminated string constant, with COMMENT as its one-line comment,
|
||||||
|
* if non-null.
|
||||||
|
*/
|
||||||
|
public void emitString(String value, String comment) {
|
||||||
|
String quoted =
|
||||||
|
value.replace("\\", "\\\\")
|
||||||
|
.replace("\n", "\\n")
|
||||||
|
.replace("\t", "\\t")
|
||||||
|
.replace("\"", "\\\"");
|
||||||
|
emitInsn(String.format(".string \"%s\"", quoted), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mark the start of a data section. */
|
||||||
|
public void startData() {
|
||||||
|
emit("\n.data");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mark the start of a code/text section. */
|
||||||
|
public void startCode() {
|
||||||
|
emit("\n.text");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Align the next instruction/word in memory to a multiple of 2**POW bytes. */
|
||||||
|
public void alignNext(int pow) {
|
||||||
|
emitInsn(String.format(".align %d", pow));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit an ecall instruction, with one-line comment COMMENT, if non-null. */
|
||||||
|
public void emitEcall(String comment) {
|
||||||
|
emitInsn("ecall", comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-address instruction with destination RD and source LABEL. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitLA(Register rd, Label label, String comment) {
|
||||||
|
emitInsn(String.format("la %s, %s", rd, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-immediate pseudo-op to set RD to IMM. COMMENT is an optional one-line comment
|
||||||
|
* (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitLI(Register rd, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("li %s, %d", rd, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-upper-immediate instruction to set the upper 20 bits of RD to IMM, where 0 <= IMM
|
||||||
|
* < 2**20. COMMENT is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitLUI(Register rd, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("lui %s, %d", rd, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a move instruction to set RD to the contents of RS. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitMV(Register rd, Register rs, String comment) {
|
||||||
|
emitInsn(String.format("mv %s, %s", rd, rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a jump-register (computed jump) instruction to the address in RS. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitJR(Register rs, String comment) {
|
||||||
|
emitInsn(String.format("jr %s", rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a jump (unconditional jump) instruction to LABEL. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitJ(Label label, String comment) {
|
||||||
|
emitInsn(String.format("j %s", label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a jump-and-link instruction to LABEL. COMMENT is an optional one-line comment (null if
|
||||||
|
* missing).
|
||||||
|
*/
|
||||||
|
public void emitJAL(Label label, String comment) {
|
||||||
|
emitInsn(String.format("jal %s", label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a computed-jump-and-link instruction to the address in RS. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitJALR(Register rs, String comment) {
|
||||||
|
emitInsn(String.format("jalr %s", rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an add-immediate instruction performing RD = RS + IMM. Requires -2048 <= IMM < 2048.
|
||||||
|
* COMMENT is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitADDI(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("addi %s, %s, %d", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an add-immediate instruction performing RD = RS + IMM. Here, IMM is a string generally
|
||||||
|
* containing a symbolic assembler constant (see defineSym) representing an integer value, or an
|
||||||
|
* expression of the form @NAME+NUM or @NAME-NUM. COMMENT is an optional one-line comment (null
|
||||||
|
* if missing).
|
||||||
|
*/
|
||||||
|
public void emitADDI(Register rd, Register rs, String imm, String comment) {
|
||||||
|
emitInsn(String.format("addi %s, %s, %s", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an add instruction performing RD = RS1 + RS2 mod 2**32. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitADD(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("add %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a subtract instruction performing RD = RS1 - RS2 mod 2**32. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSUB(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("sub %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a multiply instruction performing RD = RS1 * RS2 mod 2**32. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitMUL(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("mul %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a signed integer divide instruction performing RD = RS1 / RS2 mod 2**32, rounding the
|
||||||
|
* result toward 0. If RS2 == 0, sets RD to -1. If RS1 == -2**31 and RS2 == -1, sets RD to
|
||||||
|
* -2**31. COMMENT is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitDIV(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("div %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a remainder instruction: RD = RS1 rem RS2 defined so that (RS1 / RS2) * RS2 + (RS1 rem
|
||||||
|
* RS2) == RS1, where / is as for emitDIV. COMMENT is an optional one-line comment (null if
|
||||||
|
* missing).
|
||||||
|
*/
|
||||||
|
public void emitREM(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("rem %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an xor instruction: RD = RS1 ^ RS2. COMMENT is an optional one-line comment (null if
|
||||||
|
* missing).
|
||||||
|
*/
|
||||||
|
public void emitXOR(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("xor %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an xor-immediate instruction: RD = RS ^ IMM, where -2048 <= IMM < 2048. COMMENT is an
|
||||||
|
* optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitXORI(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("xori %s, %s, %d", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a bitwise and instruction: RD = RS1 & RS2. COMMENT is an optional one-line comment (null
|
||||||
|
* if missing).
|
||||||
|
*/
|
||||||
|
public void emitAND(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("and %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a bitwise and-immediate instruction: RD = RS & IMM, where -2048 <= IMM < 2048. COMMENT
|
||||||
|
* is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitANDI(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("andi %s, %s, %d", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a bitwise or instruction: RD = RS1 | RS2. COMMENT is an optional one-line comment (null
|
||||||
|
* if missing).
|
||||||
|
*/
|
||||||
|
public void emitOR(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("or %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a bitwise or-immediate instruction: RD = RS | IMM, where -2048 <= IMM < 2048. COMMENT is
|
||||||
|
* an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitORI(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("ori %s, %s, %d", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a logical left shift instruction: RD = RS1 << (RS2 & 0x31). COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSLL(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("sll %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a logical left shift instruction: RD = RS << (IMM & 0x31). COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSLLI(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("slli %s, %s, %d", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a logical right shift instruction: RD = RS1 >>> (RS2 & 0x31). COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSRL(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("srl %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a logical right shift instruction: RD = RS >>> (IMM & 0x31). COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSRLI(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("srli %s, %s, %d", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an arithmetic right shift instruction: RD = RS1 >> (RS2 & 0x31). COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSRA(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("sra %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit an arithmetic right shift instruction: RD = RS >> (IMM & 0x31). COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSRAI(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("srai %s, %s, %d", rd, rs, imm), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-word instruction: RD = MEMORY[RS + IMM]:4, where -2048 <= IMM < 2048. COMMENT is
|
||||||
|
* an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitLW(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("lw %s, %d(%s)", rd, imm, rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-word instruction: RD = MEMORY[RS + IMM]:4, where -2048 <= IMM < 2048. Here, IMM
|
||||||
|
* is symbolic constant expression (see emitADDI). COMMENT is an optional one-line comment (null
|
||||||
|
* if missing).
|
||||||
|
*/
|
||||||
|
public void emitLW(Register rd, Register rs, String imm, String comment) {
|
||||||
|
emitInsn(String.format("lw %s, %s(%s)", rd, imm, rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a store-word instruction: MEMORY[RS1 + IMM]:4 = RS2, where -2048 <= IMM < 2048. COMMENT
|
||||||
|
* is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSW(Register rs2, Register rs1, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("sw %s, %d(%s)", rs2, imm, rs1), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a store-word instruction: MEMORY[RS1 + IMM]:4 = RS2, where -2048 <= IMM < 2048. Here,
|
||||||
|
* IMM is symbolic constant expression (see emitADDI). COMMENT is an optional one-line comment
|
||||||
|
* (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSW(Register rs2, Register rs1, String imm, String comment) {
|
||||||
|
emitInsn(String.format("sw %s, %s(%s)", rs2, imm, rs1), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-word instruction for globals: RD = MEMORY[LABEL]:4. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitLW(Register rd, Label label, String comment) {
|
||||||
|
emitInsn(String.format("lw %s, %s", rd, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a store-word instruction for globals: MEMORY[LABEL]:4 = RS, using TMP as a temporary
|
||||||
|
* register. COMMENT is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSW(Register rs, Label label, Register tmp, String comment) {
|
||||||
|
emitInsn(String.format("sw %s, %s, %s", rs, label, tmp), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-byte instruction: RD = MEMORY[RS + IMM]:1, where -2048 <= IMM < 2048. Sign
|
||||||
|
* extends the byte loaded. COMMENT is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitLB(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("lb %s, %d(%s)", rd, imm, rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a load-byte-unsigned instruction: RD = MEMORY[RS + IMM]:1, where -2048 <= IMM < 2048.
|
||||||
|
* Zero-extends the byte loaded. COMMENT is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitLBU(Register rd, Register rs, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("lbu %s, %d(%s)", rd, imm, rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a store-byte instruction: MEMORY[RS1 + IMM]:1 = RS2, where -2048 <= IMM < 2048. Assigns
|
||||||
|
* the low-order byte of RS2 to memory. COMMENT is an optional one-line comment (null if
|
||||||
|
* missing).
|
||||||
|
*/
|
||||||
|
public void emitSB(Register rs2, Register rs1, Integer imm, String comment) {
|
||||||
|
emitInsn(String.format("sb %s, %d(%s)", rs2, imm, rs1), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-equal instruction: if RS1 == RS2 goto LABEL. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBEQ(Register rs1, Register rs2, Label label, String comment) {
|
||||||
|
emitInsn(String.format("beq %s, %s, %s", rs1, rs2, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-unequal instruction: if RS1 != RS2 goto LABEL. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBNE(Register rs1, Register rs2, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bne %s, %s, %s", rs1, rs2, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-greater-or-equal (signed) instruction: if RS1 >= RS2 goto LABEL. COMMENT is
|
||||||
|
* an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBGE(Register rs1, Register rs2, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bge %s, %s, %s", rs1, rs2, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-greater-or-equal (unsigned) instruction: if RS1 >= RS2 goto LABEL. COMMENT
|
||||||
|
* is an optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBGEU(Register rs1, Register rs2, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bgeu %s, %s, %s", rs1, rs2, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-less-than (signed) instruction: if RS1 < RS2 goto LABEL. COMMENT is an
|
||||||
|
* optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBLT(Register rs1, Register rs2, Label label, String comment) {
|
||||||
|
emitInsn(String.format("blt %s, %s, %s", rs1, rs2, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-less-than (unsigned) instruction: if RS1 < RS2 goto LABEL. COMMENT is an
|
||||||
|
* optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBLTU(Register rs1, Register rs2, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bltu %s, %s, %s", rs1, rs2, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-zero instruction: if RS == 0 goto LABEL. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBEQZ(Register rs, Label label, String comment) {
|
||||||
|
emitInsn(String.format("beqz %s, %s", rs, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-not-zero instruction: if RS != 0 goto LABEL. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBNEZ(Register rs, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bnez %s, %s", rs, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-less-than-zero instruction: if RS < 0 goto LABEL. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBLTZ(Register rs, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bltz %s, %s", rs, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-greater-than-zero instruction: if RS > 0 goto LABEL. COMMENT is an optional
|
||||||
|
* one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBGTZ(Register rs, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bgtz %s, %s", rs, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-less-than-equal-to-zero instruction: if RS <= 0 goto LABEL. COMMENT is an
|
||||||
|
* optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBLEZ(Register rs, Label label, String comment) {
|
||||||
|
emitInsn(String.format("blez %s, %s", rs, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a branch-if-greater-than-equal-to-zero instruction: if RS >= 0 goto LABEL. COMMENT is an
|
||||||
|
* optional one-line comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitBGEZ(Register rs, Label label, String comment) {
|
||||||
|
emitInsn(String.format("bgez %s, %s", rs, label), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a set-less-than instruction: RD = 1 if RS1 < RS2 else 0. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSLT(Register rd, Register rs1, Register rs2, String comment) {
|
||||||
|
emitInsn(String.format("slt %s, %s, %s", rd, rs1, rs2), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a set-if-zero instruction: RD = 1 if RS == 0 else 0. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSEQZ(Register rd, Register rs, String comment) {
|
||||||
|
emitInsn(String.format("seqz %s, %s", rd, rs), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a set-if-not-zero instruction: RD = 1 if RS != 0 else 0. COMMENT is an optional one-line
|
||||||
|
* comment (null if missing).
|
||||||
|
*/
|
||||||
|
public void emitSNEZ(Register rd, Register rs, String comment) {
|
||||||
|
emitInsn(String.format("snez %s, %s", rd, rs), comment);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.types.ValueType;
|
||||||
|
import chocopy.common.astnodes.Literal;
|
||||||
|
|
||||||
|
/** Code-generation information about a local variable or parameter. */
|
||||||
|
public class StackVarInfo extends VarInfo {
|
||||||
|
|
||||||
|
/** Information about the enclosing function. */
|
||||||
|
protected final FuncInfo funcInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptor for a local variable or parameter VARNAME of type VARTYPE, whose initial value
|
||||||
|
* is given by INITIALVALUE (null if no initial value), and which is nested immediately within
|
||||||
|
* the function described by FUNCINFO.
|
||||||
|
*/
|
||||||
|
public StackVarInfo(
|
||||||
|
String varName, ValueType varType, Literal initialValue, FuncInfo funcInfo) {
|
||||||
|
super(varName, varType, initialValue);
|
||||||
|
this.funcInfo = funcInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the descriptor of the function in which this var is defined. */
|
||||||
|
public FuncInfo getFuncInfo() {
|
||||||
|
return funcInfo;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for all the Info classes that store information about a symbol during code
|
||||||
|
* generation.
|
||||||
|
*/
|
||||||
|
public abstract class SymbolInfo {}
|
@ -0,0 +1,40 @@
|
|||||||
|
package chocopy.common.codegen;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.types.ValueType;
|
||||||
|
import chocopy.common.astnodes.Literal;
|
||||||
|
|
||||||
|
/** Information about a variable or attribute. */
|
||||||
|
public abstract class VarInfo extends SymbolInfo {
|
||||||
|
|
||||||
|
/** Name of variable or attribute. */
|
||||||
|
protected final String varName;
|
||||||
|
/** Runtime location of initial value for this variable or attribute. */
|
||||||
|
protected final Literal initialValue;
|
||||||
|
/** Static type of the variable. */
|
||||||
|
protected final ValueType varType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptor for variable or attribute VARNAME with VARTYPE as its static type and
|
||||||
|
* INITIALVALUE as its initial value (or null if None).
|
||||||
|
*/
|
||||||
|
public VarInfo(String varName, ValueType varType, Literal initialValue) {
|
||||||
|
this.varName = varName;
|
||||||
|
this.varType = varType;
|
||||||
|
this.initialValue = initialValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the name of this variable or attribute. */
|
||||||
|
public String getVarName() {
|
||||||
|
return varName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the type of this variable or attribute. */
|
||||||
|
public ValueType getVarType() {
|
||||||
|
return varType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the initial value of this variable or attribute. */
|
||||||
|
public Literal getInitialValue() {
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
package chocopy.pa3;
|
||||||
|
|
||||||
|
import chocopy.common.analysis.AbstractNodeAnalyzer;
|
||||||
|
import chocopy.common.analysis.SymbolTable;
|
||||||
|
import chocopy.common.astnodes.ReturnStmt;
|
||||||
|
import chocopy.common.astnodes.Stmt;
|
||||||
|
import chocopy.common.codegen.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static chocopy.common.codegen.RiscVBackend.Register.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is where the main implementation of PA3 will live.
|
||||||
|
*
|
||||||
|
* <p>A large part of the functionality has already been implemented in the base class, CodeGenBase.
|
||||||
|
* Make sure to read through that class, since you will want to use many of its fields and utility
|
||||||
|
* methods in this class when emitting code.
|
||||||
|
*
|
||||||
|
* <p>Also read the PDF spec for details on what the base class does and what APIs it exposes for
|
||||||
|
* its sub-class (this one). Of particular importance is knowing what all the SymbolInfo classes
|
||||||
|
* contain.
|
||||||
|
*/
|
||||||
|
public class CodeGenImpl extends CodeGenBase {
|
||||||
|
|
||||||
|
/** A code generator emitting instructions to BACKEND. */
|
||||||
|
public CodeGenImpl(RiscVBackend backend) {
|
||||||
|
super(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Operation on None. */
|
||||||
|
private final Label errorNone = new Label("error.None");
|
||||||
|
/** Division by zero. */
|
||||||
|
private final Label errorDiv = new Label("error.Div");
|
||||||
|
/** Index out of bounds. */
|
||||||
|
private final Label errorOob = new Label("error.OOB");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits the top level of the program.
|
||||||
|
*
|
||||||
|
* <p>This method is invoked exactly once, and is surrounded by some boilerplate code that: (1)
|
||||||
|
* initializes the heap before the top-level begins and (2) exits after the top-level ends.
|
||||||
|
*
|
||||||
|
* <p>You only need to generate code for statements.
|
||||||
|
*
|
||||||
|
* @param statements top level statements
|
||||||
|
*/
|
||||||
|
protected void emitTopLevel(List<Stmt> statements) {
|
||||||
|
StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(null);
|
||||||
|
backend.emitADDI(
|
||||||
|
SP, SP, -2 * backend.getWordSize(), "Saved FP and saved RA (unused at top level).");
|
||||||
|
backend.emitSW(ZERO, SP, 0, "Top saved FP is 0.");
|
||||||
|
backend.emitSW(ZERO, SP, 4, "Top saved RA is 0.");
|
||||||
|
backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Set FP to previous SP.");
|
||||||
|
|
||||||
|
for (Stmt stmt : statements) {
|
||||||
|
stmt.dispatch(stmtAnalyzer);
|
||||||
|
}
|
||||||
|
backend.emitLI(A0, EXIT_ECALL, "Code for ecall: exit");
|
||||||
|
backend.emitEcall(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits the code for a function described by FUNCINFO.
|
||||||
|
*
|
||||||
|
* <p>This method is invoked once per function and method definition. At the code generation
|
||||||
|
* stage, nested functions are emitted as separate functions of their own. So if function `bar`
|
||||||
|
* is nested within function `foo`, you only emit `foo`'s code for `foo` and only emit `bar`'s
|
||||||
|
* code for `bar`.
|
||||||
|
*/
|
||||||
|
protected void emitUserDefinedFunction(FuncInfo funcInfo) {
|
||||||
|
backend.emitGlobalLabel(funcInfo.getCodeLabel());
|
||||||
|
StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(funcInfo);
|
||||||
|
|
||||||
|
for (Stmt stmt : funcInfo.getStatements()) {
|
||||||
|
stmt.dispatch(stmtAnalyzer);
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.emitMV(A0, ZERO, "Returning None implicitly");
|
||||||
|
backend.emitLocalLabel(stmtAnalyzer.epilogue, "Epilogue");
|
||||||
|
|
||||||
|
// FIXME: {... reset fp etc. ...}
|
||||||
|
backend.emitJR(RA, "Return to caller");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An analyzer that encapsulates code generation for statements. */
|
||||||
|
private class StmtAnalyzer extends AbstractNodeAnalyzer<Void> {
|
||||||
|
/*
|
||||||
|
* The symbol table has all the info you need to determine
|
||||||
|
* what a given identifier 'x' in the current scope is. You can
|
||||||
|
* use it as follows:
|
||||||
|
* SymbolInfo x = sym.get("x");
|
||||||
|
*
|
||||||
|
* A SymbolInfo can be one the following:
|
||||||
|
* - ClassInfo: a descriptor for classes
|
||||||
|
* - FuncInfo: a descriptor for functions/methods
|
||||||
|
* - AttrInfo: a descriptor for attributes
|
||||||
|
* - GlobalVarInfo: a descriptor for global variables
|
||||||
|
* - StackVarInfo: a descriptor for variables allocated on the stack,
|
||||||
|
* such as locals and parameters
|
||||||
|
*
|
||||||
|
* Since the input program is assumed to be semantically
|
||||||
|
* valid and well-typed at this stage, you can always assume that
|
||||||
|
* the symbol table contains valid information. For example, in
|
||||||
|
* an expression `foo()` you KNOW that sym.get("foo") will either be
|
||||||
|
* a FuncInfo or ClassInfo, but not any of the other infos
|
||||||
|
* and never null.
|
||||||
|
*
|
||||||
|
* The symbol table in funcInfo has already been populated in
|
||||||
|
* the base class: CodeGenBase. You do not need to add anything to
|
||||||
|
* the symbol table. Simply query it with an identifier name to
|
||||||
|
* get a descriptor for a function, class, variable, etc.
|
||||||
|
*
|
||||||
|
* The symbol table also maps nonlocal and global vars, so you
|
||||||
|
* only need to lookup one symbol table and it will fetch the
|
||||||
|
* appropriate info for the var that is currently in scope.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Symbol table for my statements. */
|
||||||
|
private final SymbolTable<SymbolInfo> sym;
|
||||||
|
|
||||||
|
/** Label of code that exits from procedure. */
|
||||||
|
protected final Label epilogue;
|
||||||
|
|
||||||
|
/** The descriptor for the current function, or null at the top level. */
|
||||||
|
private final FuncInfo funcInfo;
|
||||||
|
|
||||||
|
/** An analyzer for the function described by FUNCINFO0, which is null for the top level. */
|
||||||
|
StmtAnalyzer(FuncInfo funcInfo0) {
|
||||||
|
funcInfo = funcInfo0;
|
||||||
|
if (funcInfo == null) {
|
||||||
|
sym = globalSymbols;
|
||||||
|
} else {
|
||||||
|
sym = funcInfo.getSymbolTable();
|
||||||
|
}
|
||||||
|
epilogue = generateLocalLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Example of statement.
|
||||||
|
@Override
|
||||||
|
public Void analyze(ReturnStmt stmt) {
|
||||||
|
// FIXME: Here, we emit an instruction that does nothing. Clearly,
|
||||||
|
// this is wrong, and you'll have to fix it.
|
||||||
|
// This is here just to demonstrate how to emit a
|
||||||
|
// RISC-V instruction.
|
||||||
|
backend.emitMV(ZERO, ZERO, "No-op");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: More, of course.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits custom code in the CODE segment.
|
||||||
|
*
|
||||||
|
* <p>This method is called after emitting the top level and the function bodies for each
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* <p>You can use this method to emit anything you want outside of the top level or functions,
|
||||||
|
* e.g. custom routines that you may want to call from within your code to do common tasks. This
|
||||||
|
* is not strictly needed. You might not modify this at all and still complete the assignment.
|
||||||
|
*
|
||||||
|
* <p>To start you off, here is an implementation of three routines that will be commonly needed
|
||||||
|
* from within the code you will generate for statements.
|
||||||
|
*
|
||||||
|
* <p>The routines are error handlers for operations on None, index out of bounds, and division
|
||||||
|
* by zero. They never return to their caller. Just jump to one of these routines to throw an
|
||||||
|
* error and exit the program. For example, to throw an OOB error: backend.emitJ(errorOob, "Go
|
||||||
|
* to out-of-bounds error and abort");
|
||||||
|
*/
|
||||||
|
protected void emitCustomCode() {
|
||||||
|
emitErrorFunc(errorNone, "Operation on None");
|
||||||
|
emitErrorFunc(errorDiv, "Division by zero");
|
||||||
|
emitErrorFunc(errorOob, "Index out of bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit an error routine labeled ERRLABEL that aborts with message MSG. */
|
||||||
|
private void emitErrorFunc(Label errLabel, String msg) {
|
||||||
|
backend.emitGlobalLabel(errLabel);
|
||||||
|
backend.emitLI(A0, ERROR_NONE, "Exit code for: " + msg);
|
||||||
|
backend.emitLA(A1, constants.getStrConstant(msg), "Load error message as str");
|
||||||
|
backend.emitADDI(
|
||||||
|
A1, A1, getAttrOffset(strClass, "__str__"), "Load address of attribute __str__");
|
||||||
|
backend.emitJ(abortLabel, "Abort");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package chocopy.pa3;
|
||||||
|
|
||||||
|
import chocopy.common.astnodes.Program;
|
||||||
|
import chocopy.common.codegen.CodeGenBase;
|
||||||
|
import chocopy.common.codegen.RiscVBackend;
|
||||||
|
|
||||||
|
/** Interface to code generator. */
|
||||||
|
public class StudentCodeGen {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform code generation from PROGRAM, assumed to be well-typed, to RISC-V, returning the
|
||||||
|
* assembly code. DEBUG iff --debug was on the command line.
|
||||||
|
*/
|
||||||
|
public static String process(Program program, boolean debug) {
|
||||||
|
/* Emit code into a ByteOutputStream, and convert to a string.
|
||||||
|
* If you need instructions not provided by RiscVBackend, simply
|
||||||
|
* use an extension of it. */
|
||||||
|
try {
|
||||||
|
RiscVBackend backend = new RiscVBackend();
|
||||||
|
CodeGenBase cgen = new CodeGenImpl(backend);
|
||||||
|
cgen.generate(program);
|
||||||
|
|
||||||
|
return backend.toString();
|
||||||
|
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||||
|
System.err.println(
|
||||||
|
"Error performing code generation. "
|
||||||
|
+ "Re-run with --debug to see stack trace.");
|
||||||
|
if (debug) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
# Compute x**y
|
||||||
|
def exp(x: int, y: int) -> int:
|
||||||
|
a: int = 0
|
||||||
|
def f(i: int) -> int:
|
||||||
|
nonlocal a
|
||||||
|
def geta() -> int:
|
||||||
|
return a
|
||||||
|
if i <= 0:
|
||||||
|
return geta()
|
||||||
|
else:
|
||||||
|
a = a * x
|
||||||
|
return f(i-1)
|
||||||
|
a = 1
|
||||||
|
return f(y)
|
||||||
|
|
||||||
|
# Input parameter
|
||||||
|
n:int = 42
|
||||||
|
|
||||||
|
# Run [0, n]
|
||||||
|
i:int = 0
|
||||||
|
|
||||||
|
# Crunch
|
||||||
|
while i <= n:
|
||||||
|
print(exp(2, i % 31))
|
||||||
|
i = i + 1
|
@ -0,0 +1,562 @@
|
|||||||
|
{
|
||||||
|
"kind" : "Program",
|
||||||
|
"location" : [ 2, 1, 26, 1 ],
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 2, 1, 14, 13 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 2, 5, 2, 7 ],
|
||||||
|
"name" : "exp"
|
||||||
|
},
|
||||||
|
"params" : [ {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 2, 9, 2, 14 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 2, 9, 2, 9 ],
|
||||||
|
"name" : "x"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 2, 12, 2, 14 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 2, 17, 2, 22 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 2, 17, 2, 17 ],
|
||||||
|
"name" : "y"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 2, 20, 2, 22 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 2, 28, 2, 30 ],
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 3, 2, 3, 11 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 3, 2, 3, 7 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 3, 2, 3, 2 ],
|
||||||
|
"name" : "a"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 3, 5, 3, 7 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 3, 11, 3, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 4, 2, 13, 1 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 4, 6, 4, 6 ],
|
||||||
|
"name" : "f"
|
||||||
|
},
|
||||||
|
"params" : [ {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 4, 8, 4, 13 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 4, 8, 4, 8 ],
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 4, 11, 4, 13 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 4, 19, 4, 21 ],
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "NonLocalDecl",
|
||||||
|
"location" : [ 5, 3, 5, 12 ],
|
||||||
|
"variable" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 5, 12, 5, 12 ],
|
||||||
|
"name" : "a"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 6, 3, 7, 12 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 6, 7, 6, 10 ],
|
||||||
|
"name" : "geta"
|
||||||
|
},
|
||||||
|
"params" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 6, 17, 6, 19 ],
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 7, 4, 7, 11 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 7, 11, 7, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "a"
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "IfStmt",
|
||||||
|
"location" : [ 8, 3, 13, 1 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 8, 6, 8, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 8, 6, 8, 6 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"operator" : "<=",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 8, 11, 8, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"thenBody" : [ {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 9, 4, 9, 16 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 9, 11, 9, 16 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 9, 11, 9, 14 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "geta"
|
||||||
|
},
|
||||||
|
"args" : [ ]
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"elseBody" : [ {
|
||||||
|
"kind" : "AssignStmt",
|
||||||
|
"location" : [ 11, 4, 11, 12 ],
|
||||||
|
"targets" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 11, 4, 11, 4 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "a"
|
||||||
|
} ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 11, 8, 11, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 11, 8, 11, 8 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "a"
|
||||||
|
},
|
||||||
|
"operator" : "*",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 11, 12, 11, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "x"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 12, 4, 12, 16 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 12, 11, 12, 16 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 12, 11, 12, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "f"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 12, 13, 12, 15 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 12, 13, 12, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"operator" : "-",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 12, 15, 12, 15 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
} ]
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "AssignStmt",
|
||||||
|
"location" : [ 13, 2, 13, 6 ],
|
||||||
|
"targets" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 13, 2, 13, 2 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "a"
|
||||||
|
} ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 13, 6, 13, 6 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 14, 2, 14, 12 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 14, 9, 14, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 14, 9, 14, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "f"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 14, 11, 14, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "y"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 17, 1, 17, 10 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 17, 1, 17, 5 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 17, 1, 17, 1 ],
|
||||||
|
"name" : "n"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 17, 3, 17, 5 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 17, 9, 17, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 42
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 20, 1, 20, 9 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 20, 1, 20, 5 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 20, 1, 20, 1 ],
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 20, 3, 20, 5 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 20, 9, 20, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "WhileStmt",
|
||||||
|
"location" : [ 23, 1, 26, 1 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 23, 7, 23, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 23, 7, 23, 7 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"operator" : "<=",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 23, 12, 23, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 24, 2, 24, 22 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 24, 2, 24, 22 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 24, 2, 24, 6 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 24, 8, 24, 21 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 24, 8, 24, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}, {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "exp"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 24, 12, 24, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 2
|
||||||
|
}, {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 24, 15, 24, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 24, 15, 24, 15 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"operator" : "%",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 24, 19, 24, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 31
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "AssignStmt",
|
||||||
|
"location" : [ 25, 2, 25, 10 ],
|
||||||
|
"targets" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 25, 2, 25, 2 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
} ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 25, 6, 25, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 25, 6, 25, 6 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"operator" : "+",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 25, 10, 25, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
} ],
|
||||||
|
"errors" : {
|
||||||
|
"errors" : [ ],
|
||||||
|
"kind" : "Errors",
|
||||||
|
"location" : [ 0, 0, 0, 0 ]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
1
|
||||||
|
2
|
||||||
|
4
|
||||||
|
8
|
||||||
|
16
|
||||||
|
32
|
||||||
|
64
|
||||||
|
128
|
||||||
|
256
|
||||||
|
512
|
||||||
|
1024
|
||||||
|
2048
|
||||||
|
4096
|
||||||
|
8192
|
||||||
|
16384
|
||||||
|
32768
|
||||||
|
65536
|
||||||
|
131072
|
||||||
|
262144
|
||||||
|
524288
|
||||||
|
1048576
|
||||||
|
2097152
|
||||||
|
4194304
|
||||||
|
8388608
|
||||||
|
16777216
|
||||||
|
33554432
|
||||||
|
67108864
|
||||||
|
134217728
|
||||||
|
268435456
|
||||||
|
536870912
|
||||||
|
1073741824
|
||||||
|
1
|
||||||
|
2
|
||||||
|
4
|
||||||
|
8
|
||||||
|
16
|
||||||
|
32
|
||||||
|
64
|
||||||
|
128
|
||||||
|
256
|
||||||
|
512
|
||||||
|
1024
|
||||||
|
2048
|
@ -0,0 +1,30 @@
|
|||||||
|
# Get the n-th prime starting from 2
|
||||||
|
def get_prime(n:int) -> int:
|
||||||
|
candidate:int = 2
|
||||||
|
found:int = 0
|
||||||
|
while True:
|
||||||
|
if is_prime(candidate):
|
||||||
|
found = found + 1
|
||||||
|
if found == n:
|
||||||
|
return candidate
|
||||||
|
candidate = candidate + 1
|
||||||
|
return 0 # Never happens
|
||||||
|
|
||||||
|
def is_prime(x:int) -> bool:
|
||||||
|
div:int = 2
|
||||||
|
while div < x:
|
||||||
|
if x % div == 0:
|
||||||
|
return False
|
||||||
|
div = div + 1
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Input parameter
|
||||||
|
n:int = 15
|
||||||
|
|
||||||
|
# Run [1, n]
|
||||||
|
i:int = 1
|
||||||
|
|
||||||
|
# Crunch
|
||||||
|
while i <= n:
|
||||||
|
print(get_prime(i))
|
||||||
|
i = i + 1
|
@ -0,0 +1,658 @@
|
|||||||
|
{
|
||||||
|
"kind" : "Program",
|
||||||
|
"location" : [ 2, 1, 31, 1 ],
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 2, 1, 11, 29 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 2, 5, 2, 13 ],
|
||||||
|
"name" : "get_prime"
|
||||||
|
},
|
||||||
|
"params" : [ {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 2, 15, 2, 19 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 2, 15, 2, 15 ],
|
||||||
|
"name" : "n"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 2, 17, 2, 19 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 2, 25, 2, 27 ],
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 3, 5, 3, 21 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 3, 5, 3, 17 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 3, 5, 3, 13 ],
|
||||||
|
"name" : "candidate"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 3, 15, 3, 17 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 3, 21, 3, 21 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 2
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 4, 5, 4, 17 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 4, 5, 4, 13 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 4, 5, 4, 9 ],
|
||||||
|
"name" : "found"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 4, 11, 4, 13 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 4, 17, 4, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "WhileStmt",
|
||||||
|
"location" : [ 5, 5, 11, 4 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "BooleanLiteral",
|
||||||
|
"location" : [ 5, 11, 5, 14 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"value" : true
|
||||||
|
},
|
||||||
|
"body" : [ {
|
||||||
|
"kind" : "IfStmt",
|
||||||
|
"location" : [ 6, 9, 10, 8 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 6, 12, 6, 30 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 6, 12, 6, 19 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "is_prime"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 6, 21, 6, 29 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "candidate"
|
||||||
|
} ]
|
||||||
|
},
|
||||||
|
"thenBody" : [ {
|
||||||
|
"kind" : "AssignStmt",
|
||||||
|
"location" : [ 7, 13, 7, 29 ],
|
||||||
|
"targets" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 7, 13, 7, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "found"
|
||||||
|
} ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 7, 21, 7, 29 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 7, 21, 7, 25 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "found"
|
||||||
|
},
|
||||||
|
"operator" : "+",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 7, 29, 7, 29 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "IfStmt",
|
||||||
|
"location" : [ 8, 13, 10, 8 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 8, 16, 8, 25 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 8, 16, 8, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "found"
|
||||||
|
},
|
||||||
|
"operator" : "==",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 8, 25, 8, 25 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"thenBody" : [ {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 9, 17, 9, 32 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 9, 24, 9, 32 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "candidate"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"elseBody" : [ ]
|
||||||
|
} ],
|
||||||
|
"elseBody" : [ ]
|
||||||
|
}, {
|
||||||
|
"kind" : "AssignStmt",
|
||||||
|
"location" : [ 10, 9, 10, 33 ],
|
||||||
|
"targets" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 10, 9, 10, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "candidate"
|
||||||
|
} ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 10, 21, 10, 33 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 10, 21, 10, 29 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "candidate"
|
||||||
|
},
|
||||||
|
"operator" : "+",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 10, 33, 10, 33 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 11, 5, 11, 12 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 11, 12, 11, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 13, 1, 19, 16 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 13, 5, 13, 12 ],
|
||||||
|
"name" : "is_prime"
|
||||||
|
},
|
||||||
|
"params" : [ {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 13, 14, 13, 18 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 13, 14, 13, 14 ],
|
||||||
|
"name" : "x"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 13, 16, 13, 18 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 13, 24, 13, 27 ],
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 14, 5, 14, 15 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 14, 5, 14, 11 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 14, 5, 14, 7 ],
|
||||||
|
"name" : "div"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 14, 9, 14, 11 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 14, 15, 14, 15 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 2
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "WhileStmt",
|
||||||
|
"location" : [ 15, 5, 19, 4 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 15, 11, 15, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 15, 11, 15, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "div"
|
||||||
|
},
|
||||||
|
"operator" : "<",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 15, 17, 15, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body" : [ {
|
||||||
|
"kind" : "IfStmt",
|
||||||
|
"location" : [ 16, 9, 18, 8 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 16, 12, 16, 23 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 16, 12, 16, 18 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 16, 12, 16, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "x"
|
||||||
|
},
|
||||||
|
"operator" : "%",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 16, 16, 16, 18 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "div"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operator" : "==",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 16, 23, 16, 23 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"thenBody" : [ {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 17, 13, 17, 24 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BooleanLiteral",
|
||||||
|
"location" : [ 17, 20, 17, 24 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"value" : false
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"elseBody" : [ ]
|
||||||
|
}, {
|
||||||
|
"kind" : "AssignStmt",
|
||||||
|
"location" : [ 18, 9, 18, 21 ],
|
||||||
|
"targets" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 18, 9, 18, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "div"
|
||||||
|
} ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 18, 15, 18, 21 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 18, 15, 18, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "div"
|
||||||
|
},
|
||||||
|
"operator" : "+",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 18, 21, 18, 21 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 19, 5, 19, 15 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BooleanLiteral",
|
||||||
|
"location" : [ 19, 12, 19, 15 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"value" : true
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 22, 1, 22, 10 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 22, 1, 22, 5 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 22, 1, 22, 1 ],
|
||||||
|
"name" : "n"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 22, 3, 22, 5 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 22, 9, 22, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 15
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "VarDef",
|
||||||
|
"location" : [ 25, 1, 25, 9 ],
|
||||||
|
"var" : {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 25, 1, 25, 5 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 25, 1, 25, 1 ],
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 25, 3, 25, 5 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 25, 9, 25, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "WhileStmt",
|
||||||
|
"location" : [ 28, 1, 31, 1 ],
|
||||||
|
"condition" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 28, 7, 28, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "bool"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 28, 7, 28, 7 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"operator" : "<=",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 28, 12, 28, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 29, 5, 29, 23 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 29, 5, 29, 23 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 29, 5, 29, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 29, 11, 29, 22 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 29, 11, 29, 19 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "get_prime"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 29, 21, 29, 21 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
} ]
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "AssignStmt",
|
||||||
|
"location" : [ 30, 5, 30, 13 ],
|
||||||
|
"targets" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 30, 5, 30, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
} ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 30, 9, 30, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 30, 9, 30, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "i"
|
||||||
|
},
|
||||||
|
"operator" : "+",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 30, 13, 30, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
} ],
|
||||||
|
"errors" : {
|
||||||
|
"errors" : [ ],
|
||||||
|
"kind" : "Errors",
|
||||||
|
"location" : [ 0, 0, 0, 0 ]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
2
|
||||||
|
3
|
||||||
|
5
|
||||||
|
7
|
||||||
|
11
|
||||||
|
13
|
||||||
|
17
|
||||||
|
19
|
||||||
|
23
|
||||||
|
29
|
||||||
|
31
|
||||||
|
37
|
||||||
|
41
|
||||||
|
43
|
||||||
|
47
|
@ -0,0 +1,107 @@
|
|||||||
|
# A resizable list of integers
|
||||||
|
class Vector(object):
|
||||||
|
items: [int] = None
|
||||||
|
size: int = 0
|
||||||
|
|
||||||
|
def __init__(self:"Vector"):
|
||||||
|
self.items = [0]
|
||||||
|
|
||||||
|
# Returns current capacity
|
||||||
|
def capacity(self:"Vector") -> int:
|
||||||
|
return len(self.items)
|
||||||
|
|
||||||
|
# Increases capacity of vector by one element
|
||||||
|
def increase_capacity(self:"Vector") -> int:
|
||||||
|
self.items = self.items + [0]
|
||||||
|
return self.capacity()
|
||||||
|
|
||||||
|
# Appends one item to end of vector
|
||||||
|
def append(self:"Vector", item: int) -> object:
|
||||||
|
if self.size == self.capacity():
|
||||||
|
self.increase_capacity()
|
||||||
|
|
||||||
|
self.items[self.size] = item
|
||||||
|
self.size = self.size + 1
|
||||||
|
|
||||||
|
# Appends many items to end of vector
|
||||||
|
def append_all(self:"Vector", new_items: [int]) -> object:
|
||||||
|
item:int = 0
|
||||||
|
for item in new_items:
|
||||||
|
self.append(item)
|
||||||
|
|
||||||
|
# Removes an item from the middle of vector
|
||||||
|
def remove_at(self:"Vector", idx: int) -> object:
|
||||||
|
if idx < 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
while idx < self.size - 1:
|
||||||
|
self.items[idx] = self.items[idx + 1]
|
||||||
|
idx = idx + 1
|
||||||
|
|
||||||
|
self.size = self.size - 1
|
||||||
|
|
||||||
|
# Retrieves an item at a given index
|
||||||
|
def get(self:"Vector", idx: int) -> int:
|
||||||
|
return self.items[idx]
|
||||||
|
|
||||||
|
# Retrieves the current size of the vector
|
||||||
|
def length(self:"Vector") -> int:
|
||||||
|
return self.size
|
||||||
|
|
||||||
|
# A faster (but more memory-consuming) implementation of vector
|
||||||
|
class DoublingVector(Vector):
|
||||||
|
doubling_limit:int = 1000
|
||||||
|
|
||||||
|
# Overriding to do fewer resizes
|
||||||
|
def increase_capacity(self:"DoublingVector") -> int:
|
||||||
|
if (self.capacity() <= self.doubling_limit // 2):
|
||||||
|
self.items = self.items + self.items
|
||||||
|
else:
|
||||||
|
# If doubling limit has been reached, fall back to
|
||||||
|
# standard capacity increases
|
||||||
|
self.items = self.items + [0]
|
||||||
|
return self.capacity()
|
||||||
|
|
||||||
|
# Makes a vector in the range [i, j)
|
||||||
|
def vrange(i:int, j:int) -> Vector:
|
||||||
|
v:Vector = None
|
||||||
|
v = DoublingVector()
|
||||||
|
|
||||||
|
while i < j:
|
||||||
|
v.append(i)
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
return v
|
||||||
|
|
||||||
|
# Sieve of Eratosthenes (not really)
|
||||||
|
def sieve(v:Vector) -> object:
|
||||||
|
i:int = 0
|
||||||
|
j:int = 0
|
||||||
|
k:int = 0
|
||||||
|
|
||||||
|
while i < v.length():
|
||||||
|
k = v.get(i)
|
||||||
|
j = i + 1
|
||||||
|
while j < v.length():
|
||||||
|
if v.get(j) % k == 0:
|
||||||
|
v.remove_at(j)
|
||||||
|
else:
|
||||||
|
j = j + 1
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
# Input parameter
|
||||||
|
n:int = 50
|
||||||
|
|
||||||
|
# Data
|
||||||
|
v:Vector = None
|
||||||
|
i:int = 0
|
||||||
|
|
||||||
|
# Crunch
|
||||||
|
v = vrange(2, n)
|
||||||
|
sieve(v)
|
||||||
|
|
||||||
|
# Print
|
||||||
|
while i < v.length():
|
||||||
|
print(v.get(i))
|
||||||
|
i = i + 1
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
|||||||
|
2
|
||||||
|
3
|
||||||
|
5
|
||||||
|
7
|
||||||
|
11
|
||||||
|
13
|
||||||
|
17
|
||||||
|
19
|
||||||
|
23
|
||||||
|
29
|
||||||
|
31
|
||||||
|
37
|
||||||
|
41
|
||||||
|
43
|
||||||
|
47
|
@ -0,0 +1,77 @@
|
|||||||
|
# ChocoPy library functions
|
||||||
|
def int_to_str(x: int) -> str:
|
||||||
|
digits:[str] = None
|
||||||
|
result:str = ""
|
||||||
|
|
||||||
|
# Set-up digit mapping
|
||||||
|
digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
|
||||||
|
|
||||||
|
# Write sign if necessary
|
||||||
|
if x < 0:
|
||||||
|
result = "-"
|
||||||
|
x = -x
|
||||||
|
|
||||||
|
# Write digits using a recursive call
|
||||||
|
if x >= 10:
|
||||||
|
result = result + int_to_str(x // 10)
|
||||||
|
result = result + digits[x % 10]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def str_to_int(x: str) -> int:
|
||||||
|
result:int = 0
|
||||||
|
digit:int = 0
|
||||||
|
char:str = ""
|
||||||
|
sign:int = 1
|
||||||
|
first_char:bool = True
|
||||||
|
|
||||||
|
# Parse digits
|
||||||
|
for char in x:
|
||||||
|
if char == "-":
|
||||||
|
if not first_char:
|
||||||
|
return 0 # Error
|
||||||
|
sign = -1
|
||||||
|
elif char == "0":
|
||||||
|
digit = 0
|
||||||
|
elif char == "1":
|
||||||
|
digit = 1
|
||||||
|
elif char == "2":
|
||||||
|
digit = 2
|
||||||
|
elif char == "3":
|
||||||
|
digit = 3
|
||||||
|
elif char == "3":
|
||||||
|
digit = 3
|
||||||
|
elif char == "4":
|
||||||
|
digit = 4
|
||||||
|
elif char == "5":
|
||||||
|
digit = 5
|
||||||
|
elif char == "6":
|
||||||
|
digit = 6
|
||||||
|
elif char == "7":
|
||||||
|
digit = 7
|
||||||
|
elif char == "8":
|
||||||
|
digit = 8
|
||||||
|
elif char == "9":
|
||||||
|
digit = 9
|
||||||
|
else:
|
||||||
|
return 0 # On error
|
||||||
|
first_char = False
|
||||||
|
result = result * 10 + digit
|
||||||
|
|
||||||
|
# Compute result
|
||||||
|
return result * sign
|
||||||
|
|
||||||
|
# Input parameters
|
||||||
|
c:int = 42
|
||||||
|
n:int = 10
|
||||||
|
|
||||||
|
# Run [-nc, nc] with step size c
|
||||||
|
s:str = ""
|
||||||
|
i:int = 0
|
||||||
|
i = -n * c
|
||||||
|
|
||||||
|
# Crunch
|
||||||
|
while i <= n * c:
|
||||||
|
s = int_to_str(i)
|
||||||
|
print(s)
|
||||||
|
i = str_to_int(s) + c
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@
|
|||||||
|
-420
|
||||||
|
-378
|
||||||
|
-336
|
||||||
|
-294
|
||||||
|
-252
|
||||||
|
-210
|
||||||
|
-168
|
||||||
|
-126
|
||||||
|
-84
|
||||||
|
-42
|
||||||
|
0
|
||||||
|
42
|
||||||
|
84
|
||||||
|
126
|
||||||
|
168
|
||||||
|
210
|
||||||
|
252
|
||||||
|
294
|
||||||
|
336
|
||||||
|
378
|
||||||
|
420
|
@ -0,0 +1,83 @@
|
|||||||
|
# Binary-search trees
|
||||||
|
class TreeNode(object):
|
||||||
|
value:int = 0
|
||||||
|
left:"TreeNode" = None
|
||||||
|
right:"TreeNode" = None
|
||||||
|
|
||||||
|
def insert(self:"TreeNode", x:int) -> bool:
|
||||||
|
if x < self.value:
|
||||||
|
if self.left is None:
|
||||||
|
self.left = makeNode(x)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return self.left.insert(x)
|
||||||
|
elif x > self.value:
|
||||||
|
if self.right is None:
|
||||||
|
self.right = makeNode(x)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return self.right.insert(x)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def contains(self:"TreeNode", x:int) -> bool:
|
||||||
|
if x < self.value:
|
||||||
|
if self.left is None:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return self.left.contains(x)
|
||||||
|
elif x > self.value:
|
||||||
|
if self.right is None:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return self.right.contains(x)
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
class Tree(object):
|
||||||
|
root:TreeNode = None
|
||||||
|
size:int = 0
|
||||||
|
|
||||||
|
def insert(self:"Tree", x:int) -> object:
|
||||||
|
if self.root is None:
|
||||||
|
self.root = makeNode(x)
|
||||||
|
self.size = 1
|
||||||
|
else:
|
||||||
|
if self.root.insert(x):
|
||||||
|
self.size = self.size + 1
|
||||||
|
|
||||||
|
def contains(self:"Tree", x:int) -> bool:
|
||||||
|
if self.root is None:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return self.root.contains(x)
|
||||||
|
|
||||||
|
def makeNode(x: int) -> TreeNode:
|
||||||
|
b:TreeNode = None
|
||||||
|
b = TreeNode()
|
||||||
|
b.value = x
|
||||||
|
return b
|
||||||
|
|
||||||
|
|
||||||
|
# Input parameters
|
||||||
|
n:int = 100
|
||||||
|
c:int = 4
|
||||||
|
|
||||||
|
# Data
|
||||||
|
t:Tree = None
|
||||||
|
i:int = 0
|
||||||
|
k:int = 37813
|
||||||
|
|
||||||
|
# Crunch
|
||||||
|
t = Tree()
|
||||||
|
while i < n:
|
||||||
|
t.insert(k)
|
||||||
|
k = (k * 37813) % 37831
|
||||||
|
if i % c != 0:
|
||||||
|
t.insert(i)
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
print(t.size)
|
||||||
|
|
||||||
|
for i in [4, 8, 15, 16, 23, 42]:
|
||||||
|
if t.contains(i):
|
||||||
|
print(i)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@
|
|||||||
|
175
|
||||||
|
15
|
||||||
|
23
|
||||||
|
42
|
@ -0,0 +1,17 @@
|
|||||||
|
def f() -> int:
|
||||||
|
print("start f")
|
||||||
|
g()
|
||||||
|
print("end f")
|
||||||
|
return 42
|
||||||
|
|
||||||
|
|
||||||
|
def g() -> object:
|
||||||
|
print("start g")
|
||||||
|
h()
|
||||||
|
print("end g")
|
||||||
|
|
||||||
|
def h() -> object:
|
||||||
|
print("start h")
|
||||||
|
print("end h")
|
||||||
|
|
||||||
|
print(f())
|
@ -0,0 +1,386 @@
|
|||||||
|
{
|
||||||
|
"kind" : "Program",
|
||||||
|
"location" : [ 1, 1, 17, 11 ],
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 1, 1, 5, 14 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 1, 5, 1, 5 ],
|
||||||
|
"name" : "f"
|
||||||
|
},
|
||||||
|
"params" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 1, 12, 1, 14 ],
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 2, 5, 2, 20 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 2, 5, 2, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 2, 5, 2, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 2, 11, 2, 19 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "start f"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 3, 5, 3, 7 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 3, 5, 3, 7 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 3, 5, 3, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "g"
|
||||||
|
},
|
||||||
|
"args" : [ ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 4, 5, 4, 18 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 4, 5, 4, 18 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 4, 5, 4, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 4, 11, 4, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "end f"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 5, 5, 5, 13 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 5, 12, 5, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 42
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 8, 1, 11, 19 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 8, 5, 8, 5 ],
|
||||||
|
"name" : "g"
|
||||||
|
},
|
||||||
|
"params" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 8, 12, 8, 17 ],
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 9, 5, 9, 20 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 9, 5, 9, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 9, 5, 9, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 9, 11, 9, 19 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "start g"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 10, 5, 10, 7 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 10, 5, 10, 7 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 10, 5, 10, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "h"
|
||||||
|
},
|
||||||
|
"args" : [ ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 11, 5, 11, 18 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 11, 5, 11, 18 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 11, 5, 11, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 11, 11, 11, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "end g"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 13, 1, 15, 19 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 13, 5, 13, 5 ],
|
||||||
|
"name" : "h"
|
||||||
|
},
|
||||||
|
"params" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 13, 12, 13, 17 ],
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 14, 5, 14, 20 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 14, 5, 14, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 14, 5, 14, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 14, 11, 14, 19 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "start h"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 15, 5, 15, 18 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 15, 5, 15, 18 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 15, 5, 15, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 15, 11, 15, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "end h"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 17, 1, 17, 10 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 17, 1, 17, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 17, 1, 17, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 17, 7, 17, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 17, 7, 17, 7 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "f"
|
||||||
|
},
|
||||||
|
"args" : [ ]
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"errors" : {
|
||||||
|
"errors" : [ ],
|
||||||
|
"kind" : "Errors",
|
||||||
|
"location" : [ 0, 0, 0, 0 ]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
start f
|
||||||
|
start g
|
||||||
|
start h
|
||||||
|
end h
|
||||||
|
end g
|
||||||
|
end f
|
||||||
|
42
|
@ -0,0 +1,19 @@
|
|||||||
|
def f(x:int) -> int:
|
||||||
|
print("start f")
|
||||||
|
print(x)
|
||||||
|
g(1, x)
|
||||||
|
print("end f")
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def g(y:int, z:int) -> object:
|
||||||
|
print("start g")
|
||||||
|
print(y)
|
||||||
|
print(z)
|
||||||
|
h("h")
|
||||||
|
print("end g")
|
||||||
|
|
||||||
|
def h(msg: str) -> object:
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
print(f(4))
|
@ -0,0 +1,554 @@
|
|||||||
|
{
|
||||||
|
"kind" : "Program",
|
||||||
|
"location" : [ 1, 1, 19, 12 ],
|
||||||
|
"declarations" : [ {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 1, 1, 6, 13 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 1, 5, 1, 5 ],
|
||||||
|
"name" : "f"
|
||||||
|
},
|
||||||
|
"params" : [ {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 1, 7, 1, 11 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 1, 7, 1, 7 ],
|
||||||
|
"name" : "x"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 1, 9, 1, 11 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 1, 17, 1, 19 ],
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 2, 5, 2, 20 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 2, 5, 2, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 2, 5, 2, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 2, 11, 2, 19 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "start f"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 3, 5, 3, 12 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 3, 5, 3, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 3, 5, 3, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 3, 11, 3, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "x"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 4, 5, 4, 11 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 4, 5, 4, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 4, 5, 4, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}, {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "g"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 4, 7, 4, 7 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 1
|
||||||
|
}, {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 4, 10, 4, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "x"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 5, 5, 5, 18 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 5, 5, 5, 18 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 5, 5, 5, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 5, 11, 5, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "end f"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ReturnStmt",
|
||||||
|
"location" : [ 6, 5, 6, 12 ],
|
||||||
|
"value" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 6, 12, 6, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "x"
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 9, 1, 14, 19 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 9, 5, 9, 5 ],
|
||||||
|
"name" : "g"
|
||||||
|
},
|
||||||
|
"params" : [ {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 9, 7, 9, 11 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 9, 7, 9, 7 ],
|
||||||
|
"name" : "y"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 9, 9, 9, 11 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 9, 14, 9, 18 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 9, 14, 9, 14 ],
|
||||||
|
"name" : "z"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 9, 16, 9, 18 ],
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 9, 24, 9, 29 ],
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 10, 5, 10, 20 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 10, 5, 10, 20 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 10, 5, 10, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 10, 11, 10, 19 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "start g"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 11, 5, 11, 12 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 11, 5, 11, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 11, 5, 11, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 11, 11, 11, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "y"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 12, 5, 12, 12 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 12, 5, 12, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 12, 5, 12, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 12, 11, 12, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"name" : "z"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 13, 5, 13, 10 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 13, 5, 13, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 13, 5, 13, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "h"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 13, 7, 13, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "h"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 14, 5, 14, 18 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 14, 5, 14, 18 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 14, 5, 14, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "StringLiteral",
|
||||||
|
"location" : [ 14, 11, 14, 17 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"value" : "end g"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}, {
|
||||||
|
"kind" : "FuncDef",
|
||||||
|
"location" : [ 16, 1, 17, 15 ],
|
||||||
|
"name" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 16, 5, 16, 5 ],
|
||||||
|
"name" : "h"
|
||||||
|
},
|
||||||
|
"params" : [ {
|
||||||
|
"kind" : "TypedVar",
|
||||||
|
"location" : [ 16, 7, 16, 14 ],
|
||||||
|
"identifier" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 16, 7, 16, 9 ],
|
||||||
|
"name" : "msg"
|
||||||
|
},
|
||||||
|
"type" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 16, 12, 16, 14 ],
|
||||||
|
"className" : "str"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassType",
|
||||||
|
"location" : [ 16, 20, 16, 25 ],
|
||||||
|
"className" : "object"
|
||||||
|
},
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 17, 5, 17, 14 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 17, 5, 17, 14 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 17, 5, 17, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 17, 11, 17, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "str"
|
||||||
|
},
|
||||||
|
"name" : "msg"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
} ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 19, 1, 19, 11 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 19, 1, 19, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 19, 1, 19, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 19, 7, 19, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 19, 7, 19, 7 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "f"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 19, 9, 19, 9 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 4
|
||||||
|
} ]
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"errors" : {
|
||||||
|
"errors" : [ ],
|
||||||
|
"kind" : "Errors",
|
||||||
|
"location" : [ 0, 0, 0, 0 ]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
start f
|
||||||
|
4
|
||||||
|
start g
|
||||||
|
1
|
||||||
|
4
|
||||||
|
h
|
||||||
|
end g
|
||||||
|
end f
|
||||||
|
4
|
@ -0,0 +1 @@
|
|||||||
|
print(42 // 0)
|
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"kind" : "Program",
|
||||||
|
"location" : [ 1, 1, 1, 15 ],
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 1, 1, 1, 14 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 1, 1, 1, 14 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 1, 1, 1, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 1, 7, 1, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 1, 7, 1, 8 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 42
|
||||||
|
},
|
||||||
|
"operator" : "//",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 1, 13, 1, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"errors" : {
|
||||||
|
"errors" : [ ],
|
||||||
|
"kind" : "Errors",
|
||||||
|
"location" : [ 0, 0, 0, 0 ]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
Division by zero
|
||||||
|
Exited with error code 2
|
@ -0,0 +1 @@
|
|||||||
|
print(None)
|
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"kind" : "Program",
|
||||||
|
"location" : [ 1, 1, 1, 12 ],
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 1, 1, 1, 11 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 1, 1, 1, 11 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 1, 1, 1, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "NoneLiteral",
|
||||||
|
"location" : [ 1, 7, 1, 10 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"errors" : {
|
||||||
|
"errors" : [ ],
|
||||||
|
"kind" : "Errors",
|
||||||
|
"location" : [ 0, 0, 0, 0 ]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
Invalid argument
|
||||||
|
Exited with error code 1
|
@ -0,0 +1 @@
|
|||||||
|
print(42 % 0)
|
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"kind" : "Program",
|
||||||
|
"location" : [ 1, 1, 1, 14 ],
|
||||||
|
"declarations" : [ ],
|
||||||
|
"statements" : [ {
|
||||||
|
"kind" : "ExprStmt",
|
||||||
|
"location" : [ 1, 1, 1, 13 ],
|
||||||
|
"expr" : {
|
||||||
|
"kind" : "CallExpr",
|
||||||
|
"location" : [ 1, 1, 1, 13 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
},
|
||||||
|
"function" : {
|
||||||
|
"kind" : "Identifier",
|
||||||
|
"location" : [ 1, 1, 1, 5 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "FuncType",
|
||||||
|
"parameters" : [ {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "object"
|
||||||
|
} ],
|
||||||
|
"returnType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "<None>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name" : "print"
|
||||||
|
},
|
||||||
|
"args" : [ {
|
||||||
|
"kind" : "BinaryExpr",
|
||||||
|
"location" : [ 1, 7, 1, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"left" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 1, 7, 1, 8 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 42
|
||||||
|
},
|
||||||
|
"operator" : "%",
|
||||||
|
"right" : {
|
||||||
|
"kind" : "IntegerLiteral",
|
||||||
|
"location" : [ 1, 12, 1, 12 ],
|
||||||
|
"inferredType" : {
|
||||||
|
"kind" : "ClassValueType",
|
||||||
|
"className" : "int"
|
||||||
|
},
|
||||||
|
"value" : 0
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"errors" : {
|
||||||
|
"errors" : [ ],
|
||||||
|
"kind" : "Errors",
|
||||||
|
"location" : [ 0, 0, 0, 0 ]
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue