From: Hannu Niemistö Date: Fri, 23 Sep 2016 12:14:20 +0000 (+0300) Subject: Automatic execution of SCL tests in Maven X-Git-Tag: v1.25.0~97 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=0364f8f54b009e9e5de482d5c9d1cb7efb023141;p=simantics%2Fplatform.git Automatic execution of SCL tests in Maven This includes both compiler tests (in tests/org.simantics.scl.compiler.tests) and a test that checks that all SCL modules in org.simantics.sdk feature compile (in tests/org.simantics.scl.osgi.tests). This commit contains also some modifications to make all SCL modules compile: * Disabled Data/Json, because it does not compile (missing jackson) * Committed away Simantics/Image/linkImage Change-Id: I22a460d756f65139971f1e7d2cc8624a7a6b8ffb --- diff --git a/.gitignore b/.gitignore index 7d3880771..d61db6ef2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /**/bin/ /features/*/target/ /bundles/*/target/ +/releng/**/target/ +/tests/*/target/ /**/.polyglot.build.properties diff --git a/bundles/org.simantics.image.ui/scl/Simantics/Image.scl b/bundles/org.simantics.image.ui/scl/Simantics/Image.scl index 74d197f2f..df9ba8360 100644 --- a/bundles/org.simantics.image.ui/scl/Simantics/Image.scl +++ b/bundles/org.simantics.image.ui/scl/Simantics/Image.scl @@ -8,6 +8,7 @@ type Image = Resource importJava "org.simantics.image.ui.SCLImage" where @JavaName importImageFromFile importImage :: File -> Library -> Image - - @JavaName linkImage - linkImage :: SVGImage -> Image -> () \ No newline at end of file + +// HN: does not exist +// @JavaName linkImage +// linkImage :: SVGImage -> Image -> () \ No newline at end of file diff --git a/bundles/org.simantics.scl.compiler/META-INF/MANIFEST.MF b/bundles/org.simantics.scl.compiler/META-INF/MANIFEST.MF index 389381c96..916e66cfd 100755 --- a/bundles/org.simantics.scl.compiler/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.scl.compiler/META-INF/MANIFEST.MF @@ -10,7 +10,8 @@ Require-Bundle: gnu.trove3;bundle-version="3.0.0", org.objectweb.asm;bundle-version="[5.0.0,6.0.0)", org.objectweb.asm.commons;bundle-version="[5.0.0,6.0.0)", org.objectweb.asm.util;bundle-version="[5.0.0,6.0.0)" -Export-Package: org.simantics.scl.compiler.commands, +Export-Package: org.cojen.classfile, + org.simantics.scl.compiler.commands, org.simantics.scl.compiler.common.datatypes, org.simantics.scl.compiler.common.exceptions, org.simantics.scl.compiler.common.names, @@ -38,12 +39,15 @@ Export-Package: org.simantics.scl.compiler.commands, org.simantics.scl.compiler.environment.filter, org.simantics.scl.compiler.environment.specification, org.simantics.scl.compiler.errors, + org.simantics.scl.compiler.internal.elaboration.constraints2, + org.simantics.scl.compiler.internal.elaboration.subsumption, org.simantics.scl.compiler.internal.parsing, org.simantics.scl.compiler.internal.parsing.exceptions, org.simantics.scl.compiler.internal.parsing.parser, org.simantics.scl.compiler.markdown.html, org.simantics.scl.compiler.markdown.inlines, org.simantics.scl.compiler.markdown.internal, + org.simantics.scl.compiler.markdown.nodes, org.simantics.scl.compiler.module, org.simantics.scl.compiler.module.coverage, org.simantics.scl.compiler.module.options, diff --git a/bundles/org.simantics.scl.data/META-INF/MANIFEST.MF b/bundles/org.simantics.scl.data/META-INF/MANIFEST.MF index 52095a101..950e59b42 100644 --- a/bundles/org.simantics.scl.data/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.scl.data/META-INF/MANIFEST.MF @@ -7,6 +7,5 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Require-Bundle: org.simantics.scl.runtime;bundle-version="0.4.0", org.simantics.scl.osgi;bundle-version="1.0.4", org.jdom2;bundle-version="2.0.6", - org.junit;bundle-version="4.12.0";resolution:=optional, - com.fasterxml.jackson.core.jackson-core;bundle-version="2.8.2" + org.junit;bundle-version="4.12.0";resolution:=optional Bundle-ClassPath: . diff --git a/bundles/org.simantics.scl.data/scl/Data/Json.scl b/bundles/org.simantics.scl.data/scl/Data/Json.scl.skip similarity index 100% rename from bundles/org.simantics.scl.data/scl/Data/Json.scl rename to bundles/org.simantics.scl.data/scl/Data/Json.scl.skip diff --git a/pom.xml b/pom.xml index eeebff8e9..85a794381 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ bundles features releng + tests diff --git a/tests/org.simantics.scl.compiler.tests/.classpath b/tests/org.simantics.scl.compiler.tests/.classpath new file mode 100644 index 000000000..b862a296d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/org.simantics.scl.compiler.tests/.project b/tests/org.simantics.scl.compiler.tests/.project new file mode 100644 index 000000000..9fa2ae131 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/.project @@ -0,0 +1,28 @@ + + + org.simantics.scl.compiler.tests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/tests/org.simantics.scl.compiler.tests/.settings/org.eclipse.jdt.core.prefs b/tests/org.simantics.scl.compiler.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..295926d96 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/tests/org.simantics.scl.compiler.tests/META-INF/MANIFEST.MF b/tests/org.simantics.scl.compiler.tests/META-INF/MANIFEST.MF new file mode 100644 index 000000000..5caaeecbd --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tests +Bundle-SymbolicName: org.simantics.scl.compiler.tests +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.junit;bundle-version="4.12.0", + org.simantics.scl.compiler;bundle-version="0.5.0", + org.simantics.scl.osgi;bundle-version="1.0.4", + gnu.trove3, + org.objectweb.asm.util, + org.eclipse.equinox.ds;bundle-version="1.4.300" diff --git a/tests/org.simantics.scl.compiler.tests/build.properties b/tests/org.simantics.scl.compiler.tests/build.properties new file mode 100644 index 000000000..41eb6ade2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java new file mode 100644 index 000000000..f9533efee --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ActiveTests.java @@ -0,0 +1,24 @@ +package org.simantics.scl.compiler.tests; + +import org.junit.Ignore; +import org.junit.Test; + +public class ActiveTests extends TestBase { + + public ActiveTests() { super("scl"); } +/* + @Test public void Equations1() { test(); } + @Test public void MarketModel2() { test(); } + @Test public void Overloading2() { test(); } + @Test public void Overloading3() { test(); } + //@Ignore + @Test public void PatternError() { test(); } + @Test public void Serialization() { test(); } + @Ignore + @Test public void TypeClass2() { test(); } + @Test public void TypeClassBug2() { test(); } + */ + + //@Test public void CityoptSetup() { test(); } + @Test public void EmptyLet() { test(); } +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/FindAllowedChars.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/FindAllowedChars.java new file mode 100644 index 000000000..1e4078670 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/FindAllowedChars.java @@ -0,0 +1,66 @@ +package org.simantics.scl.compiler.tests; + +import java.lang.reflect.Method; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class FindAllowedChars { + public static class MyClassLoader extends ClassLoader { + final String className; + final byte[] classBytes; + + public MyClassLoader(ClassLoader parent, String className, byte[] classBytes) { + super(parent); + this.className = className; + this.classBytes = classBytes; + } + + public MyClassLoader(String className, byte[] classBytes) { + this.className = className; + this.classBytes = classBytes; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if(name.equals(name)) + return defineClass(name, classBytes, 0, classBytes.length); + else + return super.findClass(name); + } + } + + public static void test(String className, String methodName) throws Exception { + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); + classWriter.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null); + + MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, methodName, "()V", null, null); + /*methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + methodVisitor.visitLdcInsn("Hello world!"); + methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);*/ + methodVisitor.visitInsn(Opcodes.RETURN); + methodVisitor.visitMaxs(0, 0); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + + ClassLoader loader = new MyClassLoader(className, classWriter.toByteArray()); + Class clazz = loader.loadClass(className); + Method method = clazz.getMethod(methodName); + method.invoke(null); + } + + public static void main(String[] args) throws Exception { + for(int a=Character.MIN_VALUE;a maybeModule = PRELUDE_MODULE_REPOSITORY.getModule("Prelude"); + if(!maybeModule.didSucceed()) + return; + Module module = maybeModule.getResult(); + ModuleCoverage coverage = CoverageUtils.getCoverage(module); + if(coverage == null) + return; + coverage.print(System.out); + printCoverageTree(module.getBranchPoints().get("lookup"), 0); + } + + private static void printCoverageTree(BranchPoint[] branchPoints, int ind) { + for(BranchPoint bp : branchPoints) { + for(int i=0;i auxModuleNameList = new ArrayList(); + while(j < testParts.length) { + String part = testParts[j]; + if(part.startsWith("// module ")) + auxModuleNameList.add(part.substring(10).split("\\n", 2)[0].trim()); + else + break; + ++j; + } + int mainId = j; + String[] moduleNames = new String[mainId+1]; + String[] moduleTexts = new String[mainId+1]; + for(int i=0;i result = testEnvironment.getModule(moduleNames[lastId]); + if(!result.didSucceed()) + return ((Failure)result).toString(moduleTexts[lastId]); + else { + Object main = testEnvironment.getRuntimeModule(moduleNames[lastId]).getResult().getValue("main"); + return String.valueOf(main); + } + } + + private String[] readTestParts(String testPath) throws IOException { + InputStream stream = getClass().getResourceAsStream(testPath); + try { + byte[] buffer = new byte[1024]; + int pos = 0; + while(true) { + int c = stream.read(buffer, pos, buffer.length-pos); + if(c <= 0) + break; + pos += c; + if(pos < buffer.length) + break; + buffer = Arrays.copyOf(buffer, pos*2); + } + String text = new String(buffer, 0, pos, UTF8); + String[] result = TEST_SEPARATOR.split(text); + for(int i=1;i print i) [1,2,3]"); + session.execute("iter (\\i -> print i) [(),(),()]"); + } + +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestExpressionEvaluator.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestExpressionEvaluator.java new file mode 100644 index 000000000..e143c6ab9 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/TestExpressionEvaluator.java @@ -0,0 +1,197 @@ +package org.simantics.scl.compiler.tests; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; +import org.simantics.scl.compiler.elaboration.expressions.EVariable; +import org.simantics.scl.compiler.elaboration.expressions.Expression; +import org.simantics.scl.compiler.elaboration.expressions.Variable; +import org.simantics.scl.compiler.environment.AbstractLocalEnvironment; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.environment.LocalEnvironment; +import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification; +import org.simantics.scl.compiler.errors.CompilationErrorFormatter; +import org.simantics.scl.compiler.module.repository.ImportFailure; +import org.simantics.scl.compiler.module.repository.ImportFailureException; +import org.simantics.scl.compiler.module.repository.ModuleRepository; +import org.simantics.scl.compiler.runtime.RuntimeEnvironment; +import org.simantics.scl.compiler.source.repository.CompositeModuleSourceRepository; +import org.simantics.scl.compiler.source.repository.SourceRepositories; +import org.simantics.scl.compiler.top.ExpressionEvaluator; +import org.simantics.scl.compiler.top.SCLExpressionCompilationException; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.runtime.function.Function; +import org.simantics.scl.runtime.tuple.Tuple0; + +import junit.framework.Assert; + +public class TestExpressionEvaluator { + + public static final boolean TIMING = false; + public static final int COUNT = 10000; + + ModuleRepository moduleRepository; + + RuntimeEnvironment runtimeEnvironment; + + @Before + public void initialize() throws Exception { + moduleRepository = InitialRepository.getInitialRepository(); + + // Environment for compiling expressions + EnvironmentSpecification environmentSpecification = new EnvironmentSpecification(); + environmentSpecification.importModule("Builtin", ""); + environmentSpecification.importModule("Prelude", ""); + + try { + runtimeEnvironment = moduleRepository.createRuntimeEnvironment(environmentSpecification, + getClass().getClassLoader()); + } catch(ImportFailureException e) { + for(ImportFailure failure : e.failures) + System.err.println("Failed to import " + failure.moduleName); + throw e; + } + } + + private void testExpression0(String expressionText, + Object expectedValue, + Type expectedType) throws Exception { + // Compiling and running expression + try { + Object result = new ExpressionEvaluator(runtimeEnvironment, expressionText) + .expectedType(expectedType) + .eval(); + if(expectedValue != null) + Assert.assertEquals(expectedValue, result); + } catch(SCLExpressionCompilationException e) { + System.out.println(CompilationErrorFormatter.toString(expressionText, e.getErrors())); + throw e; + } + } + + private void testExpression(String expressionText, + Object expectedValue, + Type expectedType) throws Exception { + if(TIMING) { + System.out.println(expressionText); + long beginTime = System.nanoTime(); + for(int i=0;i x) [(1,2),(2,3)]", + Arrays.asList(2.0, 3.0), + Types.list(Types.DOUBLE)); + testExpression("map (\\x -> snd x) [(1,2),(2,3)]", + Arrays.asList(2.0, 3.0), + Types.list(Types.DOUBLE)); + testExpression("let f x = x+1 in (f . f . f) 3", + Double.valueOf(6.0), + Types.DOUBLE); + if(!TIMING) + testExpression("print \"Hello world!\"", + Tuple0.INSTANCE, + Types.UNIT); + testExpression("[1,2+3,4+5]", + Arrays.asList(1,5,9), + Types.list(Types.INTEGER)); + testExpression("let a = 5.3 in let f x = x+a in f 3", + Double.valueOf(8.3), + Types.DOUBLE); + testExpression("let mm x y = if x < y then x else y in mm 2 (mm 1 3)", + Double.valueOf(1.0), + Types.DOUBLE); + } + + @Test + public void testLocalEnvironment() throws Exception { + String expressionText = "a + b"; + LocalEnvironment localEnvironment = new AbstractLocalEnvironment() { + Variable[] localParameters = new Variable[] { + new Variable("a", Types.DOUBLE), + new Variable("b", Types.DOUBLE), + }; + + @Override + public Expression resolve(Environment environment, String localName) { + if(localName.equals("a")) + return new EVariable(localParameters[0]); + else if(localName.equals("b")) + return new EVariable(localParameters[1]); + else + return null; + } + + @Override + protected Variable[] getContextVariables() { + return localParameters; + } + }; + try { + Object result = new ExpressionEvaluator(runtimeEnvironment, expressionText) + .localEnvironment(localEnvironment) + .expectedType(Types.DOUBLE) + .eval(); + Assert.assertEquals( + Double.valueOf(15.0), + ((Function)result).apply(7.0, 8.0)); + } catch(SCLExpressionCompilationException e) { + System.out.println(CompilationErrorFormatter.toString(expressionText, e.getErrors())); + throw e; + } + } + + @Test + public void testArities() throws Exception { + for(int arity=1;arity<50;++arity) { + // Build expressions + StringBuilder b = new StringBuilder(); + b.append('\\'); + for(int i=0;i "); + for(int i=0;i 0) + b.append(" + "); + b.append("v" + i); + } + //System.out.println(b.toString()); + + // Compile + Type expectedType = Types.INTEGER; + for(int i=0;i", "(Ljava/lang/Object;)V", false); + + methodWriter.visitVarInsn(Opcodes.ALOAD, 1); + methodWriter.visitVarInsn(Opcodes.ALOAD, 2); + methodWriter.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/util/concurrent/atomic/AtomicReference", "", "(Ljava/lang/Object;)V", false); + + methodWriter.visitVarInsn(Opcodes.ALOAD, 2); + methodWriter.visitInsn(Opcodes.ARETURN); + methodWriter.visitMaxs(0, 0); + methodWriter.visitEnd(); + + byte[] bytes = classWriter.toByteArray(); + ClassLoader classLoader = new ClassLoader() { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if(!name.equals("test.Test")) + throw new ClassNotFoundException(); + return defineClass("test.Test", bytes, 0, bytes.length); + } + }; + Class clazz = classLoader.loadClass("test.Test"); + Method method = clazz.getMethod("main"); + AtomicReference result = (AtomicReference)method.invoke(null); + System.out.println(result.hashCode()); + //System.out.println(result.get().hashCode()); + } + +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/experimentation/TestEquals.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/experimentation/TestEquals.java new file mode 100644 index 000000000..022ae572f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/experimentation/TestEquals.java @@ -0,0 +1,15 @@ +package org.simantics.scl.compiler.tests.experimentation; + +public class TestEquals { + public static boolean eqInt(int a, int b) { + return a==b; + } + + public static boolean eqDouble(double a, double b) { + return a==b; + } + + public static boolean eqObject(Object a, Object b) { + return a.equals(b); + } +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/experimentation/TestTypeDesc.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/experimentation/TestTypeDesc.java new file mode 100644 index 000000000..71538898d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/experimentation/TestTypeDesc.java @@ -0,0 +1,12 @@ +package org.simantics.scl.compiler.tests.experimentation; + +import org.cojen.classfile.TypeDesc; + +public class TestTypeDesc { + public static void main(String[] args) { + System.out.println(TypeDesc.forClass(String.class).getFullName()); + System.out.println(TypeDesc.forClass(String.class).getDescriptor()); + System.out.println(TypeDesc.forClass(String.class).getRootName()); + + } +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/imports/Maybe4Imports.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/imports/Maybe4Imports.java new file mode 100644 index 000000000..30fe62719 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/imports/Maybe4Imports.java @@ -0,0 +1,15 @@ +package org.simantics.scl.compiler.tests.imports; + +import java.util.Random; + +public class Maybe4Imports { + + public static Object toMaybeDouble(Random r, String s) { + try { + return new Double(s); + } catch(Exception e) { + return null; + } + } + +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/markdown/RunMarkdownTests.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/markdown/RunMarkdownTests.java new file mode 100644 index 000000000..9971a020b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/markdown/RunMarkdownTests.java @@ -0,0 +1,100 @@ +package org.simantics.scl.compiler.tests.markdown; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.nio.charset.Charset; + +import org.simantics.scl.compiler.markdown.internal.MarkdownParser; +import org.simantics.scl.compiler.markdown.nodes.Node; + +public class RunMarkdownTests { + + public static int FAILED = 0; + public static int SUCCEEDED = 1; + public static int SKIPPED = 2; + + public static void main(String[] args) throws IOException { + BufferedReader reader = new BufferedReader( + new InputStreamReader( + RunMarkdownTests.class.getResourceAsStream("spec.txt"), + Charset.forName("UTF-8"))); + + StringBuilder in = new StringBuilder(); + StringBuilder out = new StringBuilder(); + int state = 0; + int testId = 0; + int passed = 0; + int failed = 0; + int skipped = 0; + while(true) { + String line = reader.readLine(); + if(line == null) + break; + switch(state) { + case 0: + if(line.equals("```````````````````````````````` example")) + ++state; + break; + case 1: + if(line.equals(".")) + ++state; + else { + if(in.length() > 0) + in.append('\n'); + in.append(line); + } + break; + case 2: + if(line.equals("````````````````````````````````")) { + ++testId; + int status = test(testId, in.toString(), out.toString()); + if(status == SUCCEEDED) + ++passed; + else if(status == FAILED) + ++failed; + else + ++skipped; + in = new StringBuilder(); + out = new StringBuilder(); + state = 0; + } + else { + if(out.length() > 0) + out.append('\n'); + out.append(line); + } + break; + } + } + + System.out.println("Passed: " + passed + "/" + testId); + System.out.println("Failed: " + failed + "/" + testId); + System.out.println("Skipped: " + skipped + "/" + testId); + } + + public static int test(int id, String in, String out) throws IOException { + MarkdownParser parser = new MarkdownParser(); + Node node = parser.parseDocument(new StringReader(in.replace('\u2192', '\t'))); + + String result = node.toHtml().replace('\t', '\u2192'); + + boolean passed = result.equals(out); + + if(!passed) { + System.out.println("Example " + id); // + (passed ? " passed" : " failed")); + System.out.println("---- in --------------------------------------------------------------------"); + System.out.println(in); + System.out.println("---- expected --------------------------------------------------------------"); + System.out.println(out); + System.out.println("---- actual ----------------------------------------------------------------"); + System.out.println(result); + System.out.println("----------------------------------------------------------------------------"); + System.out.println(); + } + + return passed ? SUCCEEDED : FAILED; + } + +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/markdown/spec.txt b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/markdown/spec.txt new file mode 100644 index 000000000..bdaed436d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/markdown/spec.txt @@ -0,0 +1,9252 @@ +--- +title: CommonMark Spec +author: John MacFarlane +version: 0.25 +date: '2016-03-24' +license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)' +... + +# Introduction + +## What is Markdown? + +Markdown is a plain text format for writing structured documents, +based on conventions used for indicating formatting in email and +usenet posts. It was developed in 2004 by John Gruber, who wrote +the first Markdown-to-HTML converter in perl, and it soon became +widely used in websites. By 2014 there were dozens of +implementations in many languages. Some of them extended basic +Markdown syntax with conventions for footnotes, definition lists, +tables, and other constructs, and some allowed output not just in +HTML but in LaTeX and many other formats. + +## Why is a spec needed? + +John Gruber's [canonical description of Markdown's +syntax](http://daringfireball.net/projects/markdown/syntax) +does not specify the syntax unambiguously. Here are some examples of +questions it does not answer: + +1. How much indentation is needed for a sublist? The spec says that + continuation paragraphs need to be indented four spaces, but is + not fully explicit about sublists. It is natural to think that + they, too, must be indented four spaces, but `Markdown.pl` does + not require that. This is hardly a "corner case," and divergences + between implementations on this issue often lead to surprises for + users in real documents. (See [this comment by John + Gruber](http://article.gmane.org/gmane.text.markdown.general/1997).) + +2. Is a blank line needed before a block quote or heading? + Most implementations do not require the blank line. However, + this can lead to unexpected results in hard-wrapped text, and + also to ambiguities in parsing (note that some implementations + put the heading inside the blockquote, while others do not). + (John Gruber has also spoken [in favor of requiring the blank + lines](http://article.gmane.org/gmane.text.markdown.general/2146).) + +3. Is a blank line needed before an indented code block? + (`Markdown.pl` requires it, but this is not mentioned in the + documentation, and some implementations do not require it.) + + ``` markdown + paragraph + code? + ``` + +4. What is the exact rule for determining when list items get + wrapped in `

` tags? Can a list be partially "loose" and partially + "tight"? What should we do with a list like this? + + ``` markdown + 1. one + + 2. two + 3. three + ``` + + Or this? + + ``` markdown + 1. one + - a + + - b + 2. two + ``` + + (There are some relevant comments by John Gruber + [here](http://article.gmane.org/gmane.text.markdown.general/2554).) + +5. Can list markers be indented? Can ordered list markers be right-aligned? + + ``` markdown + 8. item 1 + 9. item 2 + 10. item 2a + ``` + +6. Is this one list with a thematic break in its second item, + or two lists separated by a thematic break? + + ``` markdown + * a + * * * * * + * b + ``` + +7. When list markers change from numbers to bullets, do we have + two lists or one? (The Markdown syntax description suggests two, + but the perl scripts and many other implementations produce one.) + + ``` markdown + 1. fee + 2. fie + - foe + - fum + ``` + +8. What are the precedence rules for the markers of inline structure? + For example, is the following a valid link, or does the code span + take precedence ? + + ``` markdown + [a backtick (`)](/url) and [another backtick (`)](/url). + ``` + +9. What are the precedence rules for markers of emphasis and strong + emphasis? For example, how should the following be parsed? + + ``` markdown + *foo *bar* baz* + ``` + +10. What are the precedence rules between block-level and inline-level + structure? For example, how should the following be parsed? + + ``` markdown + - `a long code span can contain a hyphen like this + - and it can screw things up` + ``` + +11. Can list items include section headings? (`Markdown.pl` does not + allow this, but does allow blockquotes to include headings.) + + ``` markdown + - # Heading + ``` + +12. Can list items be empty? + + ``` markdown + * a + * + * b + ``` + +13. Can link references be defined inside block quotes or list items? + + ``` markdown + > Blockquote [foo]. + > + > [foo]: /url + ``` + +14. If there are multiple definitions for the same reference, which takes + precedence? + + ``` markdown + [foo]: /url1 + [foo]: /url2 + + [foo][] + ``` + +In the absence of a spec, early implementers consulted `Markdown.pl` +to resolve these ambiguities. But `Markdown.pl` was quite buggy, and +gave manifestly bad results in many cases, so it was not a +satisfactory replacement for a spec. + +Because there is no unambiguous spec, implementations have diverged +considerably. As a result, users are often surprised to find that +a document that renders one way on one system (say, a github wiki) +renders differently on another (say, converting to docbook using +pandoc). To make matters worse, because nothing in Markdown counts +as a "syntax error," the divergence often isn't discovered right away. + +## About this document + +This document attempts to specify Markdown syntax unambiguously. +It contains many examples with side-by-side Markdown and +HTML. These are intended to double as conformance tests. An +accompanying script `spec_tests.py` can be used to run the tests +against any Markdown program: + + python test/spec_tests.py --spec spec.txt --program PROGRAM + +Since this document describes how Markdown is to be parsed into +an abstract syntax tree, it would have made sense to use an abstract +representation of the syntax tree instead of HTML. But HTML is capable +of representing the structural distinctions we need to make, and the +choice of HTML for the tests makes it possible to run the tests against +an implementation without writing an abstract syntax tree renderer. + +This document is generated from a text file, `spec.txt`, written +in Markdown with a small extension for the side-by-side tests. +The script `tools/makespec.py` can be used to convert `spec.txt` into +HTML or CommonMark (which can then be converted into other formats). + +In the examples, the `→` character is used to represent tabs. + +# Preliminaries + +## Characters and lines + +Any sequence of [characters] is a valid CommonMark +document. + +A [character](@) is a Unicode code point. Although some +code points (for example, combining accents) do not correspond to +characters in an intuitive sense, all code points count as characters +for purposes of this spec. + +This spec does not specify an encoding; it thinks of lines as composed +of [characters] rather than bytes. A conforming parser may be limited +to a certain encoding. + +A [line](@) is a sequence of zero or more [characters] +other than newline (`U+000A`) or carriage return (`U+000D`), +followed by a [line ending] or by the end of file. + +A [line ending](@) is a newline (`U+000A`), a carriage return +(`U+000D`) not followed by a newline, or a carriage return and a +following newline. + +A line containing no characters, or a line containing only spaces +(`U+0020`) or tabs (`U+0009`), is called a [blank line](@). + +The following definitions of character classes will be used in this spec: + +A [whitespace character](@) is a space +(`U+0020`), tab (`U+0009`), newline (`U+000A`), line tabulation (`U+000B`), +form feed (`U+000C`), or carriage return (`U+000D`). + +[Whitespace](@) is a sequence of one or more [whitespace +characters]. + +A [Unicode whitespace character](@) is +any code point in the Unicode `Zs` class, or a tab (`U+0009`), +carriage return (`U+000D`), newline (`U+000A`), or form feed +(`U+000C`). + +[Unicode whitespace](@) is a sequence of one +or more [Unicode whitespace characters]. + +A [space](@) is `U+0020`. + +A [non-whitespace character](@) is any character +that is not a [whitespace character]. + +An [ASCII punctuation character](@) +is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`, +`*`, `+`, `,`, `-`, `.`, `/`, `:`, `;`, `<`, `=`, `>`, `?`, `@`, +`[`, `\`, `]`, `^`, `_`, `` ` ``, `{`, `|`, `}`, or `~`. + +A [punctuation character](@) is an [ASCII +punctuation character] or anything in +the Unicode classes `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`. + +## Tabs + +Tabs in lines are not expanded to [spaces]. However, +in contexts where indentation is significant for the +document's structure, tabs behave as if they were replaced +by spaces with a tab stop of 4 characters. + +```````````````````````````````` example +→foo→baz→→bim +. +

foo→baz→→bim
+
+```````````````````````````````` + + +```````````````````````````````` example + →foo→baz→→bim +. +
foo→baz→→bim
+
+```````````````````````````````` + + +```````````````````````````````` example + a→a + ὐ→a +. +
a→a
+ὐ→a
+
+```````````````````````````````` + + +```````````````````````````````` example + - foo + +→bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +- foo + +→→bar +. +
    +
  • +

    foo

    +
      bar
    +
    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +>→→foo +. +
+
  foo
+
+
+```````````````````````````````` + +```````````````````````````````` example +-→→foo +. +
    +
  • +
      foo
    +
    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example + foo +→bar +. +
foo
+bar
+
+```````````````````````````````` + +```````````````````````````````` example + - foo + - bar +→ - baz +. +
    +
  • foo +
      +
    • bar +
        +
      • baz
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + + + +## Insecure characters + +For security reasons, the Unicode character `U+0000` must be replaced +with the REPLACEMENT CHARACTER (`U+FFFD`). + +# Blocks and inlines + +We can think of a document as a sequence of +[blocks](@)---structural elements like paragraphs, block +quotations, lists, headings, rules, and code blocks. Some blocks (like +block quotes and list items) contain other blocks; others (like +headings and paragraphs) contain [inline](@) content---text, +links, emphasized text, images, code, and so on. + +## Precedence + +Indicators of block structure always take precedence over indicators +of inline structure. So, for example, the following is a list with +two items, not a list with one item containing a code span: + +```````````````````````````````` example +- `one +- two` +. +
    +
  • `one
  • +
  • two`
  • +
+```````````````````````````````` + + +This means that parsing can proceed in two steps: first, the block +structure of the document can be discerned; second, text lines inside +paragraphs, headings, and other block constructs can be parsed for inline +structure. The second step requires information about link reference +definitions that will be available only at the end of the first +step. Note that the first step requires processing lines in sequence, +but the second can be parallelized, since the inline parsing of +one block element does not affect the inline parsing of any other. + +## Container blocks and leaf blocks + +We can divide blocks into two types: +[container block](@)s, +which can contain other blocks, and [leaf block](@)s, +which cannot. + +# Leaf blocks + +This section describes the different kinds of leaf block that make up a +Markdown document. + +## Thematic breaks + +A line consisting of 0-3 spaces of indentation, followed by a sequence +of three or more matching `-`, `_`, or `*` characters, each followed +optionally by any number of spaces, forms a +[thematic break](@). + +```````````````````````````````` example +*** +--- +___ +. +
+
+
+```````````````````````````````` + + +Wrong characters: + +```````````````````````````````` example ++++ +. +

+++

+```````````````````````````````` + + +```````````````````````````````` example +=== +. +

===

+```````````````````````````````` + + +Not enough characters: + +```````````````````````````````` example +-- +** +__ +. +

-- +** +__

+```````````````````````````````` + + +One to three spaces indent are allowed: + +```````````````````````````````` example + *** + *** + *** +. +
+
+
+```````````````````````````````` + + +Four spaces is too many: + +```````````````````````````````` example + *** +. +
***
+
+```````````````````````````````` + + +```````````````````````````````` example +Foo + *** +. +

Foo +***

+```````````````````````````````` + + +More than three characters may be used: + +```````````````````````````````` example +_____________________________________ +. +
+```````````````````````````````` + + +Spaces are allowed between the characters: + +```````````````````````````````` example + - - - +. +
+```````````````````````````````` + + +```````````````````````````````` example + ** * ** * ** * ** +. +
+```````````````````````````````` + + +```````````````````````````````` example +- - - - +. +
+```````````````````````````````` + + +Spaces are allowed at the end: + +```````````````````````````````` example +- - - - +. +
+```````````````````````````````` + + +However, no other characters may occur in the line: + +```````````````````````````````` example +_ _ _ _ a + +a------ + +---a--- +. +

_ _ _ _ a

+

a------

+

---a---

+```````````````````````````````` + + +It is required that all of the [non-whitespace characters] be the same. +So, this is not a thematic break: + +```````````````````````````````` example + *-* +. +

-

+```````````````````````````````` + + +Thematic breaks do not need blank lines before or after: + +```````````````````````````````` example +- foo +*** +- bar +. +
    +
  • foo
  • +
+
+
    +
  • bar
  • +
+```````````````````````````````` + + +Thematic breaks can interrupt a paragraph: + +```````````````````````````````` example +Foo +*** +bar +. +

Foo

+
+

bar

+```````````````````````````````` + + +If a line of dashes that meets the above conditions for being a +thematic break could also be interpreted as the underline of a [setext +heading], the interpretation as a +[setext heading] takes precedence. Thus, for example, +this is a setext heading, not a paragraph followed by a thematic break: + +```````````````````````````````` example +Foo +--- +bar +. +

Foo

+

bar

+```````````````````````````````` + + +When both a thematic break and a list item are possible +interpretations of a line, the thematic break takes precedence: + +```````````````````````````````` example +* Foo +* * * +* Bar +. +
    +
  • Foo
  • +
+
+
    +
  • Bar
  • +
+```````````````````````````````` + + +If you want a thematic break in a list item, use a different bullet: + +```````````````````````````````` example +- Foo +- * * * +. +
    +
  • Foo
  • +
  • +
    +
  • +
+```````````````````````````````` + + +## ATX headings + +An [ATX heading](@) +consists of a string of characters, parsed as inline content, between an +opening sequence of 1--6 unescaped `#` characters and an optional +closing sequence of any number of unescaped `#` characters. +The opening sequence of `#` characters must be followed by a +[space] or by the end of line. The optional closing sequence of `#`s must be +preceded by a [space] and may be followed by spaces only. The opening +`#` character may be indented 0-3 spaces. The raw contents of the +heading are stripped of leading and trailing spaces before being parsed +as inline content. The heading level is equal to the number of `#` +characters in the opening sequence. + +Simple headings: + +```````````````````````````````` example +# foo +## foo +### foo +#### foo +##### foo +###### foo +. +

foo

+

foo

+

foo

+

foo

+
foo
+
foo
+```````````````````````````````` + + +More than six `#` characters is not a heading: + +```````````````````````````````` example +####### foo +. +

####### foo

+```````````````````````````````` + + +At least one space is required between the `#` characters and the +heading's contents, unless the heading is empty. Note that many +implementations currently do not require the space. However, the +space was required by the +[original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py), +and it helps prevent things like the following from being parsed as +headings: + +```````````````````````````````` example +#5 bolt + +#hashtag +. +

#5 bolt

+

#hashtag

+```````````````````````````````` + + +A tab will not work: + +```````````````````````````````` example +#→foo +. +

#→foo

+```````````````````````````````` + + +This is not a heading, because the first `#` is escaped: + +```````````````````````````````` example +\## foo +. +

## foo

+```````````````````````````````` + + +Contents are parsed as inlines: + +```````````````````````````````` example +# foo *bar* \*baz\* +. +

foo bar *baz*

+```````````````````````````````` + + +Leading and trailing blanks are ignored in parsing inline content: + +```````````````````````````````` example +# foo +. +

foo

+```````````````````````````````` + + +One to three spaces indentation are allowed: + +```````````````````````````````` example + ### foo + ## foo + # foo +. +

foo

+

foo

+

foo

+```````````````````````````````` + + +Four spaces are too much: + +```````````````````````````````` example + # foo +. +
# foo
+
+```````````````````````````````` + + +```````````````````````````````` example +foo + # bar +. +

foo +# bar

+```````````````````````````````` + + +A closing sequence of `#` characters is optional: + +```````````````````````````````` example +## foo ## + ### bar ### +. +

foo

+

bar

+```````````````````````````````` + + +It need not be the same length as the opening sequence: + +```````````````````````````````` example +# foo ################################## +##### foo ## +. +

foo

+
foo
+```````````````````````````````` + + +Spaces are allowed after the closing sequence: + +```````````````````````````````` example +### foo ### +. +

foo

+```````````````````````````````` + + +A sequence of `#` characters with anything but [spaces] following it +is not a closing sequence, but counts as part of the contents of the +heading: + +```````````````````````````````` example +### foo ### b +. +

foo ### b

+```````````````````````````````` + + +The closing sequence must be preceded by a space: + +```````````````````````````````` example +# foo# +. +

foo#

+```````````````````````````````` + + +Backslash-escaped `#` characters do not count as part +of the closing sequence: + +```````````````````````````````` example +### foo \### +## foo #\## +# foo \# +. +

foo ###

+

foo ###

+

foo #

+```````````````````````````````` + + +ATX headings need not be separated from surrounding content by blank +lines, and they can interrupt paragraphs: + +```````````````````````````````` example +**** +## foo +**** +. +
+

foo

+
+```````````````````````````````` + + +```````````````````````````````` example +Foo bar +# baz +Bar foo +. +

Foo bar

+

baz

+

Bar foo

+```````````````````````````````` + + +ATX headings can be empty: + +```````````````````````````````` example +## +# +### ### +. +

+

+

+```````````````````````````````` + + +## Setext headings + +A [setext heading](@) consists of one or more +lines of text, each containing at least one [non-whitespace +character], with no more than 3 spaces indentation, followed by +a [setext heading underline]. The lines of text must be such +that, were they not followed by the setext heading underline, +they would be interpreted as a paragraph: they cannot be +interpretable as a [code fence], [ATX heading][ATX headings], +[block quote][block quotes], [thematic break][thematic breaks], +[list item][list items], or [HTML block][HTML blocks]. + +A [setext heading underline](@) is a sequence of +`=` characters or a sequence of `-` characters, with no more than 3 +spaces indentation and any number of trailing spaces. If a line +containing a single `-` can be interpreted as an +empty [list items], it should be interpreted this way +and not as a [setext heading underline]. + +The heading is a level 1 heading if `=` characters are used in +the [setext heading underline], and a level 2 heading if `-` +characters are used. The contents of the heading are the result +of parsing the preceding lines of text as CommonMark inline +content. + +In general, a setext heading need not be preceded or followed by a +blank line. However, it cannot interrupt a paragraph, so when a +setext heading comes after a paragraph, a blank line is needed between +them. + +Simple examples: + +```````````````````````````````` example +Foo *bar* +========= + +Foo *bar* +--------- +. +

Foo bar

+

Foo bar

+```````````````````````````````` + + +The content of the header may span more than one line: + +```````````````````````````````` example +Foo *bar +baz* +==== +. +

Foo bar +baz

+```````````````````````````````` + + +The underlining can be any length: + +```````````````````````````````` example +Foo +------------------------- + +Foo += +. +

Foo

+

Foo

+```````````````````````````````` + + +The heading content can be indented up to three spaces, and need +not line up with the underlining: + +```````````````````````````````` example + Foo +--- + + Foo +----- + + Foo + === +. +

Foo

+

Foo

+

Foo

+```````````````````````````````` + + +Four spaces indent is too much: + +```````````````````````````````` example + Foo + --- + + Foo +--- +. +
Foo
+---
+
+Foo
+
+
+```````````````````````````````` + + +The setext heading underline can be indented up to three spaces, and +may have trailing spaces: + +```````````````````````````````` example +Foo + ---- +. +

Foo

+```````````````````````````````` + + +Four spaces is too much: + +```````````````````````````````` example +Foo + --- +. +

Foo +---

+```````````````````````````````` + + +The setext heading underline cannot contain internal spaces: + +```````````````````````````````` example +Foo += = + +Foo +--- - +. +

Foo += =

+

Foo

+
+```````````````````````````````` + + +Trailing spaces in the content line do not cause a line break: + +```````````````````````````````` example +Foo +----- +. +

Foo

+```````````````````````````````` + + +Nor does a backslash at the end: + +```````````````````````````````` example +Foo\ +---- +. +

Foo\

+```````````````````````````````` + + +Since indicators of block structure take precedence over +indicators of inline structure, the following are setext headings: + +```````````````````````````````` example +`Foo +---- +` + + +. +

`Foo

+

`

+

<a title="a lot

+

of dashes"/>

