Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • shchen/cs320
  • raveendr/cs320
  • mwojnaro/cs320
3 results
Show changes
Showing
with 374 additions and 0 deletions
IntLitToken(1)(1:2)
IntLitToken(2)(2:5)
EOFToken()(3:1)
object<=id_1+++_1{id}()class<==>==<%
/* This comment is closed twice,
which should be an error:
*/*/
\ No newline at end of file
1
// This is a comment
2 /* This is also a comment */
3 /* Still * /* comment */
4 /* Multiline
/*
*
Comment
*/
5 /***/
/* abc **/ 6 /* def */
7
//
{ } ( ) , : . = => _
app boolean
caSe Class df elze Error Extends False iff int module string
True unit vals
this_is_id this_IS_id2 st1ll1s_1d
St1ll1s_1d
123 012345
6789+12345
abstract Boolean
case class def else error extends false if Int match object String
true Unit val end
; + - * / % < <= && || == ++ !
"This is a string"
"Another with ^^ | # invalid chars"
"No escape \n characters \t"
" \\ No comments /* either "
1 // Tab indented
2 // Space indented
package amyc.test
import amyc.utils._
import java.io.File
import org.junit.Assert.fail
abstract class CompilerTest extends TestUtils {
private def runPipeline(pipeline: Pipeline[List[File], Unit], fileNames: List[String]) = {
val ctx = Context(new Reporter, fileNames)
val files = ctx.files.map(new File(_))
pipeline.run(ctx)(files)
ctx.reporter.terminateIfErrors()
}
private def runPipelineRedirected(
pipeline: Pipeline[List[File], Unit],
compiledFiles: List[String],
input: String
): String = {
testWithRedirectedIO(runPipeline(pipeline, compiledFiles), input)
}
private def assertEqual(output: String, expected: String) = {
val rejectLine = (s: String) =>
s.isEmpty ||
s.startsWith("[ Info ]") ||
s.startsWith("[Warning]") ||
s.startsWith("[ Error ]") ||
s.startsWith("[ Fatal ]")
def filtered(s: String) = s.linesIterator.filterNot(rejectLine).mkString("\n")
val filteredOutput = filtered(output)
val filteredExpected = filtered(expected)
if (filteredOutput != filteredExpected) {
val sb = new StringBuffer()
sb.append("\nOutput is different:\n")
sb.append("\nOutput: \n")
sb.append(filteredOutput)
sb.append("\n\nExpected output: \n")
sb.append(filteredExpected)
sb.append("\n")
fail(sb.toString)
}
}
protected def compareOutputs(
pipeline: Pipeline[List[File], Unit],
compiledFiles: List[String],
expectedFile: String,
input: String = ""
) = {
try {
val output = runPipelineRedirected(pipeline, compiledFiles, input)
val expected = scala.io.Source.fromFile(new File(expectedFile)).mkString
assertEqual(output, expected)
} catch {
// We only want to catch AmyFatalError gracefully, the rest can propagate
case AmycFatalError(msg) =>
fail(s"\n $msg\n")
}
}
protected def demandPass(
pipeline: Pipeline[List[File], Unit],
compiledFiles: List[String],
input: String = ""
) = {
try {
runPipelineRedirected(pipeline, compiledFiles, input)
} catch {
case AmycFatalError(msg) =>
fail(s"\n $msg\n")
}
}
protected def demandFailure(
pipeline: Pipeline[List[File], Unit],
compiledFiles: List[String],
input: String = ""
) = {
try {
runPipelineRedirected(pipeline, compiledFiles, input)
fail("Test should fail but it passed!")
} catch {
case AmycFatalError(_) =>
// Ok, this is what we wanted. Other exceptions should propagate though
}
}
}
package amyc.test
import amyc.parsing._
import org.junit.Test
class LexerTests extends TestSuite {
val pipeline = AmyLexer.andThen(DisplayTokens)
val baseDir = "lexer"
val outputExt = "txt"
@Test def testKeywords = shouldOutput("Keywords")
@Test def testIdentifiers = shouldOutput("Identifiers")
@Test def testOperators = shouldOutput("Operators")
@Test def testDelimiters = shouldOutput("Delimiters")
@Test def testCombinations = shouldOutput("Combinations")
@Test def testComments = shouldOutput("Comments")
@Test def testIntLiterals = shouldOutput("IntLiterals")
@Test def testStringLiterals = shouldOutput("StringLiterals")
@Test def testTwoFiles = shouldOutput(List("Keywords", "Operators"), "TwoFiles")
@Test def testSingleAmp = shouldFail("SingleAmp")
@Test def testSingleBar = shouldFail("SingleBar")
@Test def testUnclosedComment = shouldFail("UnclosedComment")
@Test def testUnclosedComment2 = shouldFail("UnclosedComment2")
@Test def testUnclosedComment3 = shouldFail("UnclosedComment3")
@Test def testCommentClosedTwice = shouldOutput("CommentClosedTwice")
@Test def testUnclosedString1 = shouldFail("UnclosedString1")
@Test def testUnclosedString2 = shouldFail("UnclosedString2")
@Test def testInvalid = shouldFail("Invalid")
@Test def testTooBigInt = shouldFail("TooBigInt")
@Test def testWhitespace = shouldOutput("Whitespace")
}
package amyc.test
import amyc.utils.Pipeline
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
abstract class TestSuite extends CompilerTest {
val pipeline: Pipeline[List[File], Unit]
val baseDir: String
lazy val effectiveBaseDir: String =
// getClass.getResource(s"/$baseDir").getPath
s"test/resources/$baseDir"
val passing = "passing"
val failing = "failing"
val outputs = "outputs"
val tmpDir = Files.createTempDirectory("amyc");
val outputExt: String
def getResourcePath(relativePath: String, otherPath: Option[String] = None): String =
val firstPath = Path.of(effectiveBaseDir, relativePath)
val (stream, path) =
if Files.exists(firstPath) then
(Files.newInputStream(firstPath), relativePath)
else
otherPath match
case Some(p) =>
val secondPath = Path.of(effectiveBaseDir, p)
(Files.newInputStream(secondPath), p)
case None =>
assert(false, s"can not read $effectiveBaseDir/$relativePath")
(null, "")
val targetPath = tmpDir.resolve(path)
Files.createDirectories(targetPath.getParent())
Files.copy(stream, targetPath, StandardCopyOption.REPLACE_EXISTING)
targetPath.toAbsolutePath().toString()
def shouldOutput(inputFiles: List[String], outputFile: String, input: String = ""): Unit = {
compareOutputs(
pipeline,
inputFiles map (f => getResourcePath(s"$passing/$f.amy", Some(s"$passing/$f.grading.amy"))),
getResourcePath(s"$outputs/$outputFile.$outputExt", Some(s"$outputs/$outputFile.grading.$outputExt")),
input
)
}
def shouldOutput(inputFile: String): Unit = {
shouldOutput(List(inputFile), inputFile)
}
def shouldFail(inputFiles: List[String], input: String = ""): Unit = {
demandFailure(
pipeline,
inputFiles map (f => getResourcePath(s"$failing/$f.amy", Some(s"$failing/$f.grading.amy"))),
input
)
}
def shouldFail(inputFile: String): Unit = {
shouldFail(List(inputFile))
}
def shouldPass(inputFiles: List[String], input: String = ""): Unit = {
demandPass(pipeline, inputFiles map (f => getResourcePath(s"$passing/$f.amy", Some(s"$passing/$f.grading.amy"))), input)
}
def shouldPass(inputFile: String): Unit = {
shouldPass(List(inputFile))
}
}
package amyc.test
import java.io._
/** Some utilities for running tests */
trait TestUtils {
/** Run test,
* with input also redirected from a String,
* and output is redirected to a local StringBuilder.
*/
def testWithRedirectedIO[T](test: => T, input: String): String = {
import scala.Console._
val inputS = new StringReader(input)
val outputS = new ByteArrayOutputStream()
withOut(outputS) {
withErr(outputS) {
withIn(inputS) {
test
}
}
}
outputS.toString()
}
}
version := "1.7"
organization := "ch.epfl.lara"
scalaVersion := "3.5.2"
assembly / test := {}
name := "amyc"
Compile / scalaSource := baseDirectory.value / "src"
scalacOptions ++= Seq("-feature")
Test / scalaSource := baseDirectory.value / "test" / "scala"
Test / parallelExecution := false
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test"
libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.4" % "test"
testOptions += Tests.Argument(TestFrameworks.JUnit, "-v")
assembly / assemblyMergeStrategy := {
{
case _ => MergeStrategy.first
}
}
object Arithmetic
def pow(b: Int(32), e: Int(32)): Int(32) = {
if (e == 0) { 1 }
else {
if (e % 2 == 0) {
val rec: Int(32) = pow(b, e/2);
rec * rec
} else {
b * pow(b, e - 1)
}
}
}
def gcd(a: Int(32), b: Int(32)): Int(32) = {
if (a == 0 || b == 0) {
a + b
} else {
if (a < b) {
gcd(a, b % a)
} else {
gcd(a % b, b)
}
}
}
Std.printInt(pow(0, 10));
Std.printInt(pow(1, 5));
Std.printInt(pow(2, 10));
Std.printInt(pow(3, 3));
Std.printInt(gcd(0, 10));
Std.printInt(gcd(17, 99)); // 1
Std.printInt(gcd(16, 46)); // 2
Std.printInt(gcd(222, 888)) // 222
end Arithmetic
object Factorial
def fact(i: Int(32)): Int(32) = {
if (i < 2) { 1 }
else {
val rec: Int(32) = fact(i-1);
i * rec
}
}
Std.printString("5! = " ++ Std.intToString(fact(5)));
Std.printString("10! = " ++ Std.intToString(fact(10)))
end Factorial
object Hanoi
def solve(n : Int(32)) : Int(32) = {
if (n < 1) {
error("can't solve Hanoi for less than 1 plate")
} else {
if (n == 1) {
1
} else {
2 * solve(n - 1) + 1
}
}
}
Std.printString("Hanoi for 4 plates: " ++ Std.intToString(solve(4)))
end Hanoi
\ No newline at end of file
object Hello
Std.printString("Hello " ++ "world!")
end Hello