commit 091ba18f50af1e6c874fbaf6fadf27178781a5d9 Author: choelzl Date: Thu Apr 7 18:33:05 2022 +0200 Init diff --git a/Alpano b/Alpano new file mode 160000 index 0000000..7792b5c --- /dev/null +++ b/Alpano @@ -0,0 +1 @@ +Subproject commit 7792b5cd98f77942a04e32474594aaf0a18749b2 diff --git a/Permafrost b/Permafrost new file mode 160000 index 0000000..ba98326 --- /dev/null +++ b/Permafrost @@ -0,0 +1 @@ +Subproject commit ba98326985f8dbb90bb9308dc5988d06c3bd6fce diff --git a/cs206-pc b/cs206-pc new file mode 160000 index 0000000..9ff584d --- /dev/null +++ b/cs206-pc @@ -0,0 +1 @@ +Subproject commit 9ff584d5fc51ca25074dac51af0ffc32fc92c41c diff --git a/cs208-ca b/cs208-ca new file mode 160000 index 0000000..66918b1 --- /dev/null +++ b/cs208-ca @@ -0,0 +1 @@ +Subproject commit 66918b1813dd84051fa383c730dd596a494b4c85 diff --git a/cs208-ca_bonus b/cs208-ca_bonus new file mode 160000 index 0000000..20854b5 --- /dev/null +++ b/cs208-ca_bonus @@ -0,0 +1 @@ +Subproject commit 20854b5d9d9d06df3126d47140c24d0e8e7805ae diff --git a/cs320-clp b/cs320-clp new file mode 160000 index 0000000..bc6ea60 --- /dev/null +++ b/cs320-clp @@ -0,0 +1 @@ +Subproject commit bc6ea6040150df90e7d7b974c3f3b86f6d6f72ad diff --git a/cs420-acc/.idea/.gitignore b/cs420-acc/.idea/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/cs420-acc/.idea/cs420.iml b/cs420-acc/.idea/cs420.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/cs420-acc/.idea/cs420.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/cs420-acc/.idea/misc.xml b/cs420-acc/.idea/misc.xml new file mode 100644 index 0000000..40674af --- /dev/null +++ b/cs420-acc/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/cs420-acc/.idea/modules.xml b/cs420-acc/.idea/modules.xml new file mode 100644 index 0000000..25cebf3 --- /dev/null +++ b/cs420-acc/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/cs420-acc/.idea/workspace.xml b/cs420-acc/.idea/workspace.xml new file mode 100644 index 0000000..b72c615 --- /dev/null +++ b/cs420-acc/.idea/workspace.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + 1614884106024 + + + + \ No newline at end of file diff --git a/cs420-acc/l3-compiler b/cs420-acc/l3-compiler new file mode 160000 index 0000000..8d6978f --- /dev/null +++ b/cs420-acc/l3-compiler @@ -0,0 +1 @@ +Subproject commit 8d6978f41682ebd768dcf4da076171bb51b1045d diff --git a/cs420-acc/l3-warmup/.gitignore b/cs420-acc/l3-warmup/.gitignore new file mode 100644 index 0000000..0c35e78 --- /dev/null +++ b/cs420-acc/l3-warmup/.gitignore @@ -0,0 +1,8 @@ +# compiler +/compiler/.bsp/ +/compiler/**/target/ +/compiler/out.l3a + +# VM +/vm/c/bin/ +/vm/rust/target/ diff --git a/cs420-acc/l3-warmup/.idea/.gitignore b/cs420-acc/l3-warmup/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/cs420-acc/l3-warmup/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/cs420-acc/l3-warmup/.idea/codeStyles/Project.xml b/cs420-acc/l3-warmup/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..919ce1f --- /dev/null +++ b/cs420-acc/l3-warmup/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/cs420-acc/l3-warmup/.idea/codeStyles/codeStyleConfig.xml b/cs420-acc/l3-warmup/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/cs420-acc/l3-warmup/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/cs420-acc/l3-warmup/.idea/l3-warmup.iml b/cs420-acc/l3-warmup/.idea/l3-warmup.iml new file mode 100644 index 0000000..1e85cbc --- /dev/null +++ b/cs420-acc/l3-warmup/.idea/l3-warmup.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/cs420-acc/l3-warmup/.idea/misc.xml b/cs420-acc/l3-warmup/.idea/misc.xml new file mode 100644 index 0000000..40674af --- /dev/null +++ b/cs420-acc/l3-warmup/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/cs420-acc/l3-warmup/.idea/modules.xml b/cs420-acc/l3-warmup/.idea/modules.xml new file mode 100644 index 0000000..1eda890 --- /dev/null +++ b/cs420-acc/l3-warmup/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/cs420-acc/l3-warmup/README.org b/cs420-acc/l3-warmup/README.org new file mode 100644 index 0000000..4a89059 --- /dev/null +++ b/cs420-acc/l3-warmup/README.org @@ -0,0 +1,16 @@ +#+OPTIONS: toc:nil author:nil +#+TITLE: The L₃ project + +Welcome to the L₃ project, composed of an L₃ compiler, a virtual machine, a library and a few example programs. The directories are laid out as follows: + + - ~compiler~ :: contains the source code of the L₃ compiler, + + - ~vm~ :: contains the source code of the main version of the L₃ virtual machine (written in C), + + - ~vm-rust~ :: contains the source code of the Rust version of the L₃ virtual machine, + + - ~library~ :: contains the source code of the L₃ library, + + - ~examples~ :: contains a few example L₃ programs and benchmarks. + +Most of these directories contain a ~README.org~ file with further information. diff --git a/cs420-acc/l3-warmup/compiler/README.org b/cs420-acc/l3-warmup/compiler/README.org new file mode 100644 index 0000000..2a4d3c2 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/README.org @@ -0,0 +1,44 @@ +#+OPTIONS: toc:nil author:nil +#+TITLE: The L₃ compiler + +* Introduction + +This directory contains the source code of the L₃ compiler, written in Scala. All interactions with the compiler should be done through [[http://www.scala-sbt.org/][sbt]], a Scala build tool. + +~Sbt~ can either be run in interactive mode, by simply typing ~sbt~ and then entering commands at the prompt, or in batch mode. The following sections use batch mode for illustration, but in practice interactive mode is often to be preferred as it avoids repeated startup of ~sbt~ itself. + +* Compiling + +To compile the compiler, use the ~compile~ command: +: $ sbt compile +(the dollar sign ~$~ represents the shell prompt and should not be typed). + +* Testing + +To test the compiler (and compile it beforehand, if necessary), use the ~test~ command: +: $ sbt test + +* Running + +To run the compiler (and compile it beforehand, if necessary), use the ~run~ command, followed by arguments for the compiler, e.g.: +: $ sbt 'run ../library/lib.l3m ../examples/queens.l3' + +The compiler accepts a list of files to compile as arguments. These files can have one of the following extensions: + + - ~.l3~ :: A normal source file, containing L₃ code. + + - ~.l3m~ :: A module file, containing a list of other files, which must also be either source files (with a ~.l3~ extension) or other module files (with a ~.l3m~ extension). + +Modules are expanded recursively, until only ~.l3~ files remain. Then, duplicate file names are removed, with only the first occurrence kept. Finally, this list of files is fed to the compiler. + +As an example, assume that the file ~lib.l3m~ references ~characters.l3m~ and ~integers.l3m~, and that ~characters.l3m~ references ~characters.l3~ while ~integers.l3m~ references both ~characters.l3m~ and ~integers.l3~. Then, a command line consisting of ~lib.l3m~ and ~helloworld.l3~ is expanded as follows: + + 1. ~lib.l3m~ ~helloworld.l3~ (original command line), + + 2. ~characters.l3m~ ~integers.l3m~ ~helloworld.l3~ (expansion of ~lib.l3m~), + + 3. ~characters.l3~ ~characters.l3m~ ~integers.l3~ ~helloworld.l3~ (expansion of ~characters.l3m~ and ~integers.l3m~), + + 4. ~characters.l3~ ~characters.l3~ ~integers.l3~ ~helloworld.l3~ (expansion of the second ~characters.l3m~), + + 5. ~characters.l3~ ~integers.l3~ ~helloworld.l3~ (removal of duplicates). diff --git a/cs420-acc/l3-warmup/compiler/bin/sbt b/cs420-acc/l3-warmup/compiler/bin/sbt new file mode 100755 index 0000000..375b5be --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/bin/sbt @@ -0,0 +1,661 @@ +#!/usr/bin/env bash +# +# A more capable sbt runner, coincidentally also called sbt. +# Author: Paul Phillips +# https://github.com/paulp/sbt-extras +# +# Generated from http://www.opensource.org/licenses/bsd-license.php +# Copyright (c) 2011, Paul Phillips. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of the author nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# 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. + +set -o pipefail + +declare -r sbt_release_version="1.4.7" +declare -r sbt_unreleased_version="1.4.7" + +declare -r latest_213="2.13.4" +declare -r latest_212="2.12.12" +declare -r latest_211="2.11.12" +declare -r latest_210="2.10.7" +declare -r latest_29="2.9.3" +declare -r latest_28="2.8.2" + +declare -r buildProps="project/build.properties" + +declare -r sbt_launch_ivy_release_repo="https://repo.typesafe.com/typesafe/ivy-releases" +declare -r sbt_launch_ivy_snapshot_repo="https://repo.scala-sbt.org/scalasbt/ivy-snapshots" +declare -r sbt_launch_mvn_release_repo="https://repo1.maven.org/maven2" +declare -r sbt_launch_mvn_snapshot_repo="https://repo.scala-sbt.org/scalasbt/maven-snapshots" + +declare -r default_jvm_opts_common="-Xms512m -Xss2m -XX:MaxInlineLevel=18" +declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy -Dsbt.coursier.home=project/.coursier" + +declare sbt_jar sbt_dir sbt_create sbt_version sbt_script sbt_new +declare sbt_explicit_version +declare verbose noshare batch trace_level + +declare java_cmd="java" +declare sbt_launch_dir="$HOME/.sbt/launchers" +declare sbt_launch_repo + +# pull -J and -D options to give to java. +declare -a java_args scalac_args sbt_commands residual_args + +# args to jvm/sbt via files or environment variables +declare -a extra_jvm_opts extra_sbt_opts + +echoerr() { echo >&2 "$@"; } +vlog() { [[ -n "$verbose" ]] && echoerr "$@"; } +die() { + echo "Aborting: $*" + exit 1 +} + +setTrapExit() { + # save stty and trap exit, to ensure echo is re-enabled if we are interrupted. + SBT_STTY="$(stty -g 2>/dev/null)" + export SBT_STTY + + # restore stty settings (echo in particular) + onSbtRunnerExit() { + [ -t 0 ] || return + vlog "" + vlog "restoring stty: $SBT_STTY" + stty "$SBT_STTY" + } + + vlog "saving stty: $SBT_STTY" + trap onSbtRunnerExit EXIT +} + +# this seems to cover the bases on OSX, and someone will +# have to tell me about the others. +get_script_path() { + local path="$1" + [[ -L "$path" ]] || { + echo "$path" + return + } + + local -r target="$(readlink "$path")" + if [[ "${target:0:1}" == "/" ]]; then + echo "$target" + else + echo "${path%/*}/$target" + fi +} + +script_path="$(get_script_path "${BASH_SOURCE[0]}")" +declare -r script_path +script_name="${script_path##*/}" +declare -r script_name + +init_default_option_file() { + local overriding_var="${!1}" + local default_file="$2" + if [[ ! -r "$default_file" && "$overriding_var" =~ ^@(.*)$ ]]; then + local envvar_file="${BASH_REMATCH[1]}" + if [[ -r "$envvar_file" ]]; then + default_file="$envvar_file" + fi + fi + echo "$default_file" +} + +sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)" +sbtx_opts_file="$(init_default_option_file SBTX_OPTS .sbtxopts)" +jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)" + +build_props_sbt() { + [[ -r "$buildProps" ]] && + grep '^sbt\.version' "$buildProps" | tr '=\r' ' ' | awk '{ print $2; }' +} + +set_sbt_version() { + sbt_version="${sbt_explicit_version:-$(build_props_sbt)}" + [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version + export sbt_version +} + +url_base() { + local version="$1" + + case "$version" in + 0.7.*) echo "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/simple-build-tool" ;; + 0.10.*) echo "$sbt_launch_ivy_release_repo" ;; + 0.11.[12]) echo "$sbt_launch_ivy_release_repo" ;; + 0.*-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" + echo "$sbt_launch_ivy_snapshot_repo" ;; + 0.*) echo "$sbt_launch_ivy_release_repo" ;; + *-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmddThhMMss" + echo "$sbt_launch_mvn_snapshot_repo" ;; + *) echo "$sbt_launch_mvn_release_repo" ;; + esac +} + +make_url() { + local version="$1" + + local base="${sbt_launch_repo:-$(url_base "$version")}" + + case "$version" in + 0.7.*) echo "$base/sbt-launch-0.7.7.jar" ;; + 0.10.*) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; + 0.11.[12]) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; + 0.*) echo "$base/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; + *) echo "$base/org/scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; + esac +} + +addJava() { + vlog "[addJava] arg = '$1'" + java_args+=("$1") +} +addSbt() { + vlog "[addSbt] arg = '$1'" + sbt_commands+=("$1") +} +addScalac() { + vlog "[addScalac] arg = '$1'" + scalac_args+=("$1") +} +addResidual() { + vlog "[residual] arg = '$1'" + residual_args+=("$1") +} + +addResolver() { addSbt "set resolvers += $1"; } + +addDebugger() { addJava "-Xdebug" && addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"; } + +setThisBuild() { + vlog "[addBuild] args = '$*'" + local key="$1" && shift + addSbt "set $key in ThisBuild := $*" +} +setScalaVersion() { + [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")' + addSbt "++ $1" +} +setJavaHome() { + java_cmd="$1/bin/java" + setThisBuild javaHome "_root_.scala.Some(file(\"$1\"))" + export JAVA_HOME="$1" + export JDK_HOME="$1" + export PATH="$JAVA_HOME/bin:$PATH" +} + +getJavaVersion() { + local -r str=$("$1" -version 2>&1 | grep -E -e '(java|openjdk) version' | awk '{ print $3 }' | tr -d '"') + + # java -version on java8 says 1.8.x + # but on 9 and 10 it's 9.x.y and 10.x.y. + if [[ "$str" =~ ^1\.([0-9]+)(\..*)?$ ]]; then + echo "${BASH_REMATCH[1]}" + elif [[ "$str" =~ ^([0-9]+)(\..*)?$ ]]; then + echo "${BASH_REMATCH[1]}" + elif [[ -n "$str" ]]; then + echoerr "Can't parse java version from: $str" + fi +} + +checkJava() { + # Warn if there is a Java version mismatch between PATH and JAVA_HOME/JDK_HOME + + [[ -n "$JAVA_HOME" && -e "$JAVA_HOME/bin/java" ]] && java="$JAVA_HOME/bin/java" + [[ -n "$JDK_HOME" && -e "$JDK_HOME/lib/tools.jar" ]] && java="$JDK_HOME/bin/java" + + if [[ -n "$java" ]]; then + pathJavaVersion=$(getJavaVersion java) + homeJavaVersion=$(getJavaVersion "$java") + if [[ "$pathJavaVersion" != "$homeJavaVersion" ]]; then + echoerr "Warning: Java version mismatch between PATH and JAVA_HOME/JDK_HOME, sbt will use the one in PATH" + echoerr " Either: fix your PATH, remove JAVA_HOME/JDK_HOME or use -java-home" + echoerr " java version from PATH: $pathJavaVersion" + echoerr " java version from JAVA_HOME/JDK_HOME: $homeJavaVersion" + fi + fi +} + +java_version() { + local -r version=$(getJavaVersion "$java_cmd") + vlog "Detected Java version: $version" + echo "$version" +} + +is_apple_silicon() { [[ "$(uname -s)" == "Darwin" && "$(uname -m)" == "arm64" ]]; } + +# MaxPermSize critical on pre-8 JVMs but incurs noisy warning on 8+ +default_jvm_opts() { + local -r v="$(java_version)" + if [[ $v -ge 10 ]]; then + if is_apple_silicon; then + # As of Dec 2020, JVM for Apple Silicon (M1) doesn't support JVMCI + echo "$default_jvm_opts_common" + else + echo "$default_jvm_opts_common -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler" + fi + elif [[ $v -ge 8 ]]; then + echo "$default_jvm_opts_common" + else + echo "-XX:MaxPermSize=384m $default_jvm_opts_common" + fi +} + +execRunner() { + # print the arguments one to a line, quoting any containing spaces + vlog "# Executing command line:" && { + for arg; do + if [[ -n "$arg" ]]; then + if printf "%s\n" "$arg" | grep -q ' '; then + printf >&2 "\"%s\"\n" "$arg" + else + printf >&2 "%s\n" "$arg" + fi + fi + done + vlog "" + } + + setTrapExit + + if [[ -n "$batch" ]]; then + "$@" /dev/null 2>&1; then + curl --fail --silent --location "$url" --output "$jar" + elif command -v wget >/dev/null 2>&1; then + wget -q -O "$jar" "$url" + fi + } && [[ -r "$jar" ]] +} + +acquire_sbt_jar() { + { + sbt_jar="$(jar_file "$sbt_version")" + [[ -r "$sbt_jar" ]] + } || { + sbt_jar="$HOME/.ivy2/local/org.scala-sbt/sbt-launch/$sbt_version/jars/sbt-launch.jar" + [[ -r "$sbt_jar" ]] + } || { + sbt_jar="$(jar_file "$sbt_version")" + jar_url="$(make_url "$sbt_version")" + + echoerr "Downloading sbt launcher for ${sbt_version}:" + echoerr " From ${jar_url}" + echoerr " To ${sbt_jar}" + + download_url "${jar_url}" "${sbt_jar}" + + case "${sbt_version}" in + 0.*) + vlog "SBT versions < 1.0 do not have published MD5 checksums, skipping check" + echo "" + ;; + *) verify_sbt_jar "${sbt_jar}" ;; + esac + } +} + +verify_sbt_jar() { + local jar="${1}" + local md5="${jar}.md5" + md5url="$(make_url "${sbt_version}").md5" + + echoerr "Downloading sbt launcher ${sbt_version} md5 hash:" + echoerr " From ${md5url}" + echoerr " To ${md5}" + + download_url "${md5url}" "${md5}" >/dev/null 2>&1 + + if command -v md5sum >/dev/null 2>&1; then + if echo "$(cat "${md5}") ${jar}" | md5sum -c -; then + rm -rf "${md5}" + return 0 + else + echoerr "Checksum does not match" + return 1 + fi + elif command -v md5 >/dev/null 2>&1; then + if [ "$(md5 -q "${jar}")" == "$(cat "${md5}")" ]; then + rm -rf "${md5}" + return 0 + else + echoerr "Checksum does not match" + return 1 + fi + elif command -v openssl >/dev/null 2>&1; then + if [ "$(openssl md5 -r "${jar}" | awk '{print $1}')" == "$(cat "${md5}")" ]; then + rm -rf "${md5}" + return 0 + else + echoerr "Checksum does not match" + return 1 + fi + else + echoerr "Could not find an MD5 command" + return 1 + fi +} + +usage() { + set_sbt_version + cat < display stack traces with a max of frames (default: -1, traces suppressed) + -debug-inc enable debugging log for the incremental compiler + -no-colors disable ANSI color codes + -sbt-create start sbt even if current directory contains no sbt project + -sbt-dir path to global settings/plugins directory (default: ~/.sbt/) + -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11+) + -ivy path to local Ivy repository (default: ~/.ivy2) + -no-share use all local caches; no sharing + -offline put sbt in offline mode + -jvm-debug Turn on JVM debugging, open at the given port. + -batch Disable interactive mode + -prompt Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted + -script Run the specified file as a scala script + + # sbt version (default: sbt.version from $buildProps if present, otherwise $sbt_release_version) + -sbt-version use the specified version of sbt (default: $sbt_release_version) + -sbt-force-latest force the use of the latest release of sbt: $sbt_release_version + -sbt-dev use the latest pre-release version of sbt: $sbt_unreleased_version + -sbt-jar use the specified jar as the sbt launcher + -sbt-launch-dir directory to hold sbt launchers (default: $sbt_launch_dir) + -sbt-launch-repo repo url for downloading sbt launcher jar (default: $(url_base "$sbt_version")) + + # scala version (default: as chosen by sbt) + -28 use $latest_28 + -29 use $latest_29 + -210 use $latest_210 + -211 use $latest_211 + -212 use $latest_212 + -213 use $latest_213 + -scala-home use the scala build at the specified directory + -scala-version use the specified version of scala + -binary-version use the specified scala version when searching for dependencies + + # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) + -java-home alternate JAVA_HOME + + # passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution + # The default set is used if JVM_OPTS is unset and no -jvm-opts file is found + $(default_jvm_opts) + JVM_OPTS environment variable holding either the jvm args directly, or + the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts') + Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument. + -jvm-opts file containing jvm args (if not given, .jvmopts in project root is used if present) + -Dkey=val pass -Dkey=val directly to the jvm + -J-X pass option -X directly to the jvm (-J is stripped) + + # passing options to sbt, OR to this runner + SBT_OPTS environment variable holding either the sbt args directly, or + the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts') + Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument. + -sbt-opts file containing sbt args (if not given, .sbtopts in project root is used if present) + -S-X add -X to sbt's scalacOptions (-S is stripped) + + # passing options exclusively to this runner + SBTX_OPTS environment variable holding either the sbt-extras args directly, or + the reference to a file containing sbt-extras args if given path is prepended by '@' (e.g. '@/etc/sbtxopts') + Note: "@"-file is overridden by local '.sbtxopts' or '-sbtx-opts' argument. + -sbtx-opts file containing sbt-extras args (if not given, .sbtxopts in project root is used if present) +EOM + exit 0 +} + +process_args() { + require_arg() { + local type="$1" + local opt="$2" + local arg="$3" + + if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then + die "$opt requires <$type> argument" + fi + } + while [[ $# -gt 0 ]]; do + case "$1" in + -h | -help) usage ;; + -v) verbose=true && shift ;; + -d) addSbt "--debug" && shift ;; + -w) addSbt "--warn" && shift ;; + -q) addSbt "--error" && shift ;; + -x) shift ;; # currently unused + -trace) require_arg integer "$1" "$2" && trace_level="$2" && shift 2 ;; + -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; + + -no-colors) addJava "-Dsbt.log.noformat=true" && addJava "-Dsbt.color=false" && shift ;; + -sbt-create) sbt_create=true && shift ;; + -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;; + -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; + -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; + -no-share) noshare=true && shift ;; + -offline) addSbt "set offline in Global := true" && shift ;; + -jvm-debug) require_arg port "$1" "$2" && addDebugger "$2" && shift 2 ;; + -batch) batch=true && shift ;; + -prompt) require_arg "expr" "$1" "$2" && setThisBuild shellPrompt "(s => { val e = Project.extract(s) ; $2 })" && shift 2 ;; + -script) require_arg file "$1" "$2" && sbt_script="$2" && addJava "-Dsbt.main.class=sbt.ScriptMain" && shift 2 ;; + + -sbt-version) require_arg version "$1" "$2" && sbt_explicit_version="$2" && shift 2 ;; + -sbt-force-latest) sbt_explicit_version="$sbt_release_version" && shift ;; + -sbt-dev) sbt_explicit_version="$sbt_unreleased_version" && shift ;; + -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;; + -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;; + -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;; + + -28) setScalaVersion "$latest_28" && shift ;; + -29) setScalaVersion "$latest_29" && shift ;; + -210) setScalaVersion "$latest_210" && shift ;; + -211) setScalaVersion "$latest_211" && shift ;; + -212) setScalaVersion "$latest_212" && shift ;; + -213) setScalaVersion "$latest_213" && shift ;; + + -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;; + -binary-version) require_arg version "$1" "$2" && setThisBuild scalaBinaryVersion "\"$2\"" && shift 2 ;; + -scala-home) require_arg path "$1" "$2" && setThisBuild scalaHome "_root_.scala.Some(file(\"$2\"))" && shift 2 ;; + -java-home) require_arg path "$1" "$2" && setJavaHome "$2" && shift 2 ;; + -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;; + -sbtx-opts) require_arg path "$1" "$2" && sbtx_opts_file="$2" && shift 2 ;; + -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;; + + -D*) addJava "$1" && shift ;; + -J*) addJava "${1:2}" && shift ;; + -S*) addScalac "${1:2}" && shift ;; + + new) sbt_new=true && : ${sbt_explicit_version:=$sbt_release_version} && addResidual "$1" && shift ;; + + *) addResidual "$1" && shift ;; + esac + done +} + +# process the direct command line arguments +process_args "$@" + +# skip #-styled comments and blank lines +readConfigFile() { + local end=false + until $end; do + read -r || end=true + [[ $REPLY =~ ^# ]] || [[ -z $REPLY ]] || echo "$REPLY" + done <"$1" +} + +# if there are file/environment sbt_opts, process again so we +# can supply args to this runner +if [[ -r "$sbt_opts_file" ]]; then + vlog "Using sbt options defined in file $sbt_opts_file" + while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbt_opts_file") +elif [[ -n "$SBT_OPTS" && ! ("$SBT_OPTS" =~ ^@.*) ]]; then + vlog "Using sbt options defined in variable \$SBT_OPTS" + IFS=" " read -r -a extra_sbt_opts <<<"$SBT_OPTS" +else + vlog "No extra sbt options have been defined" +fi + +# if there are file/environment sbtx_opts, process again so we +# can supply args to this runner +if [[ -r "$sbtx_opts_file" ]]; then + vlog "Using sbt options defined in file $sbtx_opts_file" + while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbtx_opts_file") +elif [[ -n "$SBTX_OPTS" && ! ("$SBTX_OPTS" =~ ^@.*) ]]; then + vlog "Using sbt options defined in variable \$SBTX_OPTS" + IFS=" " read -r -a extra_sbt_opts <<<"$SBTX_OPTS" +else + vlog "No extra sbt options have been defined" +fi + +[[ -n "${extra_sbt_opts[*]}" ]] && process_args "${extra_sbt_opts[@]}" + +# reset "$@" to the residual args +set -- "${residual_args[@]}" +argumentCount=$# + +# set sbt version +set_sbt_version + +checkJava + +# only exists in 0.12+ +setTraceLevel() { + case "$sbt_version" in + "0.7."* | "0.10."* | "0.11."*) echoerr "Cannot set trace level in sbt version $sbt_version" ;; + *) setThisBuild traceLevel "$trace_level" ;; + esac +} + +# set scalacOptions if we were given any -S opts +[[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[*]}\"" + +[[ -n "$sbt_explicit_version" && -z "$sbt_new" ]] && addJava "-Dsbt.version=$sbt_explicit_version" +vlog "Detected sbt version $sbt_version" + +if [[ -n "$sbt_script" ]]; then + residual_args=("$sbt_script" "${residual_args[@]}") +else + # no args - alert them there's stuff in here + ((argumentCount > 0)) || { + vlog "Starting $script_name: invoke with -help for other options" + residual_args=(shell) + } +fi + +# verify this is an sbt dir, -create was given or user attempts to run a scala script +[[ -r ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_script" || -n "$sbt_new" ]] || { + cat < + */ + +object BlockTag extends Enumeration(200) { + val String, RegisterFrame, Function = Value +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/CL3Interpreter.scala b/cs420-acc/l3-warmup/compiler/src/l3/CL3Interpreter.scala new file mode 100644 index 0000000..424a4b0 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/CL3Interpreter.scala @@ -0,0 +1,161 @@ +package l3 + +import scala.collection.mutable.{ Map => MutableMap } +import SymbolicCL3TreeModule._ +import IO._ +import l3.L3Primitive._ + +/** + * A tree-based interpreter for the CL₃ language. + * + * @author Michel Schinz + */ + +object CL3Interpreter extends (Tree => TerminalPhaseResult) { + def apply(program: Tree): TerminalPhaseResult = + try { + eval(program)(Map.empty) + Right(0, None) + } catch { + case e: EvalHlt => + Right((e.retCode, None)) + case e: EvalErr => + val Seq(m1, ms @ _*) = e.messages + Left((m1 +: ms.reverse).mkString("\n")) + } + + // Values + private sealed trait Value { + override def toString(): String = this match { + case BlockV(t, c) => s"<$t>[${c mkString ","}]" + case IntV(i) => i.toString + case CharV(c) => s"'${new String(Array(c), 0, 1)}'" + case BoolV(b) => if (b) "#t" else "#f" + case UnitV => "#u" + case FunctionV(_, _, _) => "" + } + } + private case class BlockV(tag: L3BlockTag, contents: Array[Value]) + extends Value + private case class IntV(i: L3Int) extends Value + private case class CharV(c: L3Char) extends Value + private case class BoolV(b: Boolean) extends Value + private case object UnitV extends Value + + private case class FunctionV(args: Seq[Symbol], body: Tree, env: Env) + extends Value + + // Environment + private type Env = PartialFunction[Symbol, Value] + + // Error/halt handling (termination) + private class EvalErr(val messages: Seq[String]) extends Exception() + private class EvalHlt(val retCode: Int) extends Exception() + + private def error(pos: Position, msg: String): Nothing = + throw new EvalErr(Seq(msg, s" at $pos")) + private def halt(r: Int): Nothing = + throw new EvalHlt(r) + + private def validIndex(a: Array[Value], i: L3Int): Boolean = + 0 <= i.toInt && i.toInt < a.length + + private final def eval(tree: Tree)(implicit env: Env): Value = tree match { + case Let(bdgs, body) => + eval(body)(Map(bdgs map { case (n, e) => n -> eval(e) } : _*) orElse env) + + case LetRec(funs, body) => + val recEnv = MutableMap[Symbol, Value]() + val env1 = recEnv orElse env + for (Fun(name, args, body) <- funs) + recEnv(name) = BlockV(l3.BlockTag.Function.id, + Array(FunctionV(args, body, env1))) + eval(body)(env1) + + case If(cond, thenE, elseE) => + eval(cond) match { + case BoolV(false) => eval(elseE) + case _ => eval(thenE) + } + + case App(fun, args) => + eval(fun) match { + case BlockV(_, Array(FunctionV(cArgs, cBody, cEnv))) => + if (args.length != cArgs.length) + error(tree.pos, + s"expected ${cArgs.length} arguments, got ${args.length}") + try { + eval(cBody)(Map(cArgs zip (args map eval) : _*) orElse cEnv) + } catch { + case e: EvalErr => + throw new EvalErr(e.messages :+ s" at ${fun.pos}") + } + case _ => error(fun.pos, "function value expected") + } + + case Prim(p, args) => (p, args map eval) match { + case (BlockAlloc(t), Seq(IntV(i))) => + BlockV(t, Array.fill(i.toInt)(UnitV)) + case (BlockP, Seq(BlockV(_, _))) => BoolV(true) + case (BlockP, Seq(_)) => BoolV(false) + case (BlockTag, Seq(BlockV(t, _))) => IntV(L3Int(t)) + case (BlockLength, Seq(BlockV(_, c))) => IntV(L3Int(c.length)) + case (BlockGet, Seq(BlockV(_, v), IntV(i))) if (validIndex(v, i)) => + v(i.toInt) + case (BlockSet, Seq(BlockV(_, v), IntV(i), o)) if (validIndex(v, i)) => + v(i.toInt) = o; UnitV + + case (IntP, Seq(IntV(_))) => BoolV(true) + case (IntP, Seq(_)) => BoolV(false) + + case (IntAdd, Seq(IntV(v1), IntV(v2))) => IntV(v1 + v2) + case (IntSub, Seq(IntV(v1), IntV(v2))) => IntV(v1 - v2) + case (IntMul, Seq(IntV(v1), IntV(v2))) => IntV(v1 * v2) + case (IntDiv, Seq(IntV(v1), IntV(v2))) => IntV(v1 / v2) + case (IntMod, Seq(IntV(v1), IntV(v2))) => IntV(v1 % v2) + + case (IntShiftLeft, Seq(IntV(v1), IntV(v2))) => IntV(v1 << v2) + case (IntShiftRight, Seq(IntV(v1), IntV(v2))) => IntV(v1 >> v2) + case (IntBitwiseAnd, Seq(IntV(v1), IntV(v2))) => IntV(v1 & v2) + case (IntBitwiseOr, Seq(IntV(v1), IntV(v2))) => IntV(v1 | v2) + case (IntBitwiseXOr, Seq(IntV(v1), IntV(v2))) => IntV(v1 ^ v2) + + case (IntLt, Seq(IntV(v1), IntV(v2))) => BoolV(v1 < v2) + case (IntLe, Seq(IntV(v1), IntV(v2))) => BoolV(v1 <= v2) + case (Eq, Seq(v1, v2)) => BoolV(v1 == v2) + + case (IntToChar, Seq(IntV(i))) if Character.isValidCodePoint(i.toInt) => + CharV(i.toInt) + + case (CharP, Seq(CharV(_))) => BoolV(true) + case (CharP, Seq(_)) => BoolV(false) + + case (ByteRead, Seq()) => IntV(L3Int(readByte())) + case (ByteWrite, Seq(IntV(c))) => writeByte(c.toInt); UnitV + + case (CharToInt, Seq(CharV(c))) => IntV(L3Int(c)) + + case (BoolP, Seq(BoolV(_))) => BoolV(true) + case (BoolP, Seq(_)) => BoolV(false) + + case (UnitP, Seq(UnitV)) => BoolV(true) + case (UnitP, Seq(_)) => BoolV(false) + + case (p, vs) => + error(tree.pos, + s"""cannot apply primitive $p to values ${vs.mkString(", ")}""") + } + + case Halt(arg) => eval(arg) match { + case IntV(c) => halt(c.toInt) + case c => error(tree.pos, s"halt with code $c") + } + + case Ident(n) => env(n) + + case Lit(IntLit(i)) => IntV(i) + case Lit(CharLit(c)) => CharV(c) + case Lit(BooleanLit(b)) => BoolV(b) + case Lit(UnitLit) => UnitV + } +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/CL3Literal.scala b/cs420-acc/l3-warmup/compiler/src/l3/CL3Literal.scala new file mode 100644 index 0000000..a93b636 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/CL3Literal.scala @@ -0,0 +1,21 @@ +package l3 + +/** + * Literal values for the CL₃ language. + * + * @author Michel Schinz + */ + +sealed trait CL3Literal { + override def toString: String = this match { + case IntLit(i) => i.toString + case CharLit(c) => "'"+ (new String(Character.toChars(c))) +"'" + case BooleanLit(v) => if (v) "#t" else "#f" + case UnitLit => "#u" + } +} + +case class IntLit(value: L3Int) extends CL3Literal +case class CharLit(value: L3Char) extends CL3Literal +case class BooleanLit(value: Boolean) extends CL3Literal +case object UnitLit extends CL3Literal diff --git a/cs420-acc/l3-warmup/compiler/src/l3/CL3NameAnalyzer.scala b/cs420-acc/l3-warmup/compiler/src/l3/CL3NameAnalyzer.scala new file mode 100644 index 0000000..02e498c --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/CL3NameAnalyzer.scala @@ -0,0 +1,83 @@ +package l3 + +import l3.{ NominalCL3TreeModule => N } +import l3.{ SymbolicCL3TreeModule => S } + +/** + * Name analysis for the CL₃ language. Translates a tree in which + * identifiers are simple strings into one in which identifiers are + * symbols (i.e. globally-unique names). + * + * @author Michel Schinz + */ + +object CL3NameAnalyzer extends (N.Tree => Either[String, S.Tree]) { + def apply(tree: N.Tree): Either[String, S.Tree] = + try { + Right(rewrite(tree)(Map.empty)) + } catch { + case NameAnalysisError(msg) => + Left(msg) + } + + private type Env = Map[String, Symbol] + + private final case class NameAnalysisError(msg: String) extends Exception(msg) + private def error(msg: String)(implicit pos: Position): Nothing = + throw new NameAnalysisError(s"$pos: $msg") + + private def rewrite(tree: N.Tree)(implicit env: Env): S.Tree = { + implicit val pos = tree.pos + tree match { + case N.Let(bdgs, body) => + val syms = checkUnique(bdgs map (_._1)) map Symbol.fresh + S.Let(syms zip (bdgs map { b => rewrite(b._2) }), + rewrite(body)(augmented(env, syms))) + case N.LetRec(funs, body) => + val syms = checkUnique(funs map (_.name)) map Symbol.fresh + val env1 = augmented(env, syms) + S.LetRec((syms zip funs) map {case (s,f) => rewriteF(s, f , env1)}, + rewrite(body)(env1)) + case N.If(cond, thenE, elseE) => + S.If(rewrite(cond), rewrite(thenE), rewrite(elseE)) + case N.App(N.Ident(fun), args) if env contains altName(fun, args.length)=> + S.App(S.Ident(env(altName(fun, args.length))), args map rewrite) + case N.App(fun, args) => + S.App(rewrite(fun), args map rewrite) + case N.Prim(p, args) if L3Primitive.isDefinedAt(p, args.length) => + S.Prim(L3Primitive(p), args map rewrite) + case N.Halt(arg) => + S.Halt(rewrite(arg)) + case N.Ident(name) if env contains name => + S.Ident(env(name)) + case N.Lit(value) => + S.Lit(value) + + case N.Prim(p, _) if L3Primitive isDefinedAt p => + error(s"incorrect number of arguments for @$p") + case N.Prim(p, _) => + error(s"unknown primitive $p") + case N.Ident(name) => + error(s"unknown identifier $name") + } + } + + private def rewriteF(funSym: Symbol, fun: N.Fun, env: Env): S.Fun = { + implicit val pos = fun.pos + val argsSyms = checkUnique(fun.args) map Symbol.fresh + S.Fun(funSym, argsSyms, rewrite(fun.body)(augmented(env, argsSyms))) + } + + private def checkUnique(names: Seq[String]) + (implicit pos: Position): Seq[String] = { + for (n <- names diff names.distinct) + error(s"repeated definition of $n") + names + } + + private def altName(name: String, arity: Int): String = + s"$name@$arity" + + private def augmented(env: Env, symbols: Seq[Symbol]): Env = + env ++ (symbols map { s => (s.name, s) }) +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/CL3Tree.scala b/cs420-acc/l3-warmup/compiler/src/l3/CL3Tree.scala new file mode 100644 index 0000000..d1dd2d2 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/CL3Tree.scala @@ -0,0 +1,51 @@ +package l3 + +/** + * A module for CL₃ trees. + * + * @author Michel Schinz + */ + +trait CL3TreeModule { + type Name + type Primitive + + sealed abstract class Tree(val pos: Position) + case class Let(bindings: Seq[(Name, Tree)], body: Tree) + (implicit pos: Position) extends Tree(pos) + case class LetRec(functions: Seq[Fun], body: Tree) + (implicit pos: Position) extends Tree(pos) + case class If(cond: Tree, thenE: Tree, elseE: Tree) + (implicit pos: Position) extends Tree(pos) + case class App(fun: Tree, args: Seq[Tree]) + (implicit pos: Position) extends Tree(pos) + case class Prim(prim: Primitive, args: Seq[Tree]) + (implicit pos: Position) extends Tree(pos) + case class Halt(arg: Tree) + (implicit pos: Position) extends Tree(pos) + case class Ident(name: Name) + (implicit pos: Position) extends Tree(pos) + case class Lit(value: CL3Literal) + (implicit pos: Position) extends Tree(pos) + + case class Fun(name: Name, args: Seq[Name], body: Tree) + (implicit val pos: Position) +} + +/** + * Module for trees after parsing: names and primitives are + * represented as strings. + */ +object NominalCL3TreeModule extends CL3TreeModule { + type Name = String + type Primitive = String +} + +/** + * Module for trees after name analysis: names are represented as + * symbols (globally-unique names) and primitives as objects. + */ +object SymbolicCL3TreeModule extends CL3TreeModule { + type Name = Symbol + type Primitive = L3Primitive +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/CL3TreeFormatter.scala b/cs420-acc/l3-warmup/compiler/src/l3/CL3TreeFormatter.scala new file mode 100644 index 0000000..715bb44 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/CL3TreeFormatter.scala @@ -0,0 +1,40 @@ +package l3 + +import org.typelevel.paiges.Doc + +class CL3TreeFormatter[T <: CL3TreeModule](treeModule: T) + extends Formatter[T#Tree] { + import Formatter.par, treeModule._ + + def toDoc(tree: T#Tree): Doc = (tree: @unchecked) match { + case Let(bdgs, body) => + val bdgsDoc = + par(1, bdgs map { case (n, v) => par(1, Doc.str(n), toDoc(v)) }) + par("let", 2, bdgsDoc, toDoc(body)) + case LetRec(funs, body) => + def funToDoc(fun: T#Fun): Doc = + (Doc.str(fun.name) + / par("fun", 2, par(1, fun.args map Doc.str), toDoc(fun.body))) + val funsDoc = par(1, funs map { f => par(1, funToDoc(f)) }) + par("letrec", 2, funsDoc, toDoc(body)) + case If(c, t, e) => + par("if", 2, toDoc(c), toDoc(t), toDoc(e)) + case App(fun, args) => + par(1, (fun +: args) map toDoc) + case Halt(arg) => + par("halt", 2, toDoc(arg)) + case Prim(prim, args) => + par(1, Doc.text(s"@$prim") +: (args map toDoc)) + case Ident(name) => + Doc.str(name) + case Lit(l) => + Doc.str(l) + } +} + +object CL3TreeFormatter { + implicit object NominalCL3TreeFormatter + extends CL3TreeFormatter(NominalCL3TreeModule) + implicit object SymbolicCL3TreeFormatter + extends CL3TreeFormatter(SymbolicCL3TreeModule) +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/Formatter.scala b/cs420-acc/l3-warmup/compiler/src/l3/Formatter.scala new file mode 100644 index 0000000..65cba0f --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/Formatter.scala @@ -0,0 +1,24 @@ +package l3 + +import org.typelevel.paiges.Doc + +/** + * Utility methods for formatting. + * + * @author Michel Schinz + */ + +trait Formatter[-T] { + def toDoc(value: T): Doc +} + +object Formatter { + def par(nest: Int, ds: Iterable[Doc]): Doc = + (Doc.char('(') + Doc.intercalate(Doc.line, ds).nested(nest) + Doc.char(')')) + .grouped + def par(nest: Int, d1: Doc): Doc = par(nest, Seq(d1)) + def par(nest: Int, d1: Doc, d2: Doc): Doc = par(nest, Seq(d1, d2)) + + def par(tag: String, nest: Int, d1: Doc, ds: Doc*): Doc = + par(nest, (Doc.text(tag) space d1.aligned) +: ds) +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/IO.scala b/cs420-acc/l3-warmup/compiler/src/l3/IO.scala new file mode 100644 index 0000000..150713f --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/IO.scala @@ -0,0 +1,17 @@ +package l3 + +/** + * Helper module for IO functions in L₃ and intermediate languages. + * + * @author Michel Schinz + */ + +object IO { + def readByte(): Int = + System.in.read() + + def writeByte(c: Int): Unit = { + System.out.write(c) + System.out.flush() + } +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/L3FileReader.scala b/cs420-acc/l3-warmup/compiler/src/l3/L3FileReader.scala new file mode 100644 index 0000000..0f18f5b --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/L3FileReader.scala @@ -0,0 +1,83 @@ +package l3 + +import java.io.IOException +import java.nio.file.Path +import java.nio.file.Files.newBufferedReader + +import scala.util.Using.{resource => using} +import scala.collection.mutable.ArrayBuffer + +/** + * File reading for L₃ (both modules and source files). + * + * @author Michel Schinz + */ + +object L3FileReader { + def readFilesExpandingModules(base: Path, pathNames: Seq[String]) + : Either[String, (String, Int => Position)] = + try { + Right(readFiles(base, expandModules(base, pathNames))) + } catch { + case e: IOException => Left(e.getMessage) + } + + private def expandModules(base: Path, pathNames: Seq[String]): Seq[Path] = { + def readModule(modulePath: Path): Seq[String] = { + using(newBufferedReader(modulePath)) { moduleReader => + Iterator.continually(moduleReader.readLine) + .takeWhile (_ != null) + .map (_.trim) + .filterNot { s => (s startsWith ";") || s.isEmpty } + .toList + } + } + + def expand(base: Path, pathNames: Seq[String]): Seq[Path] = { + val basePath = base.toAbsolutePath.normalize + pathNames flatMap { pn => + val p = basePath.resolve(pn).normalize + if (p.getFileName.toString endsWith ".l3m") + expandModules(p.getParent, readModule(p)) + else + Seq(p) + } + } + expand(base, pathNames).distinct + } + + private def readFiles(basePath: Path, + paths: Seq[Path]): (String, Int=>Position) = { + def indexToPosition(indices: Array[Int], + fileLines: Int => Option[(String, Int)]) + (index: Int): Position = { + val p = { + val p0 = java.util.Arrays.binarySearch(indices, index) + // FIXME: use code-points count to get column number, not char count! + if (p0 < 0) (-p0 - 2) else p0 + } + fileLines(p) + .map { case (f, l) => new FilePosition(f, l, index - indices(p)) } + .getOrElse(UnknownPosition) + } + + val progB = new StringBuilder() + val indicesB = ArrayBuffer.empty[Int] + val fileLinesB = ArrayBuffer.empty[(String, Int)] + for (path <- paths) { + val relPath = basePath relativize path + using(newBufferedReader(path)) { fileReader => + Iterator.continually(fileReader.readLine) + .takeWhile(_ != null) + .zipWithIndex + .foreach { case (line, lineIndex) => + val index = progB.size + progB ++= line; progB += '\n' + indicesB += index + fileLinesB += ((relPath.toString, lineIndex + 1)) + } + } + } + (progB.result(), indexToPosition(indicesB.toArray, fileLinesB.toArray.lift)) + } +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/L3Int.scala b/cs420-acc/l3-warmup/compiler/src/l3/L3Int.scala new file mode 100644 index 0000000..34c59ad --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/L3Int.scala @@ -0,0 +1,47 @@ +package l3 + +final class L3Int private(private val v: Int) extends AnyVal { + def toInt: Int = v + + def +(that: L3Int): L3Int = L3Int.ofIntClipped(this.v + that.v) + def -(that: L3Int): L3Int = L3Int.ofIntClipped(this.v - that.v) + def *(that: L3Int): L3Int = L3Int.ofIntClipped(this.v * that.v) + def /(that: L3Int): L3Int = L3Int.ofIntClipped(this.v / that.v) + def %(that: L3Int): L3Int = L3Int.ofIntClipped(this.v % that.v) + def &(that: L3Int): L3Int = L3Int.ofIntClipped(this.v & that.v) + def |(that: L3Int): L3Int = L3Int.ofIntClipped(this.v | that.v) + def ^(that: L3Int): L3Int = L3Int.ofIntClipped(this.v ^ that.v) + def <<(that: L3Int): L3Int = L3Int.ofIntClipped(this.v << that.v) + def >>(that: L3Int): L3Int = L3Int.ofIntClipped(this.v >> that.v) + + def <(that: L3Int): Boolean = this.v < that.v + def <=(that: L3Int): Boolean = this.v <= that.v + def >(that: L3Int): Boolean = this.v > that.v + def >=(that: L3Int): Boolean = this.v >= that.v + + override def toString: String = v.toString +} + +object L3Int { + private def ofIntClipped(v: Int): L3Int = + L3Int((v << 1) >> 1) + + def canConvertFromInt(i: Int): Boolean = + fitsInNSignedBits(L3_INT_BITS)(i) + + def canConvertFromIntUnsigned(i: Int): Boolean = + fitsInNUnsignedBits(L3_INT_BITS)(i) + + def ofIntUnsigned(v: Int): L3Int = { + require(canConvertFromIntUnsigned(v)) + new L3Int((v << 1) >> 1) + } + + def apply(v: Int): L3Int = { + require(canConvertFromInt(v)) + new L3Int(v) + } + + def unapply(v: L3Int): Option[Int] = + Some(v.toInt) +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/L3Parser.scala b/cs420-acc/l3-warmup/compiler/src/l3/L3Parser.scala new file mode 100644 index 0000000..a83d9f9 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/L3Parser.scala @@ -0,0 +1,253 @@ +package l3 + +import fastparse._ +import NominalCL3TreeModule._ + +/** + * Parsing (including lexical analysis) for the L₃ language. + * + * @author Michel Schinz + */ + +object L3Parser { + def parse(programText: String, + indexToPosition: Int => Position): Either[String, Tree] = { + val parser = new S(indexToPosition) + fastparse.parse(programText, parser.program(_)) match { + case Parsed.Success(program, _) => + Right(program) + case Parsed.Failure(lp, index, _) => + Left(s"${indexToPosition(index)}: parse error (expected: $lp)") + } + } + + // Lexical analysis (for which whitespace is significant) + private class L(indexToPosition: Int => Position) { + import NoWhitespace._ + private implicit val indexToPositionView = indexToPosition + + // Literals + private def sign[_: P] = P(CharIn("+\\-")) + private def prefix2[_: P] = IgnoreCase("#b") + private def prefix16[_: P] = IgnoreCase("#x") + private def digit2[_: P] = CharIn("0-1") + private def digit10[_: P] = CharIn("0-9") + private def digit16[_: P] = CharIn("0-9a-fA-F") + private def unicodeChar[_: P] = P( + CharPred(!Character.isHighSurrogate(_)) + | (CharPred(Character.isHighSurrogate) + ~ CharPred(Character.isLowSurrogate))) + + private def integer2[_: P] = P( + (prefix2 ~/ digit2.rep(1).!) + .map { Integer.parseInt(_, 2) } + .filter { L3Int.canConvertFromIntUnsigned(_) } + .map { L3Int.ofIntUnsigned(_) }) + private def integer16[_: P] = P( + (prefix16 ~/ digit16.rep(1).!) + .map { Integer.parseInt(_, 16) } + .filter { L3Int.canConvertFromIntUnsigned(_) } + .map { L3Int.ofIntUnsigned(_) }) + private def integer10[_: P] = P( + (sign.? ~ digit10 ~/ digit10.rep).! + .map { Integer.parseInt(_, 10) } + .filter { L3Int.canConvertFromInt(_) }) + .map { L3Int(_) } + private def integer[_: P] = P( + (Index ~ (integer2 | integer10 | integer16)) + .map { case (i, v) => Lit(IntLit(v))(i) }) + private def string[_: P] = P( + (Index ~ "\"" ~/ CharPred(c => c != '\n' && c != '"').rep.! ~ "\"") + .map { case (i, s) => sStringLit(s)(i) }) + private def char[_: P] = P( + (Index ~ "'" ~/ unicodeChar.! ~ "'") + .map { case (i, c) => Lit(CharLit(c.codePointAt(0)))(i) }) + private def bool[_: P] = P( + (Index ~ StringIn("#t", "#f").!) + .map { case (i, v) => Lit(BooleanLit(v == "#t"))(i) }) + private def unit[_: P] = P( + (Index ~ "#u") + .map { case i => Lit(UnitLit)(i) }) + + def literal[_: P] = P(integer | string | char | bool | unit) + + // Identifiers + private def identStart[_: P] = P(CharIn("|!%&*+\\-./:<=>?^_~a-zA-Z")) + private def identCont[_: P] = P(identStart | digit10) + private def identSuffix[_: P] = P("@" ~ digit10.rep(1)) + + def identStr[_: P] = P( + (identStart ~/ identCont.rep ~/ identSuffix.?).!) + def identifier[_: P] = P( + (Index ~ identStr).map { case (i, n) => Ident(n)(i) }) + + // Keywords + def kDef[_: P] = P("def" ~ !identCont) + def kDefrec[_: P] = P("defrec" ~ !identCont) + def kFun[_: P] = P("fun" ~ !identCont) + def kLet[_: P] = P("let" ~ !identCont) + def kLet_*[_: P] = P("let*" ~ !identCont) + def kLetrec[_: P] = P("letrec" ~ !identCont) + def kRec[_: P] = P("rec" ~ !identCont) + def kBegin[_: P] = P("begin" ~ !identCont) + def kCond[_: P] = P("cond" ~ !identCont) + def kIf[_: P] = P("if" ~ !identCont) + def kAnd[_: P] = P("and" ~ !identCont) + def kOr[_: P] = P("or" ~ !identCont) + def kNot[_: P] = P("not" ~ !identCont) + def kHalt[_: P] = P("halt" ~ !identCont) + def kPrim[_: P] = P("@") + } + + // Syntactic analysis (for which whitespace and comments are ignored) + private class S(indexToPosition: Int => Position) { + val lexer = new L(indexToPosition) + import lexer._ + + private implicit val whitespace = { implicit ctx: ParsingRun[_] => + import NoWhitespace._ + (CharIn(" \t\n\r") + | (";" ~ CharPred(c => c != '\n' && c != '\r').rep)).rep + } + private implicit val indexToPositionView = indexToPosition + + def program[_: P]: P[Tree] = + P("" ~ topExpr ~ End) // The initial "" allows leading whitespace + + private def topExpr[_: P]: P[Tree] = P(defP | defrecP | exprP) + + private def defP[_: P] = P( + (iPar(kDef ~ identStr ~ expr) ~ topExpr) + .map { case (i, (n, v), p) => Let(Seq((n, v)), p)(i) }) + private def defrecP[_: P] = P( + (iPar(kDefrec ~ identStr ~ anonFun) ~ topExpr) + .map { case (i, (n, (a, b)), p) => + LetRec(Seq(Fun(n, a, b)(i)), p)(i) }) + private def exprP[_: P] = P( + (ix(expr ~ topExpr.?)) + .map { case (i, (e, p)) => sBegin(e +: p.toSeq)(i) }) + + private def expr[_: P]: P[Tree] = P( + fun | let | let_* | letrec | rec | begin | cond | if_ | and | or | not + | halt | app | prim | literal | identifier) + private def exprs[_: P] = expr.rep + private def iExprs[_: P] = ix(exprs) + private def exprs1[_: P] = expr.rep(1) + private def iExprs1[_: P] = ix(exprs1) + + private def anonFun[_: P] = P( + par("fun" ~ par(identStr.rep) ~ iExprs1) + .map { case (a, (i, e)) => (a, sBegin(e)(i)) }) + private def funDef[_: P] = P( + iPar(identStr ~ anonFun) + .map { case (i, (n, (a, e))) => Fun(n, a, e)(i) }) + private def binding[_: P] = P( + par(identStr ~ expr) + .map { case (i, e) => (i, e) }) + private def bindings[_: P] = P( + par(binding.rep)) + + private def fun[_: P] = P( + ix(anonFun) + .map { case (i, (a, e)) => sFun(a, e)(i) }) + private def let[_: P] = P( + iPar(kLet ~/ bindings ~ iExprs1) + .map { case (i1, (b, (i2, e))) => Let(b, sBegin(e)(i2))(i1) }) + private def let_*[_: P] = P( + iPar(kLet_* ~/ bindings ~ iExprs1) + .map { case (i1, (b, (i2, e))) => sLet_*(b, sBegin(e)(i2))(i1) }) + private def letrec[_: P]= P( + iPar(kLetrec ~/ par(funDef.rep) ~ iExprs1) + .map { case (i1, (f, (i2, e))) => LetRec(f, sBegin(e)(i2))(i1) }) + private def rec[_: P] = P( + iPar(kRec ~/ identStr ~ bindings ~ iExprs1) + .map { case (i1, (n, b, (i2, e))) => sRec(n, b, sBegin(e)(i2))(i1) }) + private def begin[_: P] = P( + iPar(kBegin ~/ exprs1) + .map { case (i, e) => sBegin(e)(i) }) + + private def cond[_: P] = P( + iPar(kCond ~/ par(expr ~ exprs).rep(1)) + .map { case (i, a) => sCond(a)(i) }) + private def if_[_: P] = P( + iPar(kIf ~ expr ~ expr ~ expr.?) + .map { case (i, (c, t, f)) => + If(c, t, f.getOrElse(Lit(UnitLit)(i)))(i) }) + private def and[_: P] = P( + iPar(kAnd ~/ expr.rep(2)) + .map { case (i, es) => sAnd(es)(i) }) + private def or[_: P] = P( + iPar(kOr ~/ expr.rep(2)) + .map { case (i, es) => sOr(es)(i) }) + private def not[_: P] = P( + iPar(kNot ~/ expr) + .map { case (i, e) => sNot(e)(i) }) + + private def app[_: P] = P( + iPar(expr ~ exprs) + .map { case (i, (e, es)) => App(e, es)(i) }) + private def prim[_: P] = P( + iPar(kPrim ~/ identStr ~ exprs) + .map { case (i, (p, es)) => Prim(p, es)(i) }) + private def halt[_: P] = P( + iPar(kHalt ~/ expr) + .map { case (i, e) => Halt(e)(i) }) + + private def par[T, _: P](b: =>P[T]): P[T] = P("(" ~ b ~ ")") + private def ix[T, _: P](b: =>P[T]): P[(Int, T)] = Index ~ b + private def iPar[T, _: P](b: =>P[T]): P[(Int, T)] = ix(par(b)) + } + + // Syntactic sugar translation. + private var freshCounter = 0 + private def freshName(prefix: String): String = { + freshCounter += 1 + prefix + "$" + freshCounter + } + + private def sFun(args: Seq[String], body: Tree) + (implicit p: Position): Tree = { + val fn = freshName("sfun") + LetRec(Seq(Fun(fn, args, body)), Ident(fn)) + } + + private def sLet_*(bdgs: Seq[(String,Tree)], body: Tree)(implicit p: Position): Tree = + bdgs.foldRight(body)((b,t)=>Let(Seq(b),t)) + private def sBegin(exprs: Seq[Tree])(implicit p: Position): Tree = + exprs.reduceRight((e1,e2)=>Let(Seq((freshName("sbegin"), e1)),e2)) + private def sRec(name: String, bdgs: Seq[(String, Tree)], body: Tree)(implicit p: Position) = + LetRec(Seq(Fun(name, bdgs.map(_._1), body)), App(Ident(name), bdgs.map(_._2))) + private def sAnd(es: Seq[Tree])(implicit p: Position): Tree = + es.reduceRight(If(_,_,Lit(BooleanLit(false)))) + private def sOr(es: Seq[Tree])(implicit p: Position): Tree = + es.reduceRight((e, r) =>{ + val fn = freshName("sor") + Let(Seq((fn, e)), If(Ident(fn), Ident(fn), r)) + }) + private def sNot(e: Tree)(implicit p: Position): Tree = + If(e, Lit(BooleanLit(false)), Lit(BooleanLit(true))) + private def sCond(clses: Seq[(Tree, Seq[Tree])])(implicit p: Position): Tree = + clses.foldRight(Lit(UnitLit): Tree){ case ((c, t), e) => + If(c, sBegin(t), e) + } + + private def sStringLit(s: String)(implicit p: Position): Tree = { + val b = freshName("string") + val cs = codePoints(s) + Let(Seq((b, Prim("block-alloc-"+ BlockTag.String.id, + Seq(Lit(IntLit(L3Int(cs.length))))))), + sBegin((cs.zipWithIndex map {case (c, i) => + Prim("block-set!", + Seq(Ident(b), Lit(IntLit(L3Int(i))), Lit(CharLit(c)))) }) + :+ Ident(b))) + } + + private def codePoints(chars: Seq[Char]): Seq[L3Char] = chars match { + case Seq(h, l, r @ _*) if (Character.isSurrogatePair(h, l)) => + Character.toCodePoint(h, l) +: codePoints(r) + case Seq(c, r @ _*) => + c.toInt +: codePoints(r) + case Seq() => + Seq() + } +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/L3Primitive.scala b/cs420-acc/l3-warmup/compiler/src/l3/L3Primitive.scala new file mode 100644 index 0000000..15f039c --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/L3Primitive.scala @@ -0,0 +1,92 @@ +package l3 + +/** + * A class for L₃ primitives. + * + * @author Michel Schinz + */ + +sealed abstract class L3Primitive(val name: String, val arity: Int) { + override def toString: String = name +} + +sealed abstract class L3ValuePrimitive(name: String, arity: Int) + extends L3Primitive(name, arity) +sealed abstract class L3TestPrimitive(name: String, arity: Int) + extends L3Primitive(name, arity) + +object L3Primitive { + // Primitives on blocks + case class BlockAlloc(tag: L3BlockTag) + extends L3ValuePrimitive(s"block-alloc-${tag}", 1) + case object BlockP extends L3TestPrimitive("block?", 1) + case object BlockTag extends L3ValuePrimitive("block-tag", 1) + case object BlockLength extends L3ValuePrimitive("block-length", 1) + case object BlockGet extends L3ValuePrimitive("block-get", 2) + case object BlockSet extends L3ValuePrimitive("block-set!", 3) + + // Primitives on integers + case object IntP extends L3TestPrimitive("int?", 1) + + case object IntAdd extends L3ValuePrimitive("+", 2) + case object IntSub extends L3ValuePrimitive("-", 2) + case object IntMul extends L3ValuePrimitive("*", 2) + case object IntDiv extends L3ValuePrimitive("/", 2) + case object IntMod extends L3ValuePrimitive("%", 2) + + case object IntShiftLeft extends L3ValuePrimitive("shift-left", 2) + case object IntShiftRight extends L3ValuePrimitive("shift-right", 2) + case object IntBitwiseAnd extends L3ValuePrimitive("and", 2) + case object IntBitwiseOr extends L3ValuePrimitive("or", 2) + case object IntBitwiseXOr extends L3ValuePrimitive("xor", 2) + + + case object IntLt extends L3TestPrimitive("<", 2) + case object IntLe extends L3TestPrimitive("<=", 2) + + + case object ByteRead extends L3ValuePrimitive("byte-read", 0) + case object ByteWrite extends L3ValuePrimitive("byte-write", 1) + + case object IntToChar extends L3ValuePrimitive("int->char", 1) + + // Primitives on characters + case object CharP extends L3TestPrimitive("char?", 1) + + case object CharToInt extends L3ValuePrimitive("char->int", 1) + + // Primitives on booleans + case object BoolP extends L3TestPrimitive("bool?", 1) + + // Primitives on unit + case object UnitP extends L3TestPrimitive("unit?", 1) + + // Primitives on arbitrary values + + case object Eq extends L3TestPrimitive("=", 2) + case object Id extends L3ValuePrimitive("id", 1) + + def isDefinedAt(name: String): Boolean = + byName isDefinedAt name + + def isDefinedAt(name: String, arity: Int): Boolean = + (byName isDefinedAt name) && (byName(name).arity == arity) + + def apply(name: String): L3Primitive = + byName(name) + + private val blockAllocators = for (i <- 0 to 200) yield BlockAlloc(i) + + // Note: private primitives (id and block-alloc-n for n > 200) are ommitted + // on purpose from this map, as they are not meant to be used by user code. + private val byName: Map[String, L3Primitive] = + Map((Seq(BlockP, BlockTag, BlockLength, BlockGet, BlockSet, + IntP, IntAdd, IntSub, IntMul, IntDiv, IntMod, + IntShiftLeft, IntShiftRight, + IntBitwiseAnd, IntBitwiseOr, IntBitwiseXOr, + IntLt, IntLe, Eq, IntToChar, + CharP, ByteRead, ByteWrite, CharToInt, + BoolP, + UnitP) ++ blockAllocators) + map { p => (p.name, p) } : _*) +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/Main.scala b/cs420-acc/l3-warmup/compiler/src/l3/Main.scala new file mode 100644 index 0000000..06999be --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/Main.scala @@ -0,0 +1,47 @@ +package l3 + +import java.io.PrintWriter +import java.nio.file.{ Files, Paths } + +import l3.SymbolicCL3TreeModule.Tree + +object Main { + def main(args: Array[String]): Unit = { + val backEnd: Tree => TerminalPhaseResult = ( + CL3Interpreter + ) + + val basePath = Paths.get(".").toAbsolutePath + Either.cond(! args.isEmpty, args.toIndexedSeq, "no input file given") + .flatMap(L3FileReader.readFilesExpandingModules(basePath, _)) + .flatMap(p => L3Parser.parse(p._1, p._2)) + .flatMap(CL3NameAnalyzer) + .flatMap(backEnd) match { + case Right((retCode, maybeMsg)) => + maybeMsg foreach println + sys.exit(retCode) + case Left(errMsg) => + println(s"Error: $errMsg") + sys.exit(1) + } + } + + private lazy val outPrintWriter = + new PrintWriter(System.out, true) + + private def treePrinter[T](msg: String)(implicit f: Formatter[T]): T => T = + passThrough { tree => + outPrintWriter.println(msg) + f.toDoc(tree).writeTo(80, outPrintWriter) + outPrintWriter.println() + } + + private def seqPrinter[T](msg: String): Seq[T] => Seq[T] = + passThrough { program => + outPrintWriter.println(msg) + program foreach outPrintWriter.println + } + + private def passThrough[T](f: T => Unit): T => T = + { t: T => f(t); t } +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/Position.scala b/cs420-acc/l3-warmup/compiler/src/l3/Position.scala new file mode 100644 index 0000000..f9e18b6 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/Position.scala @@ -0,0 +1,12 @@ +package l3 + +sealed trait Position + +final class FilePosition(fileName: String, line: Int, column: Int) + extends Position { + override def toString: String = s"$fileName:$line:$column" +} + +object UnknownPosition extends Position { + override def toString: String = "" +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/Symbol.scala b/cs420-acc/l3-warmup/compiler/src/l3/Symbol.scala new file mode 100644 index 0000000..4e93e9b --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/Symbol.scala @@ -0,0 +1,32 @@ +package l3 + +/** + * A class for symbols, i.e. globally-unique names. + * + * @author Michel Schinz + */ + +final class Symbol(val name: String, idProvider: => Int) { + private[this] lazy val id = + idProvider + + def copy(): Symbol = + new Symbol(name, idProvider) + + override def toString: String = + if (id == 0) name else s"${name}_${id}" +} + +object Symbol { + private[this] val counters = scala.collection.mutable.HashMap[String,Int]() + + def fresh(name: String): Symbol = { + def id: Int = { + val id = counters.getOrElse(name, 0) + counters.put(name, id + 1) + id + } + + new Symbol(name, id) + } +} diff --git a/cs420-acc/l3-warmup/compiler/src/l3/package.scala b/cs420-acc/l3-warmup/compiler/src/l3/package.scala new file mode 100644 index 0000000..dc706c4 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/src/l3/package.scala @@ -0,0 +1,49 @@ +package object l3 { + type TerminalPhaseResult = Either[String, (Int, Option[String])] + + type L3BlockTag = Int + type L3Char = Int + + // A 32-bit integer (which could contain a pointer, a tagged value, + // or an untagged value). + type Bits32 = Int + + val L3_INT_BITS = java.lang.Integer.SIZE - 1 + + // Bit twiddling + def bitsToIntMSBF(bits: Int*): Int = + bits.foldLeft(0) { (v, b) => (v << 1) | b } + + def fitsInNSignedBits(bits: Int)(value: Int): Boolean = { + require(0 <= bits && bits < Integer.SIZE) + val value1 = value >> (bits - 1) + value1 == 0 || value1 == -1 + } + + def fitsInNUnsignedBits(bits: Int)(value: Int): Boolean = { + require(0 <= bits && bits < Integer.SIZE) + (value >>> bits) == 0 + } + + // Substitutions + type Subst[T] = Map[T, T] + def emptySubst[T]: Subst[T] = + Map.empty[T, T].withDefault(identity) + def subst[T](from: T, to: T): Subst[T] = + emptySubst[T] + (from -> to) + def subst[T](from: Seq[T], to: Seq[T]): Subst[T] = + emptySubst[T] ++ (from zip to) + + // Fixed point computation + private def fixedPoint[T](start: T, maxIt: Option[Int])(f: T=>T): T = { + val approx = LazyList.iterate(start, maxIt getOrElse Integer.MAX_VALUE)(f) + val (improv, stable) = ((approx zip approx.tail) span (p => p._1 != p._2)) + if (improv.isEmpty) stable.head._1 else improv.last._2 + } + + private[l3] def fixedPoint[T](start: T)(f: T=>T): T = + fixedPoint(start, None)(f) + + private[l3] def fixedPoint[T](start: T, maxIt: Int)(f: T=>T): T = + fixedPoint(start, Some(maxIt))(f) +} diff --git a/cs420-acc/l3-warmup/compiler/test/l3/ExamplesTests.scala b/cs420-acc/l3-warmup/compiler/test/l3/ExamplesTests.scala new file mode 100644 index 0000000..94d0c72 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/test/l3/ExamplesTests.scala @@ -0,0 +1,51 @@ +package l3 + +import java.io.{ ByteArrayInputStream } +import java.nio.file.{ Files, Paths, Path } +import java.nio.charset.StandardCharsets.UTF_8 + +import scala.util.Using.{resource => using} + +import utest._ + +import SymbolicCL3TreeModule.Tree + +trait ExamplesTests { + val backEnd: Tree => TerminalPhaseResult + + def compileAndRun(fileName: String, input: String): Either[String, String] = { + using(new ByteArrayInputStream(input.getBytes(UTF_8))) { inS => + val in0 = System.in + try { + System.setIn(inS) + L3Tester.compileAndRun(backEnd)(Seq(fileName)) + } finally { + System.setIn(in0) + } + } + } + + def readFile(fileName: String): String = + new String(Files.readAllBytes(Paths.get(fileName)), UTF_8) + + def testExpectedOutput(implicit path: utest.framework.TestPath) = { + val testName = path.value.last + val input = readFile(s"../tests/${testName}.in") + val expectedOut = readFile(s"../tests/${testName}.out") + assertMatch(compileAndRun(s"../examples/${testName}.l3m", input)) { + case Right(s: String) if s == expectedOut => + } + } + + val tests = Tests { + // Note: sudoku is too slow to be included here + test("bignums") { testExpectedOutput } + test("maze") { testExpectedOutput } + test("queens") { testExpectedOutput } + test("unimaze") { testExpectedOutput } + } +} + +object ExamplesTests1 extends TestSuite with ExamplesTests { + val backEnd = L3Tester.backEnd1 +} diff --git a/cs420-acc/l3-warmup/compiler/test/l3/L3Tester.scala b/cs420-acc/l3-warmup/compiler/test/l3/L3Tester.scala new file mode 100644 index 0000000..dd1e304 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/test/l3/L3Tester.scala @@ -0,0 +1,47 @@ +package l3 + +import java.io.{ ByteArrayOutputStream, PrintStream } +import java.nio.file.{ Paths } + +import scala.util.Using.{resource => using} + +import SymbolicCL3TreeModule.Tree + +object L3Tester { + def compile[T](backEnd: Tree => Either[String, T]) + (inFileNames: Seq[String]): Either[String, T] = { + val basePath = Paths.get(".").toAbsolutePath.normalize + Right(inFileNames) + .flatMap(L3FileReader.readFilesExpandingModules(basePath, _)) + .flatMap(p => L3Parser.parse(p._1, p._2)) + .flatMap(CL3NameAnalyzer) + .flatMap(backEnd) + } + + def compileNoFail[T](backEnd: Tree => T) + (inFileNames: Seq[String]): Either[String, T] = + compile(t => Right(backEnd(t)))(inFileNames) + + def compileAndRun(backEnd: Tree => TerminalPhaseResult) + (inFileNames: Seq[String]): Either[String, String] = { + def outputCapturingBackend(t: Tree): Either[String, String] = { + val outBS = new ByteArrayOutputStream() + using(new PrintStream(outBS)) { outPS => + val out0 = System.out + try { + System.setOut(outPS) + backEnd(t) + .flatMap(_ => Right(outBS.toString("UTF-8"))) + } finally { + System.setOut(out0) + } + } + } + + compile(outputCapturingBackend(_))(inFileNames) + } + + val backEnd1 = ( + CL3Interpreter + ) +} diff --git a/cs420-acc/l3-warmup/compiler/test/l3/SyntheticTests.scala b/cs420-acc/l3-warmup/compiler/test/l3/SyntheticTests.scala new file mode 100644 index 0000000..dec7d80 --- /dev/null +++ b/cs420-acc/l3-warmup/compiler/test/l3/SyntheticTests.scala @@ -0,0 +1,87 @@ +package l3 + +import utest._ + +import SymbolicCL3TreeModule.Tree + +trait SyntheticTests { + val backEnd: Tree => TerminalPhaseResult + + def compileAndRun(inFileNames: String*): Either[String, String] = + L3Tester.compileAndRun(backEnd)(inFileNames) + + // Validate the output of a self-validating test. + def isValidTestResult(s: String): Boolean = + ! s.isEmpty && (s == ((s(0) +: ('A' to s(0))).mkString)) + + def testSelfValidatingOutput(implicit path: utest.framework.TestPath) = { + val testFileName = "../tests/" + path.value.last.split(" ")(0) + ".l3" + assertMatch(compileAndRun(testFileName)) { + case Right(s: String) if isValidTestResult(s) => + } + } + + val tests = Tests { + test("primitives") { + // Block primitives + test("prim-blockp (@block?)"){ testSelfValidatingOutput } + test("prim-block-alloc (@block-alloc-0)"){ testSelfValidatingOutput } + test("prim-block-tag (@block-tag)"){ testSelfValidatingOutput } + test("prim-block-length (@block-length)"){ testSelfValidatingOutput } + test("prim-block-get-set (@block-[sg]et,)"){ testSelfValidatingOutput } + + // Integer primitives + test("prim-intp (@int?)"){ testSelfValidatingOutput } + test("prim-add (@+)"){ testSelfValidatingOutput } + test("prim-sub (@-)"){ testSelfValidatingOutput } + test("prim-mul (@*)"){ testSelfValidatingOutput } + test("prim-div (@/)"){ testSelfValidatingOutput } + test("prim-mod (@%)"){ testSelfValidatingOutput } + test("prim-shift-left (@shift-left)"){ testSelfValidatingOutput } + test("prim-shift-right (@shift-right)"){ testSelfValidatingOutput } + test("prim-and (@and)"){ testSelfValidatingOutput } + test("prim-or (@or)"){ testSelfValidatingOutput } + test("prim-xor (@xor)"){ testSelfValidatingOutput } + test("prim-lt (@<)"){ testSelfValidatingOutput } + test("prim-le (@<=)"){ testSelfValidatingOutput } + test("prim-int-to-char (@int->char)"){ testSelfValidatingOutput } + + // Character primitives + test("prim-charp (@char?)"){ testSelfValidatingOutput } + test("prim-char-to-int (@char->int)"){ testSelfValidatingOutput } + + // Boolean primitives + test("prim-boolp (@bool?)"){ testSelfValidatingOutput } + + // Unit primitives + test("prim-unitp (@unit?)"){ testSelfValidatingOutput } + + // Primitives on arbitrary values + test("prim-eq (@=)"){ testSelfValidatingOutput } + } + + test("expressions") { + test("expr-let (let …)"){ testSelfValidatingOutput } + test("expr-lets (let* …)"){ testSelfValidatingOutput } + test("expr-letrec (letrec …)"){ testSelfValidatingOutput } + test("expr-rec (rec …)"){ testSelfValidatingOutput } + test("expr-fun (fun …)"){ testSelfValidatingOutput } + test("expr-begin (begin …)"){ testSelfValidatingOutput } + test("expr-if (if …)"){ testSelfValidatingOutput } + test("expr-cond (cond …)"){ testSelfValidatingOutput } + test("expr-and (and …)"){ testSelfValidatingOutput } + test("expr-or (or …)"){ testSelfValidatingOutput } + test("expr-not (not …)"){ testSelfValidatingOutput } + } + + test("statements") { + test("stmt-def (def …)"){ testSelfValidatingOutput } + test("stmt-defrec (defrec …)"){ testSelfValidatingOutput } + test("stmt-halt (halt …)"){ testSelfValidatingOutput } + } + } +} + +object SyntheticTests1 extends TestSuite with SyntheticTests { + val backEnd = L3Tester.backEnd1 +} diff --git a/cs420-acc/l3-warmup/examples/README.org b/cs420-acc/l3-warmup/examples/README.org new file mode 100644 index 0000000..68a1a93 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/README.org @@ -0,0 +1,34 @@ +#+OPTIONS: toc:nil author:nil +#+TITLE: L3 examples + +This directory contains several example programs written in L3. The most important ones are briefly described in the table below. + +| Name | Behavior | +|---------+-----------------------------------------------------------| +| bignums | Compute the factorial using "big integers" | +| life | Conway's "Game of Life" | +| maze | Inefficiently compute and draw a random maze | +| unimaze | Like maze, but more efficient and uses Unicode characters | +| queens | Solve the n-queens problem | +| sudoku | Solve a few Sudoku problems | +|---------+-----------------------------------------------------------| + +Once the L3 compiler is complete, that is once it can generate L3A files for the L3 virtual machine, the examples above can be compiled in different ways, as described below. + +The first, but slowest technique is to execute the compiler from sbt, using the ~run~ command. For example, to compile the "unimaze" example, enter the following command at the sbt prompt (the ~>~ below represents the sbt prompt and should not be typed): +: > run ../library/lib.l3m ../examples/unimaze.l3 + +The second, faster technique consists in first packaging the L3 compiler and then executing it from the shell. The packaging should be done from sbt using the ~stage~ command, as follows: +: > stage +This generates a launcher script called ~l3~, which can be executed from the shell. For example, to compile the "unimaze" example as above, enter the following command in your shell, while in the ~examples~ directory (the ~$~ below represents the shell prompt and should not be typed): +: $ ../compiler/target/universal/stage/bin/l3c \ +: ../library/lib.l3m unimaze.l3 + +Notice that both commands above will generate an L3 assembly file called ~out.l3a~. The name of that file can be changed using the ~l3.out-asm-file~ Java property. For example, to compile the same example as above but put the assembly file in ~unimaze.l3a~, enter the following at the shell prompt: +: $ ../compiler/target/universal/stage/bin/l3c \ +: -Dl3.out-asm-file=unimaze.l3a ../library/lib.l3m unimaze.l3 + +To compile all the examples of this directory in parallel (to take advantage of a multi-core machine), a tool like [[https://savannah.gnu.org/projects/parallel/][GNU parallel]] can be used as follows: +: $ ls *.l3 \ +: | parallel ../compiler/target/universal/stage/bin/l3c \ +: -Dl3.out-asm-file={.}.l3a ../library/lib.l3m {} diff --git a/cs420-acc/l3-warmup/examples/bignums.l3 b/cs420-acc/l3-warmup/examples/bignums.l3 new file mode 100644 index 0000000..ca84afd --- /dev/null +++ b/cs420-acc/l3-warmup/examples/bignums.l3 @@ -0,0 +1,65 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Basic computations (addition, multiplication and factorial) on big +;; numbers. These are represented as lists of "digits" in the base +;; specified below, in order of increasing weight. + +(def %base 10000) + +(def int->bignum list-make@1) + +(def bignum-print + (fun (b) + (let ((rev-b (list-reverse b))) + (int-print (list-head rev-b)) + (list-for-each (fun (d) + (if (< d 1000) (int-print 0)) + (if (< d 100) (int-print 0)) + (if (< d 10) (int-print 0)) + (int-print d)) + (list-tail rev-b))))) + +(def bignum-+ + (fun (b1 b2) + (rec loop ((b1 b1) (b2 b2) (carry 0)) + (cond ((list-empty? b1) + (if (= 0 carry) b2 (loop (int->bignum carry) b2 0))) + ((list-empty? b2) + (if (= 0 carry) b1 (loop b1 (int->bignum carry) 0))) + (#t + (let ((res (+ (list-head b1) (list-head b2) carry))) + (list-prepend (%t res %base) + (loop (list-tail b1) + (list-tail b2) + (/t res %base))))))))) + +(def bignum-scale + (fun (b n) + (rec loop ((b b) (n n) (carry 0)) + (if (list-empty? b) + (if (= 0 carry) list-empty (int->bignum carry)) + (let ((sh (+ (* (list-head b) n) carry))) + (list-prepend (%t sh %base) + (loop (list-tail b) n (/t sh %base)))))))) + +(defrec bignum-* + (fun (b1 b2) + (if (list-empty? b1) + list-empty + (bignum-+ (bignum-scale b2 (list-head b1)) + (bignum-scale (bignum-* (list-tail b1) b2) %base))))) + +(def bignum-zero? list-empty?) + +(defrec bignum-fact + (fun (n) + (if (= 0 n) + (int->bignum 1) + (bignum-* (int->bignum n) (bignum-fact (- n 1)))))) + +(string-print "Factorial of? ") +(let ((n (int-read))) + (int-print n) + (string-print "! = ") + (bignum-print (bignum-fact n)) + (newline-print)) diff --git a/cs420-acc/l3-warmup/examples/bignums.l3m b/cs420-acc/l3-warmup/examples/bignums.l3m new file mode 100644 index 0000000..e8046a3 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/bignums.l3m @@ -0,0 +1,2 @@ +../library/lib.l3m +bignums.l3 diff --git a/cs420-acc/l3-warmup/examples/calculator.l3 b/cs420-acc/l3-warmup/examples/calculator.l3 new file mode 100644 index 0000000..95954d4 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/calculator.l3 @@ -0,0 +1,105 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Expression evaluator program. + +(def space-print (fun () (char-print ' '))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; List utilities + +;; Return first element of list [l]. +(def first + (fun (l) (list-head l))) +;; Return second element of list [l]. +(def second + (fun (l) + (first (list-tail l)))) +;; Return third element of list [l]. +(def third + (fun (l) + (second (list-tail l)))) + +;; Return the pair (key value) of the association-list [l] with key +;; [k]. Produce an error if no such pair is found. +(defrec assoc + (fun (k l) + (let ((h (list-head l))) + (if (= (list-head h) k) + h + (assoc k (list-tail l)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Handling of expressions. Expressions are specified by the following +;; grammar: +;; e ::= +;; ( ) where op in { + - * / } +;; | (v . ) +;; | (c . ) + +;; Test whether the argument is an operator. +(def operator? + (fun (c) + (or (= c '+') + (= c '-') + (= c '*') + (= c '/')))) + +;; Print an expression (in Scheme-like format) +(defrec print-expr + (fun (e) + (let ((tag (first e))) + (if (operator? tag) + (begin + (char-print '(') + (char-print tag) + (space-print) + (print-expr (second e)) + (space-print) + (print-expr (third e)) + (char-print ')')) + (if (= 'v' tag) + (char-print (list-tail e)) + (int-print (list-tail e))))))) + +(def const (fun (c) (list-prepend 'c' c))) +(def var (fun (v) (list-prepend 'v' v))) + +;; (+ x y) +(def expr-1 + (list-make '+' (var 'x') (var 'y'))) + +;; (* x x) +(def expr-2 + (list-make '*' (var 'x') (var 'x'))) + +;; (- (* x x) (+ x y)) +(def expr-3 + (list-make '-' expr-2 expr-1)) + +;; { x => 12, y => 20 } +(def env-1 + (list-make (list-prepend 'x' 12) (list-prepend 'y' 20))) + +(defrec eval + (fun (e env) + (let ((tag (first e))) + (if (operator? tag) + (let ((o1 (eval (second e) env)) + (o2 (eval (third e) env))) + (if (= tag '+') + (+ o1 o2) + (if (= tag '-') + (- o1 o2) + (if (= tag '*') (* o1 o2) (/t o1 o2))))) + (if (= tag 'v') + (list-tail (assoc (list-tail e) env)) + (list-tail e)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Main program + +(print-expr expr-3) +(newline-print) +(string-print " => ") +(int-print (eval expr-3 env-1)) ;Should print 112 +(newline-print) diff --git a/cs420-acc/l3-warmup/examples/hello.l3 b/cs420-acc/l3-warmup/examples/hello.l3 new file mode 100644 index 0000000..85d8825 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/hello.l3 @@ -0,0 +1,19 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; "Hello, world" in L₃, the hard way (no syntactic sugar or library +;; functions). + +(@byte-write 72) ;H +(@byte-write 101) ;e +(@byte-write 108) ;l +(@byte-write 108) ;l +(@byte-write 111) ;o +(@byte-write 44) ;, +(@byte-write 32) ; (space) +(@byte-write 119) ;w +(@byte-write 111) ;o +(@byte-write 114) ;r +(@byte-write 108) ;l +(@byte-write 100) ;d +(@byte-write 33) ;! +(@byte-write 10) ; (newline) diff --git a/cs420-acc/l3-warmup/examples/life.l3 b/cs420-acc/l3-warmup/examples/life.l3 new file mode 100644 index 0000000..7193fa9 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/life.l3 @@ -0,0 +1,139 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Conway's game of life +;; (https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) + +;; Notice that this program uses: +;; - ANSI escape sequences, and so require a compatible terminal, +;; - Unicode Block Elements [1], and so require a font supporting them. +;; +;; [1] https://unicode-table.com/en/blocks/block-elements/ + +(def board-make@3 + (fun (w h c) + (let ((b (@block-alloc-100 3))) + (@block-set! b 0 w) + (@block-set! b 1 h) + (@block-set! b 2 c) + b))) + +(def board-make@2 + (fun (w h) + (board-make w h (vector-make (* w h) #f)))) + +(def board-width + (fun (b) (@block-get b 0))) + +(def board-height + (fun (b) (@block-get b 1))) + +(def board-cells + (fun (b) (@block-get b 2))) + +(def board-cell-index + (fun (b x y) + (let ((x1 (%f x (board-width b))) + (y1 (%f y (board-height b)))) + (+ x1 (* y1 (board-width b)))))) + +(def board-get + (fun (b x y) + (vector-get (board-cells b) (board-cell-index b x y)))) + +(def board-get/int + (fun (b x y) + (if (board-get b x y) 1 0))) + +(def board-set! + (fun (b x y v) + (vector-set! (board-cells b) (board-cell-index b x y) v))) + +(def live-neighbors-count + (let ((offsets (list-make (pair-make -1 -1) + (pair-make -1 0) + (pair-make -1 1) + (pair-make 0 -1) + (pair-make 0 1) + (pair-make 1 -1) + (pair-make 1 0) + (pair-make 1 1)))) + (fun (b x y) + (list-fold-left + (fun (c os) + (+ c + (board-get/int b (+ x (pair-fst os)) (+ y (pair-snd os))))) + 0 + offsets)))) + +(def evolve-board + (fun (b) + (let ((b1 (board-make (board-width b) (board-height b)))) + (rec loop ((x (- (board-width b) 1)) + (y (- (board-height b) 1))) + (let* ((n (live-neighbors-count b x y)) + (s (or (= n 3) (and (= n 2) (board-get b x y))))) + (board-set! b1 x y s) + (cond ((> y 0) (loop x (- y 1))) + ((> x 0) (loop (- x 1) (- (board-height b) 1))) + (#t b1))))))) + +(def draw-board + (let ((code " ▗▖▄▝▐▞▟▘▚▌▙▀▜▛█")) + (fun (b) + (rec loop ((y 0) (x 0)) + (let* ((b0 (board-get/int b (+ x 1) (+ y 1))) + (b1 (board-get/int b x (+ y 1))) + (b2 (board-get/int b (+ x 1) y)) + (b3 (board-get/int b x y)) + (i (int-bitwise-or + (int-shift-left b3 3) + (int-shift-left b2 2) + (int-shift-left b1 1) + (int-shift-left b0 0)))) + (char-print (string-get code i)) + (cond ((< x (- (board-width b) 1)) + (loop y (+ x 2))) + ((< y (- (board-height b) 1)) + (newline-print) + (loop (+ y 2) 0)) + (#t + (newline-print)))))))) + +(defrec animate-life + (fun (b n) + (string-print "") ;clear screen + (string-print "") ;set black background, white foreground + (string-print "[?25l") ;hide cursor + (rec loop ((b b) (n n)) + (string-print "") ;move to top-left + (draw-board b) + (if (> n 0) + (loop (evolve-board b) (- n 1)))))) + +(def b (board-make 158 68)) +(def glider-ul + (fun (b x y) + (board-set! b (+ x 1) (+ y 2) #t) + (board-set! b (+ x 2) (+ y 1) #t) + (board-set! b (+ x 0) (+ y 0) #t) + (board-set! b (+ x 1) (+ y 0) #t) + (board-set! b (+ x 2) (+ y 0) #t))) + +(def glider-dr + (fun (b x y) + (board-set! b (+ x 1) (+ y 0) #t) + (board-set! b (+ x 2) (+ y 1) #t) + (board-set! b (+ x 0) (+ y 2) #t) + (board-set! b (+ x 1) (+ y 2) #t) + (board-set! b (+ x 2) (+ y 2) #t))) + +(glider-dr b 4 4) +(glider-dr b 10 5) +(glider-ul b 13 15) +(glider-ul b 5 20) +(glider-ul b 17 22) +(glider-ul b 23 5) +(glider-ul b 2 7) +(glider-ul b 19 33) + +(animate-life b 5000) diff --git a/cs420-acc/l3-warmup/examples/life.l3m b/cs420-acc/l3-warmup/examples/life.l3m new file mode 100644 index 0000000..6a4939d --- /dev/null +++ b/cs420-acc/l3-warmup/examples/life.l3m @@ -0,0 +1,2 @@ +../library/lib.l3m +life.l3 diff --git a/cs420-acc/l3-warmup/examples/maze.l3 b/cs420-acc/l3-warmup/examples/maze.l3 new file mode 100644 index 0000000..776154e --- /dev/null +++ b/cs420-acc/l3-warmup/examples/maze.l3 @@ -0,0 +1,189 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +(defrec print-n-char + (fun (n c) + (if (> n 0) + (begin + (char-print c) + (print-n-char (- n 1) c))))) + +(defrec contains + (fun (l elem) + (and (not (list-empty? l)) + (or (= (list-head l) elem) + (contains (list-tail l) elem))))) + +(defrec shuffle + (fun (l seed) + (let ((v (list->vector l))) + (vector-shuffle! v seed) + (vector->list v)))) + +;; Cells + +(def cell + (fun (r c s) + (+ (* r s) c))) + +(def atE + (fun (c s) + (+ c 1))) + +(def atW + (fun (c s) + (- c 1))) + +(def atN + (fun (c s) + (- c s))) + +(def atS + (fun (c s) + (+ c s))) + +;; Walls +;; Represented as a pair of 15-bits integers (cell indices), packed in +;; a single one. + +(def wall-make + (fun (c1 c2) + (int-bitwise-or (int-shift-left c1 15) c2))) + +(def wall-cell-1 + (fun (w) + (int-shift-right w 15))) + +(def wall-cell-2 + (fun (w) + (int-bitwise-and w #x7FFF))) + +(def wall-up? + (fun (c1 c2 w) + (contains w (wall-make c1 c2)))) + + +;; Create a maze that has walls everywhere +(defrec completeMaze-acc + (fun (r c s acc) + (if (< r s) + (if (< c s) + (let* ((rc (cell r c s)) + (res1 (if (< c (- s 1)) + (list-prepend (wall-make (cell r c s) (atE rc s)) acc) + acc)) + (res2 (if (< r (- s 1)) + (list-prepend (wall-make (cell r c s) (atS rc s)) res1) + res1))) + (completeMaze-acc r (+ c 1) s res2)) + (completeMaze-acc (+ r 1) 0 s acc)) + acc))) + +(def completeMaze + (fun (s) + (completeMaze-acc 0 0 s list-empty))) + +;; Create a list of singleton lists for each cell of the maze +(defrec fullyDisconnectedSets-acc + (fun (r c s acc) + (if (< r s) + (if (< c s) + (let ((res (list-prepend (list-make (cell r c s)) acc))) + (fullyDisconnectedSets-acc r (+ c 1) s res)) + (fullyDisconnectedSets-acc (+ r 1) 0 s acc)) + acc))) + +(def fullyDisconnectedSets + (fun (s) + (fullyDisconnectedSets-acc 0 0 s list-empty))) + +(defrec connected + (fun (sets c1 c2) + (and (not (= sets list-empty)) + (let ((set (list-head sets))) + (or (and (contains set c1) + (contains set c2)) + (connected (list-tail sets) c1 c2)))))) + +;; return the first element that satisfies p +(def find + (fun (p l) + (let ((res (list-filter p l))) + (if (list-empty? res) + res + (list-head res))))) + +(def connect + (fun (sets c1 c2) + (let ((setOfC1 (find (fun (e) (contains e c1)) sets)) + (setOfC2 (find (fun (e) (contains e c2)) sets))) + (list-prepend (list-append setOfC1 setOfC2) + (list-filter (fun (e) + (and (not (contains e c1)) + (not (contains e c2)))) + sets))))) + +;; execute body for each int between from and to +(defrec for + (fun (from to body) + (if (< from to) + (begin + (body from) + (for (+ from 1) to body)) + 0))) + +(def print-maze + (fun (s w) + (let ((space ' ') + (wall 'X')) + (print-n-char (+ (* s 2) 1) wall) + (newline-print) + (for 0 s + (fun (r) + (char-print wall) + (for 0 s + (fun (c) + (char-print space) + (if (< c (- s 1)) + (let ((rc (cell r c s))) + (char-print (if (wall-up? rc (atE rc s) w) wall space))) + 0))) + (char-print wall) + (newline-print) + (if (< r (- s 1)) + (begin + (char-print wall) + (for 0 s + (fun (c) + (let ((rc (cell r c s))) + (char-print (if (wall-up? rc (atS rc s) w) wall space)) + (if (< c (- s 1)) + (char-print wall) + 0)))) + (char-print wall) + (newline-print)) + 0))) + (print-n-char (+ (* s 2) 1) wall) + (newline-print)))) + +(defrec random-maze-acc + (fun (m c acc) + (if (list-empty? m) + acc + (let ((w (list-head m))) + (if (connected c (wall-cell-1 w) (wall-cell-2 w)) + (random-maze-acc (list-tail m) c (list-prepend w acc)) + (random-maze-acc (list-tail m) (connect c (wall-cell-1 w) (wall-cell-2 w)) acc)))))) + + +(def random-maze + (fun (s seed) + (let ((m (shuffle (completeMaze s) seed)) + (c (fullyDisconnectedSets s))) + (random-maze-acc m c list-empty)))) + + +(string-print "Size: ") ; T +(let ((size (int-read))) + (string-print "Seed: ") ; G + (let ((seed (int-read))) + (print-maze size (random-maze size seed)))) diff --git a/cs420-acc/l3-warmup/examples/maze.l3m b/cs420-acc/l3-warmup/examples/maze.l3m new file mode 100644 index 0000000..3b9ec47 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/maze.l3m @@ -0,0 +1,2 @@ +../library/lib.l3m +maze.l3 diff --git a/cs420-acc/l3-warmup/examples/pascal.l3 b/cs420-acc/l3-warmup/examples/pascal.l3 new file mode 100644 index 0000000..6baee13 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/pascal.l3 @@ -0,0 +1,53 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Pascal's triangle + +(defrec zip + (fun (l1 l2) + (if (list-empty? l1) + list-empty + (list-prepend + (list-prepend (list-head l1) (list-head l2)) + (zip (list-tail l1) (list-tail l2)))))) + +(defrec %pascal + (fun (n) + (if (= n 1) + (list-make (list-make 1)) + (let* ((p (%pascal (- n 1))) + (p1 (zip (list-head p) (list-prepend 0 (list-head p)))) + (p2 (list-map (fun (pair) + (+ (list-head pair) (list-tail pair))) + p1))) + (list-prepend (list-append p2 (list-make 1)) p))))) + +(def pascal (fun (n) (list-reverse (%pascal n)))) + +(def list-int-print + (fun (l) + (char-print '(') + (list-for-each (fun (elem) + (int-print elem) + (char-print ' ')) + l) + (char-print ')'))) + +(def print-pascal + (fun (p) + (list-map + (fun (l) + (list-int-print l) + (newline-print)) + p))) + +(defrec tui + (fun () + (string-print "enter size (0 to exit)> ") + (let ((size (int-read))) + (if (= size 0) + 0 + (begin + (print-pascal (pascal size)) + (tui)))))) + +(tui) diff --git a/cs420-acc/l3-warmup/examples/pow.l3 b/cs420-acc/l3-warmup/examples/pow.l3 new file mode 100644 index 0000000..7abb08b --- /dev/null +++ b/cs420-acc/l3-warmup/examples/pow.l3 @@ -0,0 +1,4 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +(int-print (int-pow 3 12)) ; should print 531441 +(newline-print) diff --git a/cs420-acc/l3-warmup/examples/printint.l3 b/cs420-acc/l3-warmup/examples/printint.l3 new file mode 100644 index 0000000..24cc89f --- /dev/null +++ b/cs420-acc/l3-warmup/examples/printint.l3 @@ -0,0 +1,5 @@ +(string-print "Enter a number: ") +(let ((n (int-read))) + (string-print "You entered ") + (int-print n) + (newline-print)) diff --git a/cs420-acc/l3-warmup/examples/printint.l3m b/cs420-acc/l3-warmup/examples/printint.l3m new file mode 100644 index 0000000..e1952f5 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/printint.l3m @@ -0,0 +1,2 @@ +../library/lib.l3m +printint.l3 diff --git a/cs420-acc/l3-warmup/examples/queens.l3 b/cs420-acc/l3-warmup/examples/queens.l3 new file mode 100644 index 0000000..190e61d --- /dev/null +++ b/cs420-acc/l3-warmup/examples/queens.l3 @@ -0,0 +1,166 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; solutions are represented as integer list, where the index denotes the +;; row (from the bottom), the value the column. for example, the solution +;; for n = 4 +;; _ _ _ _ +;; | |o| | | +;; | | | |o| +;; |o| | | | +;; | | |o| | +;; +;; is represented as (3, 1, 4, 2) + +;; SOME USEFUL LIST FUNCTIONS + +(def list-range + (fun (f t) + (list-tabulate (+ 1 (- t f)) (fun (i) (+ f i))))) + +(def list-zip-with-index + (fun (l) + (list-zip l (list-range 1 (list-length l))))) + +(def list-int-print + (fun (l) + (char-print '(') + (list-for-each (fun (elem) + (int-print elem) + (char-print ' ')) + l) + (char-print ')'))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; CHECK IF NO TWO QUEENS IN A COLUMN + +;; essentially checks for duplicates +(defrec col-ok + (fun (rows) + (or (list-empty? rows) + (and (list-every? (fun (x) (not (= (list-head rows) x))) + (list-tail rows)) + (col-ok (list-tail rows)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; CHECK IF NO TWO QUEENS IN A DIAGONAL + +;; depth denotes how many rows x and y are separated +(def on-diag + (fun (x y depth) + (or (= (+ x depth) y) + (= (- x depth) y)))) + +(defrec diag-ok + (fun (rows) + (or (list-empty? rows) + (and (list-every? (fun (pair) + (not (on-diag (list-head rows) + (pair-fst pair) + (pair-snd pair)))) + (list-zip-with-index (list-tail rows))) ;; index is the row distance from (list-head rows) + (diag-ok (list-tail rows)))))) + +;;;;;;;;;;;;;;;;;;;;; +;; CHECKING SOLUTIONS + +(def partial-ok + (fun (rows) + (and (col-ok rows) + (diag-ok rows)))) + +;; not actually used in the algorithm below +(def queens-ok + (fun (rows n) + (and (list-every? (fun (x) (<= x n)) rows) ; no elt. bigger than n + (= n (list-length rows)) ; n queens + (partial-ok rows)))) ; no conflict + +;;;;;;;;;;;;;;;;;;;;; +;; FINDING A SOLUTION + +(def queens + (letrec ((%advance + (fun (partial n) + (if (< (list-head partial) n) + (%queens (list-prepend (+ 1 (list-head partial)) + (list-tail partial)) + n) ;; try next value of (list-head partial) + list-empty))) ;; there's no solution for (list-tail partial) + (%queens + (fun (partial n) + (if (partial-ok partial) + (if (= (list-length partial) n) + partial ;; partial solution with full length: we're done + (let ((sol (%queens (list-prepend 1 partial) n))) + (if (list-empty? sol) + (%advance partial n) + sol))) + (%advance partial n))))) + (fun (n) (%queens (list-make 1) n)))) + +;;;;;;;;;;; +;; PRINTING + +(defrec for + (fun (from to body) + (if (< from to) + (begin + (body from) + (for (+ from 1) to body))))) + +(def %header + (fun (rows) + (newline-print) + (int-print (list-length rows)) + (string-print "-queen(s)") + (newline-print) + (string-print "list: ") + (list-int-print (list-reverse rows)) + (newline-print) + (for 0 (list-length rows) + (fun (x) (string-print " _"))) + (newline-print))) + +(def %row + (fun (p n) + (for 0 n + (fun (x) + (string-print "|") + (string-print (if (= (+ x 1) p) "o" " ")))) + (string-print "|") + (newline-print))) + +(defrec %print-rows + (fun (rows n) + (if (= (list-length rows) n) + (%header rows)) + (if (list-empty? rows) + (newline-print) + (begin + (%row (list-head rows) n) + (%print-rows (list-tail rows) n))))) + +(def print-solution + (fun (rows) + (if (= (list-length rows) 0) + (begin + (string-print "no solution found!") + (newline-print)) + (%print-rows (list-reverse rows) (list-length rows))))) + +;;;;;;;;;;;;;;;;; +;; USER INTERFACE + +(defrec tui + (fun () + (string-print "enter size (0 to exit)> ") + (let ((size (int-read))) + (if (not (= size 0)) + (begin + (print-solution (queens size)) + (tui)))))) + + +;; "main" +(tui) + diff --git a/cs420-acc/l3-warmup/examples/queens.l3m b/cs420-acc/l3-warmup/examples/queens.l3m new file mode 100644 index 0000000..e413245 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/queens.l3m @@ -0,0 +1,2 @@ +../library/lib.l3m +queens.l3 diff --git a/cs420-acc/l3-warmup/examples/sudoku.l3 b/cs420-acc/l3-warmup/examples/sudoku.l3 new file mode 100644 index 0000000..24b530e --- /dev/null +++ b/cs420-acc/l3-warmup/examples/sudoku.l3 @@ -0,0 +1,317 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; brute force sudoku solver using backtracking + + +;; some list functions + +(defrec flat-map + (fun (f l) + (if (list-empty? l) + l + (list-append (f (list-head l)) (flat-map f (list-tail l)))))) + +(defrec index-of + (fun (p i l) + (if (list-empty? l) + -1 + (if (p (list-head l)) + i + (index-of p (+ i 1) (list-tail l)))))) + +(defrec list-n + (fun (init n) + (list-tabulate n (fun (i) init)))) + +(defrec list-get-value + (fun (list index) + (if (= 1 index) + (list-head list) + (list-get-value (list-tail list) (- index 1))))) + +(defrec list-set-value + (fun (list index value) + (if (= 1 index) + (list-prepend value (list-tail list)) + (list-prepend + (list-head list) + (list-set-value (list-tail list) (- index 1) value))))) + + +;; functions on tables + + +(def create-table + (fun (n) + (let ((size (* n n))) + (list-n (list-n 0 size) size)))) + + +(defrec transpose + (fun (table) + (if (list-empty? (list-head table)) + table + (list-prepend + (list-map (fun (row) (list-head row)) table) + (transpose (list-map (fun (row) (list-tail row)) table)))))) + + +(defrec table-get-value + (fun (table cell) + (if (= 1 (list-head cell)) + (list-get-value (list-head table) (list-tail cell)) + (table-get-value + (list-tail table) + (list-prepend (- (list-head cell) 1) (list-tail cell)))))) + + +(defrec table-set-value + (fun (table cell value) + (if (= 1 (list-head cell)) ;; current row? + (list-prepend + (list-set-value (list-head table) (list-tail cell) value) + (list-tail table)) + (list-prepend + (list-head table) + (table-set-value + (list-tail table) + (list-prepend (- (list-head cell) 1) (list-tail cell)) + value))))) + + +(defrec table-init + (fun (table cells values) + (if (list-empty? cells) + table + (table-init + (table-set-value table (list-head cells) (list-head values)) + (list-tail cells) + (list-tail values))))) + + +(defrec table-get-row + (fun (table i) + (if (= 1 i) + (list-head table) + (table-get-row (list-tail table) (- i 1))))) + +(def table-get-col + (fun (table i) + (table-get-row (transpose table) i))) + + +;;;;;;;;;;;;;;; +;; VERIFICATION + +;; no duplicates in the list (except 0's) +(defrec list-no-duplicates + (fun (list) + (if (list-empty? list) + #t + (and + (list-every? + (fun (x) (or (= x 0) (not (= (list-head list) x)))) + (list-tail list)) + (list-no-duplicates (list-tail list)))))) + +;; check if no duplicates in rows +(def rows-ok + (fun (table) + (list-every? + (fun (row) (list-no-duplicates row)) + table))) + +;; check if no duplicates in columns +(def cols-ok + (fun (table) + (rows-ok (transpose table)))) + + +;; blockrows contains the first n rows of a sudoku, e.g. +;; +-----+-----+ +;; | 1 2 | 3 4 | +;; | 3 4 | 1 2 | +;; +-----+-----+ +(defrec %blockrows-ok + (fun (blockrows n) + (if (list-empty? (list-head blockrows)) + #t + (and + (list-no-duplicates + (flat-map (fun (row) (list-take row n)) blockrows)) + (%blockrows-ok (list-map (fun (row) (list-drop row n)) blockrows) n))))) + + +;; check if no duplicates in blocks (n x n) +(defrec blocks-ok + (fun (table n) + (if (= 0 (list-length table)) + #t + (and + (%blockrows-ok (list-take table n) n) + (blocks-ok (list-drop table n) n))))) + + +;; no duplicates (but incomplete solution, i.e. with zeros) +(def partial-ok + (fun (table n) + (and (rows-ok table) + (cols-ok table) + (blocks-ok table n)))) + + +;; all numbers between 0 and n +(def numbers-ok + (fun (table n) + (list-every? + (fun (num) (and (> num 0) (<= num (* n n)))) + (flat-map (fun (row) row) table)))) + + +;; sudoku solved +(def table-ok + (fun (table n) + (and (rows-ok table) + (cols-ok table) + (numbers-ok table n) + (blocks-ok table n)))) + + + +;;;;;;;;;;; +;; PRINTING + +(defrec for + (fun (from to body) + (if (< from to) + (begin + (body from) + (for (+ from 1) to body)) + 0))) + + +(def %header + (fun (n) + (for 0 n + (fun (x) + (string-print "+") + (for 0 (+ (* n 2) 1) + (fun (x) (string-print "-"))))) + (string-print "+") + (newline-print))) + +(def %row + (fun (row n) + (for 0 (* n n) + (fun (x) + (if (= 0 (%t x n)) + (string-print "| ") + 0) + (let ((v (list-head (list-drop row x)))) + (if (= v 0) + (string-print " ") + (int-print v)) + (string-print " ")))) + (string-print "|") + (newline-print))) + + +(def print-table + (fun (rows n) + (int-print n) + (string-print "-sudoku") + (newline-print) + (for 0 n + (fun (x) + (%header n) + (for 0 n + (fun (y) + (%row (list-head (list-drop rows (+ (* x n) y))) n))))) + (%header n) + (newline-print))) + + + +;;;;;;;;;;;;;;;;;;;; +;; SOLVING ALGORITHM + + +(def %next-zero-cell + (fun (table) + (let* + ( (rowi + (index-of + (fun (row) (list-any? (fun (x) (= 0 x)) row)) + 1 + table)) + (row (list-head (list-drop table (- rowi 1)))) + (coli + (index-of + (fun (x) (= x 0)) + 1 + row))) + (list-prepend rowi coli)))) + + +(def sudoku + (letrec + ((%advance (fun (table cell n) + (let ((val (table-get-value table cell))) + (if (< val (* n n)) + (%sudoku (table-set-value table cell (+ val 1)) cell n) + list-empty)))) + ;; find solutions by trying values on 'cell' of 'table' + (%sudoku (fun (table cell n) + (if (and (> (table-get-value table cell) 0) (partial-ok table n)) + (if (numbers-ok table n) ;; partial solution with all numbers > 0: we're done + table + (let ((sol (%sudoku table (%next-zero-cell table) n))) + (if (list-empty? sol) + (%advance table cell n) + sol))) + (%advance table cell n))))) + (fun (table n) (%sudoku table (%next-zero-cell table) n)))) + +;;;;;;;;;;;;;;; +;; SOME TESTING + + +;; solution for +(def table2 + (list-make (list-make 1 2 3 4) (list-make 3 4 1 2) (list-make 2 1 4 3) (list-make 4 3 2 1))) + +;; sudoku from http://www.nzz.ch/magazin/unterhaltung/sudoku, 6.2.2009, schwer +(def nzz + (table-init + (create-table 3) + (list-append (list-make (list-prepend 1 1) (list-prepend 1 2) (list-prepend 1 6) (list-prepend 1 7) (list-prepend 2 1) (list-prepend 2 2) (list-prepend 2 5) (list-prepend 2 6) (list-prepend 2 8)) + (list-append (list-make (list-prepend 2 9) (list-prepend 3 2) (list-prepend 3 3) (list-prepend 3 6) (list-prepend 3 8) (list-prepend 4 5) (list-prepend 4 8) (list-prepend 5 6) (list-prepend 5 7)) + (list-append (list-make (list-prepend 6 3) (list-prepend 6 5) (list-prepend 6 9) (list-prepend 7 3) (list-prepend 7 4) (list-prepend 7 6) (list-prepend 7 8) (list-prepend 8 1) (list-prepend 8 2)) + (list-make (list-prepend 9 1) (list-prepend 9 6) (list-prepend 9 7))))) + (list-append (list-make 1 9 5 4 6 3 9 2 7) + (list-append (list-make 8 5 7 6 2 4 9 7 2) + (list-append (list-make 3 1 7 1 8 4 6 4 8) + (list-make 7 1 3)))))) + + +;; example sudoku (very hard to solve for brute force algorithm), from +;; http://en.wikipedia.org/wiki/Algorithmics_of_sudoku#Solving_sudokus_by_a_brute-force_algorithm +(def hard + (table-init + (create-table 3) + (list-append (list-make (list-prepend 2 6) (list-prepend 2 8) (list-prepend 2 9) (list-prepend 3 3) (list-prepend 3 5) (list-prepend 4 4) (list-prepend 4 6) (list-prepend 5 3) (list-prepend 5 7)) + (list-make (list-prepend 6 2) (list-prepend 7 1) (list-prepend 7 8) (list-prepend 7 9) (list-prepend 8 3) (list-prepend 8 5) (list-prepend 9 5) (list-prepend 9 9))) + (list-append (list-make 3 8 5 1 2 5 7 4 1) (list-make 9 5 7 3 2 1 4 9)))) + + +;; empty 2-sudoku (quick) +(print-table (sudoku (create-table 2) 2) 2) + +;; empty 3-sudoku (some seconds) +(print-table (sudoku (create-table 3) 3) 3) + +;; nzz 3-sudoku (some seconds) +(print-table (sudoku nzz 3) 3) + +;; very hard 3-sudoku (about an hour?) +;; (print-table (sudoku hard 3) 3) diff --git a/cs420-acc/l3-warmup/examples/sudoku.l3m b/cs420-acc/l3-warmup/examples/sudoku.l3m new file mode 100644 index 0000000..65fad96 --- /dev/null +++ b/cs420-acc/l3-warmup/examples/sudoku.l3m @@ -0,0 +1,2 @@ +../library/lib.l3m +sudoku.l3 diff --git a/cs420-acc/l3-warmup/examples/unimaze.l3 b/cs420-acc/l3-warmup/examples/unimaze.l3 new file mode 100644 index 0000000..b11504f --- /dev/null +++ b/cs420-acc/l3-warmup/examples/unimaze.l3 @@ -0,0 +1,221 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Build and display random maze, using Kruskal's spanning-tree algorithm. +;; See https://en.wikipedia.org/wiki/Kruskal's_algorithm + +;; Uses Unicode's box-drawing characters for display. + +;; Cells +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Maze cells are identified by their row and column indices in the +;; maze. Rows and columns are numbered from 0, the origin being the +;; top-left cell, as illustrated below: +;; +;; |-------+-------+-------+-----| +;; | (0,0) | (0,1) | (0,2) | ... | +;; |-------+-------+-------+-----| +;; | (1,0) | (1,1) | (1,2) | ... | +;; |-------+-------+-------+-----| +;; | ... | | | | +;; +;; The two indices are represented as 15-bits (unsigned) integers, +;; packed in a single 30-bits integer. The row index is put in the +;; high-order bits, the column index in the low-order bits. + +(def cell-make + (fun (r c) + (int-bitwise-or (int-shift-left r 15) + c))) + +(def cell-row + (fun (i) + (int-shift-right i 15))) + +(def cell-column + (fun (i) + (int-bitwise-and i #x7FFF))) + +(def cell= =) +(def cell< <) + +;; Return true iff the cell is an exterior cell (i.e. it is surrounded +;; by less than eight neighboring cells). +(def cell-exterior? + (fun (cell rows columns) + (let ((r (cell-row cell)) + (c (cell-column cell))) + (or (= 0 r) (= (- rows 1) r) + (= 0 c) (= (- columns 1) c))))) + +(def cell-interior? + (fun (cell rows columns) + (not (cell-exterior? cell rows columns)))) + +;; Walls +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Walls are represented by the two cells they separate. The two cells +;; are stored in a pair, with the smaller one first, to ensure that +;; each wall has a unique representation. + +(defrec wall-make + (fun (c1 c2) + ;; (require (cell-index-valid? c1)) + ;; (require (cell-index-valid? c2)) + (if (cell< c1 c2) + (pair-make c1 c2) + (wall-make c2 c1)))) + +(def wall-cell-1 pair-fst) +(def wall-cell-2 pair-snd) + +(def wall= (pair-derive= cell= cell=)) +(def wall< (pair-derive< cell< cell<)) + +;; Maze +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(def maze-make + (fun (rows columns walls) + (let ((m (vector-make 3))) + (vector-set! m 0 rows) + (vector-set! m 1 columns) + (vector-set! m 2 walls) + m))) + +(def maze-rows + (fun (maze) (vector-get maze 0))) + +(def maze-columns + (fun (maze) (vector-get maze 1))) + +(def maze-walls + (fun (maze) (vector-get maze 2))) + +;; Maze building +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Return the list of all walls for a maze with the given number of +;; [rows] and [columns]. Notice that only walls separating two cells +;; of the maze are returned (e.g. those on the outside, separating +;; cells with the surroundings of the maze, are not returned as they +;; cannot be represented). +(def all-walls + (fun (rows columns) + (let ((last-row (- rows 1)) + (last-column (- columns 1))) + (rec loop ((r 0) (c 0) (walls list-empty)) + (cond ((= r last-row) + walls) + ((= c last-column) + (loop (+ r 1) 0 walls)) + (#t + (let* ((cell (cell-make r c)) + (wall-E (wall-make cell (cell-make r (+ c 1)))) + (walls (list-prepend wall-E walls)) + (wall-S (wall-make cell (cell-make (+ r 1) c))) + (walls (list-prepend wall-S walls))) + (loop r (+ c 1) walls)))))))) + +(def maze-build-random-connected + (fun (rows columns rng-seed) + (let* ((wall-interiority + (fun (w) + (let ((c1 (wall-cell-1 w)) + (c2 (wall-cell-2 w))) + (+ (if (cell-interior? c1 rows columns) 1 0) + (if (cell-interior? c2 rows columns) 1 0))))) + (wall-interior? (fun (w) (= (wall-interiority w) 2))) + (wall-exterior? (fun (w) (= (wall-interiority w) 0))) + (icell-index (fun (cell) + (let ((r (cell-row cell)) + (c (cell-column cell))) + (+ (* (- columns 2) (- r 1)) + (- c 1))))) + (icells-count (* (- rows 1) (- columns 1)))) + + (let* ((non-ext-walls (list-filter (fun (w) + (not (wall-exterior? w))) + (all-walls rows columns))) + (int/bnd-walls (list-partition wall-interior? non-ext-walls)) + (int-walls (list->vector (pair-fst int/bnd-walls)))) + (vector-shuffle! int-walls rng-seed) + (let* ((icells-sets (vector-tabulate icells-count + (fun (_) (diset-make)))) + (kept-walls + (vector-fold-left + (fun (ws w) + (let* ((c1 (wall-cell-1 w)) + (e1 (vector-get icells-sets + (icell-index c1))) + (c2 (wall-cell-2 w)) + (e2 (vector-get icells-sets + (icell-index c2)))) + (if (diset-same? e1 e2) + (list-prepend w ws) + (begin + (diset-merge! e1 e2) + ws)))) + list-empty + int-walls))) + (maze-make rows + columns + (list-append (pair-snd int/bnd-walls) + kept-walls))))))) + + +;; Maze printing +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(def char-for-walls + (let ((wall-chars " ╵╶└╷│┌├╴┘─┴┐┤┬┼")) + (fun (n e s w) + (string-get wall-chars + (+ (if n #b0001 0) + (if e #b0010 0) + (if s #b0100 0) + (if w #b1000 0)))))) + +(def maze-print + (fun (maze) + (let ((last-row (- (maze-rows maze) 1)) + (last-column (- (maze-columns maze) 1)) + (has-wall? + (let ((sorted-walls (begin + (let ((ws (list->vector + (maze-walls maze)))) + (vector-sort! ws wall<) + ws)))) + (fun (c1 c2) + (let ((w (wall-make c1 c2))) + (>= (vector-binary-search sorted-walls w wall<) + 0)))))) + (rec loop ((r 0) (c 0)) + (cond ((= r last-row) + #u) + ((= c last-column) + (newline-print) + (loop (+ r 1) 0)) + (#t + (let ((c-tl (cell-make r c)) + (c-tr (cell-make r (+ c 1))) + (c-bl (cell-make (+ r 1) c)) + (c-br (cell-make (+ r 1) (+ c 1)))) + (let ((w-n (has-wall? c-tl c-tr)) + (w-e (has-wall? c-tr c-br)) + (w-s (has-wall? c-br c-bl)) + (w-w (has-wall? c-bl c-tl))) + (char-print (char-for-walls w-n w-e w-s w-w)) + (loop r (+ c 1)))))))))) + +(def int-read/prompt + (fun (prompt) + (string-print prompt) + (int-read))) + +(let* ((columns (int-read/prompt " Maze width: ")) + (rows (int-read/prompt "Maze height: ")) + (seed (int-read/prompt "Random seed: "))) + (maze-print + (maze-build-random-connected rows columns seed))) diff --git a/cs420-acc/l3-warmup/examples/unimaze.l3m b/cs420-acc/l3-warmup/examples/unimaze.l3m new file mode 100644 index 0000000..e72f5db --- /dev/null +++ b/cs420-acc/l3-warmup/examples/unimaze.l3m @@ -0,0 +1,2 @@ +../library/lib.l3m +unimaze.l3 diff --git a/cs420-acc/l3-warmup/library/README.org b/cs420-acc/l3-warmup/library/README.org new file mode 100644 index 0000000..ec4d9fe --- /dev/null +++ b/cs420-acc/l3-warmup/library/README.org @@ -0,0 +1,55 @@ +#+OPTIONS: toc:nil author:nil +#+TITLE: The L₃ library + +* Introduction + +This directory contains a basic library for L₃. It defines two kinds of modules: + + 1. Modules providing functions on values of the built-in types (unit, booleans, characters and integers). + + 2. Modules providing new types and functions to operate on these types. All these types are represented as tagged blocks. + +* Modules + +The table below lists the modules belonging to the standard library, their prefix and the block tag(s) they use, if any. Both the prefix and the tag(s) must be globally unique. + +Modules for predefined, tagged types: + +|--------------+-----------+--------------------------------------------| +| Module | Prefix | Note | +|--------------+-----------+--------------------------------------------| +| =booleans= | =boolean= | | +| =characters= | =char= | | +| =integers= | =int= | Operators (+, <, ...) don't use the prefix | +| =unit= | =unit= | | +|--------------+-----------+--------------------------------------------| + +Modules for additional types, predefined or not but represented as tagged blocks with the given tag(s): + +|-----------------+------------+--------| +| Module | Prefix | Tag(s) | +|-----------------+------------+--------| +| =pairs= | =pair= | 0 | +| =vectors= | =vector= | 1 | +| =lists= | =list= | 2,3 | +| =disjoint-sets= | =diset= | 4 | +| =random= | =rng= | 50 | +| =strings= | =string= | 200 | +| =functions= | =function= | 202 | +|-----------------+------------+--------| + +A meta-module called =lib= requires all the above modules. + +* Naming conventions + +With a few exceptions, all entities defined by the various modules obey the following naming conventions: + + - Entities defined in a module have a name starting with the (globally unique) prefix assigned to that module, given in the tables above. + + - Private entities that are not meant to be used outside of the module they are defined in have a name starting with a "%", followed by the module prefix. + + - Functions with side-effect have a name ending with a "!". + + - Predicates (functions returning a boolean) have a name ending with a "?". Type-testing predicates are simply named by concatenating the prefix of that type with a "?". + + - Conversion functions from a type t1 to a type t2 have a name formed by concatenating the prefix of t1, the string "->" and the prefix of t2. diff --git a/cs420-acc/l3-warmup/library/booleans.l3 b/cs420-acc/l3-warmup/library/booleans.l3 new file mode 100644 index 0000000..e535e4c --- /dev/null +++ b/cs420-acc/l3-warmup/library/booleans.l3 @@ -0,0 +1,5 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Booleans + +(def boolean? (fun (o) (@bool? o))) diff --git a/cs420-acc/l3-warmup/library/booleans.l3m b/cs420-acc/l3-warmup/library/booleans.l3m new file mode 100644 index 0000000..e70bc3d --- /dev/null +++ b/cs420-acc/l3-warmup/library/booleans.l3m @@ -0,0 +1 @@ +booleans.l3 diff --git a/cs420-acc/l3-warmup/library/characters.l3 b/cs420-acc/l3-warmup/library/characters.l3 new file mode 100644 index 0000000..9ca20ac --- /dev/null +++ b/cs420-acc/l3-warmup/library/characters.l3 @@ -0,0 +1,89 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Characters + +(def newline (@int->char 10)) + +(def char? (fun (o) (@char? o))) + +(def char->int (fun (c) + (@char->int c))) + +(def int->char (fun (c) + (@int->char c))) + +(def char-read + (let ((read-cont-byte (fun () (@and (@byte-read) #b00111111))) + (<< (fun (x y) (@shift-left x y))) + (b-and (fun (x y) (@and x y))) + (b-or@2 (fun (x y) (@or x y))) + (b-or@3 (fun (x y z) (@or (@or x y) z))) + (b-or@4 (fun (x y z t) (@or (@or x y) (@or z t)))) + (= (fun (x y) (@= x y)))) + (fun () + (let ((b0 (@byte-read))) + (cond + ((= -1 b0) ;EOF + #f) + ((= 0 (b-and #b10000000 b0)) ;1 byte + (int->char b0)) + ((= #b11000000 (b-and #b11100000 b0)) ;2 bytes + (let ((b1 (read-cont-byte))) + (int->char (b-or (<< (b-and #b11111 b0) 6) + b1)))) + ((= #b11100000 (b-and #b11110000 b0)) ;3 bytes + (let ((b1 (read-cont-byte)) + (b2 (read-cont-byte))) + (int->char (b-or (<< (b-and #b1111 b0) 12) + (<< b1 6) + b2)))) + (#t ;4 bytes + (let ((b1 (read-cont-byte)) + (b2 (read-cont-byte)) + (b3 (read-cont-byte))) + (int->char (b-or (<< (b-and #b111 b0) 18) + (<< b1 12) + (<< b2 6) + b3))))))))) + +(def char-print + (let ((<= (fun (x y) (@<= x y))) + (>> (fun (x y) (@shift-right x y))) + (b-and (fun (x y) (@and x y))) + (b-or (fun (x y) (@or x y)))) + (fun (c) + (let ((p (char->int c))) + (cond + ((<= p #x00007F) ;1 byte + (@byte-write p)) + ((<= p #x0007FF) ;2 bytes + (@byte-write (b-or #b11000000 (>> p 6))) + (@byte-write (b-or #b10000000 (b-and p #b111111)))) + ((<= p #x00FFFF) ;3 bytes + (@byte-write (b-or #b11100000 (>> p 12))) + (@byte-write (b-or #b10000000 (b-and (>> p 6) #b111111))) + (@byte-write (b-or #b10000000 (b-and p #b111111)))) + (#t ;4 bytes + (@byte-write (b-or #b11110000 (>> p 18))) + (@byte-write (b-or #b10000000 (b-and (>> p 12) #b111111))) + (@byte-write (b-or #b10000000 (b-and (>> p 6) #b111111))) + (@byte-write (b-or #b10000000 (b-and p #b111111))))))))) + +(def newline-print (fun () (char-print newline))) + +(def char-digit? + (let ((int-0 (@char->int '0')) + (int-9 (@char->int '9'))) + (fun (c) + (let ((int-c (@char->int c))) + (and (@<= int-0 int-c) (@<= int-c int-9)))))) + +(def char-digit->int + (let ((int-0 (@char->int '0'))) + (fun (c) + (@- (@char->int c) int-0)))) + +(def int->char-digit + (let ((int-0 (@char->int '0'))) + (fun (i) + (@int->char (@+ i int-0))))) diff --git a/cs420-acc/l3-warmup/library/characters.l3m b/cs420-acc/l3-warmup/library/characters.l3m new file mode 100644 index 0000000..b21563d --- /dev/null +++ b/cs420-acc/l3-warmup/library/characters.l3m @@ -0,0 +1 @@ +characters.l3 diff --git a/cs420-acc/l3-warmup/library/disjoint-sets.l3 b/cs420-acc/l3-warmup/library/disjoint-sets.l3 new file mode 100644 index 0000000..f7eb16b --- /dev/null +++ b/cs420-acc/l3-warmup/library/disjoint-sets.l3 @@ -0,0 +1,60 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Mutable disjoint sets / equivalence classes (a.k.a. "union-find"). +;; See https://en.wikipedia.org/wiki/Disjoint-set_data_structure + +(def diset-make + (fun () + (let ((e (@block-alloc-4 2))) + (@block-set! e 0 #f) ;parent (#f for representative) + (@block-set! e 1 1) ;rank + e))) + +(def %diset-parent + (fun (e) + (@block-get e 0))) + +(def %diset-set-parent! + (fun (e p) + (@block-set! e 0 p) + #u)) + +(def %diset-rank + (fun (e) + (@block-get e 1))) + +(def %diset-set-rank! + (fun (e r) + (@block-set! e 1 r) + #u)) + +(defrec %diset-repr + (fun (e) + (let ((maybe-parent (%diset-parent e))) + (if maybe-parent + (let ((repr (%diset-repr maybe-parent))) + (%diset-set-parent! e repr) ;path compression + repr) + e)))) + +(def diset? + (fun (o) + (and (@block? o) (= 4 (@block-tag o))))) + +(def diset-merge! + (fun (e1 e2) + (let ((repr1 (%diset-repr e1)) + (repr2 (%diset-repr e2))) + (if (!= repr1 repr2) + (let ((rank1 (%diset-rank repr1)) (rank2 (%diset-rank repr2))) + (cond ((< rank1 rank2) + (%diset-set-parent! repr1 repr2)) + ((< rank2 rank1) + (%diset-set-parent! repr2 repr1)) + (#t ;(= rank1 rank2) + (%diset-set-parent! repr1 repr2) + (%diset-set-rank! repr2 (+ 1 rank2))))))))) + +(def diset-same? + (fun (e1 e2) + (= (%diset-repr e1) (%diset-repr e2)))) diff --git a/cs420-acc/l3-warmup/library/disjoint-sets.l3m b/cs420-acc/l3-warmup/library/disjoint-sets.l3m new file mode 100644 index 0000000..5786c13 --- /dev/null +++ b/cs420-acc/l3-warmup/library/disjoint-sets.l3m @@ -0,0 +1,2 @@ +integers.l3 +disjoint-sets.l3 diff --git a/cs420-acc/l3-warmup/library/functions.l3 b/cs420-acc/l3-warmup/library/functions.l3 new file mode 100644 index 0000000..c8186f5 --- /dev/null +++ b/cs420-acc/l3-warmup/library/functions.l3 @@ -0,0 +1,11 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Functions + +(def function? + (fun (o) + (and (@block? o) (@= 202 (@block-tag o))))) + +(def function-compose + (fun (f g) + (fun (x) (f (g x))))) diff --git a/cs420-acc/l3-warmup/library/functions.l3m b/cs420-acc/l3-warmup/library/functions.l3m new file mode 100644 index 0000000..e0da19a --- /dev/null +++ b/cs420-acc/l3-warmup/library/functions.l3m @@ -0,0 +1 @@ +functions.l3 \ No newline at end of file diff --git a/cs420-acc/l3-warmup/library/integers.l3 b/cs420-acc/l3-warmup/library/integers.l3 new file mode 100644 index 0000000..067fe96 --- /dev/null +++ b/cs420-acc/l3-warmup/library/integers.l3 @@ -0,0 +1,158 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Integers + +(def int? (fun (o) (@int? o))) + +;; Basic arithmetic +(def +@2 (fun (x y) (@+ x y))) +(def +@3 (fun (x y z) (@+ x (@+ y z)))) +(def +@4 (fun (x y z t) (@+ (@+ x y) (@+ z t)))) +(def + +@2) + +(def -@1 (fun (x) (@- 0 x))) +(def -@2 (fun (x y) (@- x y))) +(def - -@2) + +(def *@2 (fun (x y) (@* x y))) +(def *@3 (fun (x y z) (@* x (@* y z)))) +(def *@4 (fun (x y z t) (@* (@* x y) (@* z t)))) +(def * *@2) + +;; Truncated division +(def /t (fun (x y) (@/ x y))) +(def %t (fun (x y) (@% x y))) + +;; Comparisons +(def <@2 (fun (x y) (@< x y))) +(def <@3 (fun (x y z) (and (@< x y) (@< y z)))) +(def < <@2) + +(def <=@2 (fun (x y) (@<= x y))) +(def <=@3 (fun (x y z) (and (@<= x y) (@<= y z)))) +(def <= <=@2) + +(def >@2 (fun (x y) (@< y x))) +(def >@3 (fun (x y z) (and (> x y) (> y z)))) +(def > >@2) + +(def >=@2 (fun (x y) (@<= y x))) +(def >=@3 (fun (x y z) (and (>= x y) (>= y z)))) +(def >= >=@2) + +(def = (fun (x y) (@= x y))) +(def != (fun (x y) (not (@= x y)))) + +(def int-min (fun (x y) (if (<= x y) x y))) +(def int-max (fun (x y) (if (>= x y) x y))) + +;; Bitwise operations +(def int-shift-left (fun (x y) (if (>= y 31) 0 (@shift-left x y)))) + +(def int-shift-right (fun (x y) (if (>= y 31) 0 (@shift-right x y)))) + +(def int-bitwise-and (fun (x y) (@and x y))) +(def int-bitwise-or@2 (fun (x y) (@or x y))) +(def int-bitwise-or@3 (fun (x y z) (@or (@or x y) z))) +(def int-bitwise-or@4 (fun (x y z t) (@or (@or x y) (@or z t)))) +(def int-bitwise-or int-bitwise-or@2) +(def int-bitwise-xor (fun (x y) (@xor x y))) +(def int-bitwise-not (fun (x) (@xor x #x7FFFFFFF))) + +;; Return a mask for the n least-significant bits +(def int-mask + (fun (n) (- (int-shift-left 1 n) 1))) + +;; Extract n bits from x, starting from bit s +(def int-extract + (fun (x s n) + (int-bitwise-and (int-shift-right x s) (int-mask n)))) + +(def int-even? + (fun (i) + (= 0 (int-bitwise-and 1 i)))) + +(def int-odd? + (fun (i) + (not (int-even? i)))) + +(def int-abs + (fun (i) + (if (< i 0) (- i) i))) + +(def int-signum + (fun (i) + (cond ((< i 0) -1) + ((= i 0) 0) + (#t 1)))) + +;; Adapted from "Hacker's Delight" by Henry Warren (2nd ed.) +(def int-count-leading-zeros + (fun (i) + (if (< i 0) + 0 + (rec loop ((i i) (n 31) (c 16)) + (if (= 0 c) + (- n i) + (let ((y (@shift-right i c))) + (if (= 0 y) + (loop i n (@shift-right c 1)) + (loop y (- n c) (@shift-right c 1))))))))) + +;; Floored division +(def /f + (fun (x y) + (let ((qt (/t x y)) (rt (%t x y))) + (if (= (int-signum rt) (- (int-signum y))) + (- qt 1) + qt)))) + +(def %f + (fun (x y) + (let ((rt (%t x y))) + (if (= (int-signum rt) (- (int-signum y))) + (+ rt y) + rt)))) + +(def int-gcd + (fun (x y) + (rec loop ((x (int-abs x)) + (y (int-abs y))) + (if (= 0 y) + x + (loop y (%t x y)))))) + +(def int-pow + (fun (x y) + (rec loop ((x x) (y y)) + (cond ((= 0 y) + 1) + ((int-even? y) + (let ((t (loop x (/t y 2)))) + (* t t))) + (#t + (* x (loop x (- y 1)))))))) + +(def int-read + (letrec ((loop + (fun (acc-f acc) + (let ((c (char-read))) + (if (char-digit? c) + (loop acc-f (acc-f (* acc 10) (char-digit->int c))) + acc))))) + (fun () + (let ((c (char-read))) + (cond ((= c '-') (loop - 0)) + ((char-digit? c) (loop + (char-digit->int c))) + (#t 0)))))) + +(def int-print + (fun (i) + (if (< i 0) (char-print '-')) + (rec loop ((i (int-abs i))) + (if (> i 9) (loop (/t i 10))) + (char-print (int->char-digit (%t i 10)))))) + +(def int->char + (fun (i) + (@int->char i))) diff --git a/cs420-acc/l3-warmup/library/integers.l3m b/cs420-acc/l3-warmup/library/integers.l3m new file mode 100644 index 0000000..c7e1173 --- /dev/null +++ b/cs420-acc/l3-warmup/library/integers.l3m @@ -0,0 +1,2 @@ +characters.l3m +integers.l3 diff --git a/cs420-acc/l3-warmup/library/lib.l3m b/cs420-acc/l3-warmup/library/lib.l3m new file mode 100644 index 0000000..57ac470 --- /dev/null +++ b/cs420-acc/l3-warmup/library/lib.l3m @@ -0,0 +1,14 @@ +;; Main meta-module for the L₃ library. + +booleans.l3m +characters.l3m +functions.l3m +integers.l3m +lists.l3m +disjoint-sets.l3m +pairs.l3m +random.l3m +strings.l3m +unit.l3m +vectors.l3m + diff --git a/cs420-acc/l3-warmup/library/lists.l3 b/cs420-acc/l3-warmup/library/lists.l3 new file mode 100644 index 0000000..5a27de0 --- /dev/null +++ b/cs420-acc/l3-warmup/library/lists.l3 @@ -0,0 +1,170 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; (Immutable) lists + +(def list? + (fun (o) + (and (@block? o) + (let ((tag (@block-tag o))) + (or (= tag 2) (= tag 3)))))) + +(def list-empty + (@block-alloc-2 0)) + +(def list-prepend + (fun (head tail) + (let ((l (@block-alloc-3 2))) + (@block-set! l 0 head) + (@block-set! l 1 tail) + l))) + +(def list-empty? + (fun (l) + (= 2 (@block-tag l)))) + +(def list-make@1 + (fun (e1) + (list-prepend e1 list-empty))) +(def list-make@2 + (fun (e1 e2) + (list-prepend e1 (list-make e2)))) +(def list-make@3 + (fun (e1 e2 e3) + (list-prepend e1 (list-make e2 e3)))) +(def list-make@4 + (fun (e1 e2 e3 e4) + (list-prepend e1 (list-make e2 e3 e4)))) +(def list-make@5 + (fun (e1 e2 e3 e4 e5) + (list-prepend e1 (list-make e2 e3 e4 e5)))) +(def list-make@6 + (fun (e1 e2 e3 e4 e5 e6) + (list-prepend e1 (list-make e2 e3 e4 e5 e6)))) +(def list-make@7 + (fun (e1 e2 e3 e4 e5 e6 e7) + (list-prepend e1 (list-make e2 e3 e4 e5 e6 e7)))) +(def list-make@8 + (fun (e1 e2 e3 e4 e5 e6 e7 e8) + (list-prepend e1 (list-make e2 e3 e4 e5 e6 e7 e8)))) +(def list-make@9 + (fun (e1 e2 e3 e4 e5 e6 e7 e8 e9) + (list-prepend e1 (list-make e2 e3 e4 e5 e6 e7 e8 e9)))) +(def list-make@10 + (fun (e1 e2 e3 e4 e5 e6 e7 e8 e9 e10) + (list-prepend e1 (list-make e2 e3 e4 e5 e6 e7 e8 e9 e10)))) + +(defrec list-tabulate + (fun (n f) + (rec loop ((i n) (l list-empty)) + (if (= i 0) + l + (loop (- i 1) (list-prepend (f (- i 1)) l)))))) + +(def list-head + (fun (l) + (@block-get l 0))) +(def list-tail + (fun (l) + (@block-get l 1))) + +(defrec list-length + (fun (l) + (if (list-empty? l) 0 (+ 1 (list-length (list-tail l)))))) + +(def list-for-each + (fun (f l) + (rec loop ((l l)) + (if (not (list-empty? l)) + (begin + (f (list-head l)) + (loop (list-tail l))))))) + +(def list-map + (fun (f l) + (rec loop ((l l)) + (if (list-empty? l) + l + (list-prepend (f (list-head l)) (loop (list-tail l))))))) + +(def list-fold-left + (fun (f z l) + (rec loop ((z z) (l l)) + (if (list-empty? l) + z + (loop (f z (list-head l)) (list-tail l)))))) + +(def list-fold-right + (fun (f z l) + (rec loop ((z z) (l l)) + (if (list-empty? l) + z + (f (list-head l) (loop z (list-tail l))))))) + +(def list-every? + (fun (p l) + (rec loop ((l l)) + (or (list-empty? l) + (and (p (list-head l)) + (loop (list-tail l))))))) + +(def list-any? + (fun (p l) + (rec loop ((l l)) + (and (not (list-empty? l)) + (or (p (list-head l)) + (loop (list-tail l))))))) + +(def list-filter + (fun (p l) + (list-fold-right (fun (e r) (if (p e) (list-prepend e r) r)) + list-empty + l))) + +(def list-partition + (fun (p l) + (list-fold-right + (fun (e y/n) + (if (p e) + (pair-make (list-prepend e (pair-fst y/n)) (pair-snd y/n)) + (pair-make (pair-fst y/n) (list-prepend e (pair-snd y/n))))) + (pair-make list-empty list-empty) + l))) + +(def list-take + (fun (l n) + (rec loop ((l l) (n n)) + (if (or (= 0 n) (list-empty? l)) + list-empty + (list-prepend (list-head l) (loop (list-tail l) (- n 1))))))) + +(def list-drop + (fun (l n) + (rec loop ((l l) (n n)) + (if (or (= 0 n) (list-empty? l)) + l + (loop (list-tail l) (- n 1)))))) + +(def list-nth + (fun (l n) + (list-head (list-drop l n)))) + +(def list-reverse + (fun (l) + (list-fold-left (fun (t h) (list-prepend h t)) list-empty l))) + +(def list-append + (fun (l1 l2) + (rec loop ((l1 l1) (l2 l2)) + (cond ((list-empty? l1) l2) + ((list-empty? l2) l1) + (#t (list-prepend (list-head l1) + (loop (list-tail l1) l2))))))) + +(def list-zip + (fun (l1 l2) + (rec loop ((l1 l1) (l2 l2)) + (if (or (list-empty? l1) (list-empty? l2)) + list-empty + (list-prepend + (pair-make (list-head l1) (list-head l2)) + (loop (list-tail l1) (list-tail l2))))))) diff --git a/cs420-acc/l3-warmup/library/lists.l3m b/cs420-acc/l3-warmup/library/lists.l3m new file mode 100644 index 0000000..b57803f --- /dev/null +++ b/cs420-acc/l3-warmup/library/lists.l3m @@ -0,0 +1,3 @@ +integers.l3m +pairs.l3m +lists.l3 diff --git a/cs420-acc/l3-warmup/library/pairs.l3 b/cs420-acc/l3-warmup/library/pairs.l3 new file mode 100644 index 0000000..0fb7d52 --- /dev/null +++ b/cs420-acc/l3-warmup/library/pairs.l3 @@ -0,0 +1,34 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Pairs + +(def pair-make (fun (fst snd) + (let ((p (@block-alloc-0 2))) + (@block-set! p 0 fst) + (@block-set! p 1 snd) + p))) + +(def pair? + (fun (o) + (and (@block? o) (= 0 (@block-tag o))))) + +(def pair-fst + (fun (p) + (@block-get p 0))) + +(def pair-snd + (fun (p) + (@block-get p 1))) + +(def pair-derive= + (fun (fst= snd=) + (fun (p1 p2) + (and (fst= (pair-fst p1) (pair-fst p2)) + (snd= (pair-snd p1) (pair-snd p2)))))) + +(def pair-derive< + (fun (fst< snd<) + (fun (p1 p2) + (or (fst< (pair-fst p1) (pair-fst p2)) + (and (not (fst< (pair-fst p2) (pair-fst p1))) + (snd< (pair-snd p1) (pair-snd p2))))))) diff --git a/cs420-acc/l3-warmup/library/pairs.l3m b/cs420-acc/l3-warmup/library/pairs.l3m new file mode 100644 index 0000000..6eefe16 --- /dev/null +++ b/cs420-acc/l3-warmup/library/pairs.l3m @@ -0,0 +1,2 @@ +integers.l3 +pairs.l3 diff --git a/cs420-acc/l3-warmup/library/random.l3 b/cs420-acc/l3-warmup/library/random.l3 new file mode 100644 index 0000000..acb0f4d --- /dev/null +++ b/cs420-acc/l3-warmup/library/random.l3 @@ -0,0 +1,67 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; A PCG random number generator. (Specifically, this is the variant +;; called XSH RR in the paper, with a 16-bit state and 8-bit output). +;; See http://www.pcg-random.org/ + +(def %rng-to-uint16 + (fun (i) (int-bitwise-and #xFFFF i))) + +(def %rng-to-uint8 + (fun (i) (int-bitwise-and #xFF i))) + +(def rng-make + (fun (seed) + (let ((rng (@block-alloc-50 1))) + (@block-set! rng 0 (%rng-to-uint16 seed)) + rng))) + +(def rng? + (fun (o) + (and (@block? o) (= (@block-tag o) 50)))) + +(def %rng-get-state + (fun (rng) + (@block-get rng 0))) + +(def %rng-set-state! + (fun (rng new-state) + (@block-set! rng 0 (%rng-to-uint16 new-state)))) + +(def %rng-rotate-right-8 + (fun (x y) + (%rng-to-uint8 (int-bitwise-or (int-shift-right x y) + (int-shift-left x (- 8 y)))))) + +(def %rng-step + (fun (rng) + (%rng-set-state! rng (+ (* (%rng-get-state rng) 12829) 47989)))) + +(def %rng-output + (fun (rng) + (let ((state (%rng-get-state rng))) + (%rng-rotate-right-8 + (%rng-to-uint8 (int-shift-right + (int-bitwise-xor state (int-shift-right state 5)) + 5)) + (int-shift-right state 13))))) + +;; Return the next 8-bit unsigned integer (0 to 255, included) +(def rng-next-int8 + (fun (rng) + (let ((i (%rng-output rng))) + (%rng-step rng) + i))) + +;; FIXME: this is hackish, find a better way to do it (probably using +;; multiple streams, see sample/pcg32x2-demo.c in the PCG source). +(def rng-next-int + (fun (rng) + (let ((b0 (rng-next-int8 rng)) + (b1 (rng-next-int8 rng)) + (b2 (rng-next-int8 rng)) + (b3 (rng-next-int8 rng))) + (int-bitwise-or (int-shift-left b0 24) + (int-shift-left b1 16) + (int-shift-left b2 8) + b3)))) diff --git a/cs420-acc/l3-warmup/library/random.l3m b/cs420-acc/l3-warmup/library/random.l3m new file mode 100644 index 0000000..c9238cd --- /dev/null +++ b/cs420-acc/l3-warmup/library/random.l3m @@ -0,0 +1,2 @@ +integers.l3m +random.l3 diff --git a/cs420-acc/l3-warmup/library/strings.l3 b/cs420-acc/l3-warmup/library/strings.l3 new file mode 100644 index 0000000..27049f8 --- /dev/null +++ b/cs420-acc/l3-warmup/library/strings.l3 @@ -0,0 +1,41 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Strings + +(def string? + (fun (o) + (and (@block? o) (= 200 (@block-tag o))))) + +(def string-length + (fun (s) + (@block-length s))) + +(def string-get + (fun (s i) + (@block-get s i))) + +(def string-print + (fun (s) + (rec loop ((i 0)) + (if (< i (string-length s)) + (begin + (char-print (string-get s i)) + (loop (+ i 1))))))) + +(def string-concat + (fun (s1 s2) + (let* ((l1 (string-length s1)) + (l2 (string-length s2)) + (n (+ l1 l2)) + (s (@block-alloc-200 n))) + (rec loop ((i 0)) + (if (< i l1) + (begin + (@block-set! s i (@block-get s1 i)) + (loop (+ i 1))))) + (rec loop ((i 0)) + (if (< i l2) + (begin + (@block-set! s (+ i l1) (@block-get s2 i)) + (loop (+ i 1))))) + s))) diff --git a/cs420-acc/l3-warmup/library/strings.l3m b/cs420-acc/l3-warmup/library/strings.l3m new file mode 100644 index 0000000..ba5a8aa --- /dev/null +++ b/cs420-acc/l3-warmup/library/strings.l3m @@ -0,0 +1,3 @@ +integers.l3m +characters.l3m +strings.l3 diff --git a/cs420-acc/l3-warmup/library/unit.l3 b/cs420-acc/l3-warmup/library/unit.l3 new file mode 100644 index 0000000..f626abf --- /dev/null +++ b/cs420-acc/l3-warmup/library/unit.l3 @@ -0,0 +1,5 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; Unit + +(def unit? (fun (o) (@unit? o))) diff --git a/cs420-acc/l3-warmup/library/unit.l3m b/cs420-acc/l3-warmup/library/unit.l3m new file mode 100644 index 0000000..1c5f70a --- /dev/null +++ b/cs420-acc/l3-warmup/library/unit.l3m @@ -0,0 +1 @@ +unit.l3 diff --git a/cs420-acc/l3-warmup/library/vectors.l3 b/cs420-acc/l3-warmup/library/vectors.l3 new file mode 100644 index 0000000..c408424 --- /dev/null +++ b/cs420-acc/l3-warmup/library/vectors.l3 @@ -0,0 +1,148 @@ +;; In Emacs, open this file in -*- Scheme -*- mode. + +;; (Mutable) vectors + +(def vector-make@1 + (fun (n) + (@block-alloc-1 n))) + +(def vector-make@2 + (fun (n o) + (let ((v (@block-alloc-1 n))) + (rec loop ((i 0)) + (if (< i n) + (begin + (@block-set! v i o) + (loop (+ i 1))))) + v))) + +(def vector? + (fun (o) + (and (@block? o) (= 1 (@block-tag o))))) + +(def vector-get + (fun (v n) + (@block-get v n))) + +(def vector-set! + (fun (v n o) + (@block-set! v n o))) + +(def vector-length + (fun (v) + (@block-length v))) + +(def vector-fill! + (fun (v o) + (rec loop ((i 0)) + (if (< i (vector-length v)) + (begin + (vector-set! v i o) + (loop (+ i 1))))))) + +(def vector-tabulate + (fun (n f) + (let ((v (vector-make n))) + (rec loop ((i 0)) + (if (< i n) + (begin + (vector-set! v i (f i)) + (loop (+ i 1))) + v))))) + +(def vector-swap! + (fun (v i1 i2) + (let ((t (vector-get v i1))) + (vector-set! v i1 (vector-get v i2)) + (vector-set! v i2 t)))) + +(def vector-shuffle! + (fun (v rng-seed) + (let ((rng (rng-make rng-seed)) + (l (vector-length v))) + (rec loop ((i 0)) + (if (< i (- l 1)) + (let ((j (+ i (int-abs (%t (rng-next-int rng) (- l i)))))) + (vector-swap! v i j) + (loop (+ i 1)))))))) + +(def %vector-partition! + (fun (v p l h) + (rec loop ((l l) (h h)) + (cond ((>= l h) + l) + ((p (vector-get v l)) + (loop (+ l 1) h)) + ((not (p (vector-get v (- h 1)))) + (loop l (- h 1))) + (#t + (vector-swap! v l (- h 1)) + (loop (+ l 1) (- h 1))))))) + +;; Reorganize the elements of the vector so that all those not +;; satisfying the predicate [p] are before those that satisfy it. +;; Return the index of the first element not satisfying [p], or the +;; length of the vector if all elements satisfy [p]. +(def vector-partition! + (fun (v p) + (%vector-partition! v p 0 (vector-length v)))) + +(def vector-fold-left + (fun (f z v) + (rec loop ((z z) (i 0)) + (if (= i (vector-length v)) + z + (loop (f z (vector-get v i)) (+ i 1)))))) + +(def vector-for-each + (fun (f v) + (rec loop ((i 0)) + (if (< i (vector-length v)) + (begin + (f (vector-get v i)) + (loop (+ i 1))))))) + +(def vector-sort! + (fun (v el<) + (letrec ((qsort! + (fun (l h) + (if (> (- h l) 0) + (let* ((p (vector-get v h)) + (