+```````````````````````````````` + + +The setext heading underline cannot be a [lazy continuation +line] in a list item or block quote: + +```````````````````````````````` example +> Foo +--- +. +
+

Foo

+
+
+```````````````````````````````` + + +```````````````````````````````` example +> foo +bar +=== +. +
+

foo +bar +===

+
+```````````````````````````````` + + +```````````````````````````````` example +- Foo +--- +. +
    +
  • Foo
  • +
+
+```````````````````````````````` + + +A blank line is needed between a paragraph and a following +setext heading, since otherwise the paragraph becomes part +of the heading's content: + +```````````````````````````````` example +Foo +Bar +--- +. +

Foo +Bar

+```````````````````````````````` + + +But in general a blank line is not required before or after +setext headings: + +```````````````````````````````` example +--- +Foo +--- +Bar +--- +Baz +. +
+

Foo

+

Bar

+

Baz

+```````````````````````````````` + + +Setext headings cannot be empty: + +```````````````````````````````` example + +==== +. +

====

+```````````````````````````````` + + +Setext heading text lines must not be interpretable as block +constructs other than paragraphs. So, the line of dashes +in these examples gets interpreted as a thematic break: + +```````````````````````````````` example +--- +--- +. +
+
+```````````````````````````````` + + +```````````````````````````````` example +- foo +----- +. +
    +
  • foo
  • +
+
+```````````````````````````````` + + +```````````````````````````````` example + foo +--- +. +
foo
+
+
+```````````````````````````````` + + +```````````````````````````````` example +> foo +----- +. +
+

foo

+
+
+```````````````````````````````` + + +If you want a heading with `> foo` as its literal text, you can +use backslash escapes: + +```````````````````````````````` example +\> foo +------ +. +

> foo

+```````````````````````````````` + + +**Compatibility note:** Most existing Markdown implementations +do not allow the text of setext headings to span multiple lines. +But there is no consensus about how to interpret + +``` markdown +Foo +bar +--- +baz +``` + +One can find four different interpretations: + +1. paragraph "Foo", heading "bar", paragraph "baz" +2. paragraph "Foo bar", thematic break, paragraph "baz" +3. paragraph "Foo bar --- baz" +4. heading "Foo bar", paragraph "baz" + +We find interpretation 4 most natural, and interpretation 4 +increases the expressive power of CommonMark, by allowing +multiline headings. Authors who want interpretation 1 can +put a blank line after the first paragraph: + +```````````````````````````````` example +Foo + +bar +--- +baz +. +

Foo

+

bar

+

baz

+```````````````````````````````` + + +Authors who want interpretation 2 can put blank lines around +the thematic break, + +```````````````````````````````` example +Foo +bar + +--- + +baz +. +

Foo +bar

+
+

baz

+```````````````````````````````` + + +or use a thematic break that cannot count as a [setext heading +underline], such as + +```````````````````````````````` example +Foo +bar +* * * +baz +. +

Foo +bar

+
+

baz

+```````````````````````````````` + + +Authors who want interpretation 3 can use backslash escapes: + +```````````````````````````````` example +Foo +bar +\--- +baz +. +

Foo +bar +--- +baz

+```````````````````````````````` + + +## Indented code blocks + +An [indented code block](@) is composed of one or more +[indented chunks] separated by blank lines. +An [indented chunk](@) is a sequence of non-blank lines, +each indented four or more spaces. The contents of the code block are +the literal contents of the lines, including trailing +[line endings], minus four spaces of indentation. +An indented code block has no [info string]. + +An indented code block cannot interrupt a paragraph, so there must be +a blank line between a paragraph and a following indented code block. +(A blank line is not needed, however, between a code block and a following +paragraph.) + +```````````````````````````````` example + a simple + indented code block +. +
a simple
+  indented code block
+
+```````````````````````````````` + + +If there is any ambiguity between an interpretation of indentation +as a code block and as indicating that material belongs to a [list +item][list items], the list item interpretation takes precedence: + +```````````````````````````````` example + - foo + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. foo + + - bar +. +
    +
  1. +

    foo

    +
      +
    • bar
    • +
    +
  2. +
+```````````````````````````````` + + + +The contents of a code block are literal text, and do not get parsed +as Markdown: + +```````````````````````````````` example +
+ *hi* + + - one +. +
<a/>
+*hi*
+
+- one
+
+```````````````````````````````` + + +Here we have three chunks separated by blank lines: + +```````````````````````````````` example + chunk1 + + chunk2 + + + + chunk3 +. +
chunk1
+
+chunk2
+
+
+
+chunk3
+
+```````````````````````````````` + + +Any initial spaces beyond four will be included in the content, even +in interior blank lines: + +```````````````````````````````` example + chunk1 + + chunk2 +. +
chunk1
+  
+  chunk2
+
+```````````````````````````````` + + +An indented code block cannot interrupt a paragraph. (This +allows hanging indents and the like.) + +```````````````````````````````` example +Foo + bar + +. +

Foo +bar

+```````````````````````````````` + + +However, any non-blank line with fewer than four leading spaces ends +the code block immediately. So a paragraph may occur immediately +after indented code: + +```````````````````````````````` example + foo +bar +. +
foo
+
+

bar

+```````````````````````````````` + + +And indented code can occur immediately before and after other kinds of +blocks: + +```````````````````````````````` example +# Heading + foo +Heading +------ + foo +---- +. +

Heading

+
foo
+
+

Heading

+
foo
+
+
+```````````````````````````````` + + +The first line can be indented more than four spaces: + +```````````````````````````````` example + foo + bar +. +
    foo
+bar
+
+```````````````````````````````` + + +Blank lines preceding or following an indented code block +are not included in it: + +```````````````````````````````` example + + + foo + + +. +
foo
+
+```````````````````````````````` + + +Trailing spaces are included in the code block's content: + +```````````````````````````````` example + foo +. +
foo  
+
+```````````````````````````````` + + + +## Fenced code blocks + +A [code fence](@) is a sequence +of at least three consecutive backtick characters (`` ` ``) or +tildes (`~`). (Tildes and backticks cannot be mixed.) +A [fenced code block](@) +begins with a code fence, indented no more than three spaces. + +The line with the opening code fence may optionally contain some text +following the code fence; this is trimmed of leading and trailing +spaces and called the [info string](@). +The [info string] may not contain any backtick +characters. (The reason for this restriction is that otherwise +some inline code would be incorrectly interpreted as the +beginning of a fenced code block.) + +The content of the code block consists of all subsequent lines, until +a closing [code fence] of the same type as the code block +began with (backticks or tildes), and with at least as many backticks +or tildes as the opening code fence. If the leading code fence is +indented N spaces, then up to N spaces of indentation are removed from +each line of the content (if present). (If a content line is not +indented, it is preserved unchanged. If it is indented less than N +spaces, all of the indentation is removed.) + +The closing code fence may be indented up to three spaces, and may be +followed only by spaces, which are ignored. If the end of the +containing block (or document) is reached and no closing code fence +has been found, the code block contains all of the lines after the +opening code fence until the end of the containing block (or +document). (An alternative spec would require backtracking in the +event that a closing code fence is not found. But this makes parsing +much less efficient, and there seems to be no real down side to the +behavior described here.) + +A fenced code block may interrupt a paragraph, and does not require +a blank line either before or after. + +The content of a code fence is treated as literal text, not parsed +as inlines. The first word of the [info string] is typically used to +specify the language of the code sample, and rendered in the `class` +attribute of the `code` tag. However, this spec does not mandate any +particular treatment of the [info string]. + +Here is a simple example with backticks: + +```````````````````````````````` example +``` +< + > +``` +. +
<
+ >
+
+```````````````````````````````` + + +With tildes: + +```````````````````````````````` example +~~~ +< + > +~~~ +. +
<
+ >
+
+```````````````````````````````` + + +The closing code fence must use the same character as the opening +fence: + +```````````````````````````````` example +``` +aaa +~~~ +``` +. +
aaa
+~~~
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~ +aaa +``` +~~~ +. +
aaa
+```
+
+```````````````````````````````` + + +The closing code fence must be at least as long as the opening fence: + +```````````````````````````````` example +```` +aaa +``` +`````` +. +
aaa
+```
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~~ +aaa +~~~ +~~~~ +. +
aaa
+~~~
+
+```````````````````````````````` + + +Unclosed code blocks are closed by the end of the document +(or the enclosing [block quote][block quotes] or [list item][list items]): + +```````````````````````````````` example +``` +. +
+```````````````````````````````` + + +```````````````````````````````` example +````` + +``` +aaa +. +

+```
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example +> ``` +> aaa + +bbb +. +
+
aaa
+
+
+

bbb

+```````````````````````````````` + + +A code block can have all empty lines as its content: + +```````````````````````````````` example +``` + + +``` +. +

+  
+
+```````````````````````````````` + + +A code block can be empty: + +```````````````````````````````` example +``` +``` +. +
+```````````````````````````````` + + +Fences can be indented. If the opening fence is indented, +content lines will have equivalent opening indentation removed, +if present: + +```````````````````````````````` example + ``` + aaa +aaa +``` +. +
aaa
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` +aaa + aaa +aaa + ``` +. +
aaa
+aaa
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` + aaa + aaa + aaa + ``` +. +
aaa
+ aaa
+aaa
+
+```````````````````````````````` + + +Four spaces indentation produces an indented code block: + +```````````````````````````````` example + ``` + aaa + ``` +. +
```
+aaa
+```
+
+```````````````````````````````` + + +Closing fences may be indented by 0-3 spaces, and their indentation +need not match that of the opening fence: + +```````````````````````````````` example +``` +aaa + ``` +. +
aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` +aaa + ``` +. +
aaa
+
+```````````````````````````````` + + +This is not a closing fence, because it is indented 4 spaces: + +```````````````````````````````` example +``` +aaa + ``` +. +
aaa
+    ```
+
+```````````````````````````````` + + + +Code fences (opening and closing) cannot contain internal spaces: + +```````````````````````````````` example +``` ``` +aaa +. +

+aaa

+```````````````````````````````` + + +```````````````````````````````` example +~~~~~~ +aaa +~~~ ~~ +. +
aaa
+~~~ ~~
+
+```````````````````````````````` + + +Fenced code blocks can interrupt paragraphs, and can be followed +directly by paragraphs, without a blank line between: + +```````````````````````````````` example +foo +``` +bar +``` +baz +. +

foo

+
bar
+
+

baz

+```````````````````````````````` + + +Other blocks can also occur before and after fenced code blocks +without an intervening blank line: + +```````````````````````````````` example +foo +--- +~~~ +bar +~~~ +# baz +. +

foo

+
bar
+
+

baz

+```````````````````````````````` + + +An [info string] can be provided after the opening code fence. +Opening and closing spaces will be stripped, and the first word, prefixed +with `language-`, is used as the value for the `class` attribute of the +`code` element within the enclosing `pre` element. + +```````````````````````````````` example +```ruby +def foo(x) + return 3 +end +``` +. +
def foo(x)
+  return 3
+end
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +. +
def foo(x)
+  return 3
+end
+
+```````````````````````````````` + + +```````````````````````````````` example +````; +```` +. +
+```````````````````````````````` + + +[Info strings] for backtick code blocks cannot contain backticks: + +```````````````````````````````` example +``` aa ``` +foo +. +

aa +foo

+```````````````````````````````` + + +Closing code fences cannot have [info strings]: + +```````````````````````````````` example +``` +``` aaa +``` +. +
``` aaa
+
+```````````````````````````````` + + + +## HTML blocks + +An [HTML block](@) is a group of lines that is treated +as raw HTML (and will not be escaped in HTML output). + +There are seven kinds of [HTML block], which can be defined +by their start and end conditions. The block begins with a line that +meets a [start condition](@) (after up to three spaces +optional indentation). It ends with the first subsequent line that +meets a matching [end condition](@), or the last line of +the document, if no line is encountered that meets the +[end condition]. If the first line meets both the [start condition] +and the [end condition], the block will contain just that line. + +1. **Start condition:** line begins with the string ``, or the end of the line.\ +**End condition:** line contains an end tag +``, ``, or `` (case-insensitive; it +need not match the start tag). + +2. **Start condition:** line begins with the string ``. + +3. **Start condition:** line begins with the string ``. + +4. **Start condition:** line begins with the string ``. + +5. **Start condition:** line begins with the string +``. + +6. **Start condition:** line begins the string `<` or ``, or +the string `/>`.\ +**End condition:** line is followed by a [blank line]. + +7. **Start condition:** line begins with a complete [open tag] +or [closing tag] (with any [tag name] other than `script`, +`style`, or `pre`) followed only by [whitespace] +or the end of the line.\ +**End condition:** line is followed by a [blank line]. + +All types of [HTML blocks] except type 7 may interrupt +a paragraph. Blocks of type 7 may not interrupt a paragraph. +(This restriction is intended to prevent unwanted interpretation +of long tags inside a wrapped paragraph as starting HTML blocks.) + +Some simple examples follow. Here are some basic HTML blocks +of type 6: + +```````````````````````````````` example + + + + +
+ hi +
+ +okay. +. + + + + +
+ hi +
+

okay.

+```````````````````````````````` + + +```````````````````````````````` example +
+*foo* +```````````````````````````````` + + +Here we have two HTML blocks with a Markdown paragraph between them: + +```````````````````````````````` example +
+ +*Markdown* + +
+. +
+

Markdown

+
+```````````````````````````````` + + +The tag on the first line can be partial, as long +as it is split where there would be whitespace: + +```````````````````````````````` example +
+
+. +
+
+```````````````````````````````` + + +```````````````````````````````` example +
+
+. +
+
+```````````````````````````````` + + +An open tag need not be closed: +```````````````````````````````` example +
+*foo* + +*bar* +. +
+*foo* +

bar

+```````````````````````````````` + + + +A partial tag need not even be completed (garbage +in, garbage out): + +```````````````````````````````` example +
+. + +```````````````````````````````` + + +```````````````````````````````` example +
+foo +
+. +
+foo +
+```````````````````````````````` + + +Everything until the next blank line or end of document +gets included in the HTML block. So, in the following +example, what looks like a Markdown code block +is actually part of the HTML block, which continues until a blank +line or the end of the document is reached: + +```````````````````````````````` example +
+``` c +int x = 33; +``` +. +
+``` c +int x = 33; +``` +```````````````````````````````` + + +To start an [HTML block] with a tag that is *not* in the +list of block-level tags in (6), you must put the tag by +itself on the first line (and it must be complete): + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +In type 7 blocks, the [tag name] can be anything: + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +```````````````````````````````` example + +*bar* +. + +*bar* +```````````````````````````````` + + +These rules are designed to allow us to work with tags that +can function as either block-level or inline-level tags. +The `` tag is a nice example. We can surround content with +`` tags in three different ways. In this case, we get a raw +HTML block, because the `` tag is on a line by itself: + +```````````````````````````````` example + +*foo* + +. + +*foo* + +```````````````````````````````` + + +In this case, we get a raw HTML block that just includes +the `` tag (because it ends with the following blank +line). So the contents get interpreted as CommonMark: + +```````````````````````````````` example + + +*foo* + + +. + +

foo

+
+```````````````````````````````` + + +Finally, in this case, the `` tags are interpreted +as [raw HTML] *inside* the CommonMark paragraph. (Because +the tag is not on a line by itself, we get inline HTML +rather than an [HTML block].) + +```````````````````````````````` example +*foo* +. +

foo

+```````````````````````````````` + + +HTML tags designed to contain literal content +(`script`, `style`, `pre`), comments, processing instructions, +and declarations are treated somewhat differently. +Instead of ending at the first blank line, these blocks +end at the first line containing a corresponding end tag. +As a result, these blocks can contain blank lines: + +A pre tag (type 1): + +```````````````````````````````` example +

+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+
+. +

+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+
+```````````````````````````````` + + +A script tag (type 1): + +```````````````````````````````` example + +. + +```````````````````````````````` + + +A style tag (type 1): + +```````````````````````````````` example + +. + +```````````````````````````````` + + +If there is no matching end tag, the block will end at the +end of the document (or the enclosing [block quote][block quotes] +or [list item][list items]): + +```````````````````````````````` example + +*foo* +. + +

foo

+```````````````````````````````` + + +```````````````````````````````` example +*bar* +*baz* +. +*bar* +

baz

+```````````````````````````````` + + +Note that anything on the last line after the +end tag will be included in the [HTML block]: + +```````````````````````````````` example +1. *bar* +. +1. *bar* +```````````````````````````````` + + +A comment (type 2): + +```````````````````````````````` example + +. + +```````````````````````````````` + + + +A processing instruction (type 3): + +```````````````````````````````` example +'; + +?> +. +'; + +?> +```````````````````````````````` + + +A declaration (type 4): + +```````````````````````````````` example + +. + +```````````````````````````````` + + +CDATA (type 5): + +```````````````````````````````` example + +. + +```````````````````````````````` + + +The opening tag can be indented 1-3 spaces, but not 4: + +```````````````````````````````` example + + + +. + +
<!-- foo -->
+
+```````````````````````````````` + + +```````````````````````````````` example +
+ +
+. +
+
<div>
+
+```````````````````````````````` + + +An HTML block of types 1--6 can interrupt a paragraph, and need not be +preceded by a blank line. + +```````````````````````````````` example +Foo +
+bar +
+. +

Foo

+
+bar +
+```````````````````````````````` + + +However, a following blank line is needed, except at the end of +a document, and except for blocks of types 1--5, above: + +```````````````````````````````` example +
+bar +
+*foo* +. +
+bar +
+*foo* +```````````````````````````````` + + +HTML blocks of type 7 cannot interrupt a paragraph: + +```````````````````````````````` example +Foo + +baz +. +

Foo + +baz

+```````````````````````````````` + + +This rule differs from John Gruber's original Markdown syntax +specification, which says: + +> The only restrictions are that block-level HTML elements — +> e.g. `
`, ``, `
`, `

`, etc. — must be separated from +> surrounding content by blank lines, and the start and end tags of the +> block should not be indented with tabs or spaces. + +In some ways Gruber's rule is more restrictive than the one given +here: + +- It requires that an HTML block be preceded by a blank line. +- It does not allow the start tag to be indented. +- It requires a matching end tag, which it also does not allow to + be indented. + +Most Markdown implementations (including some of Gruber's own) do not +respect all of these restrictions. + +There is one respect, however, in which Gruber's rule is more liberal +than the one given here, since it allows blank lines to occur inside +an HTML block. There are two reasons for disallowing them here. +First, it removes the need to parse balanced tags, which is +expensive and can require backtracking from the end of the document +if no matching end tag is found. Second, it provides a very simple +and flexible way of including Markdown content inside HTML tags: +simply separate the Markdown from the HTML using blank lines: + +Compare: + +```````````````````````````````` example +

+ +*Emphasized* text. + +
+. +
+

Emphasized text.

+
+```````````````````````````````` + + +```````````````````````````````` example +
+*Emphasized* text. +
+. +
+*Emphasized* text. +
+```````````````````````````````` + + +Some Markdown implementations have adopted a convention of +interpreting content inside tags as text if the open tag has +the attribute `markdown=1`. The rule given above seems a simpler and +more elegant way of achieving the same expressive power, which is also +much simpler to parse. + +The main potential drawback is that one can no longer paste HTML +blocks into Markdown documents with 100% reliability. However, +*in most cases* this will work fine, because the blank lines in +HTML are usually followed by HTML block tags. For example: + +```````````````````````````````` example +
+ + + + + + + +
+Hi +
+. + + + + +
+Hi +
+```````````````````````````````` + + +There are problems, however, if the inner tags are indented +*and* separated by spaces, as then they will be interpreted as +an indented code block: + +```````````````````````````````` example + + + + + + + + +
+ Hi +
+. + + +
<td>
+  Hi
+</td>
+
+ +
+```````````````````````````````` + + +Fortunately, blank lines are usually not necessary and can be +deleted. The exception is inside `
` tags, but as described
+above, raw HTML blocks starting with `
` *can* contain blank
+lines.
+
+## Link reference definitions
+
+A [link reference definition](@)
+consists of a [link label], indented up to three spaces, followed
+by a colon (`:`), optional [whitespace] (including up to one
+[line ending]), a [link destination],
+optional [whitespace] (including up to one
+[line ending]), and an optional [link
+title], which if it is present must be separated
+from the [link destination] by [whitespace].
+No further [non-whitespace characters] may occur on the line.
+
+A [link reference definition]
+does not correspond to a structural element of a document.  Instead, it
+defines a label which can be used in [reference links]
+and reference-style [images] elsewhere in the document.  [Link
+reference definitions] can come either before or after the links that use
+them.
+
+```````````````````````````````` example
+[foo]: /url "title"
+
+[foo]
+.
+

foo

+```````````````````````````````` + + +```````````````````````````````` example + [foo]: + /url + 'the title' + +[foo] +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +. +

Foo*bar]

+```````````````````````````````` + + +```````````````````````````````` example +[Foo bar]: + +'title' + +[Foo bar] +. +

Foo bar

+```````````````````````````````` + + +The title may extend over multiple lines: + +```````````````````````````````` example +[foo]: /url ' +title +line1 +line2 +' + +[foo] +. +

foo

+```````````````````````````````` + + +However, it may not contain a [blank line]: + +```````````````````````````````` example +[foo]: /url 'title + +with blank line' + +[foo] +. +

[foo]: /url 'title

+

with blank line'

+

[foo]

+```````````````````````````````` + + +The title may be omitted: + +```````````````````````````````` example +[foo]: +/url + +[foo] +. +

foo

+```````````````````````````````` + + +The link destination may not be omitted: + +```````````````````````````````` example +[foo]: + +[foo] +. +

[foo]:

+

[foo]

+```````````````````````````````` + + +Both title and destination can contain backslash escapes +and literal backslashes: + +```````````````````````````````` example +[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +. +

foo

+```````````````````````````````` + + +A link can come before its corresponding definition: + +```````````````````````````````` example +[foo] + +[foo]: url +. +

foo

+```````````````````````````````` + + +If there are several matching definitions, the first one takes +precedence: + +```````````````````````````````` example +[foo] + +[foo]: first +[foo]: second +. +

foo

+```````````````````````````````` + + +As noted in the section on [Links], matching of labels is +case-insensitive (see [matches]). + +```````````````````````````````` example +[FOO]: /url + +[Foo] +. +

Foo

+```````````````````````````````` + + +```````````````````````````````` example +[ΑΓΩ]: /φου + +[αγω] +. +

αγω

+```````````````````````````````` + + +Here is a link reference definition with no corresponding link. +It contributes nothing to the document. + +```````````````````````````````` example +[foo]: /url +. +```````````````````````````````` + + +Here is another one: + +```````````````````````````````` example +[ +foo +]: /url +bar +. +

bar

+```````````````````````````````` + + +This is not a link reference definition, because there are +[non-whitespace characters] after the title: + +```````````````````````````````` example +[foo]: /url "title" ok +. +

[foo]: /url "title" ok

+```````````````````````````````` + + +This is a link reference definition, but it has no title: + +```````````````````````````````` example +[foo]: /url +"title" ok +. +

"title" ok

+```````````````````````````````` + + +This is not a link reference definition, because it is indented +four spaces: + +```````````````````````````````` example + [foo]: /url "title" + +[foo] +. +
[foo]: /url "title"
+
+

[foo]

+```````````````````````````````` + + +This is not a link reference definition, because it occurs inside +a code block: + +```````````````````````````````` example +``` +[foo]: /url +``` + +[foo] +. +
[foo]: /url
+
+

[foo]

+```````````````````````````````` + + +A [link reference definition] cannot interrupt a paragraph. + +```````````````````````````````` example +Foo +[bar]: /baz + +[bar] +. +

Foo +[bar]: /baz

+

[bar]

+```````````````````````````````` + + +However, it can directly follow other block elements, such as headings +and thematic breaks, and it need not be followed by a blank line. + +```````````````````````````````` example +# [Foo] +[foo]: /url +> bar +. +

Foo

+
+

bar

+
+```````````````````````````````` + + +Several [link reference definitions] +can occur one after another, without intervening blank lines. + +```````````````````````````````` example +[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +. +

foo, +bar, +baz

+```````````````````````````````` + + +[Link reference definitions] can occur +inside block containers, like lists and block quotations. They +affect the entire document, not just the container in which they +are defined: + +```````````````````````````````` example +[foo] + +> [foo]: /url +. +

foo

+
+
+```````````````````````````````` + + + +## Paragraphs + +A sequence of non-blank lines that cannot be interpreted as other +kinds of blocks forms a [paragraph](@). +The contents of the paragraph are the result of parsing the +paragraph's raw content as inlines. The paragraph's raw content +is formed by concatenating the lines and removing initial and final +[whitespace]. + +A simple example with two paragraphs: + +```````````````````````````````` example +aaa + +bbb +. +

aaa

+

bbb

+```````````````````````````````` + + +Paragraphs can contain multiple lines, but no blank lines: + +```````````````````````````````` example +aaa +bbb + +ccc +ddd +. +

aaa +bbb

+

ccc +ddd

+```````````````````````````````` + + +Multiple blank lines between paragraph have no effect: + +```````````````````````````````` example +aaa + + +bbb +. +

aaa

+

bbb

+```````````````````````````````` + + +Leading spaces are skipped: + +```````````````````````````````` example + aaa + bbb +. +

aaa +bbb

+```````````````````````````````` + + +Lines after the first may be indented any amount, since indented +code blocks cannot interrupt paragraphs. + +```````````````````````````````` example +aaa + bbb + ccc +. +

aaa +bbb +ccc

+```````````````````````````````` + + +However, the first line may be indented at most three spaces, +or an indented code block will be triggered: + +```````````````````````````````` example + aaa +bbb +. +

aaa +bbb

+```````````````````````````````` + + +```````````````````````````````` example + aaa +bbb +. +
aaa
+
+

bbb

+```````````````````````````````` + + +Final spaces are stripped before inline parsing, so a paragraph +that ends with two or more spaces will not end with a [hard line +break]: + +```````````````````````````````` example +aaa +bbb +. +

aaa
+bbb

+```````````````````````````````` + + +## Blank lines + +[Blank lines] between block-level elements are ignored, +except for the role they play in determining whether a [list] +is [tight] or [loose]. + +Blank lines at the beginning and end of the document are also ignored. + +```````````````````````````````` example + + +aaa + + +# aaa + + +. +

aaa

+

aaa

+```````````````````````````````` + + + +# Container blocks + +A [container block] is a block that has other +blocks as its contents. There are two basic kinds of container blocks: +[block quotes] and [list items]. +[Lists] are meta-containers for [list items]. + +We define the syntax for container blocks recursively. The general +form of the definition is: + +> If X is a sequence of blocks, then the result of +> transforming X in such-and-such a way is a container of type Y +> with these blocks as its content. + +So, we explain what counts as a block quote or list item by explaining +how these can be *generated* from their contents. This should suffice +to define the syntax, although it does not give a recipe for *parsing* +these constructions. (A recipe is provided below in the section entitled +[A parsing strategy](#appendix-a-parsing-strategy).) + +## Block quotes + +A [block quote marker](@) +consists of 0-3 spaces of initial indent, plus (a) the character `>` together +with a following space, or (b) a single character `>` not followed by a space. + +The following rules define [block quotes]: + +1. **Basic case.** If a string of lines *Ls* constitute a sequence + of blocks *Bs*, then the result of prepending a [block quote + marker] to the beginning of each line in *Ls* + is a [block quote](#block-quotes) containing *Bs*. + +2. **Laziness.** If a string of lines *Ls* constitute a [block + quote](#block-quotes) with contents *Bs*, then the result of deleting + the initial [block quote marker] from one or + more lines in which the next [non-whitespace character] after the [block + quote marker] is [paragraph continuation + text] is a block quote with *Bs* as its content. + [Paragraph continuation text](@) is text + that will be parsed as part of the content of a paragraph, but does + not occur at the beginning of the paragraph. + +3. **Consecutiveness.** A document cannot contain two [block + quotes] in a row unless there is a [blank line] between them. + +Nothing else counts as a [block quote](#block-quotes). + +Here is a simple example: + +```````````````````````````````` example +> # Foo +> bar +> baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +The spaces after the `>` characters can be omitted: + +```````````````````````````````` example +># Foo +>bar +> baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +The `>` characters can be indented 1-3 spaces: + +```````````````````````````````` example + > # Foo + > bar + > baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +Four spaces gives us a code block: + +```````````````````````````````` example + > # Foo + > bar + > baz +. +
> # Foo
+> bar
+> baz
+
+```````````````````````````````` + + +The Laziness clause allows us to omit the `>` before a +paragraph continuation line: + +```````````````````````````````` example +> # Foo +> bar +baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +A block quote can contain some lazy and some non-lazy +continuation lines: + +```````````````````````````````` example +> bar +baz +> foo +. +
+

bar +baz +foo

+
+```````````````````````````````` + + +Laziness only applies to lines that would have been continuations of +paragraphs had they been prepended with [block quote markers]. +For example, the `> ` cannot be omitted in the second line of + +``` markdown +> foo +> --- +``` + +without changing the meaning: + +```````````````````````````````` example +> foo +--- +. +
+

foo

+
+
+```````````````````````````````` + + +Similarly, if we omit the `> ` in the second line of + +``` markdown +> - foo +> - bar +``` + +then the block quote ends after the first line: + +```````````````````````````````` example +> - foo +- bar +. +
+
    +
  • foo
  • +
+
+
    +
  • bar
  • +
+```````````````````````````````` + + +For the same reason, we can't omit the `> ` in front of +subsequent lines of an indented or fenced code block: + +```````````````````````````````` example +> foo + bar +. +
+
foo
+
+
+
bar
+
+```````````````````````````````` + + +```````````````````````````````` example +> ``` +foo +``` +. +
+
+
+

foo

+
+```````````````````````````````` + + +Note that in the following case, we have a paragraph +continuation line: + +```````````````````````````````` example +> foo + - bar +. +
+

foo +- bar

+
+```````````````````````````````` + + +To see why, note that in + +```markdown +> foo +> - bar +``` + +the `- bar` is indented too far to start a list, and can't +be an indented code block because indented code blocks cannot +interrupt paragraphs, so it is a [paragraph continuation line]. + +A block quote can be empty: + +```````````````````````````````` example +> +. +
+
+```````````````````````````````` + + +```````````````````````````````` example +> +> +> +. +
+
+```````````````````````````````` + + +A block quote can have initial or final blank lines: + +```````````````````````````````` example +> +> foo +> +. +
+

foo

+
+```````````````````````````````` + + +A blank line always separates block quotes: + +```````````````````````````````` example +> foo + +> bar +. +
+

foo

+
+
+

bar

+
+```````````````````````````````` + + +(Most current Markdown implementations, including John Gruber's +original `Markdown.pl`, will parse this example as a single block quote +with two paragraphs. But it seems better to allow the author to decide +whether two block quotes or one are wanted.) + +Consecutiveness means that if we put these block quotes together, +we get a single block quote: + +```````````````````````````````` example +> foo +> bar +. +
+

foo +bar

+
+```````````````````````````````` + + +To get a block quote with two paragraphs, use: + +```````````````````````````````` example +> foo +> +> bar +. +
+

foo

+

bar

+
+```````````````````````````````` + + +Block quotes can interrupt paragraphs: + +```````````````````````````````` example +foo +> bar +. +

foo

+
+

bar

+
+```````````````````````````````` + + +In general, blank lines are not needed before or after block +quotes: + +```````````````````````````````` example +> aaa +*** +> bbb +. +
+

aaa

+
+
+
+

bbb

+
+```````````````````````````````` + + +However, because of laziness, a blank line is needed between +a block quote and a following paragraph: + +```````````````````````````````` example +> bar +baz +. +
+

bar +baz

+
+```````````````````````````````` + + +```````````````````````````````` example +> bar + +baz +. +
+

bar

+
+

baz

+```````````````````````````````` + + +```````````````````````````````` example +> bar +> +baz +. +
+

bar

+
+

baz

+```````````````````````````````` + + +It is a consequence of the Laziness rule that any number +of initial `>`s may be omitted on a continuation line of a +nested block quote: + +```````````````````````````````` example +> > > foo +bar +. +
+
+
+

foo +bar

+
+
+
+```````````````````````````````` + + +```````````````````````````````` example +>>> foo +> bar +>>baz +. +
+
+
+

foo +bar +baz

+
+
+
+```````````````````````````````` + + +When including an indented code block in a block quote, +remember that the [block quote marker] includes +both the `>` and a following space. So *five spaces* are needed after +the `>`: + +```````````````````````````````` example +> code + +> not code +. +
+
code
+
+
+
+

not code

+
+```````````````````````````````` + + + +## List items + +A [list marker](@) is a +[bullet list marker] or an [ordered list marker]. + +A [bullet list marker](@) +is a `-`, `+`, or `*` character. + +An [ordered list marker](@) +is a sequence of 1--9 arabic digits (`0-9`), followed by either a +`.` character or a `)` character. (The reason for the length +limit is that with 10 digits we start seeing integer overflows +in some browsers.) + +The following rules define [list items]: + +1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of + blocks *Bs* starting with a [non-whitespace character] and not separated + from each other by more than one blank line, and *M* is a list + marker of width *W* followed by 0 < *N* < 5 spaces, then the result + of prepending *M* and the following spaces to the first line of + *Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a + list item with *Bs* as its contents. The type of the list item + (bullet or ordered) is determined by the type of its list marker. + If the list item is ordered, then it is also assigned a start + number, based on the ordered list marker. + +For example, let *Ls* be the lines + +```````````````````````````````` example +A paragraph +with two lines. + + indented code + +> A block quote. +. +

A paragraph +with two lines.

+
indented code
+
+
+

A block quote.

+
+```````````````````````````````` + + +And let *M* be the marker `1.`, and *N* = 2. Then rule #1 says +that the following is an ordered list item with start number 1, +and the same contents as *Ls*: + +```````````````````````````````` example +1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +The most important thing to notice is that the position of +the text after the list marker determines how much indentation +is needed in subsequent blocks in the list item. If the list +marker takes up two spaces, and there are three spaces between +the list marker and the next [non-whitespace character], then blocks +must be indented five spaces in order to fall under the list +item. + +Here are some examples showing how far content must be indented to be +put under the list item: + +```````````````````````````````` example +- one + + two +. +
    +
  • one
  • +
+

two

+```````````````````````````````` + + +```````````````````````````````` example +- one + + two +. +
    +
  • +

    one

    +

    two

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example + - one + + two +. +
    +
  • one
  • +
+
 two
+
+```````````````````````````````` + + +```````````````````````````````` example + - one + + two +. +
    +
  • +

    one

    +

    two

    +
  • +
+```````````````````````````````` + + +It is tempting to think of this in terms of columns: the continuation +blocks must be indented at least to the column of the first +[non-whitespace character] after the list marker. However, that is not quite right. +The spaces after the list marker determine how much relative indentation +is needed. Which column this indentation reaches will depend on +how the list item is embedded in other constructions, as shown by +this example: + +```````````````````````````````` example + > > 1. one +>> +>> two +. +
+
+
    +
  1. +

    one

    +

    two

    +
  2. +
+
+
+```````````````````````````````` + + +Here `two` occurs in the same column as the list marker `1.`, +but is actually contained in the list item, because there is +sufficient indentation after the last containing blockquote marker. + +The converse is also possible. In the following example, the word `two` +occurs far to the right of the initial text of the list item, `one`, but +it is not considered part of the list item, because it is not indented +far enough past the blockquote marker: + +```````````````````````````````` example +>>- one +>> + > > two +. +
+
+
    +
  • one
  • +
+

two

+
+
+```````````````````````````````` + + +Note that at least one space is needed between the list marker and +any following content, so these are not list items: + +```````````````````````````````` example +-one + +2.two +. +

-one

+

2.two

+```````````````````````````````` + + +A list item may not contain blocks that are separated by more than +one blank line. Thus, two blank lines will end a list, unless the +two blanks are contained in a [fenced code block]. + +```````````````````````````````` example +- foo + + bar + +- foo + + + bar + +- ``` + foo + + + bar + ``` + +- baz + + + ``` + foo + + + bar + ``` +. +
    +
  • +

    foo

    +

    bar

    +
  • +
  • +

    foo

    +
  • +
+

bar

+
    +
  • +
    foo
    +
    +
    +bar
    +
    +
  • +
  • +

    baz

    +
      +
    • +
      foo
      +
      +
      +bar
      +
      +
    • +
    +
  • +
+```````````````````````````````` + + +A list item may contain any kind of block: + +```````````````````````````````` example +1. foo + + ``` + bar + ``` + + baz + + > bam +. +
    +
  1. +

    foo

    +
    bar
    +
    +

    baz

    +
    +

    bam

    +
    +
  2. +
+```````````````````````````````` + + +A list item that contains an indented code block will preserve +empty lines within the code block verbatim, unless there are two +or more empty lines in a row (since as described above, two +blank lines end the list): + +```````````````````````````````` example +- Foo + + bar + + baz +. +
    +
  • +

    Foo

    +
    bar
    +
    +baz
    +
    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- Foo + + bar + + + baz +. +
    +
  • +

    Foo

    +
    bar
    +
    +
  • +
+
  baz
+
+```````````````````````````````` + + +Note that ordered list start numbers must be nine digits or less: + +```````````````````````````````` example +123456789. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +```````````````````````````````` example +1234567890. not ok +. +

1234567890. not ok

+```````````````````````````````` + + +A start number may begin with 0s: + +```````````````````````````````` example +0. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +```````````````````````````````` example +003. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +A start number may not be negative: + +```````````````````````````````` example +-1. not ok +. +

-1. not ok

+```````````````````````````````` + + + +2. **Item starting with indented code.** If a sequence of lines *Ls* + constitute a sequence of blocks *Bs* starting with an indented code + block and not separated from each other by more than one blank line, + and *M* is a list marker of width *W* followed by + one space, then the result of prepending *M* and the following + space to the first line of *Ls*, and indenting subsequent lines of + *Ls* by *W + 1* spaces, is a list item with *Bs* as its contents. + If a line is empty, then it need not be indented. The type of the + list item (bullet or ordered) is determined by the type of its list + marker. If the list item is ordered, then it is also assigned a + start number, based on the ordered list marker. + +An indented code block will have to be indented four spaces beyond +the edge of the region where text will be included in the list item. +In the following case that is 6 spaces: + +```````````````````````````````` example +- foo + + bar +. +
    +
  • +

    foo

    +
    bar
    +
    +
  • +
+```````````````````````````````` + + +And in this case it is 11 spaces: + +```````````````````````````````` example + 10. foo + + bar +. +
    +
  1. +

    foo

    +
    bar
    +
    +
  2. +
+```````````````````````````````` + + +If the *first* block in the list item is an indented code block, +then by rule #2, the contents must be indented *one* space after the +list marker: + +```````````````````````````````` example + indented code + +paragraph + + more code +. +
indented code
+
+

paragraph

+
more code
+
+```````````````````````````````` + + +```````````````````````````````` example +1. indented code + + paragraph + + more code +. +
    +
  1. +
    indented code
    +
    +

    paragraph

    +
    more code
    +
    +
  2. +
+```````````````````````````````` + + +Note that an additional space indent is interpreted as space +inside the code block: + +```````````````````````````````` example +1. indented code + + paragraph + + more code +. +
    +
  1. +
     indented code
    +
    +

    paragraph

    +
    more code
    +
    +
  2. +
+```````````````````````````````` + + +Note that rules #1 and #2 only apply to two cases: (a) cases +in which the lines to be included in a list item begin with a +[non-whitespace character], and (b) cases in which +they begin with an indented code +block. In a case like the following, where the first block begins with +a three-space indent, the rules do not allow us to form a list item by +indenting the whole thing and prepending a list marker: + +```````````````````````````````` example + foo + +bar +. +

foo

+

bar

+```````````````````````````````` + + +```````````````````````````````` example +- foo + + bar +. +
    +
  • foo
  • +
+

bar

+```````````````````````````````` + + +This is not a significant restriction, because when a block begins +with 1-3 spaces indent, the indentation can always be removed without +a change in interpretation, allowing rule #1 to be applied. So, in +the above case: + +```````````````````````````````` example +- foo + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +3. **Item starting with a blank line.** If a sequence of lines *Ls* + starting with a single [blank line] constitute a (possibly empty) + sequence of blocks *Bs*, not separated from each other by more than + one blank line, and *M* is a list marker of width *W*, + then the result of prepending *M* to the first line of *Ls*, and + indenting subsequent lines of *Ls* by *W + 1* spaces, is a list + item with *Bs* as its contents. + If a line is empty, then it need not be indented. The type of the + list item (bullet or ordered) is determined by the type of its list + marker. If the list item is ordered, then it is also assigned a + start number, based on the ordered list marker. + +Here are some list items that start with a blank line but are not empty: + +```````````````````````````````` example +- + foo +- + ``` + bar + ``` +- + baz +. +
    +
  • foo
  • +
  • +
    bar
    +
    +
  • +
  • +
    baz
    +
    +
  • +
+```````````````````````````````` + +When the list item starts with a blank line, the number of spaces +following the list marker doesn't change the required indentation: + +```````````````````````````````` example +- + foo +. +
    +
  • foo
  • +
+```````````````````````````````` + + +A list item can begin with at most one blank line. +In the following example, `foo` is not part of the list +item: + +```````````````````````````````` example +- + + foo +. +
    +
  • +
+

foo

+```````````````````````````````` + + +Here is an empty bullet list item: + +```````````````````````````````` example +- foo +- +- bar +. +
    +
  • foo
  • +
  • +
  • bar
  • +
+```````````````````````````````` + + +It does not matter whether there are spaces following the [list marker]: + +```````````````````````````````` example +- foo +- +- bar +. +
    +
  • foo
  • +
  • +
  • bar
  • +
+```````````````````````````````` + + +Here is an empty ordered list item: + +```````````````````````````````` example +1. foo +2. +3. bar +. +
    +
  1. foo
  2. +
  3. +
  4. bar
  5. +
+```````````````````````````````` + + +A list may start or end with an empty list item: + +```````````````````````````````` example +* +. +
    +
  • +
+```````````````````````````````` + + + +4. **Indentation.** If a sequence of lines *Ls* constitutes a list item + according to rule #1, #2, or #3, then the result of indenting each line + of *Ls* by 1-3 spaces (the same for each line) also constitutes a + list item with the same contents and attributes. If a line is + empty, then it need not be indented. + +Indented one space: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indented two spaces: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indented three spaces: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Four spaces indent gives a code block: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
1.  A paragraph
+    with two lines.
+
+        indented code
+
+    > A block quote.
+
+```````````````````````````````` + + + +5. **Laziness.** If a string of lines *Ls* constitute a [list + item](#list-items) with contents *Bs*, then the result of deleting + some or all of the indentation from one or more lines in which the + next [non-whitespace character] after the indentation is + [paragraph continuation text] is a + list item with the same contents and attributes. The unindented + lines are called + [lazy continuation line](@)s. + +Here is an example with [lazy continuation lines]: + +```````````````````````````````` example + 1. A paragraph +with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indentation can be partially deleted: + +```````````````````````````````` example + 1. A paragraph + with two lines. +. +
    +
  1. A paragraph +with two lines.
  2. +
+```````````````````````````````` + + +These examples show how laziness can work in nested structures: + +```````````````````````````````` example +> 1. > Blockquote +continued here. +. +
+
    +
  1. +
    +

    Blockquote +continued here.

    +
    +
  2. +
+
+```````````````````````````````` + + +```````````````````````````````` example +> 1. > Blockquote +> continued here. +. +
+
    +
  1. +
    +

    Blockquote +continued here.

    +
    +
  2. +
+
+```````````````````````````````` + + + +6. **That's all.** Nothing that is not counted as a list item by rules + #1--5 counts as a [list item](#list-items). + +The rules for sublists follow from the general rules above. A sublist +must be indented the same number of spaces a paragraph would need to be +in order to be included in the list item. + +So, in this case we need two spaces indent: + +```````````````````````````````` example +- foo + - bar + - baz +. +
    +
  • foo +
      +
    • bar +
        +
      • baz
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + + +One is not enough: + +```````````````````````````````` example +- foo + - bar + - baz +. +
    +
  • foo
  • +
  • bar
  • +
  • baz
  • +
+```````````````````````````````` + + +Here we need four, because the list marker is wider: + +```````````````````````````````` example +10) foo + - bar +. +
    +
  1. foo +
      +
    • bar
    • +
    +
  2. +
+```````````````````````````````` + + +Three is not enough: + +```````````````````````````````` example +10) foo + - bar +. +
    +
  1. foo
  2. +
+
    +
  • bar
  • +
+```````````````````````````````` + + +A list may be the first block in a list item: + +```````````````````````````````` example +- - foo +. +
    +
  • +
      +
    • foo
    • +
    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. - 2. foo +. +
    +
  1. +
      +
    • +
        +
      1. foo
      2. +
      +
    • +
    +
  2. +
+```````````````````````````````` + + +A list item can contain a heading: + +```````````````````````````````` example +- # Foo +- Bar + --- + baz +. +
    +
  • +

    Foo

    +
  • +
  • +

    Bar

    +baz
  • +
+```````````````````````````````` + + +### Motivation + +John Gruber's Markdown spec says the following about list items: + +1. "List markers typically start at the left margin, but may be indented + by up to three spaces. List markers must be followed by one or more + spaces or a tab." + +2. "To make lists look nice, you can wrap items with hanging indents.... + But if you don't want to, you don't have to." + +3. "List items may consist of multiple paragraphs. Each subsequent + paragraph in a list item must be indented by either 4 spaces or one + tab." + +4. "It looks nice if you indent every line of the subsequent paragraphs, + but here again, Markdown will allow you to be lazy." + +5. "To put a blockquote within a list item, the blockquote's `>` + delimiters need to be indented." + +6. "To put a code block within a list item, the code block needs to be + indented twice — 8 spaces or two tabs." + +These rules specify that a paragraph under a list item must be indented +four spaces (presumably, from the left margin, rather than the start of +the list marker, but this is not said), and that code under a list item +must be indented eight spaces instead of the usual four. They also say +that a block quote must be indented, but not by how much; however, the +example given has four spaces indentation. Although nothing is said +about other kinds of block-level content, it is certainly reasonable to +infer that *all* block elements under a list item, including other +lists, must be indented four spaces. This principle has been called the +*four-space rule*. + +The four-space rule is clear and principled, and if the reference +implementation `Markdown.pl` had followed it, it probably would have +become the standard. However, `Markdown.pl` allowed paragraphs and +sublists to start with only two spaces indentation, at least on the +outer level. Worse, its behavior was inconsistent: a sublist of an +outer-level list needed two spaces indentation, but a sublist of this +sublist needed three spaces. It is not surprising, then, that different +implementations of Markdown have developed very different rules for +determining what comes under a list item. (Pandoc and python-Markdown, +for example, stuck with Gruber's syntax description and the four-space +rule, while discount, redcarpet, marked, PHP Markdown, and others +followed `Markdown.pl`'s behavior more closely.) + +Unfortunately, given the divergences between implementations, there +is no way to give a spec for list items that will be guaranteed not +to break any existing documents. However, the spec given here should +correctly handle lists formatted with either the four-space rule or +the more forgiving `Markdown.pl` behavior, provided they are laid out +in a way that is natural for a human to read. + +The strategy here is to let the width and indentation of the list marker +determine the indentation necessary for blocks to fall under the list +item, rather than having a fixed and arbitrary number. The writer can +think of the body of the list item as a unit which gets indented to the +right enough to fit the list marker (and any indentation on the list +marker). (The laziness rule, #5, then allows continuation lines to be +unindented if needed.) + +This rule is superior, we claim, to any rule requiring a fixed level of +indentation from the margin. The four-space rule is clear but +unnatural. It is quite unintuitive that + +``` markdown +- foo + + bar + + - baz +``` + +should be parsed as two lists with an intervening paragraph, + +``` html +
    +
  • foo
  • +
