Add Scala example

This commit is contained in:
Alexey Andreev 2015-10-03 21:02:59 +03:00
parent 97bdd35617
commit 3b8b819c48
9 changed files with 422 additions and 2 deletions

View File

@ -640,8 +640,10 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder {
try {
IContainer container = (IContainer)workspaceRoot.findMember(
depJavaProject.getOutputLocation());
collector.addPath(container.getLocation());
binCollector.addContainer(container);
if (container != null) {
collector.addPath(container.getLocation());
binCollector.addContainer(container);
}
} catch (MalformedURLException e) {
TeaVMEclipsePlugin.logError(e);
}

View File

@ -36,5 +36,6 @@
<module>teavm-samples-video</module>
<module>teavm-samples-async</module>
<module>teavm-samples-kotlin</module>
<module>teavm-samples-scala</module>
</modules>
</project>

View File

@ -0,0 +1,4 @@
/target/
/.settings/
/.classpath
/.project

View File

@ -0,0 +1,108 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.teavm</groupId>
<artifactId>teavm-samples</artifactId>
<version>0.4.0-SNAPSHOT</version>
</parent>
<packaging>war</packaging>
<artifactId>teavm-samples-scala</artifactId>
<name>TeaVM Scala example</name>
<description>A sample application written in Scala.</description>
<properties>
<java.version>1.8</java.version>
<teavm.version>0.4.0-SNAPSHOT</teavm.version>
<scala.version>2.11.7</scala.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-classlib</artifactId>
<version>${teavm.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-jso</artifactId>
<version>${teavm.version}</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaVersion>${scala.version}</scalaVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.teavm</groupId>
<artifactId>teavm-maven-plugin</artifactId>
<version>${teavm.version}</version>
<executions>
<execution>
<id>web-client</id>
<phase>prepare-package</phase>
<goals>
<goal>build-javascript</goal>
</goals>
<configuration>
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
<mainClass>org.teavm.samples.scala.Client</mainClass>
<runtime>SEPARATE</runtime>
<minifying>false</minifying>
<debugInformationGenerated>true</debugInformationGenerated>
<sourceMapsGenerated>true</sourceMapsGenerated>
<sourceFilesCopied>true</sourceFilesCopied>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<webResources>
<resource>
<directory>${project.build.directory}/generated/js</directory>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,86 @@
package org.teavm.samples.scala
import org.teavm.jso.browser.Window
import org.teavm.jso.dom.html._
import org.teavm.jso.dom.events._
object Client extends Grammar {
def main(args: Array[String]) {
var document = HTMLDocument.current
var exprElem = document.getElementById("expr").asInstanceOf[HTMLInputElement]
var calcElem = document.getElementById("calculate")
var resultList = document.getElementById("result-list");
calcElem.addEventListener("click", new EventListener[MouseEvent]() {
def handleEvent(e : MouseEvent) {
additive.parse(exprElem.getValue().toSeq) match {
case (None, _) => Window.alert("Error parsing expression");
case (Some(x), Nil) => {
val resultElem = document.createElement("div")
var exprSpan = document.createElement("span");
exprSpan.setAttribute("class", "plan")
exprSpan.appendChild(document.createTextNode(print(x) + " = "))
var resultSpan = document.createElement("span")
resultSpan.setAttribute("class", "result")
resultSpan.appendChild(document.createTextNode(eval(x).toString()))
resultElem.appendChild(exprSpan)
resultElem.appendChild(resultSpan)
resultList.insertBefore(resultElem, resultList.getFirstChild)
}
case (_, err) => Window.alert("Error parsing expression: " + err);
}
}
})
}
def eval(expr : Expr) : BigInt = expr match {
case Add(a, b) => eval(a) + eval(b)
case Subtract(a, b) => eval(a) - eval(b)
case Multiply(a, b) => eval(a) * eval(b)
case Divide(a, b) => eval(a) * eval(b)
case Negate(n) => -eval(n)
case Number(v) => v
}
def print(expr : Expr) : String = expr match {
case Add(a, b) => "(" + print(a) + " + " + print(b) + ")"
case Subtract(a, b) => "(" + print(a) + " - " + print(b) + ")"
case Multiply(a, b) => "(" + print(a) + " * " + print(b) + ")"
case Divide(a, b) => "(" + print(a) + " / " + print(b) + ")"
case Negate(n) => "-" + print(n)
case Number(v) => v.toString()
}
def additive = multiplicative ~ ((keyword("+") | keyword("-")) ~ multiplicative).* >> {
case (h, t) => t.foldLeft(h) {
case (left, ("+", right)) => Add(left, right)
case (left, ("-", right)) => Subtract(left, right)
}
}
def multiplicative = primitive ~ ((keyword("*") | keyword("/")) ~ primitive).* >> {
case (h, t) => t.foldLeft(h) {
case (left, ("*", right)) => Multiply(left, right)
case (left, ("/", right)) => Divide(left, right)
}
}
def unary : Rule[Expr] = keyword("-").? ~ primitive >> {
case (Some(_), v) => Negate(v)
case (None, v) => v
}
def primitive : Rule[Expr] = Rule.firstOf(number >> Number, group)
def group : Rule[Expr] = keyword("(") ~ additive ~ keyword(")") >> { case ((_, result), _) => result }
def number : Rule[Int] = range('1', '9') ~ range('0', '9').* ~ ws >> {
case ((h, t), _) => t.foldLeft(h - '0')((n, c) => n * 10 + (c - '0'))
}
def keyword(str : String) = s(str) ~ ws >> { case (s, _) => s }
def ws = s(" ").* >> { case _ => Unit }
}
sealed abstract class Expr
case class Number(value : Int) extends Expr
case class Add(left : Expr, right : Expr) extends Expr
case class Subtract(left : Expr, right : Expr) extends Expr
case class Multiply(left : Expr, right : Expr) extends Expr
case class Divide(left : Expr, right : Expr) extends Expr
case class Negate(argument : Expr) extends Expr

View File

@ -0,0 +1,112 @@
package org.teavm.samples.scala
trait Grammar {
def rule[T](f : Seq[Char] => (Option[T], Seq[Char])) : Rule[T] = Rule.rule(f)
def s(str : String) : Rule[String] = Rule.expect(str)
def range(first : Char, last : Char) : Rule[Char] = Rule.range(first, last)
}
trait Rule[T] {
def parse(chars : Seq[Char]) : (Option[T], Seq[Char])
def ~[S](other : Rule[S]) : Rule[(T, S)] = Rule.concat(this, other)
def ~(other : => String) : Rule[(T, String)] = Rule.concat(this, Rule.expect(other))
def |(other : => Rule[T]) : Rule[T] = Rule.firstOf(this, other)
def *() : Rule[List[T]] = Rule.unlimited(this)
def >>[S](f : T => S) : Rule[S] = Rule.andThen(this, f)
def ?() : Rule[Option[T]] = Rule.optional(this)
def debug(str : String) = Rule.rule { x =>
var (result, rem) = parse(x)
println(str + ":" + result + ":" + rem)
(result, rem)
}
}
object Rule {
def rule[T](f : Seq[Char] => (Option[T], Seq[Char])) : Rule[T] = {
new Rule[T]() {
def parse(chars : Seq[Char]) : (Option[T], Seq[Char]) = f(chars)
}
}
def concat[S, T](left : Rule[S], right : => Rule[T]) : Rule[(S, T)] = {
lazy val right2 = right
rule(chars => {
left.parse(chars) match {
case (Some(leftResult), rem) => right2.parse(rem) match {
case (Some(rightResult), rem2) => (Some((leftResult, rightResult)), rem2)
case (None, rem2) => (None, rem)
}
case (None, rem) => (None, rem)
}
})
}
def unlimited[T](inner : Rule[T]) : Rule[List[T]] = {
def iter(chars : Seq[Char]) : (List[T], Seq[Char]) = {
inner.parse(chars) match {
case (Some(result), rem) => {
val (tail, rem2) = iter(rem)
(result :: tail, rem2)
}
case (None, rem) => (Nil, rem)
}
}
rule(chars => {
val (result, rem) = iter(chars)
(Some(result.reverse), rem)
})
}
def firstOf[T](first : Rule[T], second : => Rule[T]) : Rule[T] = {
lazy val second2 = second
rule(chars => {
first.parse(chars) match {
case (Some(result), rem) => (Some(result), rem)
case (None, _) => second2.parse(chars) match {
case (Some(result), rem) => (Some(result), rem)
case (None, _) => (None, chars)
}
}
})
}
def optional[T](inner : Rule[T]) : Rule[Option[T]] = {
rule {
chars => inner.parse(chars) match {
case (Some(result), rem) => (Some(Some(result)), rem)
case (None, rem) => (Some(None), chars)
}
}
}
implicit def expect(str : String) : Rule[String] = {
def iter(chars : Seq[Char], index : Int) : (Boolean, Seq[Char]) = {
if (index == str.length())
(true, chars)
else chars match {
case Seq() => (false, Nil);
case c +: tail if c == str.charAt(index) => iter(tail, index + 1)
case _ => (false, chars)
}
}
rule(chars => {
val (matched, rem) = iter(chars, 0)
(matched match {
case true => Some(str)
case false => None
}, rem)
})
}
def andThen[T, S](inner : Rule[T], f : T => S) : Rule[S] = {
rule(chars => {
inner.parse(chars) match {
case (Some(result), rem) => (Some(f(result)), rem)
case (None, rem) => (None, rem)
}
})
}
def range(first : Char, last : Char) : Rule[Char] = {
rule(chars => {
chars match {
case c +: rem if c >= first && c <= last => (Some(c), rem)
case _ => (None, chars)
}
})
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2014 Alexey Andreev.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
</web-app>

View File

@ -0,0 +1,65 @@
html, body {
margin: 0;
padding: 0
}
.top {
position: static;
padding-top: 10px;
padding-left: 10px;
padding-right: 10px;
top: 0;
left: 0;
right: 0;
height: 80px;
border-bottom-color: rgb(120,120,120);
border-bottom-width: 1px;
border-bottom-style: solid;
background-color: rgb(230,230,230);
}
.expr {
width: 100%;
display: block
}
.calc-panel {
margin-right: 80px;
}
.calculate {
float: right;
width: 70px;
}
.result-list {
position: static;
top: 81;
left: 0;
right: 0;
bottom: 0;
overflow: auto
}
.result-list > div {
padding-top: 4px;
padding-bottom: 4px;
border-bottom-color: rgb(170,170,170);
border-bottom-width: 1px;
border-bottom-style: dotted;
}
.result-list > div > span.result {
font-weight: bold;
}
.result-list > div:nth-child(1) {
color: rgb(0,0,0);
}
.result-list > div:nth-child(2) {
color: rgb(30,30,30);
}
.result-list > div:nth-child(3) {
color: rgb(60,60,60);
}
.result-list > div:nth-child(4) {
color: rgb(90,90,90);
}
.result-list > div:nth-child(5) {
color: rgb(120,120,120);
}
.result-list > div:nth-child(n+6) {
color: rgb(150,150,150);
}

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>Hello Scala</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<script type="text/javascript" charset="utf-8" src="teavm/runtime.js"></script>
<script type="text/javascript" charset="utf-8" src="teavm/classes.js"></script>
<link rel="stylesheet" type="text/css" href="calculator.css">
</head>
<body onload="main()">
<div class="top">
<p>This calculator supports the following operators: + - * /.
Also grouping parentheses supported. Example: (4 + 5) * 6</p>
<button id="calculate" class="calculate" tabindex="2">Calculate</button>
<div class="calc-panel">
<input type="text" id="expr" class="expr" tabindex="1"/>
</div>
</div>
<div id="result-list" class="result-list"></div>
</body>
</html>