l h) + (- -1 l) + (let* ((m (+ l (/t (- h l) 2))) + (me (vector-get v m))) + (cond ((el< e me) + (loop l (- m 1))) + ((el< me e) + (loop (+ m 1) h)) + (#t + m))))))) + +(def vector->list + (fun (v) + (rec loop ((i (- (vector-length v) 1))) + (if (= i -1) + list-empty + (list-prepend (vector-get v i) (loop (- i 1))))))) + +(def list->vector + (fun (l) + (let* ((n (list-length l)) + (v (vector-make n))) + (rec loop ((i 0) (l l)) + (if (< i n) + (begin + (vector-set! v i (list-head l)) + (loop (+ i 1) (list-tail l))) + v))))) diff --git a/cs420-acc/l3-warmup/library/vectors.l3m b/cs420-acc/l3-warmup/library/vectors.l3m new file mode 100644 index 0000000..ab8dce1 --- /dev/null +++ b/cs420-acc/l3-warmup/library/vectors.l3m @@ -0,0 +1,4 @@ +integers.l3m +lists.l3m +random.l3m +vectors.l3 diff --git a/cs420-acc/l3-warmup/tests/bignums.in b/cs420-acc/l3-warmup/tests/bignums.in new file mode 100644 index 0000000..29d6383 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/bignums.in @@ -0,0 +1 @@ +100 diff --git a/cs420-acc/l3-warmup/tests/bignums.out b/cs420-acc/l3-warmup/tests/bignums.out new file mode 100644 index 0000000..f905a6c --- /dev/null +++ b/cs420-acc/l3-warmup/tests/bignums.out @@ -0,0 +1 @@ +Factorial of? 100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 diff --git a/cs420-acc/l3-warmup/tests/expr-and.l3 b/cs420-acc/l3-warmup/tests/expr-and.l3 new file mode 100644 index 0000000..e378e6e --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-and.l3 @@ -0,0 +1,14 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "and" expression + +(@byte-write 71) + +(and (@byte-write 65) #u) +(and #t (@byte-write 66)) +(and #f (@byte-write 63)) +(and (@byte-write 67) #f (@byte-write 63)) +(@byte-write (and 63 68)) +(@byte-write (and #t 69)) +(@byte-write (and #t 'a' 70)) +(@byte-write (and "a" #u 63 71)) diff --git a/cs420-acc/l3-warmup/tests/expr-begin.l3 b/cs420-acc/l3-warmup/tests/expr-begin.l3 new file mode 100644 index 0000000..536459c --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-begin.l3 @@ -0,0 +1,16 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "begin" expression + +(@byte-write 67) + +(begin + (@byte-write 65) + (@byte-write 66)) + +(let ((b (@block-alloc-0 2))) + (@byte-write + (begin + (@block-set! b 0 60) + (@block-set! b 1 7) + (@+ (@block-get b 0) (@block-get b 1))))) diff --git a/cs420-acc/l3-warmup/tests/expr-cond.l3 b/cs420-acc/l3-warmup/tests/expr-cond.l3 new file mode 100644 index 0000000..63d0d9a --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-cond.l3 @@ -0,0 +1,18 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "cond" expression + +(@byte-write 68) + +(cond (#t (@byte-write 65)) + (#t (@byte-write 63))) + +(cond (#f (@byte-write 63)) + (#f (@byte-write 63)) + (#t (@byte-write 66))) + +(@byte-write (cond (#f 63) + (67 67) + (#t 63))) + +(cond ((@= #u (cond (#f 12))) (@byte-write 68))) diff --git a/cs420-acc/l3-warmup/tests/expr-fun.l3 b/cs420-acc/l3-warmup/tests/expr-fun.l3 new file mode 100644 index 0000000..503ccb2 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-fun.l3 @@ -0,0 +1,32 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "fun" expression + +(@byte-write 73) + +((fun (b) (@byte-write b)) 65) +((fun (b) + (@byte-write b) + (@byte-write (@+ b 1))) + 66) +(@byte-write ((fun (x) x) 68)) + +(let ((compose (fun (f g) + (fun (x) (f (g x))))) + (succ (fun (x) (@+ x 1))) + (twice (fun (x) (@+ x x)))) + (@byte-write ((compose succ twice) 34))) + +((fun (x y z) #u) + (@byte-write 70) + (@byte-write 71) + (@byte-write 72)) + +(let* ((fact (fun (self x) + (if (@= 0 x) + 1 + (@* x (self self (@- x 1)))))) + (fix (fun (f x) + (f f x)))) + (if (@= (fix fact 5) 120) + (@byte-write 73))) diff --git a/cs420-acc/l3-warmup/tests/expr-if.l3 b/cs420-acc/l3-warmup/tests/expr-if.l3 new file mode 100644 index 0000000..5ec8881 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-if.l3 @@ -0,0 +1,18 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "if" expression + +(@byte-write 71) + +(if (@byte-write 65) 1 2) +(@byte-write (if #t 66 63)) +(@byte-write (if #f 63 67)) +(if #t (@byte-write 68) (@byte-write 63)) +(if #f (@byte-write 63) (@byte-write 69)) +(if (@= #u (if #f 15)) + (@byte-write 70)) + +;; The condition has a side effect, and should therefore not be optimized away. +;; This expression is made to enter tail mode in CL3ToCPSTranslator, where we +;; want to check that it isn't optimized away +(let ((a 71)) (if (if (@byte-write 71) #t #t) 1 2)) diff --git a/cs420-acc/l3-warmup/tests/expr-let.l3 b/cs420-acc/l3-warmup/tests/expr-let.l3 new file mode 100644 index 0000000..b38149e --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-let.l3 @@ -0,0 +1,18 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "let" expression + +(@byte-write 69) + +(let ((A 65)) + (@byte-write A)) +(let ((B 63)) + (let ((B (@+ B 3))) + (@byte-write B))) +(let ((C 67)) + (@byte-write C) + (@byte-write (@+ C 1))) +(@byte-write + (let ((E 69)) + 63 + E)) diff --git a/cs420-acc/l3-warmup/tests/expr-letrec.l3 b/cs420-acc/l3-warmup/tests/expr-letrec.l3 new file mode 100644 index 0000000..35ad9e2 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-letrec.l3 @@ -0,0 +1,13 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "letrec" expression + +(@byte-write 66) + +(letrec ((fact (fun (x) (if (@= 0 x) 1 (@* x (fact (@- x 1))))))) + (@byte-write (@- (fact 5) 55))) +(letrec ((even? (fun (x) (if (@= x 0) #t (odd? (@- x 1))))) + (odd? (fun (x) (if (@= x 0) #f (even? (@- x 1)))))) + (if (even? 66) + (@byte-write 66) + (@byte-write 63))) diff --git a/cs420-acc/l3-warmup/tests/expr-lets.l3 b/cs420-acc/l3-warmup/tests/expr-lets.l3 new file mode 100644 index 0000000..461bab6 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-lets.l3 @@ -0,0 +1,18 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "let*" expression + +(@byte-write 69) + +(let* ((A 65)) + (@byte-write A)) +(let* ((B 63) + (B (@+ B 3))) + (@byte-write B)) +(let* ((C 67)) + (@byte-write C) + (@byte-write (@+ C 1))) +(@byte-write + (let* ((E 69)) + 63 + E)) diff --git a/cs420-acc/l3-warmup/tests/expr-not.l3 b/cs420-acc/l3-warmup/tests/expr-not.l3 new file mode 100644 index 0000000..02ea321 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-not.l3 @@ -0,0 +1,9 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "not" expression + +(@byte-write 67) + +(@byte-write (if (@= #t (not #f)) 65 63)) +(@byte-write (if (@= #f (not #t)) 66 63)) +(@byte-write (if (@= #f (not 42)) 67 63)) diff --git a/cs420-acc/l3-warmup/tests/expr-or.l3 b/cs420-acc/l3-warmup/tests/expr-or.l3 new file mode 100644 index 0000000..d61c22a --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-or.l3 @@ -0,0 +1,13 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "or" expression + +(@byte-write 70) + +(or (@byte-write 65) #u) +(or #f (@byte-write 66)) +(or #t (@byte-write 63)) +(or (@byte-write 67) #t (@byte-write 63)) +(@byte-write (or 68 63)) +(@byte-write (or #f 69)) +(@byte-write (or #f #f 70)) diff --git a/cs420-acc/l3-warmup/tests/expr-rec.l3 b/cs420-acc/l3-warmup/tests/expr-rec.l3 new file mode 100644 index 0000000..8348cb2 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/expr-rec.l3 @@ -0,0 +1,10 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "rec" expression + +(@byte-write 65) + +(rec loop ((i 0) (j 65)) + (if (@= j 0) + (@byte-write i) + (loop (@+ i 1) (@- j 1)))) diff --git a/cs420-acc/l3-warmup/tests/int-print.l3 b/cs420-acc/l3-warmup/tests/int-print.l3 new file mode 100644 index 0000000..f3c2676 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/int-print.l3 @@ -0,0 +1,12 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +(int-print 2018) +(@byte-write 10) ;newline +(int-print -2018) +(@byte-write 10) ;newline +(int-print 0) +(@byte-write 10) ;newline +(int-print 1073741823) +(@byte-write 10) ;newline +(int-print -1073741824) +(@byte-write 10) ;newline diff --git a/cs420-acc/l3-warmup/tests/int-print.l3m b/cs420-acc/l3-warmup/tests/int-print.l3m new file mode 100644 index 0000000..680604f --- /dev/null +++ b/cs420-acc/l3-warmup/tests/int-print.l3m @@ -0,0 +1,2 @@ +../library/integers.l3m +int-print.l3 diff --git a/cs420-acc/l3-warmup/tests/int-print.out b/cs420-acc/l3-warmup/tests/int-print.out new file mode 100644 index 0000000..e667a75 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/int-print.out @@ -0,0 +1,5 @@ +2018 +-2018 +0 +1073741823 +-1073741824 diff --git a/cs420-acc/l3-warmup/tests/maze.in b/cs420-acc/l3-warmup/tests/maze.in new file mode 100644 index 0000000..422aace --- /dev/null +++ b/cs420-acc/l3-warmup/tests/maze.in @@ -0,0 +1,2 @@ +8 +1337 diff --git a/cs420-acc/l3-warmup/tests/maze.out b/cs420-acc/l3-warmup/tests/maze.out new file mode 100644 index 0000000..5e19389 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/maze.out @@ -0,0 +1,17 @@ +Size: Seed: XXXXXXXXXXXXXXXXX +X X X X X X +X X X X X XXX X X +X X X X X +X XXXXX X XXXXXXX +X X X X +XXXXXXX X X XXXXX +X X X X X +XXX X X X X XXX X +X X X X X +XXX X X XXXXXXX X +X X X X X X +X XXXXXXX X X X X +X X X X X X +XXX XXXXX X X X X +X X X X X +XXXXXXXXXXXXXXXXX diff --git a/cs420-acc/l3-warmup/tests/prim-add.l3 b/cs420-acc/l3-warmup/tests/prim-add.l3 new file mode 100644 index 0000000..8dd9ded --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-add.l3 @@ -0,0 +1,12 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @+ primitive + +(@byte-write 70) + +(@byte-write (@+ 65 0)) ;A +(@byte-write (@+ 0 66)) ;B +(@byte-write (@+ 68 -1)) ;C +(@byte-write (@+ -1 69)) ;D +(@byte-write (@+ 1073741823 70)) ;E +(@byte-write (@+ 71 1073741823)) ;F diff --git a/cs420-acc/l3-warmup/tests/prim-and.l3 b/cs420-acc/l3-warmup/tests/prim-and.l3 new file mode 100644 index 0000000..a9a696e --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-and.l3 @@ -0,0 +1,12 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @and primitive + +(@byte-write 69) + +(@byte-write (@and #x7FFFFFFF 65)) ;A +(@byte-write (@and 66 #x7FFFFFF)) ;B +(@byte-write (@and 67 -1)) ;C +(@byte-write (@and -1 68)) ;D +(@byte-write (@and 69 237)) ;E + diff --git a/cs420-acc/l3-warmup/tests/prim-block-alloc.l3 b/cs420-acc/l3-warmup/tests/prim-block-alloc.l3 new file mode 100644 index 0000000..0baa5a5 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-block-alloc.l3 @@ -0,0 +1,8 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @block-alloc-0? primitive + +(@byte-write 66) + +(@byte-write (if (@= (@block-alloc-0 0) (@block-alloc-0 0)) 63 65)) ;A +(@byte-write (if (not (@= (@block-alloc-0 0) (@block-alloc-0 0))) 66 63)) ;B diff --git a/cs420-acc/l3-warmup/tests/prim-block-get-set.l3 b/cs420-acc/l3-warmup/tests/prim-block-get-set.l3 new file mode 100644 index 0000000..ec9618d --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-block-get-set.l3 @@ -0,0 +1,15 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @block-get and @block-set! primitives + +(@byte-write 68) + +(let ((b (@block-alloc-0 4))) + (@block-set! b 0 'a') + (@block-set! b 1 'b') + (@block-set! b 2 'c') + (@block-set! b 3 'd') + (@byte-write (if (@= (@block-get b 0) 'a') 65 63)) + (@byte-write (if (@= (@block-get b 1) 'b') 66 63)) + (@byte-write (if (@= (@block-get b 2) 'c') 67 63)) + (@byte-write (if (@= (@block-get b 3) 'd') 68 63))) diff --git a/cs420-acc/l3-warmup/tests/prim-block-length.l3 b/cs420-acc/l3-warmup/tests/prim-block-length.l3 new file mode 100644 index 0000000..ac88994 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-block-length.l3 @@ -0,0 +1,8 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @block-length primitive + +(@byte-write 66) + +(@byte-write (@block-length (@block-alloc-0 65))) ;A +(@byte-write (@block-length (@block-alloc-1 66))) ;B diff --git a/cs420-acc/l3-warmup/tests/prim-block-tag.l3 b/cs420-acc/l3-warmup/tests/prim-block-tag.l3 new file mode 100644 index 0000000..fdbd192 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-block-tag.l3 @@ -0,0 +1,8 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @block-tag primitive + +(@byte-write 66) + +(@byte-write (@block-tag (@block-alloc-65 0))) ;A +(@byte-write (@block-tag (@block-alloc-66 1))) ;B diff --git a/cs420-acc/l3-warmup/tests/prim-blockp.l3 b/cs420-acc/l3-warmup/tests/prim-blockp.l3 new file mode 100644 index 0000000..cf86195 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-blockp.l3 @@ -0,0 +1,15 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @block? primitive + +(@byte-write 72) + +(@byte-write (if (@block? 1) 63 65)) ;A +(@byte-write (if (@block? #t) 63 66)) ;B +(@byte-write (if (@block? #f) 63 67)) ;C +(@byte-write (if (@block? #u) 63 68)) ;D +(@byte-write (if (@block? 'A') 63 69)) ;E + +(@byte-write (if (@block? (@block-alloc-0 0)) 70 63)) ;F +(@byte-write (if (@block? "") 71 63)) ;G +(@byte-write (if (@block? (fun () 1)) 72 63)) ;H diff --git a/cs420-acc/l3-warmup/tests/prim-boolp.l3 b/cs420-acc/l3-warmup/tests/prim-boolp.l3 new file mode 100644 index 0000000..7c3d085 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-boolp.l3 @@ -0,0 +1,11 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @bool? primitive + +(@byte-write 69) + +(@byte-write (if (@bool? #t) 65 63)) ;A +(@byte-write (if (@bool? #f) 66 63)) ;B +(@byte-write (if (@bool? 1) 63 67)) ;C +(@byte-write (if (@bool? "1") 63 68)) ;D +(@byte-write (if (@bool? #u) 63 69)) ;E diff --git a/cs420-acc/l3-warmup/tests/prim-char-to-int.l3 b/cs420-acc/l3-warmup/tests/prim-char-to-int.l3 new file mode 100644 index 0000000..df98e71 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-char-to-int.l3 @@ -0,0 +1,8 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @char->int primitive + +(@byte-write 66) + +(@byte-write (@char->int 'A')) ;A +(@byte-write (if (@= (@char->int '€') 8364) 66 63)) ;B diff --git a/cs420-acc/l3-warmup/tests/prim-charp.l3 b/cs420-acc/l3-warmup/tests/prim-charp.l3 new file mode 100644 index 0000000..abddfe4 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-charp.l3 @@ -0,0 +1,14 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @char? primitive + +(@byte-write 72) + +(@byte-write (if (@char? 'A') 65 63)) ;A +(@byte-write (if (@char? '€') 66 63)) ;B +(@byte-write (if (@char? ' ') 67 63)) ;C +(@byte-write (if (@char? 1) 63 68)) ;D +(@byte-write (if (@char? "1") 63 69)) ;E +(@byte-write (if (@char? #t) 63 70)) ;F +(@byte-write (if (@char? #f) 63 71)) ;G +(@byte-write (if (@char? #u) 63 72)) ;H diff --git a/cs420-acc/l3-warmup/tests/prim-div.l3 b/cs420-acc/l3-warmup/tests/prim-div.l3 new file mode 100644 index 0000000..d248162 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-div.l3 @@ -0,0 +1,15 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @/ primitive + +(@byte-write 73) + +(@byte-write (@/ 65 1)) ;A +(@byte-write (@/ 132 2)) ;B +(@byte-write (@/ -201 -3)) ;C +(@byte-write (if (@= (@/ 15 4) 3) 68 63)) ;D +(@byte-write (if (@= (@/ 15 -4) -3) 69 63)) ;E +(@byte-write (if (@= (@/ -15 4) -3) 70 63)) ;F +(@byte-write (if (@= (@/ -15 -4) 3) 71 63)) ;G +(@byte-write (if (@= (@/ -1073741824 -1) -1073741824) 72 63)) ;H +(@byte-write (if (@= (@/ 1073741823 1073741823) 1) 73 63)) ;I diff --git a/cs420-acc/l3-warmup/tests/prim-eq.l3 b/cs420-acc/l3-warmup/tests/prim-eq.l3 new file mode 100644 index 0000000..b3907e2 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-eq.l3 @@ -0,0 +1,19 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @= primitive + +(@byte-write 76) + +(@byte-write (if (@= #t #t) 65 63)) ;A +(@byte-write (if (@= #f #f) 66 63)) ;B +(@byte-write (if (@= 2018 2018) 67 63)) ;C +(@byte-write (if (@= 'A' 'A') 68 63)) ;D +(let ((s "bla")) (@byte-write (if (@= s s) 69 63))) ;E +(let ((f (fun () 1))) (@byte-write (if (@= f f) 70 63))) ;F + +(@byte-write (if (@= #t #f) 63 71)) ;G +(@byte-write (if (@= #t #u) 63 72)) ;H +(@byte-write (if (@= 2018 2017) 63 73)) ;I +(@byte-write (if (@= 'A' 65) 63 74)) ;J +(@byte-write (if (@= "bla" "bla") 63 75)) ;K +(@byte-write (if (@= (fun () 1) (fun () 1)) 63 76)) ;L diff --git a/cs420-acc/l3-warmup/tests/prim-int-to-char.l3 b/cs420-acc/l3-warmup/tests/prim-int-to-char.l3 new file mode 100644 index 0000000..73597c4 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-int-to-char.l3 @@ -0,0 +1,9 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @int->char primitive + +(@byte-write 66) + +(@byte-write (if (@= (@int->char 65) 'A') 65 63)) ;A +(@byte-write (if (@= (@int->char 8364) '€') 66 63)) ;B + diff --git a/cs420-acc/l3-warmup/tests/prim-intp.l3 b/cs420-acc/l3-warmup/tests/prim-intp.l3 new file mode 100644 index 0000000..adae4c1 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-intp.l3 @@ -0,0 +1,14 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @int? primitive + +(@byte-write 72) + +(@byte-write (if (@int? 0) 65 63)) ;A +(@byte-write (if (@int? 1073741823) 66 63)) ;B +(@byte-write (if (@int? -1073741824) 67 63)) ;C +(@byte-write (if (@int? '1') 63 68)) ;D +(@byte-write (if (@int? "1") 63 69)) ;E +(@byte-write (if (@int? #t) 63 70)) ;F +(@byte-write (if (@int? #f) 63 71)) ;G +(@byte-write (if (@int? #u) 63 72)) ;H diff --git a/cs420-acc/l3-warmup/tests/prim-le.l3 b/cs420-acc/l3-warmup/tests/prim-le.l3 new file mode 100644 index 0000000..9aa5ba3 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-le.l3 @@ -0,0 +1,13 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @<= primitive + +(@byte-write 71) + +(@byte-write (if (@<= -1073741824 1073741823) 65 63)) ;A +(@byte-write (if (@<= 1073741823 -1073741824) 63 66)) ;B +(@byte-write (if (@<= 0 1) 67 63)) ;C +(@byte-write (if (@<= 1 0) 63 68)) ;D +(@byte-write (if (@<= 2018 2018) 69 63)) ;E +(@byte-write (if (@<= 2017 2018) 70 63)) ;F +(@byte-write (if (@<= -2018 -2017) 71 63)) ;G diff --git a/cs420-acc/l3-warmup/tests/prim-lt.l3 b/cs420-acc/l3-warmup/tests/prim-lt.l3 new file mode 100644 index 0000000..3a89c2a --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-lt.l3 @@ -0,0 +1,13 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @< primitive + +(@byte-write 71) + +(@byte-write (if (@< -1073741824 1073741823) 65 63)) ;A +(@byte-write (if (@< 1073741823 -1073741824) 63 66)) ;B +(@byte-write (if (@< 0 1) 67 63)) ;C +(@byte-write (if (@< 1 0) 63 68)) ;D +(@byte-write (if (@< 2018 2018) 63 69)) ;E +(@byte-write (if (@< 2017 2018) 70 63)) ;F +(@byte-write (if (@< -2018 -2017) 71 63)) ;G diff --git a/cs420-acc/l3-warmup/tests/prim-mod.l3 b/cs420-acc/l3-warmup/tests/prim-mod.l3 new file mode 100644 index 0000000..1b7198b --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-mod.l3 @@ -0,0 +1,14 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @% primitive + +(@byte-write 72) + +(@byte-write (@% 65 66)) ;A +(@byte-write (@% 133 67)) ;B +(@byte-write (if (@= (@% 15 4) 3) 67 63)) ;C +(@byte-write (if (@= (@% 15 -4) 3) 68 63)) ;D +(@byte-write (if (@= (@% -15 4) -3) 69 63)) ;E +(@byte-write (if (@= (@% -15 -4) -3) 70 63)) ;F +(@byte-write (if (@= (@% -1073741824 1) 0) 71 63)) ;G +(@byte-write (if (@= (@% 1073741823 2) 1) 72 63)) ;H diff --git a/cs420-acc/l3-warmup/tests/prim-mul.l3 b/cs420-acc/l3-warmup/tests/prim-mul.l3 new file mode 100644 index 0000000..d33a94b --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-mul.l3 @@ -0,0 +1,12 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @* primitive + +(@byte-write 70) + +(@byte-write (@* 65 1)) ;A +(@byte-write (@* -1 -66)) ;B +(@byte-write (@* -67 -1)) ;C +(@byte-write (@* -2 -34)) ;D +(@byte-write (if (@= (@* 1073741823 2) -2) 69 63)) ;E +(@byte-write (if (@= (@* -1073741822 17) -1073741790) 70 63)) ;F diff --git a/cs420-acc/l3-warmup/tests/prim-or.l3 b/cs420-acc/l3-warmup/tests/prim-or.l3 new file mode 100644 index 0000000..eed4b2f --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-or.l3 @@ -0,0 +1,12 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @or primitive + +(@byte-write 69) + +(@byte-write (@or 0 65)) ;A +(@byte-write (@or 66 0)) ;B +(@byte-write (@or 66 1)) ;C +(@byte-write (if (@= (@or -1 68) -1) 68 63)) ;D +(@byte-write (@or 68 65)) ;E + diff --git a/cs420-acc/l3-warmup/tests/prim-shift-left.l3 b/cs420-acc/l3-warmup/tests/prim-shift-left.l3 new file mode 100644 index 0000000..920d2ad --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-shift-left.l3 @@ -0,0 +1,9 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @shift-left primitive + +(@byte-write 67) + +(@byte-write (@shift-left 65 0)) ;A +(@byte-write (@shift-left 33 1)) ;B +(@byte-write (if (@= (@shift-left #x20000000 2) 0) 67 63)) ;C diff --git a/cs420-acc/l3-warmup/tests/prim-shift-right.l3 b/cs420-acc/l3-warmup/tests/prim-shift-right.l3 new file mode 100644 index 0000000..e899e13 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-shift-right.l3 @@ -0,0 +1,9 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @shift-right primitive + +(@byte-write 67) + +(@byte-write (@shift-right 65 0)) ;A +(@byte-write (@shift-right 132 1)) ;B +(@byte-write (if (@= (@shift-right #x40000000 1) #x60000000) 67 63)) ;C diff --git a/cs420-acc/l3-warmup/tests/prim-sub.l3 b/cs420-acc/l3-warmup/tests/prim-sub.l3 new file mode 100644 index 0000000..e026faa --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-sub.l3 @@ -0,0 +1,12 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @- primitive + +(@byte-write 70) + +(@byte-write (@- 65 0)) ;A +(@byte-write (@- 0 -66)) ;B +(@byte-write (@- 66 -1)) ;C +(@byte-write (@- -1 -69)) ;D +(@byte-write (@- -1073741824 1073741755)) ;E +(@byte-write (@- -1073741754 -1073741824)) ;F diff --git a/cs420-acc/l3-warmup/tests/prim-unitp.l3 b/cs420-acc/l3-warmup/tests/prim-unitp.l3 new file mode 100644 index 0000000..900c435 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-unitp.l3 @@ -0,0 +1,11 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @unit? primitive + +(@byte-write 69) + +(@byte-write (if (@unit? #u) 65 63)) ;A +(@byte-write (if (@unit? #t) 63 66)) ;B +(@byte-write (if (@unit? #f) 63 67)) ;C +(@byte-write (if (@unit? 1) 67 68)) ;D +(@byte-write (if (@unit? "1") 68 69)) ;E diff --git a/cs420-acc/l3-warmup/tests/prim-xor.l3 b/cs420-acc/l3-warmup/tests/prim-xor.l3 new file mode 100644 index 0000000..ab5f51d --- /dev/null +++ b/cs420-acc/l3-warmup/tests/prim-xor.l3 @@ -0,0 +1,13 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the @xor primitive + +(@byte-write 70) + +(@byte-write (@xor 0 65)) ;A +(@byte-write (@xor 66 0)) ;B +(@byte-write (@xor 66 1)) ;C +(@byte-write (@xor -1 -69)) ;D +(@byte-write (if (@= (@xor 2018 2018) 0) 69 63)) ;E +(@byte-write (@xor 207 137)) ;F + diff --git a/cs420-acc/l3-warmup/tests/queens.in b/cs420-acc/l3-warmup/tests/queens.in new file mode 100644 index 0000000..cdfade7 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/queens.in @@ -0,0 +1,2 @@ +6 +0 diff --git a/cs420-acc/l3-warmup/tests/queens.out b/cs420-acc/l3-warmup/tests/queens.out new file mode 100644 index 0000000..fd13a26 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/queens.out @@ -0,0 +1,12 @@ +enter size (0 to exit)> +6-queen(s) +list: (5 3 1 6 4 2 ) + _ _ _ _ _ _ +| |o| | | | | +| | | |o| | | +| | | | | |o| +|o| | | | | | +| | |o| | | | +| | | | |o| | + +enter size (0 to exit)> \ No newline at end of file diff --git a/cs420-acc/l3-warmup/tests/stmt-def.l3 b/cs420-acc/l3-warmup/tests/stmt-def.l3 new file mode 100644 index 0000000..a99fc55 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/stmt-def.l3 @@ -0,0 +1,14 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "def" statement + +(@byte-write 67) + +(def A 65) +(@byte-write A) + +(def B (begin 63 66)) +(@byte-write B) + +(def A 67) +(@byte-write A) diff --git a/cs420-acc/l3-warmup/tests/stmt-defrec.l3 b/cs420-acc/l3-warmup/tests/stmt-defrec.l3 new file mode 100644 index 0000000..8585f3f --- /dev/null +++ b/cs420-acc/l3-warmup/tests/stmt-defrec.l3 @@ -0,0 +1,14 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "defrec" statement + +(@byte-write 67) + +(defrec succ (fun (x) (@+ x 1))) +(@byte-write (succ 64)) + +(defrec fact (fun (x) (if (@= x 0) 1 (@* x (fact (@- x 1)))))) +(@byte-write (@- (fact 5) 54)) + +(defrec fact (fun (x) (@+ x 2))) +(@byte-write (fact 65)) diff --git a/cs420-acc/l3-warmup/tests/stmt-halt.l3 b/cs420-acc/l3-warmup/tests/stmt-halt.l3 new file mode 100644 index 0000000..4baa9ce --- /dev/null +++ b/cs420-acc/l3-warmup/tests/stmt-halt.l3 @@ -0,0 +1,15 @@ +;; In Emacs, open this file in -*- Scheme -*- mode + +;; Test the "halt" statement + +(@byte-write 66) + +(halt (begin + (@byte-write 65) + (halt (begin + (@byte-write 66) + 0)) + (@byte-write 63) + 1)) + +(@byte-write 63) diff --git a/cs420-acc/l3-warmup/tests/unimaze.in b/cs420-acc/l3-warmup/tests/unimaze.in new file mode 100644 index 0000000..9c55918 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/unimaze.in @@ -0,0 +1,3 @@ +20 +8 +2018 diff --git a/cs420-acc/l3-warmup/tests/unimaze.out b/cs420-acc/l3-warmup/tests/unimaze.out new file mode 100644 index 0000000..43a5025 --- /dev/null +++ b/cs420-acc/l3-warmup/tests/unimaze.out @@ -0,0 +1,7 @@ + Maze width: Maze height: Random seed: ┌────┬┬──┬┬─┬─┬─┬─┐ +│╷╷╷╷╵│╷╶┤│╷╵╶┼┐└╴│ +│├┤└┤╷└┤╷╵││┌─┘└─╴│ +├┘└╴└┴┬┴┘╷╵└┘┌╴┌╴╷│ +│╷┌╴╶┐└┬╴├┬─╴├─┤┌┘│ +│└┤╷┌┘╷╵╷│╵╶┐├╴└┴╴│ +└─┴┴┴─┴─┴┴──┴┴────┘ diff --git a/cs433-ml/project1 b/cs433-ml/project1 new file mode 160000 index 0000000..bca76a5 --- /dev/null +++ b/cs433-ml/project1 @@ -0,0 +1 @@ +Subproject commit bca76a538a39cd6088ea348e9482be4b61f46938 diff --git a/cs440-acg b/cs440-acg new file mode 160000 index 0000000..26a4c59 --- /dev/null +++ b/cs440-acg @@ -0,0 +1 @@ +Subproject commit 26a4c597d1a29724b2772a08a16685bda00b169c diff --git a/cs452-fos/fos-assignments b/cs452-fos/fos-assignments new file mode 160000 index 0000000..74fc009 --- /dev/null +++ b/cs452-fos/fos-assignments @@ -0,0 +1 @@ +Subproject commit 74fc009d30ea1b27b2d1f6861c55cc061e6d17ea diff --git a/cs453-ca/CS453-2021-project b/cs453-ca/CS453-2021-project new file mode 160000 index 0000000..ad9dbfc --- /dev/null +++ b/cs453-ca/CS453-2021-project @@ -0,0 +1 @@ +Subproject commit ad9dbfc13bae7bb62e65fbee3b83f989340fd629 diff --git a/cs453-ca/ca11-book.pdf b/cs453-ca/ca11-book.pdf new file mode 100644 index 0000000..49530fc Binary files /dev/null and b/cs453-ca/ca11-book.pdf differ diff --git a/cs453-ca/ex/ca21_ex1.pdf b/cs453-ca/ex/ca21_ex1.pdf new file mode 100644 index 0000000..4ca4c11 Binary files /dev/null and b/cs453-ca/ex/ca21_ex1.pdf differ diff --git a/cs453-ca/ex/ca21_ex10.pdf b/cs453-ca/ex/ca21_ex10.pdf new file mode 100644 index 0000000..37a5d0a Binary files /dev/null and b/cs453-ca/ex/ca21_ex10.pdf differ diff --git a/cs453-ca/ex/ca21_ex10_sol.pdf b/cs453-ca/ex/ca21_ex10_sol.pdf new file mode 100644 index 0000000..70bcad3 Binary files /dev/null and b/cs453-ca/ex/ca21_ex10_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex1_sol.pdf b/cs453-ca/ex/ca21_ex1_sol.pdf new file mode 100644 index 0000000..f5b3225 Binary files /dev/null and b/cs453-ca/ex/ca21_ex1_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex2.pdf b/cs453-ca/ex/ca21_ex2.pdf new file mode 100644 index 0000000..e315c73 Binary files /dev/null and b/cs453-ca/ex/ca21_ex2.pdf differ diff --git a/cs453-ca/ex/ca21_ex2_sol.pdf b/cs453-ca/ex/ca21_ex2_sol.pdf new file mode 100644 index 0000000..d7362d1 Binary files /dev/null and b/cs453-ca/ex/ca21_ex2_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex3.pdf b/cs453-ca/ex/ca21_ex3.pdf new file mode 100644 index 0000000..7058f83 Binary files /dev/null and b/cs453-ca/ex/ca21_ex3.pdf differ diff --git a/cs453-ca/ex/ca21_ex3_sol.pdf b/cs453-ca/ex/ca21_ex3_sol.pdf new file mode 100644 index 0000000..f7efd83 Binary files /dev/null and b/cs453-ca/ex/ca21_ex3_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex4.pdf b/cs453-ca/ex/ca21_ex4.pdf new file mode 100644 index 0000000..792c4b7 Binary files /dev/null and b/cs453-ca/ex/ca21_ex4.pdf differ diff --git a/cs453-ca/ex/ca21_ex4_sol.pdf b/cs453-ca/ex/ca21_ex4_sol.pdf new file mode 100644 index 0000000..6967b57 Binary files /dev/null and b/cs453-ca/ex/ca21_ex4_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex5.pdf b/cs453-ca/ex/ca21_ex5.pdf new file mode 100644 index 0000000..e365e5f Binary files /dev/null and b/cs453-ca/ex/ca21_ex5.pdf differ diff --git a/cs453-ca/ex/ca21_ex5_sol.pdf b/cs453-ca/ex/ca21_ex5_sol.pdf new file mode 100644 index 0000000..3738008 Binary files /dev/null and b/cs453-ca/ex/ca21_ex5_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex6.pdf b/cs453-ca/ex/ca21_ex6.pdf new file mode 100644 index 0000000..aed8d6a Binary files /dev/null and b/cs453-ca/ex/ca21_ex6.pdf differ diff --git a/cs453-ca/ex/ca21_ex6_sol.pdf b/cs453-ca/ex/ca21_ex6_sol.pdf new file mode 100644 index 0000000..a1e2d39 Binary files /dev/null and b/cs453-ca/ex/ca21_ex6_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex7.pdf b/cs453-ca/ex/ca21_ex7.pdf new file mode 100644 index 0000000..daacb9e Binary files /dev/null and b/cs453-ca/ex/ca21_ex7.pdf differ diff --git a/cs453-ca/ex/ca21_ex7_sol.pdf b/cs453-ca/ex/ca21_ex7_sol.pdf new file mode 100644 index 0000000..4e33a14 Binary files /dev/null and b/cs453-ca/ex/ca21_ex7_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex8.pdf b/cs453-ca/ex/ca21_ex8.pdf new file mode 100644 index 0000000..bbdb820 Binary files /dev/null and b/cs453-ca/ex/ca21_ex8.pdf differ diff --git a/cs453-ca/ex/ca21_ex8_sol.pdf b/cs453-ca/ex/ca21_ex8_sol.pdf new file mode 100644 index 0000000..e5e7734 Binary files /dev/null and b/cs453-ca/ex/ca21_ex8_sol.pdf differ diff --git a/cs453-ca/ex/ca21_ex9.pdf b/cs453-ca/ex/ca21_ex9.pdf new file mode 100644 index 0000000..4d409da Binary files /dev/null and b/cs453-ca/ex/ca21_ex9.pdf differ diff --git a/cs453-ca/ex/ca21_ex9_sol.pdf b/cs453-ca/ex/ca21_ex9_sol.pdf new file mode 100644 index 0000000..6f6c99e Binary files /dev/null and b/cs453-ca/ex/ca21_ex9_sol.pdf differ diff --git a/cs453-ca/ex/ca21_midterm.pdf b/cs453-ca/ex/ca21_midterm.pdf new file mode 100644 index 0000000..0d84c66 Binary files /dev/null and b/cs453-ca/ex/ca21_midterm.pdf differ diff --git a/cs453-ca/ex/ca21_midterm_sol.pdf b/cs453-ca/ex/ca21_midterm_sol.pdf new file mode 100644 index 0000000..0a3562c Binary files /dev/null and b/cs453-ca/ex/ca21_midterm_sol.pdf differ diff --git a/cs453-ca/slides/2021-12-EPFL_CA_Lecture.pdf b/cs453-ca/slides/2021-12-EPFL_CA_Lecture.pdf new file mode 100644 index 0000000..bb7c99d Binary files /dev/null and b/cs453-ca/slides/2021-12-EPFL_CA_Lecture.pdf differ diff --git a/cs453-ca/slides/AnonymousGR.pdf b/cs453-ca/slides/AnonymousGR.pdf new file mode 100644 index 0000000..05fae69 Binary files /dev/null and b/cs453-ca/slides/AnonymousGR.pdf differ diff --git a/cs453-ca/slides/ca20STM.pdf b/cs453-ca/slides/ca20STM.pdf new file mode 100644 index 0000000..055cc87 Binary files /dev/null and b/cs453-ca/slides/ca20STM.pdf differ diff --git a/cs453-ca/slides/ca21-CounterSnapshot.pdf b/cs453-ca/slides/ca21-CounterSnapshot.pdf new file mode 100644 index 0000000..8ecd4e1 Binary files /dev/null and b/cs453-ca/slides/ca21-CounterSnapshot.pdf differ diff --git a/cs453-ca/slides/ca21-consensus.pdf b/cs453-ca/slides/ca21-consensus.pdf new file mode 100644 index 0000000..cc573cf Binary files /dev/null and b/cs453-ca/slides/ca21-consensus.pdf differ diff --git a/cs453-ca/slides/ca21-consensus_timing.pdf b/cs453-ca/slides/ca21-consensus_timing.pdf new file mode 100644 index 0000000..7b386c2 Binary files /dev/null and b/cs453-ca/slides/ca21-consensus_timing.pdf differ diff --git a/cs453-ca/slides/ca21-introduction.pdf b/cs453-ca/slides/ca21-introduction.pdf new file mode 100644 index 0000000..a5057bb Binary files /dev/null and b/cs453-ca/slides/ca21-introduction.pdf differ diff --git a/cs453-ca/slides/ca21-registers.pdf b/cs453-ca/slides/ca21-registers.pdf new file mode 100644 index 0000000..e7b123d Binary files /dev/null and b/cs453-ca/slides/ca21-registers.pdf differ diff --git a/cs453-ca/slides/ca21Universal.pdf b/cs453-ca/slides/ca21Universal.pdf new file mode 100644 index 0000000..767f633 Binary files /dev/null and b/cs453-ca/slides/ca21Universal.pdf differ diff --git a/cs453-ca/slides/ca21anonymous.pdf b/cs453-ca/slides/ca21anonymous.pdf new file mode 100644 index 0000000..2b93e45 Binary files /dev/null and b/cs453-ca/slides/ca21anonymous.pdf differ diff --git a/cs457-gc b/cs457-gc new file mode 160000 index 0000000..7529606 --- /dev/null +++ b/cs457-gc @@ -0,0 +1 @@ +Subproject commit 75296066d9cdfffa2a82a1daf4f46817902931f4 diff --git a/cs473-es b/cs473-es new file mode 160000 index 0000000..28454a9 --- /dev/null +++ b/cs473-es @@ -0,0 +1 @@ +Subproject commit 28454a9232f38cc6ee4d4cd79aee88c0d3757b40 diff --git a/cs522-pocs/OP2.pdf b/cs522-pocs/OP2.pdf new file mode 100644 index 0000000..5f0cb52 Binary files /dev/null and b/cs522-pocs/OP2.pdf differ diff --git a/ee310-mes b/ee310-mes new file mode 160000 index 0000000..76b177f --- /dev/null +++ b/ee310-mes @@ -0,0 +1 @@ +Subproject commit 76b177f594d0074dd719a537feb1aec2ea81e4a6