+

bar

+
    +
  • baz
  • +
+``` + +as the four-space rule demands, rather than a single list, + +``` html +
    +
  • +

    foo

    +

    bar

    +
      +
    • baz
    • +
    +
  • +
+``` + +The choice of four spaces is arbitrary. It can be learned, but it is +not likely to be guessed, and it trips up beginners regularly. + +Would it help to adopt a two-space rule? The problem is that such +a rule, together with the rule allowing 1--3 spaces indentation of the +initial list marker, allows text that is indented *less than* the +original list marker to be included in the list item. For example, +`Markdown.pl` parses + +``` markdown + - one + + two +``` + +as a single list item, with `two` a continuation paragraph: + +``` html +
    +
  • +

    one

    +

    two

    +
  • +
+``` + +and similarly + +``` markdown +> - one +> +> two +``` + +as + +``` html +
+
    +
  • +

    one

    +

    two

    +
  • +
+
+``` + +This is extremely unintuitive. + +Rather than requiring a fixed indent from the margin, we could require +a fixed indent (say, two spaces, or even one space) from the list marker (which +may itself be indented). This proposal would remove the last anomaly +discussed. Unlike the spec presented above, it would count the following +as a list item with a subparagraph, even though the paragraph `bar` +is not indented as far as the first paragraph `foo`: + +``` markdown + 10. foo + + bar +``` + +Arguably this text does read like a list item with `bar` as a subparagraph, +which may count in favor of the proposal. However, on this proposal indented +code would have to be indented six spaces after the list marker. And this +would break a lot of existing Markdown, which has the pattern: + +``` markdown +1. foo + + indented code +``` + +where the code is indented eight spaces. The spec above, by contrast, will +parse this text as expected, since the code block's indentation is measured +from the beginning of `foo`. + +The one case that needs special treatment is a list item that *starts* +with indented code. How much indentation is required in that case, since +we don't have a "first paragraph" to measure from? Rule #2 simply stipulates +that in such cases, we require one space indentation from the list marker +(and then the normal four spaces for the indented code). This will match the +four-space rule in cases where the list marker plus its initial indentation +takes four spaces (a common case), but diverge in other cases. + +## Lists + +A [list](@) is a sequence of one or more +list items [of the same type]. The list items +may be separated by single [blank lines], but two +blank lines end all containing lists. + +Two list items are [of the same type](@) +if they begin with a [list marker] of the same type. +Two list markers are of the +same type if (a) they are bullet list markers using the same character +(`-`, `+`, or `*`) or (b) they are ordered list numbers with the same +delimiter (either `.` or `)`). + +A list is an [ordered list](@) +if its constituent list items begin with +[ordered list markers], and a +[bullet list](@) if its constituent list +items begin with [bullet list markers]. + +The [start number](@) +of an [ordered list] is determined by the list number of +its initial list item. The numbers of subsequent list items are +disregarded. + +A list is [loose](@) if any of its constituent +list items are separated by blank lines, or if any of its constituent +list items directly contain two block-level elements with a blank line +between them. Otherwise a list is [tight](@). +(The difference in HTML output is that paragraphs in a loose list are +wrapped in `

` tags, while paragraphs in a tight list are not.) + +Changing the bullet or ordered list delimiter starts a new list: + +```````````````````````````````` example +- foo +- bar ++ baz +. +

    +
  • foo
  • +
  • bar
  • +
+
    +
  • baz
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. foo +2. bar +3) baz +. +
    +
  1. foo
  2. +
  3. bar
  4. +
+
    +
  1. baz
  2. +
+```````````````````````````````` + + +In CommonMark, a list can interrupt a paragraph. That is, +no blank line is needed to separate a paragraph from a following +list: + +```````````````````````````````` example +Foo +- bar +- baz +. +

Foo

+
    +
  • bar
  • +
  • baz
  • +
+```````````````````````````````` + + +`Markdown.pl` does not allow this, through fear of triggering a list +via a numeral in a hard-wrapped line: + +```````````````````````````````` example +The number of windows in my house is +14. The number of doors is 6. +. +

The number of windows in my house is

+
    +
  1. The number of doors is 6.
  2. +
+```````````````````````````````` + + +Oddly, `Markdown.pl` *does* allow a blockquote to interrupt a paragraph, +even though the same considerations might apply. We think that the two +cases should be treated the same. Here are two reasons for allowing +lists to interrupt paragraphs: + +First, it is natural and not uncommon for people to start lists without +blank lines: + + I need to buy + - new shoes + - a coat + - a plane ticket + +Second, we are attracted to a + +> [principle of uniformity](@): +> if a chunk of text has a certain +> meaning, it will continue to have the same meaning when put into a +> container block (such as a list item or blockquote). + +(Indeed, the spec for [list items] and [block quotes] presupposes +this principle.) This principle implies that if + + * I need to buy + - new shoes + - a coat + - a plane ticket + +is a list item containing a paragraph followed by a nested sublist, +as all Markdown implementations agree it is (though the paragraph +may be rendered without `

` tags, since the list is "tight"), +then + + I need to buy + - new shoes + - a coat + - a plane ticket + +by itself should be a paragraph followed by a nested sublist. + +Our adherence to the [principle of uniformity] +thus inclines us to think that there are two coherent packages: + +1. Require blank lines before *all* lists and blockquotes, + including lists that occur as sublists inside other list items. + +2. Require blank lines in none of these places. + +[reStructuredText](http://docutils.sourceforge.net/rst.html) takes +the first approach, for which there is much to be said. But the second +seems more consistent with established practice with Markdown. + +There can be blank lines between items, but two blank lines end +a list: + +```````````````````````````````` example +- foo + +- bar + + +- baz +. +

    +
  • +

    foo

    +
  • +
  • +

    bar

    +
  • +
+
    +
  • baz
  • +
+```````````````````````````````` + + +As illustrated above in the section on [list items], +two blank lines between blocks *within* a list item will also end a +list: + +```````````````````````````````` example +- foo + + + bar +- baz +. +
    +
  • foo
  • +
+

bar

+
    +
  • baz
  • +
+```````````````````````````````` + + +Indeed, two blank lines will end *all* containing lists: + +```````````````````````````````` example +- foo + - bar + - baz + + + bim +. +
    +
  • foo +
      +
    • bar +
        +
      • baz
      • +
      +
    • +
    +
  • +
+
  bim
+
+```````````````````````````````` + + +Thus, two blank lines can be used to separate consecutive lists of +the same type, or to separate a list from an indented code block +that would otherwise be parsed as a subparagraph of the final list +item: + +```````````````````````````````` example +- foo +- bar + + +- baz +- bim +. +
    +
  • foo
  • +
  • bar
  • +
+
    +
  • baz
  • +
  • bim
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- foo + + notcode + +- foo + + + code +. +
    +
  • +

    foo

    +

    notcode

    +
  • +
  • +

    foo

    +
  • +
+
code
+
+```````````````````````````````` + + +List items need not be indented to the same level. The following +list items will be treated as items at the same list level, +since none is indented enough to belong to the previous list +item: + +```````````````````````````````` example +- a + - b + - c + - d + - e + - f + - g + - h +- i +. +
    +
  • a
  • +
  • b
  • +
  • c
  • +
  • d
  • +
  • e
  • +
  • f
  • +
  • g
  • +
  • h
  • +
  • i
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. a + + 2. b + + 3. c +. +
    +
  1. +

    a

    +
  2. +
  3. +

    b

    +
  4. +
  5. +

    c

    +
  6. +
+```````````````````````````````` + + +This is a loose list, because there is a blank line between +two of the list items: + +```````````````````````````````` example +- a +- b + +- c +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +
  • +
  • +

    c

    +
  • +
+```````````````````````````````` + + +So is this, with a empty second item: + +```````````````````````````````` example +* a +* + +* c +. +
    +
  • +

    a

    +
  • +
  • +
  • +

    c

    +
  • +
+```````````````````````````````` + + +These are loose lists, even though there is no space between the items, +because one of the items directly contains two block-level elements +with a blank line between them: + +```````````````````````````````` example +- a +- b + + c +- d +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +

    c

    +
  • +
  • +

    d

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a +- b + + [ref]: /url +- d +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +
  • +
  • +

    d

    +
  • +
+```````````````````````````````` + + +This is a tight list, because the blank lines are in a code block: + +```````````````````````````````` example +- a +- ``` + b + + + ``` +- c +. +
    +
  • a
  • +
  • +
    b
    +
    +
    +
    +
  • +
  • c
  • +
+```````````````````````````````` + + +This is a tight list, because the blank line is between two +paragraphs of a sublist. So the sublist is loose while +the outer list is tight: + +```````````````````````````````` example +- a + - b + + c +- d +. +
    +
  • a +
      +
    • +

      b

      +

      c

      +
    • +
    +
  • +
  • d
  • +
+```````````````````````````````` + + +This is a tight list, because the blank line is inside the +block quote: + +```````````````````````````````` example +* a + > b + > +* c +. +
    +
  • a +
    +

    b

    +
    +
  • +
  • c
  • +
+```````````````````````````````` + + +This list is tight, because the consecutive block elements +are not separated by blank lines: + +```````````````````````````````` example +- a + > b + ``` + c + ``` +- d +. +
    +
  • a +
    +

    b

    +
    +
    c
    +
    +
  • +
  • d
  • +
+```````````````````````````````` + + +A single-paragraph list is tight: + +```````````````````````````````` example +- a +. +
    +
  • a
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a + - b +. +
    +
  • a +
      +
    • b
    • +
    +
  • +
+```````````````````````````````` + + +This list is loose, because of the blank line between the +two block elements in the list item: + +```````````````````````````````` example +1. ``` + foo + ``` + + bar +. +
    +
  1. +
    foo
    +
    +

    bar

    +
  2. +
+```````````````````````````````` + + +Here the outer list is loose, the inner list tight: + +```````````````````````````````` example +* foo + * bar + + baz +. +
    +
  • +

    foo

    +
      +
    • bar
    • +
    +

    baz

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a + - b + - c + +- d + - e + - f +. +
    +
  • +

    a

    +
      +
    • b
    • +
    • c
    • +
    +
  • +
  • +

    d

    +
      +
    • e
    • +
    • f
    • +
    +
  • +
+```````````````````````````````` + + +# Inlines + +Inlines are parsed sequentially from the beginning of the character +stream to the end (left to right, in left-to-right languages). +Thus, for example, in + +```````````````````````````````` example +`hi`lo` +. +

hilo`

+```````````````````````````````` + + +`hi` is parsed as code, leaving the backtick at the end as a literal +backtick. + +## Backslash escapes + +Any ASCII punctuation character may be backslash-escaped: + +```````````````````````````````` example +\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +. +

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

+```````````````````````````````` + + +Backslashes before other characters are treated as literal +backslashes: + +```````````````````````````````` example +\→\A\a\ \3\φ\« +. +

\→\A\a\ \3\φ\«

+```````````````````````````````` + + +Escaped characters are treated as regular characters and do +not have their usual Markdown meanings: + +```````````````````````````````` example +\*not emphasized* +\
not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +. +

*not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference"

+```````````````````````````````` + + +If a backslash is itself escaped, the following character is not: + +```````````````````````````````` example +\\*emphasis* +. +

\emphasis

+```````````````````````````````` + + +A backslash at the end of the line is a [hard line break]: + +```````````````````````````````` example +foo\ +bar +. +

foo
+bar

+```````````````````````````````` + + +Backslash escapes do not work in code blocks, code spans, autolinks, or +raw HTML: + +```````````````````````````````` example +`` \[\` `` +. +

\[\`

+```````````````````````````````` + + +```````````````````````````````` example + \[\] +. +
\[\]
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~ +\[\] +~~~ +. +
\[\]
+
+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://example.com?find=\*

+```````````````````````````````` + + +```````````````````````````````` example + +. + +```````````````````````````````` + + +But they work in all other contexts, including URLs and link titles, +link references, and [info strings] in [fenced code blocks]: + +```````````````````````````````` example +[foo](/bar\* "ti\*tle") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo] + +[foo]: /bar\* "ti\*tle" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +``` foo\+bar +foo +``` +. +
foo
+
+```````````````````````````````` + + + +## Entity and numeric character references + +All valid HTML entity references and numeric character +references, except those occuring in code blocks and code spans, +are recognized as such and treated as equivalent to the +corresponding Unicode characters. Conforming CommonMark parsers +need not store information about whether a particular character +was represented in the source using a Unicode character or +an entity reference. + +[Entity references](@) consist of `&` + any of the valid +HTML5 entity names + `;`. The +document +is used as an authoritative source for the valid entity +references and their corresponding code points. + +```````````````````````````````` example +  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +. +

  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸

+```````````````````````````````` + + +[Decimal numeric character +references](@) +consist of `&#` + a string of 1--8 arabic digits + `;`. A +numeric character reference is parsed as the corresponding +Unicode character. Invalid Unicode code points will be replaced by +the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons, +the code point `U+0000` will also be replaced by `U+FFFD`. + +```````````````````````````````` example +# Ӓ Ϡ � � +. +

# Ӓ Ϡ � �

+```````````````````````````````` + + +[Hexadecimal numeric character +references](@) consist of `&#` + +either `X` or `x` + a string of 1-8 hexadecimal digits + `;`. +They too are parsed as the corresponding Unicode character (this +time specified with a hexadecimal numeral instead of decimal). + +```````````````````````````````` example +" ആ ಫ +. +

" ആ ಫ

+```````````````````````````````` + + +Here are some nonentities: + +```````````````````````````````` example +  &x; &#; &#x; +&ThisIsNotDefined; &hi?; +. +

&nbsp &x; &#; &#x; +&ThisIsNotDefined; &hi?;

+```````````````````````````````` + + +Although HTML5 does accept some entity references +without a trailing semicolon (such as `©`), these are not +recognized here, because it makes the grammar too ambiguous: + +```````````````````````````````` example +© +. +

&copy

+```````````````````````````````` + + +Strings that are not on the list of HTML5 named entities are not +recognized as entity references either: + +```````````````````````````````` example +&MadeUpEntity; +. +

&MadeUpEntity;

+```````````````````````````````` + + +Entity and numeric character references are recognized in any +context besides code spans or code blocks, including +URLs, [link titles], and [fenced code block][] [info strings]: + +```````````````````````````````` example + +. + +```````````````````````````````` + + +```````````````````````````````` example +[foo](/föö "föö") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo] + +[foo]: /föö "föö" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +``` föö +foo +``` +. +
foo
+
+```````````````````````````````` + + +Entity and numeric character references are treated as literal +text in code spans and code blocks: + +```````````````````````````````` example +`föö` +. +

f&ouml;&ouml;

+```````````````````````````````` + + +```````````````````````````````` example + föfö +. +
f&ouml;f&ouml;
+
+```````````````````````````````` + + +## Code spans + +A [backtick string](@) +is a string of one or more backtick characters (`` ` ``) that is neither +preceded nor followed by a backtick. + +A [code span](@) begins with a backtick string and ends with +a backtick string of equal length. The contents of the code span are +the characters between the two backtick strings, with leading and +trailing spaces and [line endings] removed, and +[whitespace] collapsed to single spaces. + +This is a simple code span: + +```````````````````````````````` example +`foo` +. +

foo

+```````````````````````````````` + + +Here two backticks are used, because the code contains a backtick. +This example also illustrates stripping of leading and trailing spaces: + +```````````````````````````````` example +`` foo ` bar `` +. +

foo ` bar

+```````````````````````````````` + + +This example shows the motivation for stripping leading and trailing +spaces: + +```````````````````````````````` example +` `` ` +. +

``

+```````````````````````````````` + + +[Line endings] are treated like spaces: + +```````````````````````````````` example +`` +foo +`` +. +

foo

+```````````````````````````````` + + +Interior spaces and [line endings] are collapsed into +single spaces, just as they would be by a browser: + +```````````````````````````````` example +`foo bar + baz` +. +

foo bar baz

+```````````````````````````````` + + +Q: Why not just leave the spaces, since browsers will collapse them +anyway? A: Because we might be targeting a non-HTML format, and we +shouldn't rely on HTML-specific rendering assumptions. + +(Existing implementations differ in their treatment of internal +spaces and [line endings]. Some, including `Markdown.pl` and +`showdown`, convert an internal [line ending] into a +`
` tag. But this makes things difficult for those who like to +hard-wrap their paragraphs, since a line break in the midst of a code +span will cause an unintended line break in the output. Others just +leave internal spaces as they are, which is fine if only HTML is being +targeted.) + +```````````````````````````````` example +`foo `` bar` +. +

foo `` bar

+```````````````````````````````` + + +Note that backslash escapes do not work in code spans. All backslashes +are treated literally: + +```````````````````````````````` example +`foo\`bar` +. +

foo\bar`

+```````````````````````````````` + + +Backslash escapes are never needed, because one can always choose a +string of *n* backtick characters as delimiters, where the code does +not contain any strings of exactly *n* backtick characters. + +Code span backticks have higher precedence than any other inline +constructs except HTML tags and autolinks. Thus, for example, this is +not parsed as emphasized text, since the second `*` is part of a code +span: + +```````````````````````````````` example +*foo`*` +. +

*foo*

+```````````````````````````````` + + +And this is not parsed as a link: + +```````````````````````````````` example +[not a `link](/foo`) +. +

[not a link](/foo)

+```````````````````````````````` + + +Code spans, HTML tags, and autolinks have the same precedence. +Thus, this is code: + +```````````````````````````````` example +`` +. +

<a href="">`

+```````````````````````````````` + + +But this is an HTML tag: + +```````````````````````````````` example +
` +. +

`

+```````````````````````````````` + + +And this is code: + +```````````````````````````````` example +`` +. +

<http://foo.bar.baz>`

+```````````````````````````````` + + +But this is an autolink: + +```````````````````````````````` example +` +. +

http://foo.bar.`baz`

+```````````````````````````````` + + +When a backtick string is not closed by a matching backtick string, +we just have literal backticks: + +```````````````````````````````` example +```foo`` +. +

```foo``

+```````````````````````````````` + + +```````````````````````````````` example +`foo +. +

`foo

+```````````````````````````````` + + +## Emphasis and strong emphasis + +John Gruber's original [Markdown syntax +description](http://daringfireball.net/projects/markdown/syntax#em) says: + +> Markdown treats asterisks (`*`) and underscores (`_`) as indicators of +> emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML +> `` tag; double `*`'s or `_`'s will be wrapped with an HTML `` +> tag. + +This is enough for most users, but these rules leave much undecided, +especially when it comes to nested emphasis. The original +`Markdown.pl` test suite makes it clear that triple `***` and +`___` delimiters can be used for strong emphasis, and most +implementations have also allowed the following patterns: + +``` markdown +***strong emph*** +***strong** in emph* +***emph* in strong** +**in strong *emph*** +*in emph **strong*** +``` + +The following patterns are less widely supported, but the intent +is clear and they are useful (especially in contexts like bibliography +entries): + +``` markdown +*emph *with emph* in it* +**strong **with strong** in it** +``` + +Many implementations have also restricted intraword emphasis to +the `*` forms, to avoid unwanted emphasis in words containing +internal underscores. (It is best practice to put these in code +spans, but users often do not.) + +``` markdown +internal emphasis: foo*bar*baz +no emphasis: foo_bar_baz +``` + +The rules given below capture all of these patterns, while allowing +for efficient parsing strategies that do not backtrack. + +First, some definitions. A [delimiter run](@) is either +a sequence of one or more `*` characters that is not preceded or +followed by a `*` character, or a sequence of one or more `_` +characters that is not preceded or followed by a `_` character. + +A [left-flanking delimiter run](@) is +a [delimiter run] that is (a) not followed by [Unicode whitespace], +and (b) either not followed by a [punctuation character], or +preceded by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace. + +A [right-flanking delimiter run](@) is +a [delimiter run] that is (a) not preceded by [Unicode whitespace], +and (b) either not preceded by a [punctuation character], or +followed by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace. + +Here are some examples of delimiter runs. + + - left-flanking but not right-flanking: + + ``` + ***abc + _abc + **"abc" + _"abc" + ``` + + - right-flanking but not left-flanking: + + ``` + abc*** + abc_ + "abc"** + "abc"_ + ``` + + - Both left and right-flanking: + + ``` + abc***def + "abc"_"def" + ``` + + - Neither left nor right-flanking: + + ``` + abc *** def + a _ b + ``` + +(The idea of distinguishing left-flanking and right-flanking +delimiter runs based on the character before and the character +after comes from Roopesh Chander's +[vfmd](http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags). +vfmd uses the terminology "emphasis indicator string" instead of "delimiter +run," and its rules for distinguishing left- and right-flanking runs +are a bit more complex than the ones given here.) + +The following rules define emphasis and strong emphasis: + +1. A single `*` character [can open emphasis](@) + iff (if and only if) it is part of a [left-flanking delimiter run]. + +2. A single `_` character [can open emphasis] iff + it is part of a [left-flanking delimiter run] + and either (a) not part of a [right-flanking delimiter run] + or (b) part of a [right-flanking delimiter run] + preceded by punctuation. + +3. A single `*` character [can close emphasis](@) + iff it is part of a [right-flanking delimiter run]. + +4. A single `_` character [can close emphasis] iff + it is part of a [right-flanking delimiter run] + and either (a) not part of a [left-flanking delimiter run] + or (b) part of a [left-flanking delimiter run] + followed by punctuation. + +5. A double `**` [can open strong emphasis](@) + iff it is part of a [left-flanking delimiter run]. + +6. A double `__` [can open strong emphasis] iff + it is part of a [left-flanking delimiter run] + and either (a) not part of a [right-flanking delimiter run] + or (b) part of a [right-flanking delimiter run] + preceded by punctuation. + +7. A double `**` [can close strong emphasis](@) + iff it is part of a [right-flanking delimiter run]. + +8. A double `__` [can close strong emphasis] + it is part of a [right-flanking delimiter run] + and either (a) not part of a [left-flanking delimiter run] + or (b) part of a [left-flanking delimiter run] + followed by punctuation. + +9. Emphasis begins with a delimiter that [can open emphasis] and ends + with a delimiter that [can close emphasis], and that uses the same + character (`_` or `*`) as the opening delimiter. There must + be a nonempty sequence of inlines between the open delimiter + and the closing delimiter; these form the contents of the emphasis + inline. + +10. Strong emphasis begins with a delimiter that + [can open strong emphasis] and ends with a delimiter that + [can close strong emphasis], and that uses the same character + (`_` or `*`) as the opening delimiter. + There must be a nonempty sequence of inlines between the open + delimiter and the closing delimiter; these form the contents of + the strong emphasis inline. + +11. A literal `*` character cannot occur at the beginning or end of + `*`-delimited emphasis or `**`-delimited strong emphasis, unless it + is backslash-escaped. + +12. A literal `_` character cannot occur at the beginning or end of + `_`-delimited emphasis or `__`-delimited strong emphasis, unless it + is backslash-escaped. + +Where rules 1--12 above are compatible with multiple parsings, +the following principles resolve ambiguity: + +13. The number of nestings should be minimized. Thus, for example, + an interpretation `...` is always preferred to + `...`. + +14. An interpretation `...` is always + preferred to `..`. + +15. When two potential emphasis or strong emphasis spans overlap, + so that the second begins before the first ends and ends after + the first ends, the first takes precedence. Thus, for example, + `*foo _bar* baz_` is parsed as `foo _bar baz_` rather + than `*foo bar* baz`. For the same reason, + `**foo*bar**` is parsed as `foobar*` + rather than `foo*bar`. + +16. When there are two potential emphasis or strong emphasis spans + with the same closing delimiter, the shorter one (the one that + opens later) takes precedence. Thus, for example, + `**foo **bar baz**` is parsed as `**foo bar baz` + rather than `foo **bar baz`. + +17. Inline code spans, links, images, and HTML tags group more tightly + than emphasis. So, when there is a choice between an interpretation + that contains one of these elements and one that does not, the + former always wins. Thus, for example, `*[foo*](bar)` is + parsed as `*foo*` rather than as + `[foo](bar)`. + +These rules can be illustrated through a series of examples. + +Rule 1: + +```````````````````````````````` example +*foo bar* +. +

foo bar

+```````````````````````````````` + + +This is not emphasis, because the opening `*` is followed by +whitespace, and hence not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a * foo bar* +. +

a * foo bar*

+```````````````````````````````` + + +This is not emphasis, because the opening `*` is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a*"foo"* +. +

a*"foo"*

+```````````````````````````````` + + +Unicode nonbreaking spaces count as whitespace, too: + +```````````````````````````````` example +* a * +. +

* a *

+```````````````````````````````` + + +Intraword emphasis with `*` is permitted: + +```````````````````````````````` example +foo*bar* +. +

foobar

+```````````````````````````````` + + +```````````````````````````````` example +5*6*78 +. +

5678

+```````````````````````````````` + + +Rule 2: + +```````````````````````````````` example +_foo bar_ +. +

foo bar

+```````````````````````````````` + + +This is not emphasis, because the opening `_` is followed by +whitespace: + +```````````````````````````````` example +_ foo bar_ +. +

_ foo bar_

+```````````````````````````````` + + +This is not emphasis, because the opening `_` is preceded +by an alphanumeric and followed by punctuation: + +```````````````````````````````` example +a_"foo"_ +. +

a_"foo"_

+```````````````````````````````` + + +Emphasis with `_` is not allowed inside words: + +```````````````````````````````` example +foo_bar_ +. +

foo_bar_

+```````````````````````````````` + + +```````````````````````````````` example +5_6_78 +. +

5_6_78

+```````````````````````````````` + + +```````````````````````````````` example +пристаням_стремятся_ +. +

пристаням_стремятся_

+```````````````````````````````` + + +Here `_` does not generate emphasis, because the first delimiter run +is right-flanking and the second left-flanking: + +```````````````````````````````` example +aa_"bb"_cc +. +

aa_"bb"_cc

+```````````````````````````````` + + +This is emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation: + +```````````````````````````````` example +foo-_(bar)_ +. +

foo-(bar)

+```````````````````````````````` + + +Rule 3: + +This is not emphasis, because the closing delimiter does +not match the opening delimiter: + +```````````````````````````````` example +_foo* +. +

_foo*

+```````````````````````````````` + + +This is not emphasis, because the closing `*` is preceded by +whitespace: + +```````````````````````````````` example +*foo bar * +. +

*foo bar *

+```````````````````````````````` + + +A newline also counts as whitespace: + +```````````````````````````````` example +*foo bar +* +. +

*foo bar

+
    +
  • +
+```````````````````````````````` + + +This is not emphasis, because the second `*` is +preceded by punctuation and followed by an alphanumeric +(hence it is not part of a [right-flanking delimiter run]: + +```````````````````````````````` example +*(*foo) +. +

*(*foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with this example: + +```````````````````````````````` example +*(*foo*)* +. +

(foo)

+```````````````````````````````` + + +Intraword emphasis with `*` is allowed: + +```````````````````````````````` example +*foo*bar +. +

foobar

+```````````````````````````````` + + + +Rule 4: + +This is not emphasis, because the closing `_` is preceded by +whitespace: + +```````````````````````````````` example +_foo bar _ +. +

_foo bar _

+```````````````````````````````` + + +This is not emphasis, because the second `_` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +_(_foo) +. +

_(_foo)

+```````````````````````````````` + + +This is emphasis within emphasis: + +```````````````````````````````` example +_(_foo_)_ +. +

(foo)

+```````````````````````````````` + + +Intraword emphasis is disallowed for `_`: + +```````````````````````````````` example +_foo_bar +. +

_foo_bar

+```````````````````````````````` + + +```````````````````````````````` example +_пристаням_стремятся +. +

_пристаням_стремятся

+```````````````````````````````` + + +```````````````````````````````` example +_foo_bar_baz_ +. +

foo_bar_baz

+```````````````````````````````` + + +This is emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation: + +```````````````````````````````` example +_(bar)_. +. +

(bar).

+```````````````````````````````` + + +Rule 5: + +```````````````````````````````` example +**foo bar** +. +

foo bar

+```````````````````````````````` + + +This is not strong emphasis, because the opening delimiter is +followed by whitespace: + +```````````````````````````````` example +** foo bar** +. +

** foo bar**

+```````````````````````````````` + + +This is not strong emphasis, because the opening `**` is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a**"foo"** +. +

a**"foo"**

+```````````````````````````````` + + +Intraword strong emphasis with `**` is permitted: + +```````````````````````````````` example +foo**bar** +. +

foobar

+```````````````````````````````` + + +Rule 6: + +```````````````````````````````` example +__foo bar__ +. +

foo bar

+```````````````````````````````` + + +This is not strong emphasis, because the opening delimiter is +followed by whitespace: + +```````````````````````````````` example +__ foo bar__ +. +

__ foo bar__

+```````````````````````````````` + + +A newline counts as whitespace: +```````````````````````````````` example +__ +foo bar__ +. +

__ +foo bar__

+```````````````````````````````` + + +This is not strong emphasis, because the opening `__` is preceded +by an alphanumeric and followed by punctuation: + +```````````````````````````````` example +a__"foo"__ +. +

a__"foo"__

+```````````````````````````````` + + +Intraword strong emphasis is forbidden with `__`: + +```````````````````````````````` example +foo__bar__ +. +

foo__bar__

+```````````````````````````````` + + +```````````````````````````````` example +5__6__78 +. +

5__6__78

+```````````````````````````````` + + +```````````````````````````````` example +пристаням__стремятся__ +. +

пристаням__стремятся__

+```````````````````````````````` + + +```````````````````````````````` example +__foo, __bar__, baz__ +. +

foo, bar, baz

+```````````````````````````````` + + +This is strong emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation: + +```````````````````````````````` example +foo-__(bar)__ +. +

foo-(bar)

+```````````````````````````````` + + + +Rule 7: + +This is not strong emphasis, because the closing delimiter is preceded +by whitespace: + +```````````````````````````````` example +**foo bar ** +. +

**foo bar **

+```````````````````````````````` + + +(Nor can it be interpreted as an emphasized `*foo bar *`, because of +Rule 11.) + +This is not strong emphasis, because the second `**` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +**(**foo) +. +

**(**foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with these examples: + +```````````````````````````````` example +*(**foo**)* +. +

(foo)

+```````````````````````````````` + + +```````````````````````````````` example +**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +. +

Gomphocarpus (Gomphocarpus physocarpus, syn. +Asclepias physocarpa)

+```````````````````````````````` + + +```````````````````````````````` example +**foo "*bar*" foo** +. +

foo "bar" foo

+```````````````````````````````` + + +Intraword emphasis: + +```````````````````````````````` example +**foo**bar +. +

foobar

+```````````````````````````````` + + +Rule 8: + +This is not strong emphasis, because the closing delimiter is +preceded by whitespace: + +```````````````````````````````` example +__foo bar __ +. +

__foo bar __

+```````````````````````````````` + + +This is not strong emphasis, because the second `__` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +__(__foo) +. +

__(__foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with this example: + +```````````````````````````````` example +_(__foo__)_ +. +

(foo)

+```````````````````````````````` + + +Intraword strong emphasis is forbidden with `__`: + +```````````````````````````````` example +__foo__bar +. +

__foo__bar

+```````````````````````````````` + + +```````````````````````````````` example +__пристаням__стремятся +. +

__пристаням__стремятся

+```````````````````````````````` + + +```````````````````````````````` example +__foo__bar__baz__ +. +

foo__bar__baz

+```````````````````````````````` + + +This is strong emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation: + +```````````````````````````````` example +__(bar)__. +. +

(bar).

+```````````````````````````````` + + +Rule 9: + +Any nonempty sequence of inline elements can be the contents of an +emphasized span. + +```````````````````````````````` example +*foo [bar](/url)* +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo +bar* +. +

foo +bar

+```````````````````````````````` + + +In particular, emphasis and strong emphasis can be nested +inside emphasis: + +```````````````````````````````` example +_foo __bar__ baz_ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +_foo _bar_ baz_ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +__foo_ bar_ +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo *bar** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo **bar** baz* +. +

foo bar baz

+```````````````````````````````` + + +But note: + +```````````````````````````````` example +*foo**bar**baz* +. +

foobarbaz

+```````````````````````````````` + + +The difference is that in the preceding case, the internal delimiters +[can close emphasis], while in the cases with spaces, they cannot. + +```````````````````````````````` example +***foo** bar* +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo **bar*** +. +

foo bar

+```````````````````````````````` + + +Note, however, that in the following case we get no strong +emphasis, because the opening delimiter is closed by the first +`*` before `bar`: + +```````````````````````````````` example +*foo**bar*** +. +

foobar**

+```````````````````````````````` + + + +Indefinite levels of nesting are possible: + +```````````````````````````````` example +*foo **bar *baz* bim** bop* +. +

foo bar baz bim bop

+```````````````````````````````` + + +```````````````````````````````` example +*foo [*bar*](/url)* +. +

foo bar

+```````````````````````````````` + + +There can be no empty emphasis or strong emphasis: + +```````````````````````````````` example +** is not an empty emphasis +. +

** is not an empty emphasis

+```````````````````````````````` + + +```````````````````````````````` example +**** is not an empty strong emphasis +. +

**** is not an empty strong emphasis

+```````````````````````````````` + + + +Rule 10: + +Any nonempty sequence of inline elements can be the contents of an +strongly emphasized span. + +```````````````````````````````` example +**foo [bar](/url)** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo +bar** +. +

foo +bar

+```````````````````````````````` + + +In particular, emphasis and strong emphasis can be nested +inside strong emphasis: + +```````````````````````````````` example +__foo _bar_ baz__ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +__foo __bar__ baz__ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +____foo__ bar__ +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo **bar**** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo *bar* baz** +. +

foo bar baz

+```````````````````````````````` + + +But note: + +```````````````````````````````` example +**foo*bar*baz** +. +

foobarbaz**

+```````````````````````````````` + + +The difference is that in the preceding case, the internal delimiters +[can close emphasis], while in the cases with spaces, they cannot. + +```````````````````````````````` example +***foo* bar** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo *bar*** +. +

foo bar

+```````````````````````````````` + + +Indefinite levels of nesting are possible: + +```````````````````````````````` example +**foo *bar **baz** +bim* bop** +. +

foo bar baz +bim bop

+```````````````````````````````` + + +```````````````````````````````` example +**foo [*bar*](/url)** +. +

foo bar

+```````````````````````````````` + + +There can be no empty emphasis or strong emphasis: + +```````````````````````````````` example +__ is not an empty emphasis +. +

__ is not an empty emphasis

+```````````````````````````````` + + +```````````````````````````````` example +____ is not an empty strong emphasis +. +

____ is not an empty strong emphasis

+```````````````````````````````` + + + +Rule 11: + +```````````````````````````````` example +foo *** +. +

foo ***

+```````````````````````````````` + + +```````````````````````````````` example +foo *\** +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo *_* +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo ***** +. +

foo *****

+```````````````````````````````` + + +```````````````````````````````` example +foo **\*** +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo **_** +. +

foo _

+```````````````````````````````` + + +Note that when delimiters do not match evenly, Rule 11 determines +that the excess literal `*` characters will appear outside of the +emphasis, rather than inside it: + +```````````````````````````````` example +**foo* +. +

*foo

+```````````````````````````````` + + +```````````````````````````````` example +*foo** +. +

foo*

+```````````````````````````````` + + +```````````````````````````````` example +***foo** +. +

*foo

+```````````````````````````````` + + +```````````````````````````````` example +****foo* +. +

***foo

+```````````````````````````````` + + +```````````````````````````````` example +**foo*** +. +

foo*

+```````````````````````````````` + + +```````````````````````````````` example +*foo**** +. +

foo***

+```````````````````````````````` + + + +Rule 12: + +```````````````````````````````` example +foo ___ +. +

foo ___

+```````````````````````````````` + + +```````````````````````````````` example +foo _\__ +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo _*_ +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo _____ +. +

foo _____

+```````````````````````````````` + + +```````````````````````````````` example +foo __\___ +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo __*__ +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +__foo_ +. +

_foo

+```````````````````````````````` + + +Note that when delimiters do not match evenly, Rule 12 determines +that the excess literal `_` characters will appear outside of the +emphasis, rather than inside it: + +```````````````````````````````` example +_foo__ +. +

foo_

+```````````````````````````````` + + +```````````````````````````````` example +___foo__ +. +

_foo

+```````````````````````````````` + + +```````````````````````````````` example +____foo_ +. +

___foo

+```````````````````````````````` + + +```````````````````````````````` example +__foo___ +. +

foo_

+```````````````````````````````` + + +```````````````````````````````` example +_foo____ +. +

foo___

+```````````````````````````````` + + +Rule 13 implies that if you want emphasis nested directly inside +emphasis, you must use different delimiters: + +```````````````````````````````` example +**foo** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +*_foo_* +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +__foo__ +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +_*foo*_ +. +

foo

+```````````````````````````````` + + +However, strong emphasis within strong emphasis is possible without +switching delimiters: + +```````````````````````````````` example +****foo**** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +____foo____ +. +

foo

+```````````````````````````````` + + + +Rule 13 can be applied to arbitrarily long sequences of +delimiters: + +```````````````````````````````` example +******foo****** +. +

foo

+```````````````````````````````` + + +Rule 14: + +```````````````````````````````` example +***foo*** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +_____foo_____ +. +

foo

+```````````````````````````````` + + +Rule 15: + +```````````````````````````````` example +*foo _bar* baz_ +. +

foo _bar baz_

+```````````````````````````````` + + +```````````````````````````````` example +**foo*bar** +. +

foobar*

+```````````````````````````````` + + +```````````````````````````````` example +*foo __bar *baz bim__ bam* +. +

foo bar *baz bim bam

+```````````````````````````````` + + +Rule 16: + +```````````````````````````````` example +**foo **bar baz** +. +

**foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +*foo *bar baz* +. +

*foo bar baz

+```````````````````````````````` + + +Rule 17: + +```````````````````````````````` example +*[bar*](/url) +. +

*bar*

+```````````````````````````````` + + +```````````````````````````````` example +_foo [bar_](/url) +. +

_foo bar_

+```````````````````````````````` + + +```````````````````````````````` example +* +. +

*

+```````````````````````````````` + + +```````````````````````````````` example +** +. +

**

+```````````````````````````````` + + +```````````````````````````````` example +__ +. +

__

+```````````````````````````````` + + +```````````````````````````````` example +*a `*`* +. +

a *

+```````````````````````````````` + + +```````````````````````````````` example +_a `_`_ +. +

a _

+```````````````````````````````` + + +```````````````````````````````` example +**a +. +

**ahttp://foo.bar/?q=**

+```````````````````````````````` + + +```````````````````````````````` example +__a +. +

__ahttp://foo.bar/?q=__

+```````````````````````````````` + + + +## Links + +A link contains [link text] (the visible text), a [link destination] +(the URI that is the link destination), and optionally a [link title]. +There are two basic kinds of links in Markdown. In [inline links] the +destination and title are given immediately after the link text. In +[reference links] the destination and title are defined elsewhere in +the document. + +A [link text](@) consists of a sequence of zero or more +inline elements enclosed by square brackets (`[` and `]`). The +following rules apply: + +- Links may not contain other links, at any level of nesting. If + multiple otherwise valid link definitions appear nested inside each + other, the inner-most definition is used. + +- Brackets are allowed in the [link text] only if (a) they + are backslash-escaped or (b) they appear as a matched pair of brackets, + with an open bracket `[`, a sequence of zero or more inlines, and + a close bracket `]`. + +- Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly + than the brackets in link text. Thus, for example, + `` [foo`]` `` could not be a link text, since the second `]` + is part of a code span. + +- The brackets in link text bind more tightly than markers for + [emphasis and strong emphasis]. Thus, for example, `*[foo*](url)` is a link. + +A [link destination](@) consists of either + +- a sequence of zero or more characters between an opening `<` and a + closing `>` that contains no spaces, line breaks, or unescaped + `<` or `>` characters, or + +- a nonempty sequence of characters that does not include + ASCII space or control characters, and includes parentheses + only if (a) they are backslash-escaped or (b) they are part of + a balanced pair of unescaped parentheses that is not itself + inside a balanced pair of unescaped parentheses. + +A [link title](@) consists of either + +- a sequence of zero or more characters between straight double-quote + characters (`"`), including a `"` character only if it is + backslash-escaped, or + +- a sequence of zero or more characters between straight single-quote + characters (`'`), including a `'` character only if it is + backslash-escaped, or + +- a sequence of zero or more characters between matching parentheses + (`(...)`), including a `)` character only if it is backslash-escaped. + +Although [link titles] may span multiple lines, they may not contain +a [blank line]. + +An [inline link](@) consists of a [link text] followed immediately +by a left parenthesis `(`, optional [whitespace], an optional +[link destination], an optional [link title] separated from the link +destination by [whitespace], optional [whitespace], and a right +parenthesis `)`. The link's text consists of the inlines contained +in the [link text] (excluding the enclosing square brackets). +The link's URI consists of the link destination, excluding enclosing +`<...>` if present, with backslash-escapes in effect as described +above. The link's title consists of the link title, excluding its +enclosing delimiters, with backslash-escapes in effect as described +above. + +Here is a simple inline link: + +```````````````````````````````` example +[link](/uri "title") +. +

link

+```````````````````````````````` + + +The title may be omitted: + +```````````````````````````````` example +[link](/uri) +. +

link

+```````````````````````````````` + + +Both the title and the destination may be omitted: + +```````````````````````````````` example +[link]() +. +

link

+```````````````````````````````` + + +```````````````````````````````` example +[link](<>) +. +

link

+```````````````````````````````` + + +The destination cannot contain spaces or line breaks, +even if enclosed in pointy brackets: + +```````````````````````````````` example +[link](/my uri) +. +

[link](/my uri)

+```````````````````````````````` + + +```````````````````````````````` example +[link]() +. +

[link](</my uri>)

+```````````````````````````````` + + +```````````````````````````````` example +[link](foo +bar) +. +

[link](foo +bar)

+```````````````````````````````` + + +```````````````````````````````` example +[link]() +. +

[link]()

+```````````````````````````````` + +Parentheses inside the link destination may be escaped: + +```````````````````````````````` example +[link](\(foo\)) +. +

link

+```````````````````````````````` + +One level of balanced parentheses is allowed without escaping: + +```````````````````````````````` example +[link]((foo)and(bar)) +. +

link

+```````````````````````````````` + +However, if you have parentheses within parentheses, you need to escape +or use the `<...>` form: + +```````````````````````````````` example +[link](foo(and(bar))) +. +

[link](foo(and(bar)))

+```````````````````````````````` + + +```````````````````````````````` example +[link](foo(and\(bar\))) +. +

link

+```````````````````````````````` + + +```````````````````````````````` example +[link]() +. +

link

+```````````````````````````````` + + +Parentheses and other symbols can also be escaped, as usual +in Markdown: + +```````````````````````````````` example +[link](foo\)\:) +. +

link

+```````````````````````````````` + + +A link can contain fragment identifiers and queries: + +```````````````````````````````` example +[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +. +

link

+

link

+

link

+```````````````````````````````` + + +Note that a backslash before a non-escapable character is +just a backslash: + +```````````````````````````````` example +[link](foo\bar) +. +

link

+```````````````````````````````` + + +URL-escaping should be left alone inside the destination, as all +URL-escaped characters are also valid URL characters. Entity and +numerical character references in the destination will be parsed +into the corresponding Unicode code points, as usual. These may +be optionally URL-escaped when written as HTML, but this spec +does not enforce any particular policy for rendering URLs in +HTML or other formats. Renderers may make different decisions +about how to escape or normalize URLs in the output. + +```````````````````````````````` example +[link](foo%20bä) +. +

link

+```````````````````````````````` + + +Note that, because titles can often be parsed as destinations, +if you try to omit the destination and keep the title, you'll +get unexpected results: + +```````````````````````````````` example +[link]("title") +. +

link

+```````````````````````````````` + + +Titles may be in single quotes, double quotes, or parentheses: + +```````````````````````````````` example +[link](/url "title") +[link](/url 'title') +[link](/url (title)) +. +

link +link +link

+```````````````````````````````` + + +Backslash escapes and entity and numeric character references +may be used in titles: + +```````````````````````````````` example +[link](/url "title \""") +. +

link

+```````````````````````````````` + + +Nested balanced quotes are not allowed without escaping: + +```````````````````````````````` example +[link](/url "title "and" title") +. +

[link](/url "title "and" title")

+```````````````````````````````` + + +But it is easy to work around this by using a different quote type: + +```````````````````````````````` example +[link](/url 'title "and" title') +. +

link

+```````````````````````````````` + + +(Note: `Markdown.pl` did allow double quotes inside a double-quoted +title, and its test suite included a test demonstrating this. +But it is hard to see a good rationale for the extra complexity this +brings, since there are already many ways---backslash escaping, +entity and numeric character references, or using a different +quote type for the enclosing title---to write titles containing +double quotes. `Markdown.pl`'s handling of titles has a number +of other strange features. For example, it allows single-quoted +titles in inline links, but not reference links. And, in +reference links but not inline links, it allows a title to begin +with `"` and end with `)`. `Markdown.pl` 1.0.1 even allows +titles with no closing quotation mark, though 1.0.2b8 does not. +It seems preferable to adopt a simple, rational rule that works +the same way in inline links and link reference definitions.) + +[Whitespace] is allowed around the destination and title: + +```````````````````````````````` example +[link]( /uri + "title" ) +. +

link

+```````````````````````````````` + + +But it is not allowed between the link text and the +following parenthesis: + +```````````````````````````````` example +[link] (/uri) +. +

[link] (/uri)

+```````````````````````````````` + + +The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped: + +```````````````````````````````` example +[link [foo [bar]]](/uri) +. +

link [foo [bar]]

+```````````````````````````````` + + +```````````````````````````````` example +[link] bar](/uri) +. +

[link] bar](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[link [bar](/uri) +. +

[link bar

+```````````````````````````````` + + +```````````````````````````````` example +[link \[bar](/uri) +. +

link [bar

+```````````````````````````````` + + +The link text may contain inline content: + +```````````````````````````````` example +[link *foo **bar** `#`*](/uri) +. +

link foo bar #

+```````````````````````````````` + + +```````````````````````````````` example +[![moon](moon.jpg)](/uri) +. +

moon

+```````````````````````````````` + + +However, links may not contain other links, at any level of nesting. + +```````````````````````````````` example +[foo [bar](/uri)](/uri) +. +

[foo bar](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[foo *[bar [baz](/uri)](/uri)*](/uri) +. +

[foo [bar baz](/uri)](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +![[[foo](uri1)](uri2)](uri3) +. +

[foo](uri2)

+```````````````````````````````` + + +These cases illustrate the precedence of link text grouping over +emphasis grouping: + +```````````````````````````````` example +*[foo*](/uri) +. +

*foo*

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar](baz*) +. +

foo *bar

+```````````````````````````````` + + +Note that brackets that *aren't* part of links do not take +precedence: + +```````````````````````````````` example +*foo [bar* baz] +. +

foo [bar baz]

+```````````````````````````````` + + +These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping: + +```````````````````````````````` example +[foo +. +

[foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo`](/uri)` +. +

[foo](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[foo +. +

[foohttp://example.com/?search=](uri)

+```````````````````````````````` + + +There are three kinds of [reference link](@)s: +[full](#full-reference-link), [collapsed](#collapsed-reference-link), +and [shortcut](#shortcut-reference-link). + +A [full reference link](@) +consists of a [link text] immediately followed by a [link label] +that [matches] a [link reference definition] elsewhere in the document. + +A [link label](@) begins with a left bracket (`[`) and ends +with the first right bracket (`]`) that is not backslash-escaped. +Between these brackets there must be at least one [non-whitespace character]. +Unescaped square bracket characters are not allowed in +[link labels]. A link label can have at most 999 +characters inside the square brackets. + +One label [matches](@) +another just in case their normalized forms are equal. To normalize a +label, perform the *Unicode case fold* and collapse consecutive internal +[whitespace] to a single space. If there are multiple +matching reference link definitions, the one that comes first in the +document is used. (It is desirable in such cases to emit a warning.) + +The contents of the first link label are parsed as inlines, which are +used as the link's text. The link's URI and title are provided by the +matching [link reference definition]. + +Here is a simple example: + +```````````````````````````````` example +[foo][bar] + +[bar]: /url "title" +. +

foo

+```````````````````````````````` + + +The rules for the [link text] are the same as with +[inline links]. Thus: + +The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped: + +```````````````````````````````` example +[link [foo [bar]]][ref] + +[ref]: /uri +. +

link [foo [bar]]

+```````````````````````````````` + + +```````````````````````````````` example +[link \[bar][ref] + +[ref]: /uri +. +

link [bar

+```````````````````````````````` + + +The link text may contain inline content: + +```````````````````````````````` example +[link *foo **bar** `#`*][ref] + +[ref]: /uri +. +

link foo bar #

+```````````````````````````````` + + +```````````````````````````````` example +[![moon](moon.jpg)][ref] + +[ref]: /uri +. +

moon

+```````````````````````````````` + + +However, links may not contain other links, at any level of nesting. + +```````````````````````````````` example +[foo [bar](/uri)][ref] + +[ref]: /uri +. +

[foo bar]ref

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar [baz][ref]*][ref] + +[ref]: /uri +. +

[foo bar baz]ref

+```````````````````````````````` + + +(In the examples above, we have two [shortcut reference links] +instead of one [full reference link].) + +The following cases illustrate the precedence of link text grouping over +emphasis grouping: + +```````````````````````````````` example +*[foo*][ref] + +[ref]: /uri +. +

*foo*

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar][ref] + +[ref]: /uri +. +

foo *bar

+```````````````````````````````` + + +These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping: + +```````````````````````````````` example +[foo + +[ref]: /uri +. +

[foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo`][ref]` + +[ref]: /uri +. +

[foo][ref]

+```````````````````````````````` + + +```````````````````````````````` example +[foo + +[ref]: /uri +. +

[foohttp://example.com/?search=][ref]

+```````````````````````````````` + + +Matching is case-insensitive: + +```````````````````````````````` example +[foo][BaR] + +[bar]: /url "title" +. +

foo

+```````````````````````````````` + + +Unicode case fold is used: + +```````````````````````````````` example +[Толпой][Толпой] is a Russian word. + +[ТОЛПОЙ]: /url +. +

Толпой is a Russian word.

+```````````````````````````````` + + +Consecutive internal [whitespace] is treated as one space for +purposes of determining matching: + +```````````````````````````````` example +[Foo + bar]: /url + +[Baz][Foo bar] +. +

Baz

+```````````````````````````````` + + +No [whitespace] is allowed between the [link text] and the +[link label]: + +```````````````````````````````` example +[foo] [bar] + +[bar]: /url "title" +. +

[foo] bar

+```````````````````````````````` + + +```````````````````````````````` example +[foo] +[bar] + +[bar]: /url "title" +. +

[foo] +bar

+```````````````````````````````` + + +This is a departure from John Gruber's original Markdown syntax +description, which explicitly allows whitespace between the link +text and the link label. It brings reference links in line with +[inline links], which (according to both original Markdown and +this spec) cannot have whitespace after the link text. More +importantly, it prevents inadvertent capture of consecutive +[shortcut reference links]. If whitespace is allowed between the +link text and the link label, then in the following we will have +a single reference link, not two shortcut reference links, as +intended: + +``` markdown +[foo] +[bar] + +[foo]: /url1 +[bar]: /url2 +``` + +(Note that [shortcut reference links] were introduced by Gruber +himself in a beta version of `Markdown.pl`, but never included +in the official syntax description. Without shortcut reference +links, it is harmless to allow space between the link text and +link label; but once shortcut references are introduced, it is +too dangerous to allow this, as it frequently leads to +unintended results.) + +When there are multiple matching [link reference definitions], +the first is used: + +```````````````````````````````` example +[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +. +

bar

+```````````````````````````````` + + +Note that matching is performed on normalized strings, not parsed +inline content. So the following does not match, even though the +labels define equivalent inline content: + +```````````````````````````````` example +[bar][foo\!] + +[foo!]: /url +. +

[bar][foo!]

+```````````````````````````````` + + +[Link labels] cannot contain brackets, unless they are +backslash-escaped: + +```````````````````````````````` example +[foo][ref[] + +[ref[]: /uri +. +

[foo][ref[]

+

[ref[]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[foo][ref[bar]] + +[ref[bar]]: /uri +. +

[foo][ref[bar]]

+

[ref[bar]]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[[[foo]]] + +[[[foo]]]: /url +. +

[[[foo]]]

+

[[[foo]]]: /url

+```````````````````````````````` + + +```````````````````````````````` example +[foo][ref\[] + +[ref\[]: /uri +. +

foo

+```````````````````````````````` + + +Note that in this example `]` is not backslash-escaped: + +```````````````````````````````` example +[bar\\]: /uri + +[bar\\] +. +

bar\

+```````````````````````````````` + + +A [link label] must contain at least one [non-whitespace character]: + +```````````````````````````````` example +[] + +[]: /uri +. +

[]

+

[]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[ + ] + +[ + ]: /uri +. +

[ +]

+

[ +]: /uri

+```````````````````````````````` + + +A [collapsed reference link](@) +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document, followed by the string `[]`. +The contents of the first link label are parsed as inlines, +which are used as the link's text. The link's URI and title are +provided by the matching reference link definition. Thus, +`[foo][]` is equivalent to `[foo][foo]`. + +```````````````````````````````` example +[foo][] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[*foo* bar][] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +[Foo][] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + + +As with full reference links, [whitespace] is not +allowed between the two sets of brackets: + +```````````````````````````````` example +[foo] +[] + +[foo]: /url "title" +. +

foo +[]

+```````````````````````````````` + + +A [shortcut reference link](@) +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document and is not followed by `[]` or a link label. +The contents of the first link label are parsed as inlines, +which are used as the link's text. the link's URI and title +are provided by the matching link reference definition. +Thus, `[foo]` is equivalent to `[foo][]`. + +```````````````````````````````` example +[foo] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[*foo* bar] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +[[*foo* bar]] + +[*foo* bar]: /url "title" +. +

[foo bar]

+```````````````````````````````` + + +```````````````````````````````` example +[[bar [foo] + +[foo]: /url +. +

[[bar foo

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +[Foo] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +A space after the link text should be preserved: + +```````````````````````````````` example +[foo] bar + +[foo]: /url +. +

foo bar

+```````````````````````````````` + + +If you just want bracketed text, you can backslash-escape the +opening bracket to avoid links: + +```````````````````````````````` example +\[foo] + +[foo]: /url "title" +. +

[foo]

+```````````````````````````````` + + +Note that this is a link, because a link label ends with the first +following closing bracket: + +```````````````````````````````` example +[foo*]: /url + +*[foo*] +. +

*foo*

+```````````````````````````````` + + +Full references take precedence over shortcut references: + +```````````````````````````````` example +[foo][bar] + +[foo]: /url1 +[bar]: /url2 +. +

foo

+```````````````````````````````` + + +In the following case `[bar][baz]` is parsed as a reference, +`[foo]` as normal text: + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url +. +

[foo]bar

+```````````````````````````````` + + +Here, though, `[foo][bar]` is parsed as a reference, since +`[bar]` is defined: + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +. +

foobaz

+```````````````````````````````` + + +Here `[foo]` is not parsed as a shortcut reference, because it +is followed by a link label (even though `[bar]` is not defined): + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +. +

[foo]bar

+```````````````````````````````` + + + +## Images + +Syntax for images is like the syntax for links, with one +difference. Instead of [link text], we have an +[image description](@). The rules for this are the +same as for [link text], except that (a) an +image description starts with `![` rather than `[`, and +(b) an image description may contain links. +An image description has inline elements +as its contents. When an image is rendered to HTML, +this is standardly used as the image's `alt` attribute. + +```````````````````````````````` example +![foo](/url "title") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo ![bar](/url)](/url2) +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo [bar](/url)](/url2) +. +

foo bar

+```````````````````````````````` + + +Though this spec is concerned with parsing, not rendering, it is +recommended that in rendering to HTML, only the plain string content +of the [image description] be used. Note that in +the above example, the alt attribute's value is `foo bar`, not `foo +[bar](/url)` or `foo bar`. Only the plain string +content is rendered, without formatting. + +```````````````````````````````` example +![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo](train.jpg) +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +My ![foo bar](/path/to/train.jpg "title" ) +. +

My foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo]() +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![](/url) +. +

+```````````````````````````````` + + +Reference-style: + +```````````````````````````````` example +![foo][bar] + +[bar]: /url +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![foo][bar] + +[BAR]: /url +. +

foo

+```````````````````````````````` + + +Collapsed: + +```````````````````````````````` example +![foo][] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![*foo* bar][] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +The labels are case-insensitive: + +```````````````````````````````` example +![Foo][] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +As with reference links, [whitespace] is not allowed +between the two sets of brackets: + +```````````````````````````````` example +![foo] +[] + +[foo]: /url "title" +. +

foo +[]

+```````````````````````````````` + + +Shortcut: + +```````````````````````````````` example +![foo] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![*foo* bar] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +Note that link labels cannot contain unescaped brackets: + +```````````````````````````````` example +![[foo]] + +[[foo]]: /url "title" +. +

![[foo]]

+

[[foo]]: /url "title"

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +![Foo] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +If you just want bracketed text, you can backslash-escape the +opening `!` and `[`: + +```````````````````````````````` example +\!\[foo] + +[foo]: /url "title" +. +

![foo]

+```````````````````````````````` + + +If you want a link after a literal `!`, backslash-escape the +`!`: + +```````````````````````````````` example +\![foo] + +[foo]: /url "title" +. +

!foo

+```````````````````````````````` + + +## Autolinks + +[Autolink](@)s are absolute URIs and email addresses inside +`<` and `>`. They are parsed as links, with the URL or email address +as the link label. + +A [URI autolink](@) consists of `<`, followed by an +[absolute URI] not containing `<`, followed by `>`. It is parsed as +a link to the URI, with the URI as the link's label. + +An [absolute URI](@), +for these purposes, consists of a [scheme] followed by a colon (`:`) +followed by zero or more characters other than ASCII +[whitespace] and control characters, `<`, and `>`. If +the URI includes these characters, they must be percent-encoded +(e.g. `%20` for a space). + +For purposes of this spec, a [scheme](@) is any sequence +of 2--32 characters beginning with an ASCII letter and followed +by any combination of ASCII letters, digits, or the symbols plus +("+"), period ("."), or hyphen ("-"). + +Here are some valid autolinks: + +```````````````````````````````` example + +. +

http://foo.bar.baz

+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://foo.bar.baz/test?q=hello&id=22&boolean

+```````````````````````````````` + + +```````````````````````````````` example + +. +

irc://foo.bar:2233/baz

+```````````````````````````````` + + +Uppercase is also fine: + +```````````````````````````````` example + +. +

MAILTO:FOO@BAR.BAZ

+```````````````````````````````` + + +Note that many strings that count as [absolute URIs] for +purposes of this spec are not valid URIs, because their +schemes are not registered or because of other problems +with their syntax: + +```````````````````````````````` example + +. +

a+b+c:d

+```````````````````````````````` + + +```````````````````````````````` example + +. +

made-up-scheme://foo,bar

+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://../

+```````````````````````````````` + + +```````````````````````````````` example + +. +

localhost:5001/foo

+```````````````````````````````` + + +Spaces are not allowed in autolinks: + +```````````````````````````````` example + +. +

<http://foo.bar/baz bim>

+```````````````````````````````` + + +Backslash-escapes do not work inside autolinks: + +```````````````````````````````` example + +. +

http://example.com/\[\

+```````````````````````````````` + + +An [email autolink](@) +consists of `<`, followed by an [email address], +followed by `>`. The link's label is the email address, +and the URL is `mailto:` followed by the email address. + +An [email address](@), +for these purposes, is anything that matches +the [non-normative regex from the HTML5 +spec](https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)): + + /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + +Examples of email autolinks: + +```````````````````````````````` example + +. +

foo@bar.example.com

+```````````````````````````````` + + +```````````````````````````````` example + +. +

foo+special@Bar.baz-bar0.com

+```````````````````````````````` + + +Backslash-escapes do not work inside email autolinks: + +```````````````````````````````` example + +. +

<foo+@bar.example.com>

+```````````````````````````````` + + +These are not autolinks: + +```````````````````````````````` example +<> +. +

<>

+```````````````````````````````` + + +```````````````````````````````` example +< http://foo.bar > +. +

< http://foo.bar >

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<m:abc>

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<foo.bar.baz>

+```````````````````````````````` + + +```````````````````````````````` example +http://example.com +. +

http://example.com

+```````````````````````````````` + + +```````````````````````````````` example +foo@bar.example.com +. +

foo@bar.example.com

+```````````````````````````````` + + +## Raw HTML + +Text between `<` and `>` that looks like an HTML tag is parsed as a +raw HTML tag and will be rendered in HTML without escaping. +Tag and attribute names are not limited to current HTML tags, +so custom tags (and even, say, DocBook tags) may be used. + +Here is the grammar for tags: + +A [tag name](@) consists of an ASCII letter +followed by zero or more ASCII letters, digits, or +hyphens (`-`). + +An [attribute](@) consists of [whitespace], +an [attribute name], and an optional +[attribute value specification]. + +An [attribute name](@) +consists of an ASCII letter, `_`, or `:`, followed by zero or more ASCII +letters, digits, `_`, `.`, `:`, or `-`. (Note: This is the XML +specification restricted to ASCII. HTML5 is laxer.) + +An [attribute value specification](@) +consists of optional [whitespace], +a `=` character, optional [whitespace], and an [attribute +value]. + +An [attribute value](@) +consists of an [unquoted attribute value], +a [single-quoted attribute value], or a [double-quoted attribute value]. + +An [unquoted attribute value](@) +is a nonempty string of characters not +including spaces, `"`, `'`, `=`, `<`, `>`, or `` ` ``. + +A [single-quoted attribute value](@) +consists of `'`, zero or more +characters not including `'`, and a final `'`. + +A [double-quoted attribute value](@) +consists of `"`, zero or more +characters not including `"`, and a final `"`. + +An [open tag](@) consists of a `<` character, a [tag name], +zero or more [attributes], optional [whitespace], an optional `/` +character, and a `>` character. + +A [closing tag](@) consists of the string ``. + +An [HTML comment](@) consists of ``, +where *text* does not start with `>` or `->`, does not end with `-`, +and does not contain `--`. (See the +[HTML5 spec](http://www.w3.org/TR/html5/syntax.html#comments).) + +A [processing instruction](@) +consists of the string ``, and the string +`?>`. + +A [declaration](@) consists of the +string ``, and the character `>`. + +A [CDATA section](@) consists of +the string ``, and the string `]]>`. + +An [HTML tag](@) consists of an [open tag], a [closing tag], +an [HTML comment], a [processing instruction], a [declaration], +or a [CDATA section]. + +Here are some simple open tags: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Empty elements: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +[Whitespace] is allowed: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +With attributes: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Custom tag names can be used: + +```````````````````````````````` example +Foo +. +

Foo

+```````````````````````````````` + + +Illegal tag names, not parsed as HTML: + +```````````````````````````````` example +<33> <__> +. +

<33> <__>

+```````````````````````````````` + + +Illegal attribute names: + +```````````````````````````````` example +
+. +

<a h*#ref="hi">

+```````````````````````````````` + + +Illegal attribute values: + +```````````````````````````````` example +
+. +

</a href="foo">

+```````````````````````````````` + + +Comments: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +foo +. +

foo <!-- not a comment -- two hyphens -->

+```````````````````````````````` + + +Not comments: + +```````````````````````````````` example +foo foo --> + +foo +. +

foo <!--> foo -->

+

foo <!-- foo--->

+```````````````````````````````` + + +Processing instructions: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +Declarations: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +CDATA sections: + +```````````````````````````````` example +foo &<]]> +. +

foo &<]]>

+```````````````````````````````` + + +Entity and numeric character references are preserved in HTML +attributes: + +```````````````````````````````` example +foo
+. +

foo

+```````````````````````````````` + + +Backslash escapes do not work in HTML attributes: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<a href=""">

+```````````````````````````````` + + +## Hard line breaks + +A line break (not in a code span or HTML tag) that is preceded +by two or more spaces and does not occur at the end of a block +is parsed as a [hard line break](@) (rendered +in HTML as a `
` tag): + +```````````````````````````````` example +foo +baz +. +

foo
+baz

+```````````````````````````````` + + +For a more visible alternative, a backslash before the +[line ending] may be used instead of two spaces: + +```````````````````````````````` example +foo\ +baz +. +

foo
+baz

+```````````````````````````````` + + +More than two spaces can be used: + +```````````````````````````````` example +foo +baz +. +

foo
+baz

+```````````````````````````````` + + +Leading spaces at the beginning of the next line are ignored: + +```````````````````````````````` example +foo + bar +. +

foo
+bar

+```````````````````````````````` + + +```````````````````````````````` example +foo\ + bar +. +

foo
+bar

+```````````````````````````````` + + +Line breaks can occur inside emphasis, links, and other constructs +that allow inline content: + +```````````````````````````````` example +*foo +bar* +. +

foo
+bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo\ +bar* +. +

foo
+bar

+```````````````````````````````` + + +Line breaks do not occur inside code spans + +```````````````````````````````` example +`code +span` +. +

code span

+```````````````````````````````` + + +```````````````````````````````` example +`code\ +span` +. +

code\ span

+```````````````````````````````` + + +or HTML tags: + +```````````````````````````````` example +
+. +

+```````````````````````````````` + + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Hard line breaks are for separating inline content within a block. +Neither syntax for hard line breaks works at the end of a paragraph or +other block element: + +```````````````````````````````` example +foo\ +. +

foo\

+```````````````````````````````` + + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +### foo\ +. +

foo\

+```````````````````````````````` + + +```````````````````````````````` example +### foo +. +

foo

+```````````````````````````````` + + +## Soft line breaks + +A regular line break (not in a code span or HTML tag) that is not +preceded by two or more spaces or a backslash is parsed as a +softbreak. (A softbreak may be rendered in HTML either as a +[line ending] or as a space. The result will be the same in +browsers. In the examples here, a [line ending] will be used.) + +```````````````````````````````` example +foo +baz +. +

foo +baz

+```````````````````````````````` + + +Spaces at the end of the line and beginning of the next line are +removed: + +```````````````````````````````` example +foo + baz +. +

foo +baz

+```````````````````````````````` + + +A conforming parser may render a soft line break in HTML either as a +line break or as a space. + +A renderer may also provide an option to render soft line breaks +as hard line breaks. + +## Textual content + +Any characters not given an interpretation by the above rules will +be parsed as plain textual content. + +```````````````````````````````` example +hello $.;'there +. +

hello $.;'there

+```````````````````````````````` + + +```````````````````````````````` example +Foo χρῆν +. +

Foo χρῆν

+```````````````````````````````` + + +Internal spaces are preserved verbatim: + +```````````````````````````````` example +Multiple spaces +. +

Multiple spaces

+```````````````````````````````` + + + + +# Appendix: A parsing strategy + +In this appendix we describe some features of the parsing strategy +used in the CommonMark reference implementations. + +## Overview + +Parsing has two phases: + +1. In the first phase, lines of input are consumed and the block +structure of the document---its division into paragraphs, block quotes, +list items, and so on---is constructed. Text is assigned to these +blocks but not parsed. Link reference definitions are parsed and a +map of links is constructed. + +2. In the second phase, the raw text contents of paragraphs and headings +are parsed into sequences of Markdown inline elements (strings, +code spans, links, emphasis, and so on), using the map of link +references constructed in phase 1. + +At each point in processing, the document is represented as a tree of +**blocks**. The root of the tree is a `document` block. The `document` +may have any number of other blocks as **children**. These children +may, in turn, have other blocks as children. The last child of a block +is normally considered **open**, meaning that subsequent lines of input +can alter its contents. (Blocks that are not open are **closed**.) +Here, for example, is a possible document tree, with the open blocks +marked by arrows: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + list_item + paragraph + "Qui *quodsi iracundia*" + -> list_item + -> paragraph + "aliquando id" +``` + +## Phase 1: block structure + +Each line that is processed has an effect on this tree. The line is +analyzed and, depending on its contents, the document may be altered +in one or more of the following ways: + +1. One or more open blocks may be closed. +2. One or more new blocks may be created as children of the + last open block. +3. Text may be added to the last (deepest) open block remaining + on the tree. + +Once a line has been incorporated into the tree in this way, +it can be discarded, so input can be read in a stream. + +For each line, we follow this procedure: + +1. First we iterate through the open blocks, starting with the +root document, and descending through last children down to the last +open block. Each block imposes a condition that the line must satisfy +if the block is to remain open. For example, a block quote requires a +`>` character. A paragraph requires a non-blank line. +In this phase we may match all or just some of the open +blocks. But we cannot close unmatched blocks yet, because we may have a +[lazy continuation line]. + +2. Next, after consuming the continuation markers for existing +blocks, we look for new block starts (e.g. `>` for a block quote. +If we encounter a new block start, we close any blocks unmatched +in step 1 before creating the new block as a child of the last +matched block. + +3. Finally, we look at the remainder of the line (after block +markers like `>`, list markers, and indentation have been consumed). +This is text that can be incorporated into the last open +block (a paragraph, code block, heading, or raw HTML). + +Setext headings are formed when we see a line of a paragraph +that is a [setext heading underline]. + +Reference link definitions are detected when a paragraph is closed; +the accumulated text lines are parsed to see if they begin with +one or more reference link definitions. Any remainder becomes a +normal paragraph. + +We can see how this works by considering how the tree above is +generated by four lines of Markdown: + +``` markdown +> Lorem ipsum dolor +sit amet. +> - Qui *quodsi iracundia* +> - aliquando id +``` + +At the outset, our document model is just + +``` tree +-> document +``` + +The first line of our text, + +``` markdown +> Lorem ipsum dolor +``` + +causes a `block_quote` block to be created as a child of our +open `document` block, and a `paragraph` block as a child of +the `block_quote`. Then the text is added to the last open +block, the `paragraph`: + +``` tree +-> document + -> block_quote + -> paragraph + "Lorem ipsum dolor" +``` + +The next line, + +``` markdown +sit amet. +``` + +is a "lazy continuation" of the open `paragraph`, so it gets added +to the paragraph's text: + +``` tree +-> document + -> block_quote + -> paragraph + "Lorem ipsum dolor\nsit amet." +``` + +The third line, + +``` markdown +> - Qui *quodsi iracundia* +``` + +causes the `paragraph` block to be closed, and a new `list` block +opened as a child of the `block_quote`. A `list_item` is also +added as a child of the `list`, and a `paragraph` as a child of +the `list_item`. The text is then added to the new `paragraph`: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + -> list_item + -> paragraph + "Qui *quodsi iracundia*" +``` + +The fourth line, + +``` markdown +> - aliquando id +``` + +causes the `list_item` (and its child the `paragraph`) to be closed, +and a new `list_item` opened up as child of the `list`. A `paragraph` +is added as a child of the new `list_item`, to contain the text. +We thus obtain the final tree: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + list_item + paragraph + "Qui *quodsi iracundia*" + -> list_item + -> paragraph + "aliquando id" +``` + +## Phase 2: inline structure + +Once all of the input has been parsed, all open blocks are closed. + +We then "walk the tree," visiting every node, and parse raw +string contents of paragraphs and headings as inlines. At this +point we have seen all the link reference definitions, so we can +resolve reference links as we go. + +``` tree +document + block_quote + paragraph + str "Lorem ipsum dolor" + softbreak + str "sit amet." + list (type=bullet tight=true bullet_char=-) + list_item + paragraph + str "Qui " + emph + str "quodsi iracundia" + list_item + paragraph + str "aliquando id" +``` + +Notice how the [line ending] in the first paragraph has +been parsed as a `softbreak`, and the asterisks in the first list item +have become an `emph`. + +### An algorithm for parsing nested emphasis and links + +By far the trickiest part of inline parsing is handling emphasis, +strong emphasis, links, and images. This is done using the following +algorithm. + +When we're parsing inlines and we hit either + +- a run of `*` or `_` characters, or +- a `[` or `![` + +we insert a text node with these symbols as its literal content, and we +add a pointer to this text node to the [delimiter stack](@). + +The [delimiter stack] is a doubly linked list. Each +element contains a pointer to a text node, plus information about + +- the type of delimiter (`[`, `![`, `*`, `_`) +- the number of delimiters, +- whether the delimiter is "active" (all are active to start), and +- whether the delimiter is a potential opener, a potential closer, + or both (which depends on what sort of characters precede + and follow the delimiters). + +When we hit a `]` character, we call the *look for link or image* +procedure (see below). + +When we hit the end of the input, we call the *process emphasis* +procedure (see below), with `stack_bottom` = NULL. + +#### *look for link or image* + +Starting at the top of the delimiter stack, we look backwards +through the stack for an opening `[` or `![` delimiter. + +- If we don't find one, we return a literal text node `]`. + +- If we do find one, but it's not *active*, we remove the inactive + delimiter from the stack, and return a literal text node `]`. + +- If we find one and it's active, then we parse ahead to see if + we have an inline link/image, reference link/image, compact reference + link/image, or shortcut reference link/image. + + + If we don't, then we remove the opening delimiter from the + delimiter stack and return a literal text node `]`. + + + If we do, then + + * We return a link or image node whose children are the inlines + after the text node pointed to by the opening delimiter. + + * We run *process emphasis* on these inlines, with the `[` opener + as `stack_bottom`. + + * We remove the opening delimiter. + + * If we have a link (and not an image), we also set all + `[` delimiters before the opening delimiter to *inactive*. (This + will prevent us from getting links within links.) + +#### *process emphasis* + +Parameter `stack_bottom` sets a lower bound to how far we +descend in the [delimiter stack]. If it is NULL, we can +go all the way to the bottom. Otherwise, we stop before +visiting `stack_bottom`. + +Let `current_position` point to the element on the [delimiter stack] +just above `stack_bottom` (or the first element if `stack_bottom` +is NULL). + +We keep track of the `openers_bottom` for each delimiter +type (`*`, `_`). Initialize this to `stack_bottom`. + +Then we repeat the following until we run out of potential +closers: + +- Move `current_position` forward in the delimiter stack (if needed) + until we find the first potential closer with delimiter `*` or `_`. + (This will be the potential closer closest + to the beginning of the input -- the first one in parse order.) + +- Now, look back in the stack (staying above `stack_bottom` and + the `openers_bottom` for this delimiter type) for the + first matching potential opener ("matching" means same delimiter). + +- If one is found: + + + Figure out whether we have emphasis or strong emphasis: + if both closer and opener spans have length >= 2, we have + strong, otherwise regular. + + + Insert an emph or strong emph node accordingly, after + the text node corresponding to the opener. + + + Remove any delimiters between the opener and closer from + the delimiter stack. + + + Remove 1 (for regular emph) or 2 (for strong emph) delimiters + from the opening and closing text nodes. If they become empty + as a result, remove them and remove the corresponding element + of the delimiter stack. If the closing node is removed, reset + `current_position` to the next element in the stack. + +- If none in found: + + + Set `openers_bottom` to the element before `current_position`. + (We know that there are no openers for this kind of closer up to and + including this point, so this puts a lower bound on future searches.) + + + If the closer at `current_position` is not a potential opener, + remove it from the delimiter stack (since we know it can't + be a closer either). + + + Advance `current_position` to the next element in the stack. + +After we're done, we remove all delimiters above `stack_bottom` from the +delimiter stack. + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/performance/SumOfInverses.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/performance/SumOfInverses.scl new file mode 100644 index 000000000..a3f940760 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/performance/SumOfInverses.scl @@ -0,0 +1,8 @@ +import "Prelude" + +main :: Double -> Double +main m = loop 1 0 + where + loop x cur = if x > m + then cur + else loop (x+1) (cur + 1 / x) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/performance/SumOfInverses2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/performance/SumOfInverses2.scl new file mode 100644 index 000000000..7745029bf --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/performance/SumOfInverses2.scl @@ -0,0 +1,4 @@ +import "Prelude" + +main :: Integer -> Double +main m = sum [1/(fromInteger x) | x <- [1..m]] diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/AmbiguousType.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/AmbiguousType.scl new file mode 100644 index 000000000..f4871d7d5 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/AmbiguousType.scl @@ -0,0 +1,12 @@ + + +class Show a where + show :: a -> String + +class Read a where + read :: String -> a + +combine x = show (read x) +-- +9:13-9:17: Constrain Show a contains free variables not mentioned in the type of the value. +9:19-9:23: Constrain Read a contains free variables not mentioned in the type of the value. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ApplicationOfNunfunction.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ApplicationOfNunfunction.scl new file mode 100644 index 000000000..13167bee6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ApplicationOfNunfunction.scl @@ -0,0 +1,3 @@ +main = "Hello" "world!" +-- +1:8-1:24: Application of non-function. diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Arity1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Arity1.scl new file mode 100644 index 000000000..fa48e47c1 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Arity1.scl @@ -0,0 +1,9 @@ + +data Foo a = Foo a + +f :: Foo a -> a +f = \Foo a -> a + +main = "Not to be executed" +-- +5:6-5:11: Arity is 1 but 2 patterns have been given. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/AsPattern.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/AsPattern.scl new file mode 100644 index 000000000..0e3337099 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/AsPattern.scl @@ -0,0 +1,8 @@ +import "JavaBuiltin" as Java + +sort p@(a,b) | Java.icmpgt a b = (b,a) + | True = p + +main = sort (sort (2 :: Integer,1 :: Integer)) +-- +(1,2) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigContext.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigContext.scl new file mode 100644 index 000000000..fc70cc23c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigContext.scl @@ -0,0 +1,28 @@ +import "Prelude" + +main = do + a1 = 1 + a2 = 1 + a3 = 1 + a4 = 1 + a5 = 1 + a6 = 1 + a7 = 1 + a8 = 1 + a9 = 1 + a10 = 1 + a11 = 1 + a12 = 1 + a13 = 1 + a14 = 1 + a15 = 1 + a16 = 1 + a17 = 1 + a18 = 1 + a19 = 1 + a20 = 1 + f x = x + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20 + f 10 +-- +30 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigFunction.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigFunction.scl new file mode 100644 index 000000000..102bc1d7e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigFunction.scl @@ -0,0 +1,7 @@ +import "Prelude" + +f a b c d e f g h = a + b + c + d + e + f + g + h + +main = (id f) 1 2 3 4 5 6 7 8 +-- +36 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigInstances.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigInstances.scl new file mode 100644 index 000000000..c64b1b703 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BigInstances.scl @@ -0,0 +1,16 @@ + +class Foo a where + foo :: a + +class (Foo a) => Bar a where + bar :: a + +instance Bar Double where + foo x = x + bar x = x + +main = foo 3.0 + bar 4.0 +-- +7.0 + + \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BinaryOperators1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BinaryOperators1.scl new file mode 100644 index 000000000..86263c9aa --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BinaryOperators1.scl @@ -0,0 +1,25 @@ +import "Prelude" + +data E = E String + +instance Additive E where + zero = E "0" + E a + E b = E ("(" + a + "+" + b + ")") + +instance Ring E where + one = E "1" + neg (E a) = E ("(-" + a + ")") + E a - E b = E ("(" + a + "-" + b + ")") + E a * E b = E ("(" + a + "*" + b + ")") + fromInteger x = E (show x) + +eToString (E a) = a + +a = E "a" +b = E "b" +c = E "c" +d = E "d" + +main = eToString (-a + b + (-c*d)) +-- +(((-a)+b)+(-(c*d))) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BlankExpression.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BlankExpression.scl new file mode 100644 index 000000000..f31e144e8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BlankExpression.scl @@ -0,0 +1,3 @@ +main = _ +-- +??? \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BooleanId.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BooleanId.scl new file mode 100644 index 000000000..2044c1c9b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/BooleanId.scl @@ -0,0 +1,12 @@ +@private +@inline +not True = False +not False = True + +@private +@inline +id x = not (not x) + +main = id True +-- +true \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Bug4450.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Bug4450.scl new file mode 100644 index 000000000..54e65c2e9 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Bug4450.scl @@ -0,0 +1,15 @@ +import "Prelude" + +csvWrite :: String -> [[String]] -> () +csvWrite fname rows = () + +/// Like writeEntries but with a transformer function also for values. +/// kfun key + vfun value should have the length of header. +writeEntries' :: (k -> [String]) -> (v -> [String]) + -> String -> [String] -> [(k, v)] -> () +writeEntries' kfun vfun fname header rows = + csvWrite fname $ [header] + [kfun k + vfun v | (k, v) <- rows] + +main = "OK" +-- +OK \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Character1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Character1.scl new file mode 100644 index 000000000..b08d2aef3 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Character1.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = subChar '6' '0' +-- +6 diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingClass.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingClass.scl new file mode 100644 index 000000000..dee1e8d43 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingClass.scl @@ -0,0 +1,8 @@ + +class A a where + foo :: a + +class A a where + bar :: a +-- +5:1-6:13: Class A has already been defined in this module. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingData.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingData.scl new file mode 100644 index 000000000..60245db07 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingData.scl @@ -0,0 +1,5 @@ + +data A = A +data A = B +-- +3:1-3:11: Type A has already been defined in this module. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingInstance.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingInstance.scl new file mode 100644 index 000000000..72178db3a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingInstance.scl @@ -0,0 +1,14 @@ +import "JavaBuiltin" as Java + +infixl 6 (+) + +class Additive a where + (+) :: a -> a -> a + +instance Additive Double where + (+) = Java.dadd + +instance Additive Double where + (+) = Java.dadd +-- +11:1-12:20: Duplicate definition of the instance Additive Double. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingValueDefinition.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingValueDefinition.scl new file mode 100644 index 000000000..f7ec72a43 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingValueDefinition.scl @@ -0,0 +1,5 @@ +a = 1 +a = 2 +main = "Should not be executed." +-- +??? \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingValueType.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingValueType.scl new file mode 100644 index 000000000..d248d20f2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ClashingValueType.scl @@ -0,0 +1,6 @@ + +id :: Integer -> Integer +id :: Double -> Double +id x = x +-- +3:1-3:23: Type of id has already been declared in this module. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Collaz.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Collaz.scl new file mode 100644 index 000000000..2e4552d0d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Collaz.scl @@ -0,0 +1,16 @@ +import "Prelude" + +f x = if x `mod` 2 == 0 + then x `div` 2 + else 3*x + 1 +fd x = unfoldr (\x -> do + r = f x + if x == 1 + then Nothing + else Just (x,r) + ) x + +//main :: [Integer] +main = fd 7 +-- +[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Compose.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Compose.scl new file mode 100644 index 000000000..fad8b9b67 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Compose.scl @@ -0,0 +1,20 @@ +import "JavaBuiltin" as Java + +(+) = Java.iadd +(-) = Java.isub +(*) = Java.imul + +data List a = Nil | Cons a (List a) + +compose :: List (a -> a) -> a -> a +compose Nil x = x +compose (Cons h t) x = compose t (h x) + +succ x = x + 1 +prec x = x - 1 +double x = x * 2 + +f = compose (Cons succ (Cons double (Cons prec Nil))) +main = f 13 +-- +27 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Composition.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Composition.scl new file mode 100644 index 000000000..80b1c06a4 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Composition.scl @@ -0,0 +1,17 @@ +infixr 9 (.) + +@private +@inline +(f . g) = \x -> f (g x) + +@private +@inline +flip (x,y) = (y,x) + +@private +@inline +flip4 = flip . flip . flip . flip + +main = flip4 ("a", "b") +-- +(a,b) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ConjunctionMacro.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ConjunctionMacro.scl new file mode 100644 index 000000000..99188f8bb --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ConjunctionMacro.scl @@ -0,0 +1,6 @@ +(&&) :: Boolean -> ( Boolean) -> Boolean +a && b = if a then b else False + +main = False && fail "Should not be evaluated!" +-- +false \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Constant.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Constant.scl new file mode 100644 index 000000000..7ea0367bd --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Constant.scl @@ -0,0 +1,6 @@ + +a = 14 :: Integer + +main = a +-- +14 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ConstructorNameClash.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ConstructorNameClash.scl new file mode 100644 index 000000000..52826a538 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ConstructorNameClash.scl @@ -0,0 +1,7 @@ + +data Vec2 = Vec2 Double Double +data Vec3 = Vec2 Double Double Double + +main = "Not to be executed." +-- +3:13-3:38: Value Vec2 is already defined. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DefaultMethods1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DefaultMethods1.scl new file mode 100644 index 000000000..142dd30a5 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DefaultMethods1.scl @@ -0,0 +1,13 @@ +import "JavaBuiltin" as Java + +class Ord a where + (<) :: a -> a -> Boolean + min :: a -> a -> a + min x y = if x < y then x else y + +instance Ord Integer where + (<) = Java.icmplt + +main = min (43 :: Integer) (69 :: Integer) +-- +43 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Deriving3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Deriving3.scl new file mode 100644 index 000000000..ec2f5b7bd --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Deriving3.scl @@ -0,0 +1,29 @@ +import "Prelude" + +a,b,c,d :: Either Boolean Boolean +a = Left False +b = Left True +c = Right False +d = Right True + +main = a == a + && a < b + && a < c + && a < d + + && b > a + && b == b + && b < c + && b < d + + && c > a + && c > b + && c == c + && c < d + + && d > a + && d > b + && d > c + && d == d +-- +true \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Deriving4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Deriving4.scl new file mode 100644 index 000000000..03ea0d609 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Deriving4.scl @@ -0,0 +1,9 @@ +import "Prelude" + +data Foo = Foo Integer Long Double Float + +deriving instance Show Foo + +main = show (Foo (-1) (-1) (-1) (-1)) +-- +Foo (-1) (-1) (-1.0) (-1.0) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DifferentBranchTypes.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DifferentBranchTypes.scl new file mode 100644 index 000000000..2a0925fe9 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DifferentBranchTypes.scl @@ -0,0 +1,19 @@ +import "Prelude" + +foo n = n + where + if n > 0 + then 1 + else "asd" + +bar n = n + where + do + c = n+1 + if c > 0 + then 1 + else "asd" + +main = foo 3 + bar 3 +-- +6 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Div.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Div.scl new file mode 100644 index 000000000..4a8e1ca24 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Div.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = 7 `div` 3 +-- +2 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DoubleConversion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DoubleConversion.scl new file mode 100644 index 000000000..31e95edb3 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DoubleConversion.scl @@ -0,0 +1,17 @@ +import "Prelude" + +f :: Float +f = 1.0 + +d :: Double +d = 1.0 + +d2f :: Float +d2f = fromDouble d + +f2d :: Double +f2d = toDouble f + +main = show (d+f2d, f+d2f) +-- +(2.0, 2.0) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DoubleEffect.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DoubleEffect.scl new file mode 100644 index 000000000..b0615106f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DoubleEffect.scl @@ -0,0 +1,8 @@ +app :: (Integer -> Integer) -> ((Integer -> Integer) -> Integer) +app f = do + a = f 1 + \g -> g a + +main = app (\x -> x) (\x -> x) +-- +1 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects1.scl new file mode 100644 index 000000000..11a3303d4 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects1.scl @@ -0,0 +1,18 @@ +import "JavaBuiltin" as Java + +importJava "java.util.regex.Pattern" where + data Pattern + + compile :: String -> Pattern + matcher :: Pattern -> String -> Matcher + +importJava "java.util.regex.Matcher" where + data Matcher + + matches :: Matcher -> Boolean + +doMatch pattern text = matches (matcher pattern text) + +main = doMatch (compile ".*xxx.*") "fffxxooxxxlll" +-- +true \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects2.scl new file mode 100644 index 000000000..d595ee938 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects2.scl @@ -0,0 +1,21 @@ +import "JavaBuiltin" as Java + +importJava "java.util.List" where + data List a + + add :: List a -> a -> Boolean + +importJava "java.util.ArrayList" where + @JavaName "" + arrayList :: Integer -> List a + +singleton :: a -> List a +singleton el = result + where + result = arrayList 1 + r = add result el + +main :: List Integer +main = runProc (singleton (13 :: Integer)) +-- +[13] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects3.scl new file mode 100644 index 000000000..718482938 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects3.scl @@ -0,0 +1,12 @@ +effectfulId :: a -> a +effectfulId x = x + +(.) :: (b -> c) -> (a -> b) -> a -> c +(f . g) x = f (g x) + +doubleId = effectfulId . effectfulId + +main :: Integer +main = runProc (doubleId (13 :: Integer)) +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects4.scl new file mode 100644 index 000000000..85138a68a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects4.scl @@ -0,0 +1,12 @@ +effectfulId :: a -> a +effectfulId x = x + +//double :: (a -> a) -> a -> a +double f x = f (f x) + +doubleId = double effectfulId + +main :: Integer +main = runProc (doubleId (13 :: Integer)) +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects5.scl new file mode 100644 index 000000000..595b6346b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects5.scl @@ -0,0 +1,13 @@ +effectfulId :: a -> a +effectfulId x = x + +(.) :: (b -> c) -> (a -> b) -> a -> c +(f . g) x = f (g x) + +//doubleId :: a -> a +doubleId = effectfulId . effectfulId + +main :: Integer +main = runProc (doubleId (13 :: Integer)) +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects6.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects6.scl new file mode 100644 index 000000000..e99dd4fcb --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Effects6.scl @@ -0,0 +1,13 @@ +effectfulId :: a -> a +effectfulId x = x + +(.) :: (b -> c) -> (a -> b) -> a -> c +(f . g) x = f (g x) + +doubleId :: a -> a +doubleId = effectfulId . effectfulId + +main :: Integer +main = runProc (doubleId (13 :: Integer)) +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/EmptyLet.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/EmptyLet.scl new file mode 100644 index 000000000..68c662378 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/EmptyLet.scl @@ -0,0 +1,9 @@ +import "Prelude" + +ex1 = let in 1 +ex2 = let {} in 2 +ex3 = let {a=3} in a + +main = ex1 + ex2 + ex3 +-- +6 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Equality.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Equality.scl new file mode 100644 index 000000000..acf00e936 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Equality.scl @@ -0,0 +1,41 @@ +import "Prelude" + +main = """ +\(newEq () ()) +\(newEq True True) +\(newEq False False) +\(newEq True False) +\(newEq False True) +\(newEq (1::Integer) (1::Integer)) +\(newEq (1::Integer) (2::Integer)) +\(newEq (1::Long) (1::Long)) +\(newEq (1::Long) (2::Long)) +\(newEq (1::Double) (1::Double)) +\(newEq (1::Double) (2::Double)) +\(newEq "a" "a") +\(newEq "a" "b") +\(newEq (Just "a") (Just "a")) +\(newEq (Just "a") (Just "b")) +\(newEq Nothing Nothing) +\(newEq (Just "a") Nothing) +\(newEq Nothing (Just "a")) +""" +-- +True +True +True +False +False +True +False +True +False +True +False +True +False +True +False +True +False +False \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Equations1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Equations1.scl new file mode 100644 index 000000000..613d56bff --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Equations1.scl @@ -0,0 +1,13 @@ +import "Prelude" +import "Expressions/Equations" + +main = v + where + v = solveEquations do + listenEquationVariable "a" $ \a -> setEquationVariable "c" (a-1) + setEquationVariable "a" 123 + listenEquationVariable "a" $ \a -> setEquationVariable "b" (a+1) + print v +-- +[(a,123), (b,124), (c,122)] + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExistentialData.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExistentialData.scl new file mode 100644 index 000000000..62130b49f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExistentialData.scl @@ -0,0 +1,23 @@ +import "JavaBuiltin" as Java + +(+) = Java.iadd + +data Thunk a = /* forall s. */ Thunk s (s -> a) + +id :: a -> a +id x = x + +runThunk :: Thunk a -> a +runThunk (Thunk s f) = f s + +makeThunk :: a -> Thunk a +makeThunk x = Thunk x id + +mapThunk :: (a -> b) -> Thunk a -> Thunk b +mapThunk f (Thunk s g) = Thunk s (\x -> f (g x)) + +a = makeThunk (13 :: Integer) +b = mapThunk (\x -> x+1) a +main = runThunk b +-- +14 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExistentialData2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExistentialData2.scl new file mode 100644 index 000000000..b0299691e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExistentialData2.scl @@ -0,0 +1,7 @@ +data Thunk a = /* forall s. */ Thunk s (s -> a) + +mixThunks (Thunk s0 f0) (Thunk s1 f1) = f0 s1 + +main = "Not to be executed!" +-- +3:44-3:46: Expected
got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExpressionParsing.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExpressionParsing.scl new file mode 100644 index 000000000..6719bf935 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ExpressionParsing.scl @@ -0,0 +1,27 @@ +import "Prelude" + +data Exp = Exp String + +expToString :: Exp -> String +expToString (Exp s) = s + +instance Additive Exp where + zero = Exp "0" + Exp a + Exp b = Exp ("(" + a + " + " + b + ")") + +instance Ring Exp where + one = Exp "1" + neg (Exp a) = Exp ("(-" + a + ")") + Exp a * Exp b = Exp ("(" + a + " * " + b + ")") + Exp a - Exp b = Exp ("(" + a + " - " + b + ")") + fromInteger x = Exp (show x) + +a = Exp "a" +b = Exp "b" +c = Exp "c" +d = Exp "d" +e = Exp "e" + +main = expToString (a + b*c + d*e) +-- +((a + (b * c)) + (d * e)) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FaultyRecursion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FaultyRecursion.scl new file mode 100644 index 000000000..523b40877 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FaultyRecursion.scl @@ -0,0 +1,3 @@ +fib n = fib +-- +1:9-1:12: Expected got a>. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci.scl new file mode 100644 index 000000000..b7b56f50c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci.scl @@ -0,0 +1,14 @@ +import "JavaBuiltin" as Java + +(+) = Java.iadd +(-) = Java.isub +(<=) = Java.icmple + +fibonacci x = if x <= (1 :: Integer) + then 1 :: Integer + else fibonacci (x - 1) + + fibonacci (x - 2) + +main = fibonacci 10 +-- +89 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci2.scl new file mode 100644 index 000000000..229145fbc --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci2.scl @@ -0,0 +1,11 @@ +import "Prelude" + +fibonacci :: Integer -> Integer +fibonacci x = if x <= 1 + then 1 + else fibonacci (x - 1) + + fibonacci (x - 2) + +main = fibonacci 10 +-- +89 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci3.scl new file mode 100644 index 000000000..d5ce91c60 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Fibonacci3.scl @@ -0,0 +1,20 @@ +import "JavaBuiltin" as Java + +class Num a where + (+) :: a -> a -> a + (-) :: a -> a -> a + +instance Num Integer where + (+) = Java.iadd + (-) = Java.isub + +(<=) = Java.icmple + +fibonacci x = if x <= (1 :: Integer) + then 1 :: Integer + else fibonacci (x - (1 :: Integer)) + + fibonacci (x - (2 :: Integer)) + +main = fibonacci 10 +-- +89 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FingerTree.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FingerTree.scl new file mode 100644 index 000000000..b81f642f6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FingerTree.scl @@ -0,0 +1,173 @@ +import "JavaBuiltin" as Java + +main = foldl Java.iadd (0 :: Integer) (concat (concat (Single (1 :: Integer)) + (Single (2 :: Integer))) (Single (3 :: Integer))) + +data Digit a = Digit1 a + | Digit2 a a + | Digit3 a a a + | Digit4 a a a a +data Node a = Node2 a a | Node3 a a a +data FingerTree a = Empty | Single a | Deep (Digit a) (FingerTree (Node a)) (Digit a) + +insertL :: a -> FingerTree a -> FingerTree a +insertL a Empty = Single a +insertL a (Single b) = Deep (Digit1 a) Empty (Digit1 b) +insertL a (Deep (Digit1 b) m r) = Deep (Digit2 a b) m r +insertL a (Deep (Digit2 b c) m r) = Deep (Digit3 a b c) m r +insertL a (Deep (Digit3 b c d) m r) = Deep (Digit4 a b c d) m r +insertL a (Deep (Digit4 b c d e) m r) = Deep (Digit2 a b) (insertL (Node3 c d e) m) r + +insertR :: FingerTree a -> a -> FingerTree a +insertR Empty a = Single a +insertR (Single a) b = Deep (Digit1 a) Empty (Digit1 b) +insertR (Deep l m (Digit1 a)) b = Deep l m (Digit2 a b) +insertR (Deep l m (Digit2 a b)) c = Deep l m (Digit3 a b c) +insertR (Deep l m (Digit3 a b c)) d = Deep l m (Digit4 a b c d) +insertR (Deep l m (Digit4 a b c d)) e = Deep l (insertR m (Node3 a b c)) (Digit2 d e) + +foldl :: (a -> b -> a) -> a -> FingerTree b -> a +foldl f init Empty = init +foldl f init (Single x) = f init x +foldl f init (Deep l m r) = foldlD (foldl foldlN (foldlD init l) m) r + where + foldlD init (Digit1 a) = f init a + foldlD init (Digit2 a b) = f (f init a) b + foldlD init (Digit3 a b c) = f (f (f init a) b) c + foldlD init (Digit4 a b c d) = f (f (f (f init a) b) c) d + + foldlN init (Node2 a b) = f (f init a) b + foldlN init (Node3 a b c) = f (f (f init a) b) c + +data View a = Nil | Cons a (FingerTree a) + +viewL :: FingerTree a -> View a +viewL Empty = Nil +viewL (Single a) = Cons a Empty +viewL (Deep (Digit1 a) m r) = Cons a tail + where + tail = match viewL m with + Nil -> digitToFingerTree r + Cons h t -> Deep (nodeToDigit h) t r +viewL (Deep (Digit2 a b) m r) = Cons a (Deep (Digit1 a) m r) +viewL (Deep (Digit3 a b c) m r) = Cons a (Deep (Digit2 a b) m r) +viewL (Deep (Digit4 a b c d) m r) = Cons a (Deep (Digit3 a b c) m r) + +concat :: FingerTree a -> FingerTree a -> FingerTree a +concat Empty a = a +concat a Empty = a +concat (Single a) b = insertL a b +concat a (Single b) = insertR a b +concat (Deep l1 m1 r1) (Deep l2 m2 r2) = Deep l1 mm r2 + where + mm = concatAux m1 (digitsToNodes r1 l2) m2 + +// --- Implementation details ------------------------------------------------- + +digitToFingerTree :: Digit a -> FingerTree a +digitToFingerTree (Digit1 a) = Single a +digitToFingerTree (Digit2 a b) = Deep (Digit1 a) Empty (Digit1 b) +digitToFingerTree (Digit3 a b c) = Deep (Digit2 a b) Empty (Digit1 c) +digitToFingerTree (Digit4 a b c d) = Deep (Digit2 a b) Empty (Digit2 c d) + +nodeToDigit :: Node a -> Digit a +nodeToDigit (Node2 a b) = Digit2 a b +nodeToDigit (Node3 a b c) = Digit3 a b c + +concatAux :: FingerTree a -> Digit a -> FingerTree a -> FingerTree a +concatAux Empty ds a = insertLD ds a +concatAux a ds Empty = insertRD a ds +concatAux (Single a) ds b = insertL a (insertLD ds b) +concatAux a ds (Single b) = insertR (insertRD a ds) b +concatAux (Deep l1 m1 r1) ds (Deep l2 m2 r2) = Deep l1 mm r2 + where + mm = concatAux m1 (digitsToNodes3 r1 ds r2) m2 + +insertLD :: Digit a -> FingerTree a -> FingerTree a +insertLD (Digit1 a) t = insertL a t +insertLD (Digit2 a b) t = insertL a (insertL b t) +insertLD (Digit3 a b c) t = insertL a (insertL b (insertL c t)) +insertLD (Digit4 a b c d) t = insertL a (insertL b (insertL c (insertL d t))) + +insertRD :: FingerTree a -> Digit a -> FingerTree a +insertRD t (Digit1 a) = insertR t a +insertRD t (Digit2 a b) = insertR (insertR t a) b +insertRD t (Digit3 a b c) = insertR (insertR (insertR t a) b) c +insertRD t (Digit4 a b c d) = insertR (insertR (insertR (insertR t a) b) c) d + +digitsToNodes :: Digit a -> Digit a -> Digit (Node a) +digitsToNodes (Digit1 a) x = dd1 a x +digitsToNodes (Digit2 a b) x = dd2 a b x +digitsToNodes (Digit3 a b c) x = dd3 a b c x +digitsToNodes (Digit4 a b c d) x = dd4 a b c d x + +digitsToNodes3 :: Digit a -> Digit a -> Digit a -> Digit (Node a) +digitsToNodes3 (Digit1 a) x y = ddd1 a x y +digitsToNodes3 (Digit2 a b) x y = ddd2 a b x y +digitsToNodes3 (Digit3 a b c) x y = ddd3 a b c x y +digitsToNodes3 (Digit4 a b c d) x y = ddd4 a b c d x y + +d2 a b = Digit1 (Node2 a b) +d3 a b c = Digit1 (Node3 a b c) +d4 a b c d = Digit2 (Node2 a b) (Node2 c d) +d5 a b c d e = Digit2 (Node3 a b c) (Node2 d e) +d6 a b c d e f = Digit2 (Node3 a b c) (Node3 d e f) +d7 a b c d e f g = Digit3 (Node3 a b c) (Node2 d e) (Node2 f g) +d8 a b c d e f g h = Digit3 (Node3 a b c) (Node3 d e f) (Node2 g h) +d9 a b c d e f g h i = Digit3 (Node3 a b c) (Node3 d e f) (Node3 g h i) +d10 a b c d e f g h i j = Digit4 (Node3 a b c) (Node3 d e f) (Node2 g h) (Node2 i j) +d11 a b c d e f g h i j k = Digit4 (Node3 a b c) (Node3 d e f) (Node3 g h i) (Node2 j k) +d12 a b c d e f g h i j k l = Digit4 (Node3 a b c) (Node3 d e f) (Node3 g h i) (Node3 j k l) + +dd1 a (Digit1 b) = d2 a b +dd1 a (Digit2 b c) = d3 a b c +dd1 a (Digit3 b c d) = d4 a b c d +dd1 a (Digit4 b c d e) = d5 a b c d e +dd2 a b (Digit1 c) = d3 a b c +dd2 a b (Digit2 c d) = d4 a b c d +dd2 a b (Digit3 c d e) = d5 a b c d e +dd2 a b (Digit4 c d e f) = d6 a b c d e f +dd3 a b c (Digit1 d) = d4 a b c d +dd3 a b c (Digit2 d e) = d5 a b c d e +dd3 a b c (Digit3 d e f) = d6 a b c d e f +dd3 a b c (Digit4 d e f g) = d7 a b c d e f g +dd4 a b c d (Digit1 e) = d5 a b c d e +dd4 a b c d (Digit2 e f) = d6 a b c d e f +dd4 a b c d (Digit3 e f g) = d7 a b c d e f g +dd4 a b c d (Digit4 e f g h) = d8 a b c d e f g h +dd5 a b c d e (Digit1 f) = d6 a b c d e f +dd5 a b c d e (Digit2 f g) = d7 a b c d e f g +dd5 a b c d e (Digit3 f g h) = d8 a b c d e f g h +dd5 a b c d e (Digit4 f g h i) = d9 a b c d e f g h i +dd6 a b c d e f (Digit1 g) = d7 a b c d e f g +dd6 a b c d e f (Digit2 g h) = d8 a b c d e f g h +dd6 a b c d e f (Digit3 g h i) = d9 a b c d e f g h i +dd6 a b c d e f (Digit4 g h i j) = d10 a b c d e f g h i j +dd7 a b c d e f g (Digit1 h) = d8 a b c d e f g h +dd7 a b c d e f g (Digit2 h i) = d9 a b c d e f g h i +dd7 a b c d e f g (Digit3 h i j) = d10 a b c d e f g h i j +dd7 a b c d e f g (Digit4 h i j k) = d11 a b c d e f g h i j k +dd8 a b c d e f g h (Digit1 i) = d9 a b c d e f g h i +dd8 a b c d e f g h (Digit2 i j) = d10 a b c d e f g h i j +dd8 a b c d e f g h (Digit3 i j k) = d11 a b c d e f g h i j k +dd8 a b c d e f g h (Digit4 i j k l) = d12 a b c d e f g h i j k l + +ddd1 a (Digit1 b) y = dd2 a b y +ddd1 a (Digit2 b c) y = dd3 a b c y +ddd1 a (Digit3 b c d) y = dd4 a b c d y +ddd1 a (Digit4 b c d e) y = dd5 a b c d e y +ddd2 a b (Digit1 c) y = dd3 a b c y +ddd2 a b (Digit2 c d) y = dd4 a b c d y +ddd2 a b (Digit3 c d e) y = dd5 a b c d e y +ddd2 a b (Digit4 c d e f) y = dd6 a b c d e f y +ddd3 a b c (Digit1 d) y = dd4 a b c d y +ddd3 a b c (Digit2 d e) y = dd5 a b c d e y +ddd3 a b c (Digit3 d e f) y = dd6 a b c d e f y +ddd3 a b c (Digit4 d e f g) y = dd7 a b c d e f g y +ddd4 a b c d (Digit1 e) y = dd5 a b c d e y +ddd4 a b c d (Digit2 e f) y = dd6 a b c d e f y +ddd4 a b c d (Digit3 e f g) y = dd7 a b c d e f g y +ddd4 a b c d (Digit4 e f g h) y = dd8 a b c d e f g h y + +-- +6 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldMissingInitialValue.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldMissingInitialValue.scl new file mode 100644 index 000000000..affa2e66f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldMissingInitialValue.scl @@ -0,0 +1,6 @@ +import "Prelude" + +f p l = (foldl (+) (map ((+)p) l)) + p +-- +3:1-3:39: Couldn't simplify all effect subsumptions away. The current compiler cannot handle this situation. Try adding more type annotations. +3:25-3:31: Type [a b] -> a b is not a subtype of a. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldlBuild1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldlBuild1.scl new file mode 100644 index 000000000..21dfdea64 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldlBuild1.scl @@ -0,0 +1,18 @@ +import "Prelude" + +inc :: Ref Integer -> Integer +inc r = do + v = getRef r + newV = v+1 + r := newV + newV + +main = do + r = ref 0 + // Because both map and for get side-effectful functions + // as parameters, the fusion is not allowed. + l = map (\_ -> inc r) [1..4] + for l (\i -> r := i+1) + getRef r +-- +5 diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldlBuild2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldlBuild2.scl new file mode 100644 index 000000000..2078fb7c2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FoldlBuild2.scl @@ -0,0 +1,16 @@ +import "Prelude" + +inc :: Ref Integer -> Integer +inc r = do + v = getRef r + newV = v+1 + r := newV + newV + +main = do + r = ref 0 + l = map (\_ -> inc r) [1..4] + r := 4 // Map must be executed before this statement + foldl (+) 0 l +-- +10 diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall1.scl new file mode 100644 index 000000000..32e51a716 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall1.scl @@ -0,0 +1,8 @@ + +id :: forall a. a -> a + // ^ not usually needed, but we test just that this is possible +id x = x + +main = id (3 :: Integer) +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall2.scl new file mode 100644 index 000000000..97d1c3510 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall2.scl @@ -0,0 +1,9 @@ + +data List a = Nil | Cons a (List a) + +build :: (forall l. l -> (a -> l -> l) -> l) -> List a +build f = f Nil Cons + +main = build (\nil cons -> cons (1 :: Integer) (cons (2 :: Integer) nil)) +-- +(Cons 1 (Cons 2 Nil)) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall3.scl new file mode 100644 index 000000000..018a2a0be --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Forall3.scl @@ -0,0 +1,11 @@ + +data List a = Nil | Cons a (List a) + +build :: (forall l. l -> (a -> l -> l) -> l) -> List a +build f = f Nil Cons + +main = build (\nil cons -> cons (1 :: Integer) (Cons (2 :: Integer) nil)) + // ^^^^ +-- +7:48-7:73: Expected got . +7:69-7:72: Expected got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Formula.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Formula.scl new file mode 100644 index 000000000..10eafb061 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Formula.scl @@ -0,0 +1,131 @@ +import "Prelude" + +data Formula a = TrueF + | FalseF + | XorF (Formula a) (Formula a) + | AndF (Formula a) (Formula a) + | ConditionF a + | NextF (Formula a) + | UntilF (Formula a) (Formula a) + +deriving instance (Ord a) => Ord (Formula a) + +instance (Show a) => Show (Formula a) where + sb <+ TrueF = sb << "true" + sb <+ FalseF = sb << "false" + sb <+ XorF a b = sb << "(" <+ a << " `XorF` " <+ b << ")" + sb <+ AndF a b = sb << "(" <+ a << " &&& " <+ b << ")" + sb <+ ConditionF c = sb <+ c + sb <+ NextF a = sb << "(next " <+ a << ")" + sb <+ UntilF a b = sb << "(" <+ a << " `UntilF` " <+ b << ")" + +xorF FalseF f2 = f2 +xorF f1 FalseF = f1 +xorF f1@(XorF h1 t1) f2@(XorF h2 t2) = + let cmp = compare h1 h2 + in if cmp < 0 + then XorF h1 (xorF t1 f2) + else if cmp > 0 + then XorF h2 (xorF f1 t2) + else xorF t1 t2 +xorF f1@(XorF h1 t1) f2 = + let cmp = compare h1 f2 + in if cmp < 0 + then XorF h1 (xorF t1 f2) + else if cmp > 0 + then XorF f2 f1 + else t1 +xorF f1 f2@(XorF h2 t2) = + let cmp = compare f1 h2 + in if cmp < 0 + then XorF f1 f2 + else if cmp > 0 + then XorF h2 (xorF f1 t2) + else t2 +xorF f1 f2 = + let cmp = compare f1 f2 + in if cmp < 0 + then XorF f1 f2 + else if cmp > 0 + then XorF f2 f1 + else TrueF + +notF f = xorF TrueF f + +TrueF &&& f2 = f2 +f1 &&& TrueF = f1 +FalseF &&& _ = FalseF +_ &&& FalseF = FalseF +XorF h1 t1 &&& f2 = xorF (h1 &&& f2) (t1 &&& f2) +f1 &&& XorF h2 t2 = xorF (f1 &&& h2) (f1 &&& t2) +f1@(AndF h1 t1) &&& f2@(AndF h2 t2) = + let cmp = compare h1 h2 + in if cmp < 0 + then AndF h1 (t1 &&& f2) + else if cmp > 0 + then AndF h2 (f1 &&& t2) + else AndF h1 (t1 &&& t2) +f1@(AndF h1 t1) &&& f2 = + let cmp = compare h1 f2 + in if cmp < 0 + then AndF h1 (t1 &&& f2) + else if cmp > 0 + then AndF f2 f1 + else f1 +f1 &&& f2@(AndF h2 t2) = + let cmp = compare f1 h2 + in if cmp < 0 + then AndF f1 f2 + else if cmp > 0 + then AndF h2 (f1 &&& t2) + else f2 +f1 &&& f2 = + let cmp = compare f1 f2 + in if cmp < 0 + then AndF f1 f2 + else if cmp > 0 + then AndF f2 f1 + else f1 + +f1 ||| f2 = xorF (xorF f1 f2) (f1 &&& f2) + +eval :: Ord a => (a -> Boolean) -> Formula a -> Formula a +eval s TrueF = TrueF +eval s FalseF = FalseF +eval s (XorF f1 f2) = xorF (eval s f1) (eval s f2) +eval s (AndF f1 f2) = eval s f1 &&& eval s f2 +eval s (ConditionF c) = if s c then TrueF else FalseF +eval s (NextF f) = f +eval s (UntilF f1 f2) = eval s f2 ||| (eval s f1 &&& UntilF f1 f2) + +// Concrete conditions + +data V = V String (Ref Boolean) + +instance Ord V where + compare (V a _) (V b _) = compare a b +instance Show V where + sb <+ V a _ = sb <+ a + +cond :: String -> Ref Boolean -> Formula V +cond name ref = ConditionF (V name ref) + +// Testing + +x = ref True +y = ref False + +f = cond "x" x `UntilF` cond "y" y + +evalV = eval (\(V _ c) -> getRef c) + +main = do + print (evalV f) + x := False + print (evalV f) + y = ref True + print (evalV f) + x := True + print (evalV f) +-- +() \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic.scl new file mode 100644 index 000000000..1ac2e7704 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = (fromDynamic (toDynamic 42) :: String) + "foo" +-- +42foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic2.scl new file mode 100644 index 000000000..1b6c1d99d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic2.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = (fromDynamic (toDynamic "42") :: Integer) - 2 +-- +40 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic3.scl new file mode 100644 index 000000000..a3318d4de --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic3.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = arrayToList (fromDynamic (toDynamic ["42"]) :: (Array Integer)) +-- +[42] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic4.scl new file mode 100644 index 000000000..fb4c32088 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic4.scl @@ -0,0 +1,6 @@ +import "Prelude" +import "Vector" + +main = (fromDynamic (toDynamic ["42"]) :: (Vector Double))!0 +-- +42.0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic5.scl new file mode 100644 index 000000000..d0d0fd3a2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FromDynamic5.scl @@ -0,0 +1,6 @@ +import "Prelude" +import "Vector" + +main = (fromDynamic (toDynamic (mvector [42.0]))) :: [Integer] +-- +[42] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionFunctor.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionFunctor.scl new file mode 100644 index 000000000..f63481032 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionFunctor.scl @@ -0,0 +1,9 @@ +import "Prelude" + +// vvvvvv mistake, parantheses missing +instance Functor (->) a where + map f g x = f (g x) + +main = "Not to be executed." +-- +4:1-5:24: Wrong number of parameters to type class Functor. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionalDependencies1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionalDependencies1.scl new file mode 100644 index 000000000..203de1dba --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionalDependencies1.scl @@ -0,0 +1,11 @@ +import "Prelude" + +class Container c a b | c -> a, c -> b where + get :: c -> a -> b + +instance Container [a] Integer a where + get = (!) + +main = get [1,2,3,4,5] 3 +-- +4 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionalDependencies2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionalDependencies2.scl new file mode 100644 index 000000000..707bb9e2e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionalDependencies2.scl @@ -0,0 +1,12 @@ +import "Prelude" + +class Mul a b c | a b -> c where + mul :: a -> b -> c + +instance Mul Integer Integer Integer where + mul = (*) + +main :: Integer +main = mul (mul (1 :: Integer) (2 :: Integer)) (3 :: Integer) +-- +6 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Functor.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Functor.scl new file mode 100644 index 000000000..6bbd35979 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Functor.scl @@ -0,0 +1,23 @@ +import "JavaBuiltin" as Java + +class Functor f where + map :: (a -> b) -> f a -> f b + +data Foo a = Foo a + +instance Functor Foo where + map f (Foo x) = Foo (f x) + +instance Functor Maybe where + map f Nothing = Nothing + map f (Just x) = Just (f x) + +data List a = Nil | Cons a (List a) + +instance Functor List where + map f Nil = Nil + map f (Cons h t) = Cons (f h) (map f t) + +main = map (map (Java.iadd 1)) (Cons Nothing (Cons (Just (1 :: Integer)) Nil)) +-- +(Cons null (Cons 2 Nil)) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctorM1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctorM1.scl new file mode 100644 index 000000000..5e1874e31 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctorM1.scl @@ -0,0 +1,11 @@ +import "Prelude" + +main = sequence [[1,2], [3,4], [5,6]] +/* + x <- [1,2] + y <- [3,4] + z <- [5,6] + return [x,y,z] +*/ +-- +[[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Generalization.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Generalization.scl new file mode 100644 index 000000000..e5503349f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Generalization.scl @@ -0,0 +1,13 @@ +import "JavaBuiltin" as Java + +(+) = Java.iadd + +data Foo = Foo Integer + +escapeFoo (Foo x) = x + +id x = x + +main = id (3 :: Integer) + escapeFoo (id (Foo (4 :: Integer))) +-- +7 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GenericMutualRecursion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GenericMutualRecursion.scl new file mode 100644 index 000000000..24c5858d6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GenericMutualRecursion.scl @@ -0,0 +1,12 @@ +// Idea of this test is to ensure that generic type variables +// and constraints are handled correctly with mutually recursive +// functions + +import "Prelude" + +deepId count x = deepId2 count x +deepId2 count x = if count <= 0 then x else deepId (count-1) x + +main = deepId 5 "FOO" +-- +FOO \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GlobalVariables.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GlobalVariables.scl new file mode 100644 index 000000000..c6dc99edf --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GlobalVariables.scl @@ -0,0 +1,14 @@ +import "Prelude" + +global :: Ref Integer +global = ref 0 + +inc :: () +inc = global := getRef global + 1 + +main = do + inc + inc + getRef global +-- +2 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GraphPrelude.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GraphPrelude.scl new file mode 100644 index 000000000..ddb2d58be --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GraphPrelude.scl @@ -0,0 +1,41 @@ + +/** + * Databoard + */ +data Binding // Private +class Serializable a where + getBinding :: Binding + +/** + * Reading graph + */ +data Resource +data ReadGraph // Private +class ReadTransaction where + getGraph :: ReadGraph + +resource :: ReadTransaction => String -> Resource +(#) :: ReadTransaction => Resource -> Resource -> [Resource] +valueOf :: ReadTransaction => Serializable a => Resource -> a + +/** + * Writing graph + */ +data WriteGraph // Private +data Graph a = Graph (WriteGraph -> a) + +instance Monad Graph where + return x = Graph (\_ -> x) + Graph g >>= f = \wg -> f (g wg) wg + map f (Graph g) = Graph (f . g) + +newResource :: Graph Resource +newResource = Graph __WriteGraph_newResource +newLiteral :: Serializable a => a -> Graph Resource +newLiteral = Graph (\wg -> + literal = __WriteGraph_newResource wg + _ = __WriteGraph_claimValue wg literal a getBinding + literal +) +statement :: Resource -> Resource -> Resource -> Graph () +statement s p o = Graph (\wg -> __WriteGraph_claim wg s p o) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GuardedExpressionBug.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GuardedExpressionBug.scl new file mode 100644 index 000000000..c0d45f161 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/GuardedExpressionBug.scl @@ -0,0 +1,9 @@ +tableIndex :: Double -> Double +tableIndex x + | True = x + where + f _ = x + +main = "Foo" +-- +Foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Guards1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Guards1.scl new file mode 100644 index 000000000..db3b43833 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Guards1.scl @@ -0,0 +1,9 @@ +import "Prelude" + +fib :: Integer -> Integer +fib x | x <= 2 = 1 + | True = fib (x-1) + fib (x-2) + +main = fib 13 +-- +233 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Guards2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Guards2.scl new file mode 100644 index 000000000..88734c1ac --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Guards2.scl @@ -0,0 +1,10 @@ +import "Prelude" + +fib :: Integer -> Integer +fib x = match x with + v | v <= 2 -> 1 + | True -> fib (v-1) + fib (v-2) + +main = fib 13 +-- +233 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IdAsOperator.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IdAsOperator.scl new file mode 100644 index 000000000..576ff86f1 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IdAsOperator.scl @@ -0,0 +1,9 @@ +import "JavaBuiltin" as Java + +infixl 5 minus + +minus = Java.isub + +main = 5 `minus` 3 `minus` 2 +-- +0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IllegalChar.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IllegalChar.scl new file mode 100644 index 000000000..371492bb7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IllegalChar.scl @@ -0,0 +1,3 @@ +a = ¤ +-- +1:5-1:6: Illegal character '¤'. diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ImportJavaConstructor.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ImportJavaConstructor.scl new file mode 100644 index 000000000..8c45e438b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ImportJavaConstructor.scl @@ -0,0 +1,18 @@ + +@JavaType "org.simantics.scl.compiler.elaboration.expressions.Expression" +data Expression = + @JavaType "org/simantics/scl/compiler/elaboration/expressions/EIntegerLiteral" + @FieldNames [value] + EIntegerLiteral String + | @JavaType "org.simantics.scl.compiler.elaboration.expressions.ERealLiteral" + @FieldNames [value] + ERealLiteral String + +changeType :: Expression -> Expression +changeType (EIntegerLiteral value) = ERealLiteral value +changeType (ERealLiteral value) = EIntegerLiteral value + +main :: Expression +main = changeType (EIntegerLiteral "123") +-- +123 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ImportRef.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ImportRef.scl new file mode 100644 index 000000000..9fb6f62d2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ImportRef.scl @@ -0,0 +1,18 @@ +importJava "org.simantics.scl.runtime.procedure.Ref" where + data Ref a + + @JavaName "" + ref :: a -> (Ref a) + + @JavaName "value" + getRef :: Ref a -> a + + @JavaName "value" + (:=) :: Ref a -> a -> () + +main = do + r = ref (13 :: Integer) + r := (14 :: Integer) + getRef r +-- +14 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InconsistentArity.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InconsistentArity.scl new file mode 100644 index 000000000..82a966892 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InconsistentArity.scl @@ -0,0 +1,4 @@ +f a b = a +f x = x +-- +2:1-2:4: Inconsistent arity. This case has arity 1 while previous cases had arity 2. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InconsistentIndentation.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InconsistentIndentation.scl new file mode 100644 index 000000000..bd732cf21 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InconsistentIndentation.scl @@ -0,0 +1,5 @@ +class Foo a where + x :: a + y :: a +-- +3:3-3:4: Unexpected token 'y' (ID). Expected one of EOF, RBRACE, SEMICOLON. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IndentationAndParenthesis.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IndentationAndParenthesis.scl new file mode 100644 index 000000000..3a8dc3de7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/IndentationAndParenthesis.scl @@ -0,0 +1,16 @@ +// The last character of the program is an extra closing parenthesis +data List a = Nil | Cons a (List a) + +first Nil = 0 +first (Cons x _) = x + +reverse l = reverseAux Nil l + where + reverseAux accum Nil = accum + reverseAux accum (Cons h t) = reverseAux (Cons h accum) t + +main = first (reverse l) + where + l = Cons 1 (Cons 2 (Cons 3 Nil))) +-- +14:37-14:38: No corresponding opening parenthesis for ')'. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Index.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Index.scl new file mode 100644 index 000000000..8a98aec03 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Index.scl @@ -0,0 +1,8 @@ +import "Prelude" + +f :: Integer -> Maybe Integer +f = index [(1,2),(2,4),(3,6),(4,8)] + +main = f 3 +-- +6 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Inline1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Inline1.scl new file mode 100644 index 000000000..118abc4c5 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Inline1.scl @@ -0,0 +1,5 @@ +main = id "Foo" + where + id x = x +-- +Foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InlineLoop.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InlineLoop.scl new file mode 100644 index 000000000..df8433c5c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InlineLoop.scl @@ -0,0 +1,9 @@ +data SList a = Nil | Cons a (SList a) + +@inline +copy (Cons h t) = Cons h (copy t) +copy l = l + +main = "OK" +-- +OK \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceHierarchy.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceHierarchy.scl new file mode 100644 index 000000000..1c751f397 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceHierarchy.scl @@ -0,0 +1,26 @@ +import "Prelude" hiding (zero, one) + +class MyAdditive a where + zero :: a + +class (MyAdditive a) => MyRing a where + one :: a + +instance MyAdditive Integer where + zero = 0 + +instance MyRing Integer where + one = 1 + +data Poly a = Poly [a] + +instance (MyAdditive a) => MyAdditive (Poly a) where + zero = Poly [] + +instance (MyRing a) => MyRing (Poly a) where + one = Poly [one] + +main :: Poly Integer +main = one +-- +[1] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceIsTypoedAsClass.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceIsTypoedAsClass.scl new file mode 100644 index 000000000..f3973cccd --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceIsTypoedAsClass.scl @@ -0,0 +1,9 @@ +class Functor f where + map :: (a -> b) -> f a -> f b + +data Foo a = Foo a + +class Functor Foo where + map f (Foo x) = Foo (f x) +-- +6:1-7:30: Class Functor has already been defined in this module. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceTypeVariables.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceTypeVariables.scl new file mode 100644 index 000000000..e4ee646a9 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InstanceTypeVariables.scl @@ -0,0 +1,10 @@ +class Foo a b where + foo :: a -> b + +instance Foo a a where + foo x = x :: a + +main = "OK" +-- +OK + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidClass1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidClass1.scl new file mode 100644 index 000000000..796f92c29 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidClass1.scl @@ -0,0 +1,4 @@ +class Foo a where + infix 3 (+) +-- +2:5-2:16: Invalid declaration under class definition. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidEncoding.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidEncoding.scl new file mode 100644 index 000000000..513b36f58 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidEncoding.scl @@ -0,0 +1,3 @@ +main = "Hello w�rld!" +-- +1:16-1:17: Character does not conform to UTF-8 encoding. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidInstance1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidInstance1.scl new file mode 100644 index 000000000..35064c645 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidInstance1.scl @@ -0,0 +1,8 @@ +class Foo a where + (+) :: a -> a -> a + +instance Foo Double where + infix 3 (+) + x + y = x +-- +5:5-5:16: Invalid declaration under instance definition. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidJavaTypeAnnotation.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidJavaTypeAnnotation.scl new file mode 100644 index 000000000..9f7270cd1 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidJavaTypeAnnotation.scl @@ -0,0 +1,6 @@ +@JavaType 123 "sdf" +data Foo + +main = "Not to be executed" +-- +1:1-1:20: Invalid parameters. Expected @JavaType "className". \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds.scl new file mode 100644 index 000000000..a18c062ee --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds.scl @@ -0,0 +1,7 @@ + +data List a = Nil | Cons a (List a) + +foo :: List +foo = foo +-- +4:8-4:12: Expected a type with kind * but got * -> *. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds2.scl new file mode 100644 index 000000000..ffdf0a9f6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds2.scl @@ -0,0 +1,9 @@ +class Functor f where + map :: (a -> b) -> f a -> f b + +instance Functor Integer where + map = fail "Not implemented." + +main = "Not to be executed." +-- +4:18-4:25: Expected a type with kind * -> * but got *. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds3.scl new file mode 100644 index 000000000..445dd7ead --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidKinds3.scl @@ -0,0 +1,5 @@ + +data List a = Nil | Cons a List + +-- +2:28-2:32: Expected a type with kind * but got ?a -> *. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidLambda.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidLambda.scl new file mode 100644 index 000000000..8897d43dd --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidLambda.scl @@ -0,0 +1,4 @@ + +main = \ /* no parameters */ -> 3 +-- +2:30-2:32: Unexpected token '->' (ARROW). Expected one of ATTACHED_HASH, BEGIN_STRING, BLANK, CHAR, DO, ENFORCE, EQ, ESCAPED_SYMBOL, FLOAT, ID, IF, INTEGER, LAMBDA, LBRACKET, LET, LPAREN, MATCH, MDO, SELECT, SELECT_DISTINCT, SELECT_FIRST, TRANSFORMATION, WHEN. diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidModule.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidModule.scl new file mode 100644 index 000000000..7cf5f959f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidModule.scl @@ -0,0 +1,3 @@ +import "INVALID_MODULE" as Foo +-- +1:1-1:31: Failed to import INVALID_MODULE, because it does not exist. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern1.scl new file mode 100644 index 000000000..5ba56cffe --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern1.scl @@ -0,0 +1,7 @@ +id x = x + +f (\x -> x) y = y + +main = f id "Foo" +-- +3:3-3:12: Pattern was expected here. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern2.scl new file mode 100644 index 000000000..2bf9613e6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern2.scl @@ -0,0 +1,5 @@ +if x then y else z = x + +main = "Not to be executed." +-- +1:1-1:19: Illegal left hand side of the definition. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern3.scl new file mode 100644 index 000000000..460a9bdfe --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern3.scl @@ -0,0 +1,8 @@ +foo x = b + where + if a then b else c = x + +main = "Not to be executed." +-- +1:9-1:10: Couldn't resolve variable b. +3:5-3:23: Pattern was expected here. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern4.scl new file mode 100644 index 000000000..11dfd0702 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidPattern4.scl @@ -0,0 +1,7 @@ +import "Prelude" + +a # b # c = a + b + c + +main = "Not to be executed." +-- +3:1-3:10: Illegal left hand side of the definition. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidRuleset1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidRuleset1.scl new file mode 100644 index 000000000..e53520b28 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidRuleset1.scl @@ -0,0 +1,10 @@ +data Fact = Foo | Bar + +rs = ruleset + Foo => Bar + +main = "Not to be executed." +-- +4:10-4:13: Expected + <[Fact]> got + . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidRuleset2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidRuleset2.scl new file mode 100644 index 000000000..675ee4985 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidRuleset2.scl @@ -0,0 +1,11 @@ +data Fact = Foo1 | Foo2 +data Fact2 = Bar + +rs = ruleset + Foo1, Foo2 <=> [Bar] + +main = "Not to be executed." +-- +5:19-5:22: Expected + got + . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidTypeClassInstance1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidTypeClassInstance1.scl new file mode 100644 index 000000000..8860c3b01 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/InvalidTypeClassInstance1.scl @@ -0,0 +1,9 @@ + +class Foo a where + foo :: a -> Integer + +instance Foo Long where + foo x = x + +-- +6:13-6:14: Expected got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaAccess1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaAccess1.scl new file mode 100644 index 000000000..0576f4385 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaAccess1.scl @@ -0,0 +1,8 @@ +import "JavaBuiltin" as Java + +importJava "java.lang.String" where + substring :: String -> Integer -> Integer -> String + +main = substring "01234" 1 4 +-- +123 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaConstructors.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaConstructors.scl new file mode 100644 index 000000000..d3ee020f9 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaConstructors.scl @@ -0,0 +1,11 @@ + +@JavaType "org.simantics.scl.runtime.tuple.Tuple3" +data Tuple3 a b c = + @FieldNames [c0, c1, c2] + Tuple3 a b c + +toTuple (Tuple3 x y z) = (x, y, z) + +main = toTuple (Tuple3 "x" "y" "z") +-- +(x,y,z) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaMethods.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaMethods.scl new file mode 100644 index 000000000..d51bd4bb8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaMethods.scl @@ -0,0 +1,9 @@ +import "JavaBuiltin" as Java + +importJava "java.lang.Integer" where + @JavaName "parseInt" + stringToInteger :: String -> Integer + +main = stringToInteger "13" +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaTypes.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaTypes.scl new file mode 100644 index 000000000..830c5a426 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/JavaTypes.scl @@ -0,0 +1,14 @@ +import "JavaBuiltin" as Java + +importJava "java.math.BigInteger" where + data BigInteger + + @JavaName "add" + (+) :: BigInteger -> BigInteger -> BigInteger + + @JavaName "" + fromString :: String -> BigInteger + +main = fromString "123" + fromString "234" +-- +357 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Kinds1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Kinds1.scl new file mode 100644 index 000000000..2f2f0d1d1 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Kinds1.scl @@ -0,0 +1,15 @@ +class Functor f where + map :: (a -> b) -> f a -> f b + +data Either a b = Left a | Right b + +instance Functor (Either a) where + map _ (Left x) = Left x + map f (Right y) = Right (f y) + +id :: Integer -> Integer +id x = x + +main = map id (Left (12 :: Integer)) +-- +(Left 12) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LP.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LP.scl new file mode 100644 index 000000000..0c3ddc121 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LP.scl @@ -0,0 +1,86 @@ +import "Prelude" + +importJava "gnu.trove.map.hash.TIntFloatHashMap" where + data LMap + + @JavaName adjustOrPutValue + adjustLMap_ :: LMap -> Integer -> Float -> Float -> () + +@inline +adjustLMap :: LMap -> Integer -> Float -> () +adjustLMap m k v = adjustLMap_ m k v v + +data LPTerm = LPTerm (LMap -> Float -> ()) + +instance Additive LPTerm where + @inline + zero = LPTerm (\_ _ -> ()) + @inline + LPTerm a + LPTerm b = LPTerm (\m s -> do a m s ; b m s) + sum ts = LPTerm (\m s -> for ts (\(LPTerm t) -> t m s)) + +instance Ring LPTerm where + @inline + neg (LPTerm a) = LPTerm (\m s -> a m (-s)) + @inline + LPTerm a - LPTerm b = LPTerm (\m s -> do a m s ; b m (-s)) + @inline + fromInteger c = LPTerm (\m s -> adjustLMap m (-1) (fromInteger c*s)) + @inline + one = LPTerm (\m s -> adjustLMap m (-1) s) + _ * _ = fail "Multiplication is not supported." + +data LPProblem = LPProblem (Ref Integer) + +newProblem :: () -> LPProblem +newProblem _ = LPProblem (ref 0) + +newVar :: LPProblem -> LPTerm +newVar (LPProblem varCounter) = do + curId = getRef varCounter + varCounter := curId + 1 + LPTerm (\m s -> adjustLMap m curId s) + +infixl 7 (**) + +@inline +(**) :: Float -> LPTerm -> LPTerm +s0 ** LPTerm t = LPTerm (\m s -> t m (s0*s)) + +/* +data LPTerm = LPTerm Double (Map.T String Double) + +instance Additive LPTerm where + zero = LPTerm 0 Map.empty + LPTerm c1 m1 + LPTerm c2 m2 = LPTerm (c1+c2) (Map.merge (+) m1 m2) + +instance Ring LPTerm where + one = LPTerm 1 Map.empty + neg (LPTerm c m) = LPTerm (-c) (map neg m) + LPTerm c1 m1 - LPTerm c2 m2 = LPTerm (c1-c2) (Map.merge (-) m1 m2) + + LPTerm c1 [] * LPTerm c2 m2 = LPTerm (c1*c2) (Map.merge (\x -> c1*x) m2) + LPTerm c1 m1 * LPTerm c2 [] = LPTerm (c1*c2) (Map.merge (\x -> c2*x) m1) + _ * _ = fail "Invalid expression: not linear." + + fromInteger i = LPTerm (fromInteger i) Map.empty + +data LPConstraint = LPConstraint String LPTerm + +(>==) :: LPTerm -> LPTerm -> String -> [LPConstraint] +(a >== b) name = [LPConstraint name (a-b)] + +(<==) :: LPTerm -> LPTerm -> String -> [LPConstraint] +(a <== b) name = [LPConstraint name (b-a)] + +*/ + +testi () = do + problem = newProblem () + a = newVar problem + b = newVar problem + 3 ** a + 4 ** b + 15 + +main = "OK" +-- +OK \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Lambda.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Lambda.scl new file mode 100644 index 000000000..2316b30b4 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Lambda.scl @@ -0,0 +1,13 @@ + +data List a = Nil | Cons a (List a) + +map :: (a -> b) -> List a -> List b +map f Nil = Nil +map f (Cons h t) = Cons (f h) (map f t) + +constMap :: a -> List b -> List a +constMap c = map (\x -> c) + +main = constMap (5 :: Integer) (Cons (1 :: Integer) (Cons (2 :: Integer) (Cons (3 :: Integer) Nil))) +-- +(Cons 5 (Cons 5 (Cons 5 Nil))) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Layout1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Layout1.scl new file mode 100644 index 000000000..f68e9a6a7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Layout1.scl @@ -0,0 +1,12 @@ +import "Prelude" + +foobar x = match x with + Left lt -> foo lt + Right rt -> bar rt + where + foo x = "left " + show x + bar x = "right " + show x + +main = foobar (Left "ASD" :: Either String String) +-- +left "ASD" \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/List.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/List.scl new file mode 100644 index 000000000..b746c31ca --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/List.scl @@ -0,0 +1,7 @@ + +data List a = Nil | Cons a (List a) + +main :: List Integer +main = Cons (3 :: Integer) Nil +-- +(Cons 3 Nil) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListError1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListError1.scl new file mode 100644 index 000000000..0fece992c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListError1.scl @@ -0,0 +1,7 @@ +a :: [Integer] +a = a + +main :: [Double] +main = [x | x <- a] +-- +5:9-5:10: Expected got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListError2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListError2.scl new file mode 100644 index 000000000..135e2704b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListError2.scl @@ -0,0 +1,7 @@ +a :: Integer +a = a + +main :: [Integer] +main = [x | x <- a] +-- +5:18-5:19: Expected <[a]> got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax.scl new file mode 100644 index 000000000..1747a6f62 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax.scl @@ -0,0 +1,7 @@ +import "Prelude" + +a = [1,2] +b = [5,9] +main = [(x,y) | x <- a, y <- b] +-- +[(1,5), (1,9), (2,5), (2,9)] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax10.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax10.scl new file mode 100644 index 000000000..726dba5c8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax10.scl @@ -0,0 +1,12 @@ +import "Prelude" + +dists l = sum [sqrt (dx*dx + dy*dy) + | i <- [0..length l-2] + , (x1,y1) = l!i + , (x2,y2) = l!(i+1) + , dx = x1-x2 + , dy = y1-y2 ] + +main = dists [(0,0),(1,1),(2,0)] +-- +2.8284271247461903 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax11.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax11.scl new file mode 100644 index 000000000..15f044190 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax11.scl @@ -0,0 +1,8 @@ +import "Prelude" + +dists l = sum [sqrt (x*x+y*y) + | (x,y) <- l ] + +main = dists [(0,0),(1,1),(2,0)] +-- +3.414213562373095 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax12.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax12.scl new file mode 100644 index 000000000..8b18eb3d0 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax12.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = foldl (+) 0 [x | y <- [1..10], x <- [1..y]] +-- +220 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax2.scl new file mode 100644 index 000000000..e020731a7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax2.scl @@ -0,0 +1,7 @@ +import "Prelude" + +a = [1,2] +b = [5,9] +main = [(x, y) | x <- a, x==2, y <- b] +-- +[(2,5), (2,9)] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax3.scl new file mode 100644 index 000000000..c6cbbca7d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax3.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = [1,2,3,4] +-- +[1, 2, 3, 4] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax4.scl new file mode 100644 index 000000000..a95063523 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax4.scl @@ -0,0 +1,6 @@ +import "Prelude" + +main :: [Integer] +main = [y | x <- [1..3], y = x+4] +-- +[5, 6, 7] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax5.scl new file mode 100644 index 000000000..6ba833078 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax5.scl @@ -0,0 +1,8 @@ +import "Prelude" + +a = [1,2,3,4] + +main :: [Integer] +main = [x+y | x <- a, y <- a, x!=y] +-- +[3, 4, 5, 3, 5, 6, 4, 5, 7, 5, 6, 7] diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax6.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax6.scl new file mode 100644 index 000000000..a3e08c47d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax6.scl @@ -0,0 +1,6 @@ +import "Prelude" + +main :: [Integer] +main = [x | x <- [1..10], then take 3] +-- +[1, 2, 3] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax7.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax7.scl new file mode 100644 index 000000000..54cf21c54 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax7.scl @@ -0,0 +1,6 @@ +import "Prelude" + +main :: [Integer] +main = [x | x <- [2,4,3,5,4,6], then sortBy by x] +-- +[2, 3, 4, 4, 5, 6] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax8.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax8.scl new file mode 100644 index 000000000..ac5ce5765 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax8.scl @@ -0,0 +1,12 @@ +import "Prelude" + +a :: [Either Integer Integer] +a = [Left 1, Right 2, Left 3, Right 4] + +lefts :: [Either a b] -> [a] +lefts l = [x | Left x <- l] + +main :: [Integer] +main = lefts a +-- +[1, 3] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax9.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax9.scl new file mode 100644 index 000000000..83de25518 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntax9.scl @@ -0,0 +1,12 @@ +import "Prelude" + +a :: [Either Integer Integer] +a = [Left 1, Right 2, Left 3, Right 4] + +lefts :: [Either a b] -> [a] +lefts l = [x | y <- l, Left x = y] + +main :: [Integer] +main = lefts a +-- +[1, 3] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntaxWithoutPrelude.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntaxWithoutPrelude.scl new file mode 100644 index 000000000..8806f93a3 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ListSyntaxWithoutPrelude.scl @@ -0,0 +1,3 @@ +main = [1 :: Integer,2 :: Integer,3 :: Integer] +-- +[1, 2, 3] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions.scl new file mode 100644 index 000000000..0e4690a65 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions.scl @@ -0,0 +1,12 @@ + +data List a = Nil | Cons a (List a) + +reverse :: List a -> List a +reverse l = do + reverseAux accum Nil = accum + reverseAux accum (Cons h t) = reverseAux (Cons h accum) t + reverseAux Nil l + +main = reverse (Cons (1 :: Integer) (Cons (2 :: Integer) (Cons (3 :: Integer) (Cons (4 :: Integer) Nil)))) +-- +(Cons 4 (Cons 3 (Cons 2 (Cons 1 Nil)))) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions2.scl new file mode 100644 index 000000000..f17a8beee --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions2.scl @@ -0,0 +1,14 @@ + +data List a = Nil | Cons a (List a) + +hasEvenLength :: List a -> Boolean +hasEvenLength l = do + even Nil = True + even (Cons _ t) = odd t + odd Nil = False + odd (Cons _ t) = even t + even l + +main = hasEvenLength (Cons (1 :: Integer) (Cons (2 :: Integer) (Cons (3 :: Integer) (Cons (4 :: Integer) Nil)))) +-- +true \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions3.scl new file mode 100644 index 000000000..71a193f6e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions3.scl @@ -0,0 +1,10 @@ + +data Step s = Skip s + +next :: (s -> Step s) -> s -> Step s +next next0 ss = match next0 ss with + Skip ss -> Skip ss + +main = next (\x -> Skip x) (3 :: Integer) +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions4.scl new file mode 100644 index 000000000..fe07e4742 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions4.scl @@ -0,0 +1,8 @@ + +first p = x + where + (x,y) = p + +main = first (3 :: Integer,4 :: Integer) +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions5.scl new file mode 100644 index 000000000..97cf72c2f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/LocalDefinitions5.scl @@ -0,0 +1,13 @@ +import "Prelude" + +data Foo = Foo Double Double + +a = Foo 1 2 + +b = y + where + Foo x y = a + +main = show b +-- +2.0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros1.scl new file mode 100644 index 000000000..37b4e053e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros1.scl @@ -0,0 +1,8 @@ +@macro +(||) :: Boolean -> Boolean -> Boolean +a || b = if a then True else b + +main :: Boolean +main = True || (fail "This should not be executed") +-- +true \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros2.scl new file mode 100644 index 000000000..d1379cd8e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros2.scl @@ -0,0 +1,13 @@ +import "JavaBuiltin" as Java + +(==) = Java.icmpeq + +@macro +(&<&) :: Integer -> Integer -> Integer +a &<& b = if cmp == 0 then b else cmp + where + cmp = a + +main = 3 &<& 7 +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros3.scl new file mode 100644 index 000000000..ec1571dc0 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros3.scl @@ -0,0 +1,16 @@ +import "JavaBuiltin" as Java + +@JavaType "java.util.Collection" +data Collection a + +@macro +collectionToList :: Collection a -> [a] +collectionToList = Java.unsafeCoerce + +singleton :: a -> Collection a +singleton = Java.staticMethod "java.util.Collections.singletonList" + +main :: [Integer] +main = collectionToList (singleton 15) +-- +[15] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros4.scl new file mode 100644 index 000000000..87e41e0af --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Macros4.scl @@ -0,0 +1,12 @@ +@macro +@inline +($) :: (a -> b) -> a -> b +f $ x = f x + +justExecute :: (() -> a) -> a +justExecute f = f () + +main :: Integer +main = justExecute $ \() -> (13 :: Integer) +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Map1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Map1.scl new file mode 100644 index 000000000..5d9f38c99 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Map1.scl @@ -0,0 +1,18 @@ +data List a = Nil | Cons a (List a) + +map f Nil = Nil +map f (Cons h t) = Cons (f h) (map f t) + +map2 f l = run l + where + run Nil = Nil + run (Cons h t) = Cons (f h) (run t) + +map3 f l = run l + where + run Nil = Nil + run (Cons h t) = Cons (f h) (map f t) + +main = "Foo" +-- +Foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MarketModel.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MarketModel.scl new file mode 100644 index 000000000..da27b041d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MarketModel.scl @@ -0,0 +1,11 @@ +import "Prelude" + +l :: [Integer] +l = [2,3] + +f :: Integer -> [Integer] +f n = [n] + [0 | i <- l] + +main = f 1 +-- +[1, 0, 0] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MarketModel2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MarketModel2.scl new file mode 100644 index 000000000..bcd576bb1 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MarketModel2.scl @@ -0,0 +1,12 @@ +import "IterN" +import "Random" + +foo :: Integer -> Double +foo n = runRandom $ foldlN addRandom 0.0 n + +addRandom :: Double -> Integer -> Double +addRandom v i = v + randomDouble + +main = "Foo" +-- +Foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching.scl new file mode 100644 index 000000000..f240a1c2b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching.scl @@ -0,0 +1,19 @@ + +data List a = Nil | Cons a (List a) + +first :: List Integer -> Integer +//first Nil = 0 :: Integer +first (Cons x _) = x + +reverse :: List a -> List a +reverse l = reverseAux Nil l + where + reverseAux accum Nil = accum + reverseAux accum (Cons h t) = reverseAux (Cons h accum) t + +main :: Integer +main = first (reverse l) + where + l = Cons (1 :: Integer) (Cons (2 :: Integer) (Cons (3 :: Integer) Nil)) +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching2.scl new file mode 100644 index 000000000..c71b98bf8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching2.scl @@ -0,0 +1,9 @@ + +main = match (5 :: Integer) with + (1 :: Integer) -> "wrong" + (2 :: Integer) -> "wrong" + (5 :: Integer) -> "right" + (6 :: Integer) -> "wrong" + _ -> "wrong" +-- +right \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching3.scl new file mode 100644 index 000000000..904a84397 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching3.scl @@ -0,0 +1,10 @@ + +a = 5 :: Long +main = match a with + 1 -> "wrong" + 2 -> "wrong" + 5 -> "right" + 6 -> "wrong" + _ -> "wrong" +-- +right \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching3b.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching3b.scl new file mode 100644 index 000000000..486434583 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching3b.scl @@ -0,0 +1,8 @@ +import "StandardLibrary" + +foo 1 = "one" +foo 2 = "two" + +main = if True then foo (2 :: Long) else foo (1 :: Integer) +-- +two \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching4.scl new file mode 100644 index 000000000..8c8812b50 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching4.scl @@ -0,0 +1,11 @@ +import "Prelude" + +dummySum [] = 0 +dummySum [a] = a +dummySum [a,b] = a + b +dummySum [a,b,c] = a + b + c +dummySum l = sum l + +main = dummySum [] + dummySum [1] + dummySum [1,2] + dummySum [1,2,3] +-- +10 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching5.scl new file mode 100644 index 000000000..61723e8f8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Matching5.scl @@ -0,0 +1,5 @@ +main = do + match () with + () -> "Hello" +-- +Hello \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MatchingWithMissingParameter.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MatchingWithMissingParameter.scl new file mode 100644 index 000000000..33a681fd3 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MatchingWithMissingParameter.scl @@ -0,0 +1,10 @@ +data Foo = Foo Integer Integer + | Bar + +isFoo (Foo _) = True +isFoo _ = False + +main = "Hello world!" +-- +4:7-4:14: The function is applied with too few parameters. + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MatchingWithoutTypeAnnotations.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MatchingWithoutTypeAnnotations.scl new file mode 100644 index 000000000..80d147773 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MatchingWithoutTypeAnnotations.scl @@ -0,0 +1,10 @@ + +data List a = Nil | Cons a (List a) + +//first :: List Integer -> Integer +first Nil = 0 :: Integer +first (Cons x _) = x + +main = first (Cons (9 :: Integer) (Cons (8 :: Integer) Nil)) +-- +9 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MaximumBy.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MaximumBy.scl new file mode 100644 index 000000000..c70c9dae8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MaximumBy.scl @@ -0,0 +1,10 @@ +import "Prelude" hiding (maximumBy) + +maximumBy :: Ord b => (a -> b) -> [a] -> a +maximumBy f = snd . foldl1 maxF . map (\x -> (f x, x)) + where + maxF (a @ (aV,_)) (b @ (bV,_)) = if aV >= bV then a else b + +main = maximumBy (`mod` 10) [1::Integer, 14, 23, 9, 14, 67] +-- +9 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe1.scl new file mode 100644 index 000000000..98a7d71ae --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe1.scl @@ -0,0 +1,6 @@ +a = Nothing +main = match a with + Nothing -> "Correct" + Just x -> "Incorrect" +-- +Correct \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe2.scl new file mode 100644 index 000000000..0bc50fb5e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe2.scl @@ -0,0 +1,6 @@ +a = Just True +main = match a with + Nothing -> False + Just x -> x +-- +true \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe3.scl new file mode 100644 index 000000000..8a0f12070 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe3.scl @@ -0,0 +1,6 @@ +a = Just "ABC" +main = match a with + Nothing -> "Incorrect" + Just x -> x +-- +ABC \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe4.scl new file mode 100644 index 000000000..53e3ed3d7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Maybe4.scl @@ -0,0 +1,18 @@ +import "Prelude" hiding (fromMaybe) +import "Random" + +importJava "org.simantics.scl.compiler.tests.imports.Maybe4Imports" where + toMaybeDouble :: String -> Maybe a + +fromMaybe :: a -> Maybe a -> a +fromMaybe _ (Just v) = v +fromMaybe def _ = def + +f x = do + a = fromMaybe (-1.0) (toMaybeDouble x) + b = fromMaybe (-1.0) (toMaybeDouble ("1" + x)) + a+b + +main = withSeed 123 (f "2.0") +-- +14.0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingEffect.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingEffect.scl new file mode 100644 index 000000000..9a5ea98c4 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingEffect.scl @@ -0,0 +1,15 @@ +import "Prelude" hiding (findFirst) + +findFirst :: (a -> Maybe b) -> [a] -> Maybe b +findFirst f l = loop 0 + where + len = length l + loop i + | i >= len = Nothing + | otherwise = match f (l!i) with + s @ (Just _) -> s + Nothing -> loop (i+1) + +main = "Not to be executed" +-- +9:29-9:36: Side-effect a is forbidden here. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingMethod.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingMethod.scl new file mode 100644 index 000000000..d5b1b27f8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingMethod.scl @@ -0,0 +1,12 @@ +class FooBar a where + foo :: a -> a + bar :: a -> a + +instance FooBar Integer where + foo x = x + +main = "Not to be executed." +-- +5:1-6:14: Method bar is not defined. + + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingTypeParameter.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingTypeParameter.scl new file mode 100644 index 000000000..fc40ab9cd --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MissingTypeParameter.scl @@ -0,0 +1,6 @@ +importJava "java.util.Arrays" where + toString :: MVector /*Double*/ -> String + +main = "Not to be executed." +-- +??? \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ModuleInitialization.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ModuleInitialization.scl new file mode 100644 index 000000000..bd3dfa10b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ModuleInitialization.scl @@ -0,0 +1,11 @@ +import "Prelude" + +d = map (+1) c +a = [1,2,3] +c = map (+1) b +b = map (+1) a +e = map (+1) d + +main = e +-- +[5, 6, 7] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadBug1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadBug1.scl new file mode 100644 index 000000000..44ddf00e6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadBug1.scl @@ -0,0 +1,10 @@ +class Monad m where + (>>=) :: m a -> (a -> m b) -> m b + +@macro +(>>) :: Monad m => m a -> m b -> m b +ma >> mb = ma >>= (\_ -> mb) + +main = "OK" +-- +OK \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadSyntax1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadSyntax1.scl new file mode 100644 index 000000000..94774a4f2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadSyntax1.scl @@ -0,0 +1,11 @@ +import "Prelude" + +a = [1, 2] +b = [5, 6] + +main = mdo + x <- a + y <- b + return (x+y) +-- +[6, 7, 7, 8] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadSyntax2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadSyntax2.scl new file mode 100644 index 000000000..6244a6162 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/MonadSyntax2.scl @@ -0,0 +1,12 @@ +import "Prelude" + +a = [1, 2] +b = [5, 6] + +main = do + x <- a + y <- b + return (x+y) +-- +7:3-7:9: Bind statements are allowed only in mdo-blocks. +8:3-8:9: Bind statements are allowed only in mdo-blocks. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Monads1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Monads1.scl new file mode 100644 index 000000000..90115d3ff --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Monads1.scl @@ -0,0 +1,8 @@ +import "Prelude" + +a = [1, 2] +b = [5, 6] + +main = a >>= \x -> b >>= \y -> return (x+y) +-- +[6, 7, 7, 8] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoDefinitionErrorMessage.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoDefinitionErrorMessage.scl new file mode 100644 index 000000000..8597a78ac --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoDefinitionErrorMessage.scl @@ -0,0 +1,7 @@ +// Idea of this test is that the missing definition should only cause +// one error message pointing to the type declaration. +a :: Double +b :: Double +b = a +-- +3:1-3:12: a is not defined. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoInstance.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoInstance.scl new file mode 100644 index 000000000..4bc5cabba --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoInstance.scl @@ -0,0 +1,9 @@ + +class Foo a where + foo :: a + +x :: Double +x = foo + +-- +6:5-6:8: Constraint is not given and cannot be derived. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoInstance2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoInstance2.scl new file mode 100644 index 000000000..9490a822d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NoInstance2.scl @@ -0,0 +1,10 @@ + +class Foo a where + foo :: a + +y :: Double +y = y + +x = if True then foo else y +-- +8:18-8:21: There is no instance for . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonassociativeOperator.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonassociativeOperator.scl new file mode 100644 index 000000000..f2b473ae9 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonassociativeOperator.scl @@ -0,0 +1,7 @@ +infix 3 (+) + +a + b = a + +threeTimes x = x + x + x +-- +5:22-5:23: Operator + is not associative. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonexistentTypeClassInAnnotation.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonexistentTypeClassInAnnotation.scl new file mode 100644 index 000000000..40306395a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonexistentTypeClassInAnnotation.scl @@ -0,0 +1,9 @@ +import "Prelude" + +deepId :: FooBar b => b -> a -> a +deepId count x = deepId2 count x +deepId2 count x = if count <= 0 then x else deepId (count-1) x + +main = deepId (5 :: Integer) "FOO" +-- +3:11-3:17: Unresolved type class FooBar. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonexistingEffect.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonexistingEffect.scl new file mode 100644 index 000000000..8ed51f912 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/NonexistingEffect.scl @@ -0,0 +1,6 @@ +importJava "java.lang.System" where + nanoTime :: () -> Long + +main = nanoTime () +-- +2:24-2:28: Didn't find effect constructor Pred. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OneLineMatch.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OneLineMatch.scl new file mode 100644 index 000000000..3f16b0783 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OneLineMatch.scl @@ -0,0 +1,6 @@ +// Tests that match cases can be given in the same line as the scrutinee +data FooBar a = Foo a | Bar a +extract x = match x with Foo v -> v ; Bar v -> v +main = extract (Foo (3 :: Integer)) +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OpenString1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OpenString1.scl new file mode 100644 index 000000000..e8a7c4c76 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OpenString1.scl @@ -0,0 +1,3 @@ +"asd +-- +1:1-1:6: Unclosed string literal. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OpenString2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OpenString2.scl new file mode 100644 index 000000000..31953cc01 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OpenString2.scl @@ -0,0 +1,6 @@ +"asd + + +asd +-- +1:1-1:6: Unclosed string literal. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic1.scl new file mode 100644 index 000000000..de083e814 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic1.scl @@ -0,0 +1,17 @@ +import "JavaBuiltin" as Java + +infixl 6 (+) + +class Additive a where + (+) :: a -> a -> a + +instance Additive Double where + x + y = Java.dadd x y + +instance Additive Integer where + x + y = Java.iadd x y + +main = ((1.0 :: Double)+(2.0 :: Double),(3::Integer)+(4::Integer)) +-- +(3.0,7) + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic2.scl new file mode 100644 index 000000000..1619f585d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic2.scl @@ -0,0 +1,20 @@ +import "JavaBuiltin" as Java + +infixl 6 (+) + +class Additive a where + (+) :: a -> a -> a + +instance Additive Double where + x + y = Java.dadd x y + +instance Additive Integer where + x + y = Java.iadd x y + +instance (Additive a, Additive b) => Additive (a,b) where + (x1,y1) + (x2,y2) = (x1+x2,y1+y2) + +main = (1.0::Double,3::Integer) + (2.0::Double,4::Integer) +-- +(3.0,7) + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic3.scl new file mode 100644 index 000000000..230e486cf --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedArithmetic3.scl @@ -0,0 +1,27 @@ +import "JavaBuiltin" as Java + +infixl 7 (*) +infixl 6 (+) + +class Additive a where + (+) :: a -> a -> a + +class (Additive a) => Ring a where + (*) :: a -> a -> a + +instance Additive Double where + x + y = Java.dadd x y + +instance Ring Double where + x * y = Java.dmul x y + +instance Additive Integer where + x + y = Java.iadd x y + +instance Ring Integer where + x * y = Java.imul x y + +main = (1.0 :: Double)*(2.0 :: Double)+(3.0 :: Double)*(4.0 :: Double) +-- +14.0 + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedLiterals2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedLiterals2.scl new file mode 100644 index 000000000..c1670972a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/OverloadedLiterals2.scl @@ -0,0 +1,9 @@ +import "Prelude" + +inc :: Ring a => a -> a +inc x = x + 1 + +main :: Double +main = inc 34 +-- +35.0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading1.scl new file mode 100644 index 000000000..dfb607934 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading1.scl @@ -0,0 +1,19 @@ +// module Foo1 +import "Prelude" + +foo :: Integer -> Boolean +foo i = i == 5 +-- +// module Foo2 +import "Prelude" + +foo :: Integer -> Integer -> Boolean +foo i j = i == j +-- +import "Prelude" +import "Foo1" +import "Foo2" + +main = foo 5 && foo 5 4 +-- +false \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading2.scl new file mode 100644 index 000000000..e7a28de00 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading2.scl @@ -0,0 +1,20 @@ +// module Max1 +import "Prelude" + +myMax :: Ord a => a -> a -> a +myMax = max +-- +// module Max2 +import "Prelude" + +myMax :: Ord a => a -> a -> a -> a +myMax a b c = max a (max b c) +-- +import "Prelude" +import "Max1" +import "Max2" + +main = myMax (1 :: Integer) 2 3 + myMax (3 :: Integer) 2 1 + myMax 4 2 :: Integer +-- +10 + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading3.scl new file mode 100644 index 000000000..9385ce7bc --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Overloading3.scl @@ -0,0 +1,23 @@ +// module M1 +import "Prelude" + +foo :: Ring a => Boolean -> a -> a +foo True v = v+1 +foo False v = v+1 +-- +// module M2 +import "Prelude" + +foo :: Ring a => String -> a -> a +foo cond v = if cond=="true" + then v+1 + else v-1 +-- +import "Prelude" +import "M1" +import "M2" + +main = foo False (foo "True" 10) :: Integer +-- +10 + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Parsing.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Parsing.scl new file mode 100644 index 000000000..0ca342a34 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Parsing.scl @@ -0,0 +1,62 @@ +import "Prelude" + +""" +Parser is a function from a string and a position in the +string to a possible semantics of a substring and the +end of the substring. +""" +data Parser a = Parser (String -> Integer -> Maybe (a, Integer)) + +runParser :: Parser a -> String -> Integer -> Maybe (a, Integer) +runParser (Parser f) = f + +instance Functor Parser where + fmap f (Parser p) = Parser (\input pos -> match p input pos with + Nothing -> Nothing + Just (a, newPos) -> Just (f a, newPos) + ) + +instance Monad Parser where + return x = Parser (\_ pos -> Just (x, pos)) + (pa >>= f) = Parser (\input pos -> match runParser pa input pos with + Nothing -> Nothing + Just (a, newPos) -> runParser (f a) input newPos + ) + +(|||) :: Parser a -> Parser a -> Parser a +Parser a ||| Parser b = Parser (\input pos -> match a input pos with + Nothing -> b input pos + Just x -> Just x +) + +keyword :: String -> Parser () +keyword word = Parser (\input pos -> + if regionMatches word 0 input pos (length word) + then Just ((), pos + (length word)) + else Nothing +) + +data List a = Nil | Cons a (List a) + +listSepL :: Parser () -> Parser a -> Parser (List a) +listSepL sep el = mdo + head <- el + tail <- (sep >> listSepL sep el) ||| return Nil + return (Cons head tail) + +fromList :: List a -> [a] +fromList = unfoldr gen + where + gen Nil = Nothing + gen (Cons h t) = Just (h, t) + +listSep :: Parser () -> Parser a -> Parser [a] +listSep sep el = fmap fromList (listSepL sep el) + +aOrB = (keyword "a" >> return "a") ||| (keyword "b" >> return "b") + +myParser = listSep (keyword ",") aOrB + +main = show (runParser myParser "a,b,b,a" 0) +-- +Just (["a", "b", "b", "a"], 7) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PatternError.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PatternError.scl new file mode 100644 index 000000000..ce417affc --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PatternError.scl @@ -0,0 +1,22 @@ +import "Prelude" + +data CP = CP Integer String + +//cpName :: CP -> String +cpName CP cp name = name + +connectionPoints :: Integer -> [(CP, CP)] +connectionPoints n = [] + +hasTerminalProblems :: Integer -> Boolean +hasTerminalProblems uc = + let cps = connectionPoints uc + cpCount = length cps + dcps = map snd cps + dnames = map cpName dcps + dcpNameCount = length $ unique $ sort dnames + in cpCount != dcpNameCount + +main = "Not OK" +-- +6:8-6:10: ??? \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PolymorphicRecursion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PolymorphicRecursion.scl new file mode 100644 index 000000000..ed84193b7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PolymorphicRecursion.scl @@ -0,0 +1,16 @@ +// Idea here is to test the following property: +// When a function is called recursively it has locally a monomorphic type. +// Therefore the definition of cons does not work even if it works +// with a proper type annotation. + +data Vec a = Nil | Zero (Vec (a,a)) | One a (Vec (a,a)) + +// cons :: a -> Vec a -> Vec a +cons x Nil = One x Nil +cons x (Zero ps) = One x ps +cons x (One y ps) = Zero (cons (x, y) ps) +-- +11:21-11:42: Expected got . +11:33-11:34: Type (a, a) is not a subtype of a. +11:36-11:37: Type (a, a) is not a subtype of a. +11:39-11:41: Expected got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PolymorphicRecursion2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PolymorphicRecursion2.scl new file mode 100644 index 000000000..44738e055 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PolymorphicRecursion2.scl @@ -0,0 +1,12 @@ + + +class Foo a where + foo :: a + +data List a = Nil | Cons a (List a) + +r x = Cons foo (r x) + +main = (1.0 :: Double) +-- +1.0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Polynomials.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Polynomials.scl new file mode 100644 index 000000000..5e35b9424 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Polynomials.scl @@ -0,0 +1,50 @@ +import "Prelude" + +data Poly a = Poly [a] + +normalize l = go (length l) + where + go i = if i > 0 && l!(i-1)==zero + then go (i-1) + else take i l + +instance (Eq a, Additive a) => Additive (Poly a) where + zero = Poly [] + Poly a + Poly b = + Poly ( + normalize ( + zipWith (+) a b + + if la > lb + then drop lb a + else drop la b + ) + ) + where + la = length a + lb = length b + +instance (Eq a, Ring a) => Ring (Poly a) where + one = Poly [one] + neg (Poly l) = Poly (map neg l) + a - b = a + (neg b) + Poly a * Poly b = + Poly ( if aDeg < bDeg + then [ segSum n 0 n | n <- [0 ..aDeg] ] + + [ segSum n 0 aDeg | n <- [aDeg+1..bDeg] ] + + [ segSum n (n-bDeg) aDeg | n <- [bDeg+1..sumDeg] ] + else [ segSum n 0 n | n <- [0 ..bDeg] ] + + [ segSum n (n-bDeg) n | n <- [bDeg+1..aDeg] ] + + [ segSum n (n-bDeg) aDeg | n <- [aDeg+1..sumDeg] ] + ) + where + aDeg = length a - 1 + bDeg = length b - 1 + sumDeg = aDeg + bDeg + segSum n low high = sum [ a!i * b!(n-i) | i <- [low..high] ] + fromInteger x = Poly [fromInteger x] + +a = Poly [4.0,5.0,8.0,3.0,2.0,1.0] +b = Poly [1.0,0.0,2.0,1.0] +main = a * a + a * b + b * a + b * b - (a+b)*(a+b) +-- +[] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PrecedenceOfNonoperators.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PrecedenceOfNonoperators.scl new file mode 100644 index 000000000..3321e8958 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/PrecedenceOfNonoperators.scl @@ -0,0 +1,9 @@ +infixr 2 l +infixr 1 r + +l a b = a +r a b = b + +main = (1 :: Integer) `l` (2 :: Integer) `r` (3 :: Integer) `l` (4 :: Integer) +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Primes.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Primes.scl new file mode 100644 index 000000000..830186ba7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Primes.scl @@ -0,0 +1,24 @@ +import "JavaBuiltin" as Java + +infixl 7 (%) +infixl 6 (+) +infix 4 (==), (<) + +(+) = Java.iadd +(%) = Java.irem +(<) = Java.icmplt +(==) = Java.icmpeq + +isPrime p = isPrimeAux (2 :: Integer) p + where + isPrimeAux d p = if d == p then True + else if p % d == 0 then False + else isPrimeAux (d+1) p + +nextPrime p = if isPrime p + then p + else nextPrime (p+(1 :: Integer)) + +main = nextPrime 32 +-- +37 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc1.scl new file mode 100644 index 000000000..b91eed34f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc1.scl @@ -0,0 +1,8 @@ +import "Prelude" + +main = do + r = ref 13 + r := 14 + getRef r +-- +14 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc2.scl new file mode 100644 index 000000000..bd8021b13 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc2.scl @@ -0,0 +1,29 @@ +import "Prelude" + +data RealWorld = RealWorld +data IO a = IO (RealWorld -> (RealWorld, a)) + +@inline +unIO (IO m) = m + +instance Functor IO where + @inline + fmap f x = x >>= (return . f) + +instance Monad IO where + @inline + return x = IO (\s -> (s, x)) + + @inline + (IO m) >>= f = IO (\s -> do + (newS, v) = m s + unIO (f v) newS + ) + +@inline +runIO :: IO a -> a +runIO m = snd (unIO m RealWorld) + +main = runIO (return (13 :: Integer)) +-- +13 diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc3.scl new file mode 100644 index 000000000..4a17fe480 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Proc3.scl @@ -0,0 +1,16 @@ +import "Prelude" + +@private +repeat :: Integer -> (() -> a) -> () +repeat n proc = + if n > 0 then do + proc () + repeat (n-1) proc + else () + +main = do + a = ref 1 + repeat 3 (\() -> a := 2) + getRef a +-- +2 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Pythagoras.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Pythagoras.scl new file mode 100644 index 000000000..95a5b9b78 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Pythagoras.scl @@ -0,0 +1,24 @@ +import "JavaBuiltin" as Java + +infixl 7 (*) +infixl 6 (+) + +(+) :: Double -> Double -> Double +(+) = Java.dadd +(*) :: Double -> Double -> Double +(*) = Java.dmul + +importJava "java.lang.Math" where + sqrt :: Double -> Double + sin :: Double -> Double + cos :: Double -> Double + +square x = x * x + +length x y = sqrt (square x + square y) + +pythagoras a = length (cos a) (sin a) + +main = pythagoras 2.0 +-- +1.0 diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Random1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Random1.scl new file mode 100644 index 000000000..66922eadb --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Random1.scl @@ -0,0 +1,19 @@ +import "StandardLibrary" + +// Actual program + +"""This function returns either 0 or 1 such that +the expected value is pi/4""" +approximatePi :: () -> Double +approximatePi () = if x*x + y*y < 1 then 1 else 0 + where + x = randomDouble + y = randomDouble + +averageOfNRepeats n f = sum [f () | n <- [1..n]] / fromInteger n + +betterApproximatePi () = averageOfNRepeats 1000 approximatePi * 4 + +main = withSeed 13 (betterApproximatePi ()) +-- +3.068 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RangeSyntax.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RangeSyntax.scl new file mode 100644 index 000000000..662255248 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RangeSyntax.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = [5..9] +-- +[5, 6, 7, 8, 9] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record1.scl new file mode 100644 index 000000000..fcfbf6a25 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Record1.scl @@ -0,0 +1,9 @@ +import "Prelude" + +data XYS = XYS { x :: Double, y :: Double, s :: String } + +len XYS {x = x, y = y} = sqrt (x*x + y*y) + +main = len (XYS { x = 4, y = 3, s = "Hello world!" }) +-- +5.0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecordShorthand.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecordShorthand.scl new file mode 100644 index 000000000..d3af73e02 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecordShorthand.scl @@ -0,0 +1,11 @@ +import "Prelude" + +data Vec = Vec { x :: Double, y :: Double } +deriving instance Show Vec + +createVec x y = Vec {x, y} +sumVec Vec { x1, y1 } Vec { x2, y2 } = Vec { x = x1+x2, y = y1 + y2 } + +main = sumVec (createVec 1 2) (createVec 3 4) +-- +(Vec 4.0 6.0) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveContext.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveContext.scl new file mode 100644 index 000000000..741286211 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveContext.scl @@ -0,0 +1,23 @@ +import "JavaBuiltin" as Java + +infixl 6 (+), (-) + +class Num a where + (+) :: a -> a -> a + (-) :: a -> a -> a + isZero :: a -> Boolean + one :: a + +instance Num Integer where + x + y = Java.iadd x y + x - y = Java.isub x y + isZero x = Java.icmpeq Java.iconst_0 x + one = Java.iconst_1 + +even x = if isZero x then True else odd (x - one) +odd x = if isZero x then False else even (x - one) + +main = odd (8 :: Integer) +-- +false + diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues.scl new file mode 100644 index 000000000..554852045 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues.scl @@ -0,0 +1,6 @@ +a = b +b = a + +main = a +-- +???: Variables defined recursively must all be functions. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues2.scl new file mode 100644 index 000000000..7291bb990 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues2.scl @@ -0,0 +1,5 @@ +f g = a + where + a = g a +-- +3:11-3:12: Couldn't resolve variable a. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues3.scl new file mode 100644 index 000000000..020a967d5 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues3.scl @@ -0,0 +1,12 @@ +data Nat = O | S Nat + +// It is important for this test that even and or are not annotated +even O = True +even (S x) = odd x + +odd O = False +odd (S x) = even x + +main = even (S (S (S (S (S O))))) +-- +false \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues4.scl new file mode 100644 index 000000000..0315be34a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RecursiveValues4.scl @@ -0,0 +1,5 @@ +(foo, bar) = (foo, "Hello world!") + +main = "ERROR" +-- +1:1-1:11: Illegal left hand side of the definition. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RedBlackTrees.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RedBlackTrees.scl new file mode 100644 index 000000000..6f47bd013 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RedBlackTrees.scl @@ -0,0 +1,101 @@ +import "Prelude" + +// Version 1, 'untyped' +data Color = R | B + +deriving instance Show Color + +data RB a = E | T Color (RB a) a (RB a) + +rbToList :: RB a -> [a] +rbToList E = [] +rbToList (T _ l a r) = rbToList l + [a] + rbToList r + +deriving instance (Show a) => Show (RB a) + +// Insertion and membership test as by Okasaki +insert :: Ord a => a -> RB a -> RB a +insert x s = (match ins s with T _ a z b -> T B a z b) + where + ins E = T R E x E + ins s = match s with + T B a y b -> + if xy + then balance a y (ins b) + else s + T R a y b -> + if xy + then T R a y (ins b) + else s + +member :: Ord a => a -> RB a -> Boolean +member x E = False +member x (T _ a y b) + | xy = member x b + | otherwise = True + +// balance: first equation is new, to make it work with a weaker invariant +balance :: RB a -> a -> RB a -> RB a +balance (T R a x b) y (T R c z d) = T R (T B a x b) y (T B c z d) +balance (T R (T R a x b) y c) z d = T R (T B a x b) y (T B c z d) +balance (T R a x (T R b y c)) z d = T R (T B a x b) y (T B c z d) +balance a x (T R b y (T R c z d)) = T R (T B a x b) y (T B c z d) +balance a x (T R (T R b y c) z d) = T R (T B a x b) y (T B c z d) +balance a x b = T B a x b + +// deletion a la SMK +delete :: Ord a => a -> RB a -> RB a +delete x t = (match del t with + T _ a y b -> T B a y b + _ -> E) + where + del E = E + del (T _ a y b) + | xy = delformRight a y b + | otherwise = app a b + delformLeft a y b= match a with + T B _ _ _ -> balleft (del a) y b + _ -> T R (del a) y b + delformRight a y b = match b with + T B _ _ _ -> balright a y (del b) + _ -> T R a y (del b) + +balleft :: RB a -> a -> RB a -> RB a +balleft (T R a x b) y c = T R (T B a x b) y c +balleft bl x (T B a y b) = balance bl x (T R a y b) +balleft bl x (T R (T B a y b) z c) = T R (T B bl x a) y (balance b z (sub1 c)) + +balright :: RB a -> a -> RB a -> RB a +balright a x (T R b y c) = T R a x (T B b y c) +balright (T B a x b) y bl = balance (T R a x b) y bl +balright (T R a x (T B b y c)) z bl = T R (balance (sub1 a) x b) y (T B c z bl) + +sub1 :: RB a -> RB a +sub1 (T B a x b) = T R a x b +sub1 _ = fail "invariance violation" + +app :: RB a -> RB a -> RB a +app E x = x +app x E = x +app (T R a x b) (T R c y d) = + match app b c with + T R b' z c' -> T R(T R a x b') z (T R c' y d) + bc -> T R a x (T R bc y d) +app (T B a x b) (T B c y d) = + match app b c with + T R b' z c' -> T R(T B a x b') z (T B c' y d) + bc -> balleft a x (T B bc y d) +app a (T R b x c) = T R (app a b) x c +app (T R a x b) c = T R a x (app b c) + +testList = [4,6,2,7,4,7,2,5] + +main = rbToList (foldl (flip insert) E testList) +-- +[2, 4, 5, 6, 7] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Relations1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Relations1.scl new file mode 100644 index 000000000..b15c1b861 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Relations1.scl @@ -0,0 +1,18 @@ +import "StandardLibrary" + +Concat ?x ?y ?z :- + @bbf 1 + ?z = ?x + ?y + + @bfb 0.5 + startsWith ?z ?x + ?y = drop (length ?x) ?z + + @fbb 0.5 + endsWith ?z ?y + ?x = take (length ?z - length ?y) ?z + +main = select ?y where + Concat "Hello " ?y "Hello world!" +-- +[world!] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Relations2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Relations2.scl new file mode 100644 index 000000000..825685edc --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Relations2.scl @@ -0,0 +1,12 @@ +import "StandardLibrary" + +MyExecute ?procedure :- + @enforce + Execute (?procedure "Foo") + +main = do + v = ref "" + enforce MyExecute (v :=) + getRef v +-- +Foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RepeatedVariableInPattern.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RepeatedVariableInPattern.scl new file mode 100644 index 000000000..8e5cf084c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/RepeatedVariableInPattern.scl @@ -0,0 +1,6 @@ +invalidProject :: (a,a) -> a +invalidProject (a,a) = a + +main = "Not to be executed!" +-- +2:19-2:20: Repeated variable a in pattern. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SSATypingBug.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SSATypingBug.scl new file mode 100644 index 000000000..15ff01275 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SSATypingBug.scl @@ -0,0 +1,11 @@ +import "Prelude" + +test :: () -> [Integer] +test _ = do + header = [0] + rows = map (\foo -> map (\bar -> bar) [foo]) [1..5] + foldl (+) header rows + +main = test () +-- +[0, 1, 2, 3, 4, 5] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Scanl.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Scanl.scl new file mode 100644 index 000000000..67821ddef --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Scanl.scl @@ -0,0 +1,14 @@ +import "Prelude" hiding (scanl) + +scanl :: (b -> a -> b) -> b -> [a] -> [b] +scanl f initial l = build (loop initial 0) + where + len = length l + loop cur i accum cons = let nl = cons accum cur + in if i==len + then nl + else loop (f cur (l!i)) (i+1) nl cons + +main = scanl (+) 0 [1,2,3] +-- +[0, 1, 3, 6] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Search.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Search.scl new file mode 100644 index 000000000..352e92c74 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Search.scl @@ -0,0 +1,47 @@ +import "Prelude" hiding (findFirst) + +infinity = 1e9 + +@inline +findFirst :: (a -> Maybe b) -> [a] -> Maybe b +findFirst f l = loop 0 + where + len = length l + loop i + | i >= len = Nothing + | otherwise = match f (l!i) with + s @ (Just _) -> s + Nothing -> loop (i+1) + +dfsFirst :: (a -> Boolean) -> (a -> [a]) -> [a] -> (Maybe a) +dfsFirst acceptable successors initial = tryAll initial + where + tryAll l = findFirst loop l + loop p + | acceptable p = Just p + | otherwise = tryAll (successors p) + +data Weighted a = Weighted a Double + +//type SearchAlgorithm e a = +// (a -> Boolean) -> (a -> [Weighted a]) -> [Weighted a] -> Weighted (Maybe a) + +//dfs :: SearchAlgorithm e a +dfs :: (a -> Boolean) -> (a -> [Weighted a]) -> [Weighted a] -> Weighted (Maybe a) +dfs acceptable successors initial = foldl loop (Weighted Nothing infinity) initial + where + loop best@(Weighted _ bestW) (Weighted p w) + | w >= bestW = best + | acceptable p = Weighted (Just p) w + | otherwise = foldl loop best + $ map (\(Weighted p' w') -> Weighted p' (w+w')) + $ successors p + +/* +bfs :: SearchAlgorithm e a + +aStar :: (a -> Double) -> SearchAlgorithm e a +*/ +main = "Hello" +-- +Hello \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sections.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sections.scl new file mode 100644 index 000000000..2d7e57677 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sections.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = map (1/) $ map (*3) [1,2,3] +-- +[0.3333333333333333, 0.16666666666666666, 0.1111111111111111] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select1.scl new file mode 100644 index 000000000..f8d0359ec --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select1.scl @@ -0,0 +1,11 @@ +import "StandardLibrary" + +main = let + l = [1..3] + in + select (?x,?y) where + ?x <- l + ?y <- l + ?x = ?y +-- +[(1,1), (2,2), (3,3)] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select2.scl new file mode 100644 index 000000000..a4928238c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select2.scl @@ -0,0 +1,20 @@ +import "StandardLibrary" +import "Minigraph" + +main = withGraph do + a = resource "a" + b = map resource ["b0", "b1", "b2", "b3", "b4"] + r = map resource ["r0", "r1"] + + enforce + Statement a (r!0) (b!0) + Statement a (r!0) (b!1) + Statement a (r!1) (b!4) + Statement a (r!1) (b!3) + Statement (b!1) (r!0) (b!2) + R a :- {} + R ?x :- R ?y ; Statement ?y (r!0) ?x + S ?x :- R ?x ; Statement ?x (r!0) _ + sort $ map uriOf $ select ?x where S ?x +-- +[a, b1] diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select3.scl new file mode 100644 index 000000000..a3e4f44e8 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select3.scl @@ -0,0 +1,18 @@ +import "StandardLibrary" +import "Minigraph" + +main = withGraph do + a = resource "a" + b = map resource ["b0", "b1", "b2", "b3", "b4"] + r = map resource ["r0", "r1"] + + enforce + Statement a (r!0) (b!0) + Statement a (r!0) (b!1) + Statement a (r!1) (b!4) + Statement (b!1) (r!1) (b!3) + Statement (b!1) (r!0) (b!2) + sort $ map uriOf $ select ?x where + Statement a (r!0) (_ : Resource { #r1 = ?x }) +-- +[b3] diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select4.scl new file mode 100644 index 000000000..3199e9545 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select4.scl @@ -0,0 +1,18 @@ +import "StandardLibrary" +import "Minigraph" + +main = withGraph do + a = resource "a" + b = map resource ["b0", "b1", "b2"] + r = map resource ["r0", "r1"] + + enforce + Statement a (r!0) (b!0) + Statement a (r!0) (b!1) + Statement a (r!1) (b!1) + Statement a (r!1) (b!2) + sort $ map uriOf $ select ?x where + <|> Statement a (r!0) ?x + Statement a (r!1) ?x +-- +[b0, b1, b1, b2] diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select5.scl new file mode 100644 index 000000000..18172473f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select5.scl @@ -0,0 +1,11 @@ +import "StandardLibrary" +import "Minigraph" + +main = withGraph do + r = map resource ["r0", "r1"] + sort $ map uriOf $ select ?x where + Statement ?y (r!0) ?x + Statement ?x (r!1) ?y +-- +6:24-8:30: Failed to compile the query. +Unsolved variables: ?x, ?y \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select6.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select6.scl new file mode 100644 index 000000000..84e4df30e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select6.scl @@ -0,0 +1,6 @@ +import "StandardLibrary" + +main = select ?x where + (?x,?y) = (1,2) +-- +[1] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select7.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select7.scl new file mode 100644 index 000000000..b0be01ade --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select7.scl @@ -0,0 +1,6 @@ +import "StandardLibrary" + +main = select ?x where + (?x, 3) <- [(1,2),(2,3),(3,4)] +-- +[2] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select8.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select8.scl new file mode 100644 index 000000000..787704445 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select8.scl @@ -0,0 +1,10 @@ +import "StandardLibrary" + +Foo ?a ?b ?l :- + @ffb + (?a,?b) <- ?l + +main = select ?x where + Foo ?x 3 [(1,2),(2,3),(3,4)] +-- +[2] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select9.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select9.scl new file mode 100644 index 000000000..56806793c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Select9.scl @@ -0,0 +1,12 @@ +import "StandardLibrary" + +s1 = [1,2,3] +s2 = [1,3] + +main = do + C ?x :- + ?x <- s1 + ?x <- s2 + select ?x where C ?x +-- +[2] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SelfReferringContextInTypeClass.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SelfReferringContextInTypeClass.scl new file mode 100644 index 000000000..d2f1bd7a5 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SelfReferringContextInTypeClass.scl @@ -0,0 +1,6 @@ +class Ord a where + min :: Ord a => a -> a -> a + +main = "Not to be executed." +-- +2:12-2:15: Unresolved type class Ord. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization.scl new file mode 100644 index 000000000..e0d44e357 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization.scl @@ -0,0 +1,14 @@ +import "Prelude" + +rt :: Serializable a => a -> a +rt v = deserialize (serialize v) + +main :: String +main = show ( + (rt "Hello", rt ()), + (rt 1.2 :: Double, rt 1.2 :: Float, 3 :: Integer, 4 :: Long), + rt (Just (1 :: Integer)), + (rt [1::Integer,2,3], rt [[1::Integer,2],[3,4]], fromDoubleArray (rt (toDoubleArray [3::Double,2,1]))) + ) +-- +(("Hello", ()), (1.2, 1.2, 3, 4), Just 1, ([1, 2, 3], [[1, 2], [3, 4]], [3.0, 2.0, 1.0])) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization2.scl new file mode 100644 index 000000000..8384527e7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization2.scl @@ -0,0 +1,14 @@ +import "Prelude" +import "Serialization" + +rt :: IO a => a -> a +rt v = readByteArray (writeByteArray v) + +main = show ( + (rt "Hello", rt ()), + (rt 1.2 :: Double, rt 1.2 :: Float, 3 :: Integer, 4 :: Long), + rt (Just (1 :: Integer)), + (rt [1::Integer,2,3], rt [[1::Integer,2],[3,4]], fromDoubleArray (rt (toDoubleArray [3,2,1]))) + ) +-- +(("Hello", ()), (1.2, 1.2, 3, 4), Just 1, ([1, 2, 3], [[1, 2], [3, 4]], [3.0, 2.0, 1.0])) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization3.scl new file mode 100644 index 000000000..d883dfea7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Serialization3.scl @@ -0,0 +1,22 @@ +import "Prelude" +import "Serialization" as Serialization + +rt :: Serialization.IO a => a -> a +rt v = Serialization.readByteArray (Serialization.writeByteArray v) + +data FooBar a = Foo Integer | Bar a + +deriving instance (Show a) => Show (FooBar a) +deriving instance (Serialization.IO a) => Serialization.IO (FooBar a) + +/* +instance IO FooBar where + read s = match Serialization.read s :: Integer with + 0 -> Foo (Serialization.read s) + 1 -> Bar (Serialization.read s) + write s (Foo x) = do Serialization.write s (0 :: Integer) ; Serialization.write s x + write s (Bar x) = do Serialization.write s (1 :: Integer) ; Serialization.write s x +*/ +main = show (rt (Foo 3 :: FooBar Double)) +-- +Foo 3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Set1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Set1.scl new file mode 100644 index 000000000..b868ecf89 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Set1.scl @@ -0,0 +1,9 @@ +import "StandardLibrary" + +s1 = Set.set [3,2,1,4] +s2 = Set.set [9,8,3,2] +s1s2 = Set.union s1 s2 + +main = show s1s2 +-- +set [1, 2, 3, 4, 8, 9] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SharedTypeVariable.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SharedTypeVariable.scl new file mode 100644 index 000000000..19fd565e3 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SharedTypeVariable.scl @@ -0,0 +1,8 @@ +// Idea here is that the type variable in the top level type annotation +// and the type annotation in the expression should be the same type. +id :: a -> a +id x = (x :: a) + +main = id "OK" +-- +OK \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ShortcutFusion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ShortcutFusion.scl new file mode 100644 index 000000000..6423ecbef --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ShortcutFusion.scl @@ -0,0 +1,25 @@ +data List a = Nil | Cons a (List a) + +@private +@inline +build :: (forall a. a -> (b -> a -> a) -> a) -> List b +build f = f Nil Cons + +@private +foldr :: (a -> b -> b) -> b -> List a -> b +foldr cons nil Nil = nil +foldr cons nil (Cons h t) = cons h (foldr cons nil t) + +@private +@inline +singleton :: a -> List a +singleton x = build (\nil cons -> cons x nil) + +@private +@inline +last :: List a -> a -> a +last l def = foldr (\x _ -> x) def l + +main = last (singleton "Hello") "Foo" +-- +Hello \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Show1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Show1.scl new file mode 100644 index 000000000..649f3cbce --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Show1.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = show [(1,2),(3,4),(5,6)] +-- +[(1, 2), (3, 4), (5, 6)] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Signals.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Signals.scl new file mode 100644 index 000000000..726a3f5be --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Signals.scl @@ -0,0 +1,34 @@ +import "Prelude" + +// --- Signals ------------------------------------------------------ + +data Signal = + SigSum [Signal] + | SigConst Double + | SigNeg Signal + | SigMul [Signal] + +deriving instance Eq Signal +deriving instance Hashable Signal +deriving instance Show Signal + +instance Additive Signal where + zero = SigConst 0 + a + b = SigSum [a,b] + sum l = SigSum l + +instance Ring Signal where + one = SigConst 1 + neg a = SigNeg a + fromInteger i = SigConst (fromInteger i) + a * b = SigMul [a,b] + +/* +instance Real Signal where + fromDouble d = SigConst d +*/ + +main :: Signal +main = 1 + 2 * 3 - 4 +-- +??? \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SinConst1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SinConst1.scl new file mode 100644 index 000000000..66621b13b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SinConst1.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = (sin + const 1) 0 +-- +1.0 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sort.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sort.scl new file mode 100644 index 000000000..7efdf8941 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sort.scl @@ -0,0 +1,6 @@ +import "Prelude" + +main :: [Integer] +main = sort [1,5,2,4,3] +-- +[1, 2, 3, 4, 5] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sort2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sort2.scl new file mode 100644 index 000000000..8518264ec --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Sort2.scl @@ -0,0 +1,19 @@ +import "JavaBuiltin" as Java + +importJava "org.simantics.scl.runtime.Lists" where + sortWith :: (a -> a -> Integer) -> [a] -> [a] + +//@JavaStaticMethod "org.simantics.scl.runtime.Lists.sortWith" +//sortWith :: (a -> a -> Integer) -> [a] -> [a] + + +//sortWith = Java.staticMethod "org.simantics.scl.runtime.Lists.sortWith" + +dumbCompare :: a -> a -> Integer +dumbCompare x y = 0 + +dumbSort = sortWith dumbCompare + +main = "Foo" +-- +Foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SpecConstr1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SpecConstr1.scl new file mode 100644 index 000000000..4ff7d476f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SpecConstr1.scl @@ -0,0 +1,25 @@ +data Either a b = Left a | Right b + +data List a = Nil | Cons a (List a) + +data Nat = Zero | Succ Nat + +sum Zero a = a +sum a Zero = a +sum (Succ a) (Succ b) = Succ (Succ (sum a b)) + +sum_append xs ys + = go Zero (Left xs) + where + go z (Left xs) + = match xs with + Nil -> go z (Right ys) + Cons x xs' -> go (sum x z) (Left xs') + go z (Right ys) + = match ys with + Nil -> z + Cons y ys' -> go (sum y z) (Right ys') + +main = "Hello world!" +-- +Hello world! \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StackTrace.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StackTrace.scl new file mode 100644 index 000000000..fe30fa3af --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StackTrace.scl @@ -0,0 +1,3 @@ +main = fail "badly" +-- +??? \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StreamFusion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StreamFusion.scl new file mode 100644 index 000000000..6d1864a22 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StreamFusion.scl @@ -0,0 +1,139 @@ +import "JavaBuiltin" as Java + +data Either a b = Left a | Right b + +data Stream a = Stream (s -> Step a s) s +data Step a s = Done | Yield a s | Skip s + +// stream :: [a] -> Stream a +// unstream :: Stream a -> [a] +// streamRev :: [a] -> Stream a +// unstreamRev :: Stream a -> [a] + +//toStream :: [a] -> Stream a +//toStream l = Stream (\i -> if i >= length l then Done else Yield (get l i) (i+1)) 0 + +filterS :: (a -> Boolean) -> Stream a -> Stream a +filterS p (Stream next0 s0) = Stream next s0 + where + next s = match next s with + Done -> Done + Skip s -> Skip s + Yield a s -> if p a then Yield a s else Skip s + +mapS :: (a -> b) -> Stream a -> Stream b +mapS f (Stream next0 s0) = Stream next s0 + where + next s = match next0 s with + Done -> Done + Skip s -> Skip s + Yield a s -> Yield (f a) s + +appendS :: Stream a -> Stream a -> Stream a +appendS (Stream next1 s1) (Stream next2 s2) = Stream next (Left s1) + where + next (Left s) = match next1 s with + Done -> Skip (Right s2) + Skip s -> Skip (Left s) + Yield a s -> Yield a (Left s) + next (Right s) = match next2 s with + Done -> Done + Skip s -> Skip (Right s) + Yield a s -> Yield a (Right s) + +decomposeS :: Stream a -> Maybe (a, Stream a) +decomposeS (Stream next s0) = loop s0 + where + loop s = match next s with + Done -> Nothing + Skip s -> loop s + Yield a s -> Just (a, Stream next s) + +returnS :: a -> Stream a +returnS x = Stream next True + where + next True = Yield x False + next False = Done + +isEmptyS :: Stream a -> Boolean +isEmptyS (Stream next s0) = loop s0 + where + loop s = match next s with + Done -> True + Skip s -> loop s + Yield _ _ -> False + +foldlS :: (a -> b -> a) -> a -> Stream b -> a +foldlS f init (Stream next s0) = go init s0 + where + go cur s = match next s with + Done -> cur + Skip s -> go cur s + Yield x s -> go (f cur x) s + +scanlS :: (a -> b -> a) -> a -> Stream b -> Stream a +scanlS f init (Stream next0 s0) = Stream next (s0, init) + where + next (s,v) = match next0 s with + Done -> Done + Skip s -> Skip (s, v) + Yield x s -> Yield v (s, f v x) + +concatMapS :: (a -> Stream b) -> Stream a -> Stream b +concatMapS f (Stream next0 s0) = Stream next (s0, Nothing) + where + next (s, Nothing) = match next0 s with + Done -> Done + Skip s -> Skip (s, Nothing) + Yield x s -> Skip (s, Just (f x)) + next (s0, Just (Stream next1 s1)) = match next1 s1 with + Done -> Skip (s0, Nothing) + Skip s -> Skip (s0, Just (Stream next1 s)) + Yield x s -> Yield x (s0, Just (Stream next1 s)) + +zipWithS :: (a -> b -> c) -> Stream a -> Stream b -> Stream c +zipWithS f (Stream next0 s0) (Stream next1 s1) = Stream next (s0, s1, Nothing) + where + next (s0, s1, Nothing) = match next0 s0 with + Done -> Done + Skip s -> Skip (s, s1, Nothing) + Yield x s -> Skip (s, s1, Just x) + next (s0, s1, Just x) = match next1 s1 with + Done -> Done + Skip s -> Skip (s0, s, Just x) + Yield y s -> Yield (f x y) (s0, s, Nothing) + +guardS :: Boolean -> Stream a -> Stream a +guardS b (Stream next0 s0) = Stream next (b, s0) + where + next (False, _) = Done + next (True, s) = match next0 s with + Done -> Done + Skip s -> Skip (True, s) + Yield x s -> Yield x (True, s) +/* +takeS :: Integer -> Stream a -> Stream a +takeS count (Stream next0 s0) = Stream next (count, s0) + where + next (count, s) = if count <= 0 then Done + else match next0 s with + Done -> Done + | Skip s -> Skip (count, s) + | Yield x s -> Yield x (count, s) +*/ +repeatS :: a -> Stream a +repeatS v = Stream next () + where + next () = Yield v () + +iterateS :: (a -> a) -> a -> Stream a +iterateS f v = Stream next v + where + next v = Yield v (f v) + +main :: Integer +main = foldlS Java.iadd (0 :: Integer) + (appendS (appendS (returnS (1 :: Integer)) + (returnS (2 :: Integer))) (returnS (3 :: Integer))) +-- +6 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringEscape.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringEscape.scl new file mode 100644 index 000000000..51a75d3cb --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringEscape.scl @@ -0,0 +1,12 @@ +main = "a\nb\"c\'d" +-- +a +b"c'd +-- +main = "a\u0053" +-- +aS +-- +main = "a\xb" +-- +1:8-1:10: Illegal string escape character. diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringInterpolation1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringInterpolation1.scl new file mode 100644 index 000000000..eabad781a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringInterpolation1.scl @@ -0,0 +1,9 @@ +import "Prelude" + +f x = x + 1 + +g a b = """\(a) + \(b) = \(a+b)""" + +main = "f 3 = \(f 3), " + g 1 2 +-- +f 3 = 4, 1 + 2 = 3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringInterpolation2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringInterpolation2.scl new file mode 100644 index 000000000..9d219430b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringInterpolation2.scl @@ -0,0 +1,6 @@ +stringSum :: String -> Integer +stringSum "(\(a),\(b),\(c))" = a + b + c + +main = stringSum "(1,2,3)" +-- +6 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringMatching1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringMatching1.scl new file mode 100644 index 000000000..5865926af --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/StringMatching1.scl @@ -0,0 +1,7 @@ +main :: Integer +main = match "Bar" with + "Foo" -> 1 + "Bar" -> 2 + _ -> 3 +-- +2 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SumOfInverses2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SumOfInverses2.scl new file mode 100644 index 000000000..d3cacbae2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/SumOfInverses2.scl @@ -0,0 +1,8 @@ +import "Prelude" + +f :: Integer -> Double +f m = sum [1/(fromInteger x) | x <- [1..m]] + +main = f 100 +-- +5.187377517639621 diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Timing.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Timing.scl new file mode 100644 index 000000000..deb6d507c --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Timing.scl @@ -0,0 +1,10 @@ +import "StandardLibrary" + +main = do + (r,t) = Debug.time (foldl (+) 0 + $ map (\(_,_,z) -> z) + $ [(a,b,c) | a <- [1..50], b <- [1..50], c <- [1..50], a*a + b*b == c*c]) + print t + r +-- +1172 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TooManyParametersToSin.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TooManyParametersToSin.scl new file mode 100644 index 000000000..bfaf3db56 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TooManyParametersToSin.scl @@ -0,0 +1,6 @@ +import "Prelude" + +main = sin 1 2 +-- +3:8-3:11: Constrain Real (a -> b) contains free variables not mentioned in the type of the value. +3:14-3:15: Constrain Ring a contains free variables not mentioned in the type of the value. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation1.scl new file mode 100644 index 000000000..144b03155 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation1.scl @@ -0,0 +1,59 @@ +import "StandardLibrary" +import "Minigraph" +import "MMap" as MMap + +consistsOf :: Integer +consistsOf = resource "consistsOf" +instanceOf :: Integer +instanceOf = resource "instanceOf" +areConnected :: Integer +areConnected = resource "areConnected" +from :: Integer +from = resource "from" +to :: Integer +to = resource "to" + +element :: Integer +element = resource "Element" +connection :: Integer +connection = resource "Connection" + +mapping relation MapDiagrams Integer Integer + +rule ElementsRule where + @when + MapDiagrams ?dA ?dB + + @from + Statement ?dA consistsOf ?elA + Statement ?elA instanceOf element + + @to + Statement ?dB consistsOf ?elB + Statement ?elB instanceOf element + + @where + MapElements ?elA ?elB + +rule ConnectionsRule where + @when + MapElements ?elA1 ?elB1 + MapElements ?elA2 ?elB2 + + @from + Statement ?elA1 areConnected ?elA2 + + @to + Statement ?conn instanceOf connection + Statement ?conn from ?elB1 + Statement ?conn to ?elB2 + +foo :: () +foo = transformation OneShotForward where + MapDiagrams 0 0 + +main = withGraph do + foo + "OK" +-- +OK diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation2.scl new file mode 100644 index 000000000..dbb1609a9 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation2.scl @@ -0,0 +1,25 @@ +import "StandardLibrary" + +mapping relation Fib Integer Integer + +rule FibRecurrence where + @when + Fib ?n ?a + Fib (?n+1) ?b + ?n < 20 + + @where + Fib (?n+2) (?a + 1) +/* +rule PrintIt where + @when + Fib ?n ?a + + @to + Execute (print "\(?n) -> \(?a)") +*/ +main = transformation OneShotForward where + Fib 0 1 + Fib 1 1 +-- +() diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation3.scl new file mode 100644 index 000000000..f9b995cee --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation3.scl @@ -0,0 +1,32 @@ +import "StandardLibrary" + +mapping relation Fib Integer Integer + +rule FibRecurrence where + @when + Fib ?n (?a + ?b) + ?n >= 2 + + @where + Fib (?n-1) ?b + Fib (?n-2) ?a + +rule Init where + @when + Fib ?x 1 + ?x < 2 + +rule Seed where + @where + Fib 20 ?hmm + +rule PrintIt where + @when + Fib ?n ?a + + @to + Execute (print "\(?n) -> \(?a)") + +main = transformation OneShotForward where +-- +() diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation4.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation4.scl new file mode 100644 index 000000000..5a889e1e0 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation4.scl @@ -0,0 +1,27 @@ +import "StandardLibrary" + +mapping relation M Integer (Integer,Integer) + +rule Mix where + @when + M ?a (?b, ?c) + ?a <= 10 + + @where + M (?a + 1) (?c, ?b) + +rule PrintIt where + @when + M ?a (?b,?c) + + @to + Execute (print "\(?a) -> \(?b), \(?c)") + +rule Seed where + @where + M 0 (1,?x) + M 10 (?y,2) + +main = transformation OneShotForward where +-- +() diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation5.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation5.scl new file mode 100644 index 000000000..e041430ee --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation5.scl @@ -0,0 +1,22 @@ +import "StandardLibrary" + +Foo ?x :- + @enforce 1 + Execute (?x := (1 :: Integer)) + +Bar ?x :- + @enforce 2 + Execute (if getRef ?x == 1 then () else fail "Test failed.") + +rule DoIt where + @from + ?x = ref (0 :: Integer) + + @to + Bar ?x + Foo ?x + +main :: () +main = transformation OneShotForward where +-- +() diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation6.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation6.scl new file mode 100644 index 000000000..74aed46dc --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation6.scl @@ -0,0 +1,15 @@ +import "StandardLibrary" + +mapping relation Foo String String + +rule DoIt where + @when + Foo ?a ?b + + @to + Foo ?b "c" + +main = transformation OneShotForward where + Foo "a" "b" +-- +10:9-10:11: Cannot resolve the variable ?b using the source patterns. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation7.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation7.scl new file mode 100644 index 000000000..cce48f6ed --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Transformation7.scl @@ -0,0 +1,14 @@ +import "StandardLibrary" + +Foo ?x :- + @enforce + Execute (iterList printString [?x :: String]) + + +rule DoIt where + @to + Foo "Hello world!" + +main = transformation OneShotForward where +-- +() diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TransformationOrder.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TransformationOrder.scl new file mode 100644 index 000000000..36c08c7b7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TransformationOrder.scl @@ -0,0 +1,17 @@ +import "StandardLibrary" + +rule A where + @to + Execute (print "A") + +rule B where + @to + Execute (print "B") + +rule C where + @to + Execute (print "C") + +main = transformation OneShotForward where +-- +() diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Tuples.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Tuples.scl new file mode 100644 index 000000000..5f70e4bea --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Tuples.scl @@ -0,0 +1,18 @@ +id0 () = () + +id0A :: () -> () +id0A () = () + +id2 (a,b) = (a,b) + +id2A :: (a,b) -> (a,b) +id2A (a,b) = (a,b) + +id3 (a,b,c) = (a,b,c) + +id3A :: (a,b,c) -> (a,b,c) +id3A (a,b,c) = (a,b,c) + +main = id3 (1 :: Integer,id0 (),3 :: Integer) +-- +(1,(),3) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Tuples2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Tuples2.scl new file mode 100644 index 000000000..75b478513 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Tuples2.scl @@ -0,0 +1,6 @@ +// This is just a restricted version of Tuples test +id0 () = () + +main = id0 () +-- +() \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias1.scl new file mode 100644 index 000000000..3aad9bf4f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias1.scl @@ -0,0 +1,9 @@ + +type Id = Integer + +incrementId :: Id -> Id +incrementId x = x + +main = incrementId 3 +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias2.scl new file mode 100644 index 000000000..61925153b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias2.scl @@ -0,0 +1,8 @@ +type List a = [a] + +convert :: List Integer -> List Double +convert v = v + +main = "Not to be executed." +-- +4:13-4:14: Expected <[Double]> got <[Integer]>. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias3.scl new file mode 100644 index 000000000..b25a8abfe --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAlias3.scl @@ -0,0 +1,9 @@ +type IntegerList = [Integer] +type DoubleList = [Double] + +convert :: IntegerList -> DoubleList +convert v = v + +main = "Not to be executed." +-- +5:13-5:14: Expected <[Double]> got <[Integer]>. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAliasRefsToTypeAlias.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAliasRefsToTypeAlias.scl new file mode 100644 index 000000000..7ebb60636 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAliasRefsToTypeAlias.scl @@ -0,0 +1,22 @@ +type Foo = Bar +type Bar = Integer +main = 1 :: Foo +-- +1 +-- +type Bar = Integer +type Foo = Bar +main = 1 :: Foo +-- +1 +-- +type Foo = Foo +main = 1 :: Foo +-- +1:1-1:15: Type alias has a self reference. +-- +type Foo = Bar +type Bar = Foo +main = 1 :: Foo +-- +1:1-1:15: Recursively defined type alias (Foo, Bar). \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAnnotation1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAnnotation1.scl new file mode 100644 index 000000000..5ba565f12 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAnnotation1.scl @@ -0,0 +1,5 @@ +id x = x :: Integer + +main = id "foo" +-- +3:11-3:16: Expected got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAnnotation2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAnnotation2.scl new file mode 100644 index 000000000..ab855f8dc --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeAnnotation2.scl @@ -0,0 +1,5 @@ +id (x :: Integer) = x + +main = id "foo" +-- +3:11-3:16: Expected got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClass.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClass.scl new file mode 100644 index 000000000..540d44e0e --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClass.scl @@ -0,0 +1,10 @@ + +class Foo a where + foo :: a -> Integer + +instance Foo Integer where + foo x = x + +main = foo (13 :: Integer) +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClass2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClass2.scl new file mode 100644 index 000000000..5bd09350b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClass2.scl @@ -0,0 +1,28 @@ +import "JavaBuiltin" as Java + +(+) = Java.iadd + +class Foo a where + foo :: a -> Integer + /* +class (Foo a) => Bar a where + bar :: a -> Integer + */ +instance Foo Integer where + foo x = x+1 + /* +instance Bar Integer where + bar x = x+2 +*/ +data X a = X a + +instance (Foo a) => Foo (X a) where + foo (X a) = foo a + /* +instance (Bar a) => Bar (X a) where + bar (X a) = bar a*/ + +main = foo (X (1 :: Integer)) +// + bar (X (2 :: Integer)) +-- +2 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClassBug1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClassBug1.scl new file mode 100644 index 000000000..2ea51bef6 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClassBug1.scl @@ -0,0 +1,19 @@ +import "JavaBuiltin" as Java + +importJava "org.simantics.scl.runtime.Lists" where + foldl :: (a -> b -> a) -> a -> [b] -> a + +class Additive a where + zero :: a + (+) :: a -> a -> a + + sum :: [a] -> a + sum = foldl (+) zero + +instance (Additive a, Additive b, Additive c) => Additive (a, b, c) where + zero = (zero, zero, zero) + (a0, b0, c0) + (a1, b1, c1) = (a0+a1, b0+b1, c0+c1) + +main = "OK" +-- +OK \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClassBug2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClassBug2.scl new file mode 100644 index 000000000..a341ba6b2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeClassBug2.scl @@ -0,0 +1,54 @@ +data Foo1 a = Foo1 a +data Foo2 a = Foo2 a + +foo1 :: Foo1 a -> a +foo1 (Foo1 x) = x + +foo2 :: Foo2 a -> a +foo2 (Foo2 x) = x + +class Makeable s where + make :: a -> s a + +instance Makeable Foo1 where + make = Foo1 + +instance Makeable Foo2 where + make = Foo2 + +class (Makeable f) => Foo f where + foo :: f a -> a + +class (Makeable b) => Bar b where + bar :: b a -> a + +class (Makeable b) => Baz b where + baz :: b a -> a + +class (Makeable b) => Bim b where + bim :: b a -> a + +instance Foo Foo1 where + foo = foo1 + +instance Bar Foo2 where + bar = foo2 + +instance (Bar b) => Baz b where + baz = bar + +instance Bim Foo1 where + bim = foo1 + +instance (Baz b) => Bim b where + bim = baz + +doFoo1 (Foo1 x) = x +doFoo2 (Foo2 x) = x + +useBim :: Bim b => (forall a. b a -> a) -> a -> [a] +useBim doit x = [doit (make x), bim (make x :: Foo1 a)] + +main = "OK" +-- +"OK" diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeInferenceBug2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeInferenceBug2.scl new file mode 100644 index 000000000..4fa08a52d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeInferenceBug2.scl @@ -0,0 +1,9 @@ +import "Prelude" + +distance (x1,y1) (x2,y2) = let dx = x1-x2 + dy = y1-y2 + in sqrt (dx*dx + dy*dy) print x1 +-- +5:31-5:35: Constrain Real ((a -> ()) -> ((c -> ()) -> e -> f) -> i) contains free variables not mentioned in the type of the value. +5:52-5:57: Constrain Show a contains free variables not mentioned in the type of the value. +5:58-5:60: Unification of types failed. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeOf1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeOf1.scl new file mode 100644 index 000000000..933a29b79 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypeOf1.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = typeOf (\(a,b) -> a+b :: Double) +-- +(Double, Double) -> Double \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingBug1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingBug1.scl new file mode 100644 index 000000000..3e69ebf52 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingBug1.scl @@ -0,0 +1,4 @@ +id x = x +main = id id (5 :: Integer) +-- +5 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingError1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingError1.scl new file mode 100644 index 000000000..9f39243c4 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingError1.scl @@ -0,0 +1,9 @@ +a :: Double +a = a + +id :: Integer -> Integer +id x = x + +b = id a +-- +7:8-7:9: Expected got . \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingError2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingError2.scl new file mode 100644 index 000000000..7632ffcef --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/TypingError2.scl @@ -0,0 +1,9 @@ +a :: Integer +a = a + +id :: Integer -> Integer +id x = x + +b = id a a +-- +7:5-7:11: Function of arity 1 is applied with 2 parameters. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnaryMinus.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnaryMinus.scl new file mode 100644 index 000000000..ff0e51271 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnaryMinus.scl @@ -0,0 +1,5 @@ +import "Prelude" + +main = -5 +-- +-5 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UndefinedValue.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UndefinedValue.scl new file mode 100644 index 000000000..02de8b645 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UndefinedValue.scl @@ -0,0 +1,6 @@ + +foo :: Integer +// foo = 0 + +-- +2:1-2:15: foo is not defined. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnexpectedToken.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnexpectedToken.scl new file mode 100644 index 000000000..270d5751b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnexpectedToken.scl @@ -0,0 +1,4 @@ +a = = +b = 4 +-- +1:5-1:6: Unexpected token '=' (EQUALS). Expected one of ATTACHED_HASH, BEGIN_STRING, BLANK, CHAR, DO, ENFORCE, EQ, ESCAPED_SYMBOL, FLOAT, ID, IF, INTEGER, LAMBDA, LBRACKET, LET, LPAREN, MATCH, MDO, MINUS, SELECT, SELECT_DISTINCT, SELECT_FIRST, TRANSFORMATION, WHEN. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Unification1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Unification1.scl new file mode 100644 index 000000000..a174362f4 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Unification1.scl @@ -0,0 +1,28 @@ +import "JavaBuiltin" as Java +import "StandardLibrary" +import "Unification" + +pair :: Default a => Default b => UTag (a, b) (Unifiable a, Unifiable b) +pair = uTag 0 (\(ua, ub) -> (extract ua, extract ub)) Java.unsafeCoerce + +/*triple :: Default a => Default b => Default c => + UTag (a, b, c) (Unifiable a, Unifiable b, Unifiable c)*/ +triple = uTag 0 (\(ua, ub, uc) -> (extract ua, extract ub, extract uc)) Java.unsafeCoerce + +main :: (Integer,Integer,Integer) +main = do + um1 = createUMap + um2 = createUMap + v1 = uVar + v2 = uVar + v3 = uVar + vX = uVar + putUMap um1 "a" (uCons triple (v1, v2, v3)) + putUMap um1 "a" (uCons triple (v2, v3, v1)) + putUMap um1 "a" (uCons triple (vX, uVar, uVar)) + putUMap um2 "b" vX + putUMapC um2 "b" 12 + + getUMap um1 "a" +-- +(12,12,12) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnknownAnnotation.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnknownAnnotation.scl new file mode 100644 index 000000000..c1b5ef8ea --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnknownAnnotation.scl @@ -0,0 +1,5 @@ + +@sdlfkmsdlfkm +main = "Not to be executed" +-- +2:1-2:14: Unknown annotation. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedClass.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedClass.scl new file mode 100644 index 000000000..0e1765c4d --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedClass.scl @@ -0,0 +1,8 @@ + +data List a = Nil | Cons a (List a) + +instance Monoid List where + zero = Nil + +-- +4:10-4:16: Couldn't resolve class Monoid. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedTypeInAnnotation.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedTypeInAnnotation.scl new file mode 100644 index 000000000..18e075104 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedTypeInAnnotation.scl @@ -0,0 +1,4 @@ +main :: List Integer +main = 13 +-- +1:9-1:13: Didn't find type constructor List. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedTypeInInstance.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedTypeInInstance.scl new file mode 100644 index 000000000..1b5400cb0 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedTypeInInstance.scl @@ -0,0 +1,9 @@ +class Functor f where + map :: (a -> b) -> f a -> f b + +data Iddd a = Idd a + +instance Functor Idd where + map (Idd x) = x +-- +6:18-6:21: Didn't find type constructor Idd. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedVariable.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedVariable.scl new file mode 100644 index 000000000..ad28907ee --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedVariable.scl @@ -0,0 +1,4 @@ +a = b + +-- +1:5-1:6: Couldn't resolve variable b. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedVariable2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedVariable2.scl new file mode 100644 index 000000000..32438cda2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/UnresolvedVariable2.scl @@ -0,0 +1,7 @@ + +a = a +b = b +c = a + b + +-- +4:7-4:8: Couldn't resolve variable +. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ValueAsOperator.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ValueAsOperator.scl new file mode 100644 index 000000000..37235370f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ValueAsOperator.scl @@ -0,0 +1,8 @@ + +data List a = Nil | Cons a (List a) + +data Foo = Foo + +main = Foo `Cons` (Foo `Cons` Nil) +-- +(Cons Foo (Cons Foo Nil)) \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ValueConversion.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ValueConversion.scl new file mode 100644 index 000000000..3afda1b32 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/ValueConversion.scl @@ -0,0 +1,6 @@ +import "Prelude" +import "Vector" + +main = fromDynamic (toDynamic (vector [3 :: Double])) :: [Double] +-- +[3.0] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Vector1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Vector1.scl new file mode 100644 index 000000000..33b6c86df --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Vector1.scl @@ -0,0 +1,8 @@ +import "StandardLibrary" + +a :: Vector Double +a = vector [1,2,3] + +main = map (a !) [0..length a-1] +-- +[1.0, 2.0, 3.0] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Vector2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Vector2.scl new file mode 100644 index 000000000..43c0c5359 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Vector2.scl @@ -0,0 +1,8 @@ +import "StandardLibrary" + +convertDataset :: [Double] -> [Double] -> Vector (Vector Double) +convertDataset xs ys = vector [vector xs, vector ys] + +main = "Foo" +-- +Foo \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void1.scl new file mode 100644 index 000000000..40a710fa2 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void1.scl @@ -0,0 +1,16 @@ +importJava "java.util.List" where + data List a + + @JavaName add + addList :: List a -> a -> Boolean + +importJava "java.util.ArrayList" where + @JavaName "" + newList :: () -> (List a) + +main = do + l = newList () + addList l (3 :: Integer) + l +-- +[3] \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void2.scl new file mode 100644 index 000000000..f953aaf58 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void2.scl @@ -0,0 +1,13 @@ +import "JavaBuiltin" as Java + +class Foo a where + foo :: a -> () -> a + +instance Foo Integer where + foo x () = x + +idWithFoo x = foo x () + +main = idWithFoo (13 :: Integer) +-- +13 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void3.scl new file mode 100644 index 000000000..0530c8a11 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Void3.scl @@ -0,0 +1,12 @@ +import "JavaBuiltin" as Java + +data Foo = Foo () + + +ff = Foo () + +gg () = 3 :: Integer + +main = gg (match ff with Foo a -> a) +-- +3 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While.scl new file mode 100644 index 000000000..3e450439b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While.scl @@ -0,0 +1,10 @@ + +while :: ( Boolean) -> ( a) -> () +while cond body = loop () + where loop _ = if cond + then do body ; loop () + else () + +main = "FOO" +-- +FOO \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While2.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While2.scl new file mode 100644 index 000000000..6567c22ab --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While2.scl @@ -0,0 +1,12 @@ +import "Prelude" hiding (while) + +while :: Maybe Boolean -> Maybe a -> Maybe () +while condM bodyM = mdo + cond <- condM + if cond + then bodyM >> while condM bodyM + else return () + +main = "FOO" +-- +FOO \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While3.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While3.scl new file mode 100644 index 000000000..052076958 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/While3.scl @@ -0,0 +1,11 @@ +import "Prelude" + +main = do + a = ref 1 + b = ref 0 + while (getRef a < 5) do + b := getRef b + 1 + a := getRef a + 1 + getRef b +-- +4 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/WrongDefaultMethod.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/WrongDefaultMethod.scl new file mode 100644 index 000000000..d94046b4a --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/WrongDefaultMethod.scl @@ -0,0 +1,8 @@ + +class Foo a where + foo :: a + bar = foo + +main = "Not to be executed." +-- +4:5-4:14: Method bar is not defined in this class. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/WrongInstanceMethod.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/WrongInstanceMethod.scl new file mode 100644 index 000000000..2cdc4e86b --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/WrongInstanceMethod.scl @@ -0,0 +1,11 @@ + +class Foo a where + foo :: a + +instance Foo Integer where + foo = foo + bar = foo + +main = "Not to be executed." +-- +7:5-7:14: Method bar is not defined in the type class Foo. \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Arithmetic.sts b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Arithmetic.sts new file mode 100644 index 000000000..e8f7dce07 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Arithmetic.sts @@ -0,0 +1,12 @@ +> 1+1 +2 +> 1-1 +0 +> 1+1.0 +2.0 +> 2*5 +10 +> 4/3 +1.3333333333333333 +> 4 `div` 3 +1 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Functions.sts b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Functions.sts new file mode 100644 index 000000000..76348b876 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Functions.sts @@ -0,0 +1,20 @@ +> id x = x +> id 2 +2 +> id "Hello!" +"Hello!" + +> id = \x -> x +> id 2 +2 + +> fib 0 = 1 +> fib 1 = 1 +> fib n = fib (n-1) + fib (n-2) + +> fib 2 +2 +> fib 3 +3 +> fib 4 +5 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Functions2.sts b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Functions2.sts new file mode 100644 index 000000000..9879931b7 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Functions2.sts @@ -0,0 +1,5 @@ +> f x = x + 1 +> f 3 +4 +> f 4.5 +5.5 \ No newline at end of file diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Lists.sts b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Lists.sts new file mode 100644 index 000000000..024db2467 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scripts/Lists.sts @@ -0,0 +1,5 @@ +> [1,2,3] +[1, 2, 3] + +> [5..9] +[5, 6, 7, 8, 9] diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestNamespaceFilter.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestNamespaceFilter.java new file mode 100644 index 000000000..fa3bd9f65 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestNamespaceFilter.java @@ -0,0 +1,89 @@ +package org.simantics.scl.compiler.tests.unit; + +import java.util.Collection; + +import org.junit.Test; +import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter; +import org.simantics.scl.compiler.environment.filter.NamespaceFilter; +import org.simantics.scl.compiler.environment.filter.NamespaceFilters; +import org.simantics.scl.compiler.environment.filter.NegativeNamespaceFilter; +import org.simantics.scl.compiler.environment.filter.PositiveNamespaceFilter; + +import gnu.trove.set.hash.THashSet; +import junit.framework.Assert; + +public class TestNamespaceFilter { + + private void testBooleanOperations(Collection all, NamespaceFilter a, NamespaceFilter b) { + { + NamespaceFilter c = NamespaceFilters.union(a, b); + //System.out.println("union(" + a + ", " + b + ") = " + c); + for(String name : all) + Assert.assertEquals( + a.isValueIncluded(name) || b.isValueIncluded(name), + c.isValueIncluded(name)); + } + { + NamespaceFilter c = NamespaceFilters.intersection(a, b); + //System.out.println("intersection(" + a + ", " + b + ") = " + c); + for(String name : all) + Assert.assertEquals( + a.isValueIncluded(name) && b.isValueIncluded(name), + c.isValueIncluded(name)); + } + } + + private void testBooleanOperations(THashSet a, THashSet b) { + THashSet all = new THashSet(); + all.addAll(a); + all.addAll(b); + all.add("dummy"); + + PositiveNamespaceFilter pa = new PositiveNamespaceFilter(a); + NegativeNamespaceFilter na = new NegativeNamespaceFilter(a); + PositiveNamespaceFilter pb = new PositiveNamespaceFilter(b); + NegativeNamespaceFilter nb = new NegativeNamespaceFilter(b); + testBooleanOperations(all, pa, pb); + testBooleanOperations(all, na, pb); + testBooleanOperations(all, pa, nb); + testBooleanOperations(all, na, nb); + } + + private void testBooleanOperations(THashSet a) { + THashSet all = new THashSet(); + all.addAll(a); + all.add("dummy"); + + PositiveNamespaceFilter pa = new PositiveNamespaceFilter(a); + NegativeNamespaceFilter na = new NegativeNamespaceFilter(a); + testBooleanOperations(all, pa, AcceptAllNamespaceFilter.INSTANCE); + testBooleanOperations(all, na, AcceptAllNamespaceFilter.INSTANCE); + testBooleanOperations(all, AcceptAllNamespaceFilter.INSTANCE, pa); + testBooleanOperations(all, AcceptAllNamespaceFilter.INSTANCE, na); + testBooleanOperations(all, AcceptAllNamespaceFilter.INSTANCE, AcceptAllNamespaceFilter.INSTANCE); + } + + @Test + public void testBooleanOperations() { + for(int p=0;p<8;++p) { + THashSet a = new THashSet(); + for(int i=0;i<3;++i) + if(((p >> i) & 1) == 1) + a.add(String.valueOf(i)); + testBooleanOperations(a); + } + + for(int p=0;p<64;++p) { + THashSet a = new THashSet(); + THashSet b = new THashSet(); + for(int i=0;i<3;++i) { + if(((p >> i) & 1) == 1) + a.add(String.valueOf(i)); + if(((p >> (i+3)) & 1) == 1) + b.add(String.valueOf(i)); + } + testBooleanOperations(a, b); + } + } + +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestSubSolver.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestSubSolver.java new file mode 100644 index 000000000..87b9eeb4f --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestSubSolver.java @@ -0,0 +1,37 @@ +package org.simantics.scl.compiler.tests.unit; + +import java.util.ArrayList; + +import org.junit.Assert; +import org.junit.Test; +import org.simantics.scl.compiler.errors.ErrorLog; +import org.simantics.scl.compiler.internal.elaboration.subsumption.SubSolver; +import org.simantics.scl.compiler.internal.elaboration.subsumption.Subsumption; +import org.simantics.scl.compiler.types.TMetaVar; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.kinds.Kinds; +import org.simantics.scl.compiler.types.util.Polarity; + + +public class TestSubSolver { + + @Test + public void testBipolarBounded() { + ErrorLog errorLog = new ErrorLog(); + ArrayList subsumptions = new ArrayList(); + ArrayList potentialSingletonEffects = new ArrayList(); + + TMetaVar in = Types.metaVar(Kinds.EFFECT); + TMetaVar out = Types.metaVar(Kinds.EFFECT); + in.addPolarity(Polarity.NEGATIVE); + out.addPolarity(Polarity.POSITIVE); + subsumptions.add(new Subsumption(0, Types.READ_GRAPH, out)); + subsumptions.add(new Subsumption(0, in, out)); + + SubSolver solver = new SubSolver(errorLog, subsumptions, potentialSingletonEffects, 0); + solver.solve(); + Assert.assertEquals("", errorLog.getErrorsAsString()); + } + +} diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestTypeParser.java b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestTypeParser.java new file mode 100644 index 000000000..5ce369042 --- /dev/null +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/unit/TestTypeParser.java @@ -0,0 +1,25 @@ +package org.simantics.scl.compiler.tests.unit; + +import org.junit.Test; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.environment.Environments; +import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification; +import org.simantics.scl.compiler.runtime.RuntimeEnvironment; +import org.simantics.scl.compiler.tests.TestBase; +import org.simantics.scl.compiler.types.Type; + +public class TestTypeParser { + + @Test + public void testTypeParser() throws Exception { + EnvironmentSpecification spec = new EnvironmentSpecification(); + spec.importModule("Builtin", ""); + spec.importModule("Prelude", ""); + RuntimeEnvironment runtimeEnvironment = + TestBase.PRELUDE_MODULE_REPOSITORY.createRuntimeEnvironment(spec, getClass().getClassLoader()); + Environment environment = runtimeEnvironment.getEnvironment(); + Type type = Environments.getType(environment, "String -> ()"); + System.out.println(type); + } + +} diff --git a/tests/org.simantics.scl.osgi.tests/.classpath b/tests/org.simantics.scl.osgi.tests/.classpath new file mode 100644 index 000000000..b862a296d --- /dev/null +++ b/tests/org.simantics.scl.osgi.tests/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/org.simantics.scl.osgi.tests/.project b/tests/org.simantics.scl.osgi.tests/.project new file mode 100644 index 000000000..d9af653fc --- /dev/null +++ b/tests/org.simantics.scl.osgi.tests/.project @@ -0,0 +1,28 @@ + + + org.simantics.scl.osgi.tests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/tests/org.simantics.scl.osgi.tests/.settings/org.eclipse.jdt.core.prefs b/tests/org.simantics.scl.osgi.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..295926d96 --- /dev/null +++ b/tests/org.simantics.scl.osgi.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/tests/org.simantics.scl.osgi.tests/META-INF/MANIFEST.MF b/tests/org.simantics.scl.osgi.tests/META-INF/MANIFEST.MF new file mode 100644 index 000000000..da7e1c6fd --- /dev/null +++ b/tests/org.simantics.scl.osgi.tests/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tests +Bundle-SymbolicName: org.simantics.scl.osgi.tests +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.junit;bundle-version="4.12.0", + org.simantics.scl.compiler;bundle-version="0.5.0", + org.simantics.scl.osgi;bundle-version="1.0.4", + gnu.trove3, + org.objectweb.asm.util, + org.eclipse.equinox.ds;bundle-version="1.4.300", + org.simantics;bundle-version="1.0.0", + org.simantics.acorn;bundle-version="1.1.2", + org.simantics.workbench;bundle-version="1.5.1", + org.simantics.application diff --git a/tests/org.simantics.scl.osgi.tests/build.properties b/tests/org.simantics.scl.osgi.tests/build.properties new file mode 100644 index 000000000..41eb6ade2 --- /dev/null +++ b/tests/org.simantics.scl.osgi.tests/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/tests/org.simantics.scl.osgi.tests/pom.xml b/tests/org.simantics.scl.osgi.tests/pom.xml new file mode 100644 index 000000000..f22ff3334 --- /dev/null +++ b/tests/org.simantics.scl.osgi.tests/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + org.simantics + org.simantics.scl.osgi.tests + 1.0.0-SNAPSHOT + eclipse-test-plugin + + + org.simantics + org.simantics.root.tests + 1.0.0-SNAPSHOT + + + + + + org.eclipse.tycho + target-platform-configuration + + + + + eclipse-feature + org.simantics.sdk + 0.0.0 + + + + + + + org.eclipse.tycho + tycho-surefire-plugin + ${tycho.version} + + + + + + diff --git a/tests/org.simantics.scl.osgi.tests/src/org/simantics/scl/osgi/tests/TestSCLOsgi.java b/tests/org.simantics.scl.osgi.tests/src/org/simantics/scl/osgi/tests/TestSCLOsgi.java new file mode 100644 index 000000000..35a74c4f6 --- /dev/null +++ b/tests/org.simantics.scl.osgi.tests/src/org/simantics/scl/osgi/tests/TestSCLOsgi.java @@ -0,0 +1,75 @@ +package org.simantics.scl.osgi.tests; + +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.simantics.PlatformException; +import org.simantics.Simantics; +import org.simantics.application.arguments.Arguments; +import org.simantics.application.arguments.IArgumentFactory; +import org.simantics.application.arguments.IArguments; +import org.simantics.application.arguments.SimanticsArguments; +import org.simantics.scl.compiler.errors.DoesNotExist; +import org.simantics.scl.compiler.errors.Failable; +import org.simantics.scl.compiler.module.Module; +import org.simantics.scl.osgi.SCLOsgi; + +import gnu.trove.procedure.TObjectProcedure; + + +public class TestSCLOsgi { + private static IProgressMonitor progress = new NullProgressMonitor(); + + @BeforeClass + public static void setupDatabase() throws PlatformException { + String[] args = new String[0]; + IArgumentFactory[] accepted = { + SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS, + SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL, + SimanticsArguments.SERVER, + SimanticsArguments.LOCAL_SERVER_PORT, + }; + IArguments arguments = Arguments.parse(args, accepted); + Simantics.startUpHeadless(arguments, progress); + } + + @AfterClass + public static void teardownDatabase() throws PlatformException { + Simantics.shutdown(progress); + } + + @Test + public void testDataJsonExists() { + ArrayList modulesWithErrors = new ArrayList(); + SCLOsgi.SOURCE_REPOSITORY.forAllModules(new TObjectProcedure() { + @Override + public boolean execute(String moduleName) { + System.out.print(moduleName); + System.out.print(" - "); + Failable module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName); + if(module.didSucceed()) + System.out.println("succeeded"); + else if(module == DoesNotExist.INSTANCE) + System.out.println("does not exist"); // should not happen + else { + System.out.println("error"); + modulesWithErrors.add(moduleName); + } + return true; + } + }); + if(!modulesWithErrors.isEmpty()) { + StringBuilder b = new StringBuilder(); + b.append("Some SCL modules failed to compile:"); + for(String module : modulesWithErrors) + b.append(' ').append(module); + Assert.fail(b.toString()); + } + } +} diff --git a/tests/pom.xml b/tests/pom.xml new file mode 100644 index 000000000..20d4c4832 --- /dev/null +++ b/tests/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + org.simantics + org.simantics.root.tests + 1.0.0-SNAPSHOT + pom + + + org.simantics + org.simantics.root + 1.0.0-SNAPSHOT + + + + + + org.eclipse.tycho + tycho-compiler-plugin + ${tycho.version} + + -err:-forbidden + + + + + + + org.simantics.scl.compiler.tests + org.simantics.scl.osgi.tests + +