From 5a59ecbc2a44ed856da57c3f9503229cdc775e6b Mon Sep 17 00:00:00 2001 From: Romain Lespinasse Date: Wed, 17 Sep 2014 13:59:02 +0200 Subject: [PATCH 001/142] Add support for Golo language --- lib/linguist/languages.yml | 7 ++ samples/Golo/adapters.golo | 67 ++++++++++++++++++ samples/Golo/async.golo | 84 +++++++++++++++++++++++ samples/Golo/augmentations.golo | 37 ++++++++++ samples/Golo/closures.golo | 43 ++++++++++++ samples/Golo/coin-change.golo | 34 ++++++++++ samples/Golo/collection-literals.golo | 55 +++++++++++++++ samples/Golo/context-decorator.golo | 53 +++++++++++++++ samples/Golo/decorators.golo | 83 +++++++++++++++++++++++ samples/Golo/dynamic-evaluation.golo | 88 ++++++++++++++++++++++++ samples/Golo/dynamic-object-person.golo | 29 ++++++++ samples/Golo/echo-args.golo | 34 ++++++++++ samples/Golo/enums-thread-state.golo | 31 +++++++++ samples/Golo/fibonacci.golo | 39 +++++++++++ samples/Golo/helloworld.golo | 20 ++++++ samples/Golo/http-server.golo | 53 +++++++++++++++ samples/Golo/logdeco.golo | 65 ++++++++++++++++++ samples/Golo/matching-operator.golo | 40 +++++++++++ samples/Golo/max-int.golo | 24 +++++++ samples/Golo/memoize.golo | 55 +++++++++++++++ samples/Golo/null-safety.golo | 43 ++++++++++++ samples/Golo/prepost-decorators.golo | 65 ++++++++++++++++++ samples/Golo/structs.golo | 69 +++++++++++++++++++ samples/Golo/swing-actionlistener.golo | 43 ++++++++++++ samples/Golo/swing-helloworld.golo | 31 +++++++++ samples/Golo/templates-chat-webapp.golo | 90 +++++++++++++++++++++++++ samples/Golo/util-containers.golo | 51 ++++++++++++++ samples/Golo/workers.golo | 48 +++++++++++++ 28 files changed, 1381 insertions(+) create mode 100755 samples/Golo/adapters.golo create mode 100755 samples/Golo/async.golo create mode 100755 samples/Golo/augmentations.golo create mode 100755 samples/Golo/closures.golo create mode 100755 samples/Golo/coin-change.golo create mode 100755 samples/Golo/collection-literals.golo create mode 100755 samples/Golo/context-decorator.golo create mode 100755 samples/Golo/decorators.golo create mode 100755 samples/Golo/dynamic-evaluation.golo create mode 100755 samples/Golo/dynamic-object-person.golo create mode 100755 samples/Golo/echo-args.golo create mode 100755 samples/Golo/enums-thread-state.golo create mode 100755 samples/Golo/fibonacci.golo create mode 100755 samples/Golo/helloworld.golo create mode 100755 samples/Golo/http-server.golo create mode 100755 samples/Golo/logdeco.golo create mode 100755 samples/Golo/matching-operator.golo create mode 100755 samples/Golo/max-int.golo create mode 100755 samples/Golo/memoize.golo create mode 100755 samples/Golo/null-safety.golo create mode 100755 samples/Golo/prepost-decorators.golo create mode 100755 samples/Golo/structs.golo create mode 100755 samples/Golo/swing-actionlistener.golo create mode 100755 samples/Golo/swing-helloworld.golo create mode 100755 samples/Golo/templates-chat-webapp.golo create mode 100755 samples/Golo/util-containers.golo create mode 100755 samples/Golo/workers.golo diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 7923b7da..51dd9d74 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -865,6 +865,13 @@ Go: extensions: - .go +Golo: + type: programming + color: "#195be0" + lexer: Golo + extensions: + - .golo + Gosu: type: programming color: "#82937f" diff --git a/samples/Golo/adapters.golo b/samples/Golo/adapters.golo new file mode 100755 index 00000000..20c7d031 --- /dev/null +++ b/samples/Golo/adapters.golo @@ -0,0 +1,67 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.Adapters + +local function list_sample = |fabric| { + println(">>> list_sample()") + let carbonCopy = list[] + let conf = map[ + ["extends", "java.util.ArrayList"], + ["overrides", map[ + ["*", |super, name, args| { + if name == "add" { + if args: length() == 2 { + carbonCopy: add(args: get(1)) + } else { + carbonCopy: add(args: get(1), args: get(2)) + } + } + return super: invokeWithArguments(args) + } + ]] + ]] + let list = fabric: maker(conf): newInstance() + list: add("bar") + list: add(0, "foo") + list: add("baz") + println(" list: " + list + " " + list: getClass()) + println("carbonCopy: " + carbonCopy + " " + carbonCopy: getClass()) +} + +local function runnable_sample = |fabric| { + println(">>> runnable_sample") + let result = array[1, 2, 3] + let conf = map[ + ["interfaces", ["java.io.Serializable", "java.lang.Runnable"]], + ["implements", map[ + ["run", |this| { + for (var i = 0, i < result: length(), i = i + 1) { + result: set(i, result: get(i) + 10) + } + }] + ]] + ] + let runner = fabric: maker(conf): newInstance() + runner: run() + println(" result: " + result: toString()) + println("serializable? " + (runner oftype java.io.Serializable.class)) + println(" runnable? " + (runner oftype java.lang.Runnable.class)) +} + +function main = |args| { + let fabric = AdapterFabric() + list_sample(fabric) + runnable_sample(fabric) +} diff --git a/samples/Golo/async.golo b/samples/Golo/async.golo new file mode 100755 index 00000000..432f8c94 --- /dev/null +++ b/samples/Golo/async.golo @@ -0,0 +1,84 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.AsyncHelpers + +import gololang.Async +import java.util.concurrent.TimeUnit +import java.util.concurrent.Executors + +local function fib = |n| { + if n <= 1 { + return n + } else { + return fib(n - 1) + fib(n - 2) + } +} + +function main = |args| { + + let executor = newCachedThreadPool() + println("Let's do some useless asynchronous operations...") + + var f = executor: enqueue({ + Thread.sleep(1000_L) + return 666 + }) + f: + onSet(|v| -> println(">>> #slow -> " + v)): + onFail(|e| -> println(">>> #fail -> " + e)) + f: + cancel(true) + + f = executor: enqueue({ + Thread.sleep(1000_L) + return 666 + }) + f: + onSet(|v| -> println(">>> #ok -> " + v)): + onFail(|e| -> println(">>> #wtf? -> " + e)) + + let fib_10 = promise() + let fib_20 = promise() + let fib_30 = promise() + let fib_40 = promise() + + let futures = [ + fib_10: future(), fib_20: future(), + fib_30: future(), fib_40: future() + ] + + executor: submit(-> fib_10: set(fib(10))) + executor: submit(-> fib_20: set(fib(20))) + executor: submit(-> fib_30: set(fib(30))) + executor: submit(-> fib_40: set(fib(40))) + + all(futures): onSet(|results| -> println(">>> Fibs: " + results)) + + let truth = promise() + truth: + future(): + map(|v| -> "truth=" + v): + onSet(|v| -> executor: submit(-> println(">>> (another thread) " + v))): + onSet(|v| -> println(">>> (same thread) " + v)) + executor: submit({ + Thread.sleep(500_L) + truth: set(42) + }) + + Thread.sleep(1000_L) + executor: shutdown() + executor: awaitTermination(2_L, SECONDS()) + println("Bye!") +} diff --git a/samples/Golo/augmentations.golo b/samples/Golo/augmentations.golo new file mode 100755 index 00000000..bed289a4 --- /dev/null +++ b/samples/Golo/augmentations.golo @@ -0,0 +1,37 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.Augmentations + +import java.util.LinkedList + +augment java.util.List { + function with = |this, value| { + this: add(value) + return this + } +} + +augment java.util.Collection { + function doToEach = |this, func| { + foreach (element in this) { + func(element) + } + } +} + +function main = |args| { + let list = LinkedList(): with("foo"): with("bar"): with("baz") + list: doToEach(|value| -> println(">>> " + value)) +} diff --git a/samples/Golo/closures.golo b/samples/Golo/closures.golo new file mode 100755 index 00000000..32378017 --- /dev/null +++ b/samples/Golo/closures.golo @@ -0,0 +1,43 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Closures + +local function sayHello = |who| -> "Hello " + who + "!" + +function main = |args| { + let adder = |a, b| -> a + b + println(adder: invokeWithArguments(1, 2)) + println(adder(1, 2)) + + let addToTen = adder: bindTo(10) + println(addToTen: invokeWithArguments(2)) + println(addToTen(2)) + + let adding = |x| -> |y| -> adder(x, y) + let addingTen = adding(10) + println(addingTen(4)) + println(adding(2)(4)) + + println(sayHello("Julien")) + + let list = java.util.LinkedList() + let pump_it = { + list: add("I heard you say") + list: add("Hey!") + list: add("Hey!") + } + pump_it() + println(list) +} diff --git a/samples/Golo/coin-change.golo b/samples/Golo/coin-change.golo new file mode 100755 index 00000000..fe82bb04 --- /dev/null +++ b/samples/Golo/coin-change.golo @@ -0,0 +1,34 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module CoinChange + +import java.util.LinkedList + +function change = |money, coins| -> match { + when money == 0 then 1 + when (money < 0) or (coins: isEmpty()) then 0 + otherwise change(money - coins: head(), coins) + change(money, coins: tail()) +} + +function main = |args| { + let coins = LinkedList(): append(1, 2, 5, 10, 20) + println("Coins: " + coins) + println("0: " + change(0, coins)) + println("1: " + change(1, coins)) + println("2: " + change(2, coins)) + println("10: " + change(10, coins)) + println("12: " + change(12, coins)) + println("6: " + change(6, coins)) +} diff --git a/samples/Golo/collection-literals.golo b/samples/Golo/collection-literals.golo new file mode 100755 index 00000000..ac19b35e --- /dev/null +++ b/samples/Golo/collection-literals.golo @@ -0,0 +1,55 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.CollectionLiterals + +local function play_with_tuples = { + let hello = ["Hello", "world", "!"] + foreach str in hello { + print(str + " ") + } + println("") + + println(hello: get(0) + "-" + hello: get(1) + "-" + hello: get(2)) + + println(hello: join("/")) +} + +local function play_with_literals = { + let data = [ + [1, 2, 3], + tuple[1, 2, 3], + array[1, 2, 3], + set[1, 2, 3, 3, 1], + map[ + ["a", 10], + ["b", 20] + ], + vector[1, 2, 3], + list[1, 2, 3] + ] + + data: each(|element| { + println(element: toString()) + println(" type: " + element: getClass()) + }) +} + +function main = |args| { + println(">>> Literals") + play_with_literals() + println("\n>>> Tuples") + play_with_tuples() +} + diff --git a/samples/Golo/context-decorator.golo b/samples/Golo/context-decorator.golo new file mode 100755 index 00000000..6a3bb889 --- /dev/null +++ b/samples/Golo/context-decorator.golo @@ -0,0 +1,53 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.ContextDecorator + +import gololang.Decorators + +let myContext = defaultContext(): + count(0): + define("entry", |this, args| { + this: count(this: count() + 1) + println("hello:" + this: count()) + return args + }): + define("exit", |this, result| { + require(result >= 3, "wrong value") + println("goobye") + return result + }): + define("catcher", |this, e| { + println("Caught " + e) + throw e + }): + define("finallizer", |this| {println("do some cleanup")}) + + +@withContext(myContext) +function foo = |a, b| { + println("Hard computation") + return a + b +} + +function main = |args| { + println(foo(1,2)) + println("====") + println(withContext(myContext)(|a| -> 2*a)(3)) + println("====") + try { + println(foo(1, 1)) + } catch (e) { } +} + diff --git a/samples/Golo/decorators.golo b/samples/Golo/decorators.golo new file mode 100755 index 00000000..c3acbfc4 --- /dev/null +++ b/samples/Golo/decorators.golo @@ -0,0 +1,83 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.Decorators + +import java.util.LinkedList + +function simple_decorator = |func| { + return |a,b| -> func(a+1,b+1) +} + +@simple_decorator +function simple_adder = |x,y| -> x + y + +function decorator_with_params = |param1, param2|{ + return |func| { + return |a,b| -> func(a+param1,b+param2) + } +} + +@decorator_with_params(10,2) +function parametrized_adder = |x,y| -> x + y + +function generic_decorator = |func| { + return |args...| { + println("number of params : "+args: length()) + return func: invokeWithArguments(args) + } +} + +@generic_decorator +function generic_adder0 = -> 42 + +@generic_decorator +function generic_adder1 = |x| -> x + +@generic_decorator +function generic_adder2 = |x,y| -> x + y + +@generic_decorator +function generic_adder3 = |x,y,z| -> x + y + z + +function list_sum_decorator = |func| { + return |this| -> func(this) - 8 +} + +augment java.util.List { + + @list_sum_decorator + function sum = |this| { + var acc = 0 + foreach elem in this { + acc = acc + elem + } + return acc + } +} + +function main = |args| { + println(simple_adder(10,30)) + println(parametrized_adder(10,20)) + println(generic_adder0()) + println(generic_adder1(42)) + println(generic_adder2(20,22)) + println(generic_adder3(10,12,20)) + let list = LinkedList() + list: add(5) + list: add(10) + list: add(15) + list: add(20) + println(list: sum()) +} \ No newline at end of file diff --git a/samples/Golo/dynamic-evaluation.golo b/samples/Golo/dynamic-evaluation.golo new file mode 100755 index 00000000..af5351f4 --- /dev/null +++ b/samples/Golo/dynamic-evaluation.golo @@ -0,0 +1,88 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.DynamicEvaluation + +import gololang.EvaluationEnvironment + +local function test_asModule = |env| { + let code = +""" +module foo + +function a = -> "a!" +function b = -> "b!" +""" + let mod = env: asModule(code) + let a = fun("a", mod) + let b = fun("b", mod) + println(">>> asModule()") + println(a()) + println(b()) +} + +local function test_anonymousModule = |env| { + let code = +""" +function a = -> "a." +function b = -> "b." +""" + let mod = env: anonymousModule(code) + let a = fun("a", mod) + let b = fun("b", mod) + println(">>> anonymousModule()") + println(a()) + println(b()) +} + +local function test_asFunction = |env| { + let code = "return (a + b) * 2" + let f = env: asFunction(code, "a", "b") + println(">>> asFunction") + println(f(10, 20)) +} + +local function test_def = |env| { + let code = "|a, b| -> (a + b) * 2" + let f = env: def(code) + println(">>> def") + println(f(10, 20)) +} + +local function test_run = |env| { + let code = """println(">>> run") + foreach (i in range(0, 3)) { + println("w00t") + }""" + env: run(code) +} + +local function test_run_map = |env| { + let code = """println(">>> run_map") + println(a) + println(b) + """ + let values = java.util.TreeMap(): add("a", 1): add("b", 2) + env: run(code, values) +} + +function main = |args| { + let env = EvaluationEnvironment() + test_asModule(env) + test_anonymousModule(env) + test_asFunction(env) + test_def(env) + test_run(env) + test_run_map(env) +} diff --git a/samples/Golo/dynamic-object-person.golo b/samples/Golo/dynamic-object-person.golo new file mode 100755 index 00000000..27f3ab6d --- /dev/null +++ b/samples/Golo/dynamic-object-person.golo @@ -0,0 +1,29 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.DynamicObjectPerson + +local function mrbean = -> DynamicObject(): + name("Mr Bean"): + email("mrbean@gmail.com"): + define("toString", |this| -> this: name() + " <" + this: email() + ">") + +function main = |args| { + + let bean = mrbean() + println(bean: toString()) + + bean: email("mrbean@outlook.com") + println(bean: toString()) +} diff --git a/samples/Golo/echo-args.golo b/samples/Golo/echo-args.golo new file mode 100755 index 00000000..7bf1e093 --- /dev/null +++ b/samples/Golo/echo-args.golo @@ -0,0 +1,34 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module EchoArgs + +function main = |args| { + + println("With a for loop and an index:") + for (var i = 0, i < args: length(), i = i + 1) { + println(" #" + i + " -> " + args: get(i)) + } + + println("With a foreach loop:") + foreach arg in args { + println(" " + arg) + } + + println("With a foreach over a range:") + foreach i in range(0, args: length()) { + println(" #" + i + " -> " + args: get(i)) + } +} + diff --git a/samples/Golo/enums-thread-state.golo b/samples/Golo/enums-thread-state.golo new file mode 100755 index 00000000..4310ea26 --- /dev/null +++ b/samples/Golo/enums-thread-state.golo @@ -0,0 +1,31 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module sample.EnumsThreadState + +import java.lang.Thread$State + +function main = |args| { + + # Call the enum entry like a function + let new = Thread$State.NEW() + println("name=" + new: name() + ", ordinal=" + new: ordinal()) + println("-----------") + + # Walk through all enum entries + foreach element in Thread$State.values() { + println("name=" + element: name() + ", ordinal=" + element: ordinal()) + } +} + diff --git a/samples/Golo/fibonacci.golo b/samples/Golo/fibonacci.golo new file mode 100755 index 00000000..53455a7d --- /dev/null +++ b/samples/Golo/fibonacci.golo @@ -0,0 +1,39 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.Fibonacci + +import java.lang.System + +function fib = |n| { + if n <= 1 { + return n + } else { + return fib(n - 1) + fib(n - 2) + } +} + +local function run = { + let start = System.currentTimeMillis() + let result = fib(40) + let duration = System.currentTimeMillis() - start + println(">>> " + result + " (took " + duration + "ms)") +} + +function main = |args| { + while true { + run() + } +} + diff --git a/samples/Golo/helloworld.golo b/samples/Golo/helloworld.golo new file mode 100755 index 00000000..4800de6d --- /dev/null +++ b/samples/Golo/helloworld.golo @@ -0,0 +1,20 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module hello.World + +function main = |args| { + println("Hello world!") +} + diff --git a/samples/Golo/http-server.golo b/samples/Golo/http-server.golo new file mode 100755 index 00000000..ce4ff857 --- /dev/null +++ b/samples/Golo/http-server.golo @@ -0,0 +1,53 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.WebServer + +import java.lang +import java.net.InetSocketAddress +import com.sun.net.httpserver +import com.sun.net.httpserver.HttpServer + +function main = |args| { + + let server = HttpServer.create(InetSocketAddress("localhost", 8081), 0) + + server: createContext("/", |exchange| { + let headers = exchange: getResponseHeaders() + let response = StringBuilder(): + append("Requested URI: "): + append(exchange: getRequestURI()): + append("\n"): + append("Current time: "): + append(java.util.Date()): + append("\n"): + toString() + headers: set("Content-Type", "text/plain") + exchange: sendResponseHeaders(200, response: length()) + exchange: getResponseBody(): write(response: getBytes()) + exchange: close() + }) + + server: createContext("/shutdown", |exchange| { + let response = "Ok, thanks, bye!" + exchange: getResponseHeaders(): set("Content-Type", "text/plain") + exchange: sendResponseHeaders(200, response: length()) + exchange: getResponseBody(): write(response: getBytes()) + exchange: close() + server: stop(5) + }) + + server: start() + println(">>> http://localhost:8081/") +} diff --git a/samples/Golo/logdeco.golo b/samples/Golo/logdeco.golo new file mode 100755 index 00000000..ae42a133 --- /dev/null +++ b/samples/Golo/logdeco.golo @@ -0,0 +1,65 @@ + +module samples.LogDeco + +function log1 = |msg| { + return |fun| { + return |args...| { + println(msg) + return fun: invokeWithArguments(args) + } + } +} + +@log1("calling foo") +function foo = |a| { + println("foo got a " + a) +} + +@log1("I'am a bar") +function bar = |a| -> 2*a + +let sayHello = log1("Hello") + +@sayHello +function baz = -> "Goodbye" + +function log2 = |msgBefore| -> |msgAfter| -> |func| -> |args...| { + println(msgBefore) + let res = func: invokeWithArguments(args) + println(msgAfter) + return res +} + +@log2("enter foo")("exit foo") +function spam = |a| { + println("foo: " + a) +} + +function logEnterExit = |name| -> log2("# enter " + name)("# exit " + name) + +@logEnterExit("bar") +function egg = { println("doing something...") } + +function main = |args| { + + foo("bar") + + println("---") + println(bar(21)) + + println("---") + println(baz()) + + println("---") + spam("bar") + + println("---") + egg() + + println("---") + let strange_use = log2("hello")("goodbye")({println(":p")}) + strange_use() + + println("---") + log2("another")("use")(|a|{println(a)})("strange") +} diff --git a/samples/Golo/matching-operator.golo b/samples/Golo/matching-operator.golo new file mode 100755 index 00000000..380d2259 --- /dev/null +++ b/samples/Golo/matching-operator.golo @@ -0,0 +1,40 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Matching + +import java.util.LinkedList + +local function data = { + let list = LinkedList() + list: add("foo@bar.com") + list: add("+33.6.11.22.33") + list: add("http://golo-lang.org/") + list: add("def foo = bar(_._) with :> T") + return list +} + +local function what_it_could_be = |item| -> match { + when item: contains("@") then "an email?" + when item: startsWith("+33") then "a French phone number?" + when item: startsWith("http://") then "a website URL?" + otherwise "I have no clue, mate!" +} + +function main = |args| { + foreach item in data() { + println(item + " => " + what_it_could_be(item)) + } +} + diff --git a/samples/Golo/max-int.golo b/samples/Golo/max-int.golo new file mode 100755 index 00000000..457a5dff --- /dev/null +++ b/samples/Golo/max-int.golo @@ -0,0 +1,24 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.MaxInt + +local function max_int = { + return java.lang.Integer.MAX_VALUE() +} + +function main = |args| { + println(max_int()) +} + diff --git a/samples/Golo/memoize.golo b/samples/Golo/memoize.golo new file mode 100755 index 00000000..8fb1b455 --- /dev/null +++ b/samples/Golo/memoize.golo @@ -0,0 +1,55 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.MemoizeDecorator + +import gololang.Decorators + +import java.lang.System + +let memo = memoizer() + +@memo +function fib = |n| { + if n <= 1 { + return n + } else { + return fib(n - 1) + fib(n - 2) + } +} + +@memo +function foo = |n| -> n + +local function run = { + let start = System.currentTimeMillis() + let result = fib(40) + let duration = System.currentTimeMillis() - start + println(">>> fib(40) = " + result + " (took " + duration + "ms)") +} + +local function run2 = { + let start = System.currentTimeMillis() + let result = foo(40) + let duration = System.currentTimeMillis() - start + println(">>> foo(40) = " + result + " (took " + duration + "ms)") +} + +function main = |args| { + foreach i in range(0, 5) { + println("run " + i) + run() + run2() + } +} diff --git a/samples/Golo/null-safety.golo b/samples/Golo/null-safety.golo new file mode 100755 index 00000000..903f5309 --- /dev/null +++ b/samples/Golo/null-safety.golo @@ -0,0 +1,43 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module DealingWithNull + +import java.util + +function main = |args| { + + # Data model + let contacts = map[ + ["mrbean", map[ + ["email", "bean@gmail.com"], + ["url", "http://mrbean.com"] + ]], + ["larry", map[ + ["email", "larry@iamricherthanyou.com"] + ]] + ] + + # MrBean and Larry + let mrbean = contacts: get("mrbean") + let larry = contacts: get("larry") + + # Illustrates orIfNull + println(mrbean: get("url") orIfNull "n/a") + println(larry: get("url") orIfNull "n/a") + + # Querying a non-existent data model because there is no 'address' entry + println(mrbean: get("address")?: street()?: number() orIfNull "n/a") +} + diff --git a/samples/Golo/prepost-decorators.golo b/samples/Golo/prepost-decorators.golo new file mode 100755 index 00000000..a7ea73ca --- /dev/null +++ b/samples/Golo/prepost-decorators.golo @@ -0,0 +1,65 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.PrepostDecorator + +import gololang.Decorators + +let isInteger = isOfType(Integer.class) + +@checkResult(isString(): andThen(lengthIs(2))) +@checkArguments(isInteger: andThen(isPositive()), isString()) +function foo = |a, b| { + return b + a +} + +let myCheck = checkArguments(isInteger: andThen(isPositive())) + +@myCheck +function inv = |v| -> 1.0 / v + +let isPositiveInt = isInteger: andThen(isPositive()) + +@checkArguments(isPositiveInt) +function mul = |v| -> 10 * v + +@checkArguments(isNumber()) +function num = |v| -> "ok" + +@checkArguments(isNotNull()) +function notnull = |v| -> "ok" + +function main = |args| { + try { println(foo(1, "b")) } catch (e) { println(e) } + try { println(foo(-1, "b")) } catch (e) { println(e) } + try { println(foo("a", 2)) } catch (e) { println(e) } + try { println(foo(1, 2)) } catch (e) { println(e) } + try { println(foo(10, "ab")) } catch (e) { println(e) } + + try { println(inv(10)) } catch (e) { println(e) } + try { println(inv(0)) } catch (e) { println(e) } + + try { println(mul(5)) } catch (e) { println(e) } + try { println(mul(0)) } catch (e) { println(e) } + + try { println(num(1)) } catch (e) { println(e) } + try { println(num(1_L)) } catch (e) { println(e) } + try { println(num(1.5)) } catch (e) { println(e) } + try { println(num(1.5_F)) } catch (e) { println(e) } + try { println(num("a")) } catch (e) { println(e) } + try { println(num('a')) } catch (e) { println(e) } + + try { println(notnull('1')) } catch (e) { println(e) } + try { println(notnull(null)) } catch (e) { println(e) } +} diff --git a/samples/Golo/structs.golo b/samples/Golo/structs.golo new file mode 100755 index 00000000..de18836a --- /dev/null +++ b/samples/Golo/structs.golo @@ -0,0 +1,69 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module StructDemo + +struct Point = { x, y } + +augment StructDemo.types.Point { + + function move = |this, offsetX, offsetY| { + this: x(this: x() + offsetX) + this: y(this: y() + offsetY) + return this + } + + function relative = |this, offsetX, offsetY| -> Point(this: x() + offsetX, this: y() + offsetY) +} + +function main = |args| { + + let p1 = Point(1, 2) + let p2 = Point(): x(1): y(2) + let p3 = p1: frozenCopy() + let p4 = p1: frozenCopy() + + println(p1) + println("x = " + p1: x()) + println("y = " + p1: y()) + + println("p1 == p2 " + (p1 == p2)) + println("p1 == p3 " + (p1 == p3)) + println("p3 == p4 " + (p3 == p4)) + + println("#p1 " + p1: hashCode()) + println("#p2 " + p2: hashCode()) + println("#p3 " + p3: hashCode()) + println("#p4 " + p4: hashCode()) + + println("p1: members() " + p1: members()) + println("p1: values() " + p1: values()) + foreach item in p1 { + println(item: get(0) + " -> " + item: get(1)) + } + + println("p1: set(\"x\", 10) " + p1: set("x", 10)) + println("p1: move(10, 5) " + p1: move(10, 5)) + println("p1: relative(11, 6) " + p1: relative(11, 6)) + + let p5 = ImmutablePoint(10, 20) + println("p5: " + p5) + try { + p5: x(100) + } catch (expected) { + println("p5 is immutable, so... " + expected: getMessage()) + } +} + + diff --git a/samples/Golo/swing-actionlistener.golo b/samples/Golo/swing-actionlistener.golo new file mode 100755 index 00000000..61d0f7f3 --- /dev/null +++ b/samples/Golo/swing-actionlistener.golo @@ -0,0 +1,43 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.SwingActionListener + +import java.awt.event +import javax.swing +import javax.swing.WindowConstants + +local function listener = |handler| -> asInterfaceInstance(ActionListener.class, handler) + +function main = |args| { + + let frame = JFrame("Action listeners") + frame: setDefaultCloseOperation(EXIT_ON_CLOSE()) + + let button = JButton("Click me!") + button: setFont(button: getFont(): deriveFont(96.0_F)) + + # Using a helper function + button: addActionListener(listener(|event| -> println("Clicked!"))) + + # Using a standard augmentation: MethodHandle::to(Class) + button: addActionListener((|event| -> println("[click]")): to(ActionListener.class)) + + # Straight closure passing + button: addActionListener(|event| -> println("( )")) + + frame: getContentPane(): add(button) + frame: pack() + frame: setVisible(true) +} diff --git a/samples/Golo/swing-helloworld.golo b/samples/Golo/swing-helloworld.golo new file mode 100755 index 00000000..9d5e0541 --- /dev/null +++ b/samples/Golo/swing-helloworld.golo @@ -0,0 +1,31 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.SwingHelloWorld + +import javax.swing +import javax.swing.WindowConstants + +function main = |args| { + + let frame = JFrame("Hello world") + frame: setDefaultCloseOperation(EXIT_ON_CLOSE()) + + let label = JLabel("Hello world") + label: setFont(label: getFont(): deriveFont(128.0_F)) + + frame: getContentPane(): add(label) + frame: pack() + frame: setVisible(true) +} diff --git a/samples/Golo/templates-chat-webapp.golo b/samples/Golo/templates-chat-webapp.golo new file mode 100755 index 00000000..a5eab98b --- /dev/null +++ b/samples/Golo/templates-chat-webapp.golo @@ -0,0 +1,90 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module samples.TemplatesChatWebapp + +import java.lang +import java.io +import java.net.InetSocketAddress +import com.sun.net.httpserver +import com.sun.net.httpserver.HttpServer + +local function redirect = |exchange, to| { + exchange: getResponseHeaders(): set("Location", to) + exchange: sendResponseHeaders(303, 0) + exchange: close() +} + +local function respond = |exchange, body| { + exchange: getResponseHeaders(): set("Content-Type", "text/html") + exchange: sendResponseHeaders(200, body: length()) + exchange: getResponseBody(): write(body: getBytes()) + exchange: close() +} + +# This is leaky and works with just 1 POST parameter... +local function extract_post = |exchange, posts| { + let reader = BufferedReader(InputStreamReader(exchange: getRequestBody())) + var line = reader: readLine() + while line isnt null { + if line: startsWith("msg=") { + posts: add(java.net.URLDecoder.decode(line: substring(4), "UTF-8")) + } + line = reader: readLine() + } + reader: close() +} + + +local function index = |posts, template, exchange| { + if exchange: getRequestMethod() == "POST" { + extract_post(exchange, posts) + redirect(exchange, "/") + } else { + respond(exchange, template(posts)) + } +} + +local function index_template = -> """ +<%@params posts %> + + + + Golo Chat + + +
+ + +
+
+

Last posts

+ <% foreach post in posts { %> +
+ <%= post %> +
+ <% } %> +
+ + +""" + +function main = |args| { + let index_tpl = gololang.TemplateEngine(): compile(index_template()) + let posts = java.util.concurrent.ConcurrentLinkedDeque() + let server = HttpServer.create(InetSocketAddress("localhost", 8081), 0) + server: createContext("/", ^index: bindTo(posts): bindTo(index_tpl)) + server: start() + println(">>> http://localhost:8081/") +} diff --git a/samples/Golo/util-containers.golo b/samples/Golo/util-containers.golo new file mode 100755 index 00000000..63d09b6a --- /dev/null +++ b/samples/Golo/util-containers.golo @@ -0,0 +1,51 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module MoreCoolContainers + +function main = |args| { + + println(">>> DynamicVariable") + + let dyn = DynamicVariable("Foo") + println(dyn: value()) + + let t1 = Thread({ + dyn: withValue(666, { + println(dyn: value()) + }) + }) + + let t2 = Thread({ + dyn: withValue(69, { + println(dyn: value()) + }) + }) + + t1: start() + t2: start() + t1: join() + t2: join() + println(dyn: value()) + + println(">>> Observable") + + let foo = Observable("Foo") + foo: onChange(|v| -> println("foo = " + v)) + + let mapped = foo: map(|v| -> v + "!") + mapped: onChange(|v| -> println("mapped = " + v)) + + foo: set("69") +} diff --git a/samples/Golo/workers.golo b/samples/Golo/workers.golo new file mode 100755 index 00000000..8c08f650 --- /dev/null +++ b/samples/Golo/workers.golo @@ -0,0 +1,48 @@ +# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Workers + +import java.lang.Thread +import java.util.concurrent +import gololang.concurrent.workers.WorkerEnvironment + +local function pusher = |queue, message| -> queue: offer(message) + +local function generator = |port, message| { + foreach i in range(0, 100) { + port: send(message) + } +} + +function main = |args| { + + let env = WorkerEnvironment.builder(): withFixedThreadPool() + let queue = ConcurrentLinkedQueue() + + let pusherPort = env: spawn(^pusher: bindTo(queue)) + let generatorPort = env: spawn(^generator: bindTo(pusherPort)) + + let finishPort = env: spawn(|any| -> env: shutdown()) + + foreach i in range(0, 10) { + generatorPort: send("[" + i + "]") + } + Thread.sleep(2000_L) + finishPort: send("Die!") + + env: awaitTermination(2000) + println(queue: reduce("", |acc, next| -> acc + " " + next)) +} + From ce1e2441f4895cc8903f1e5f5d4e98404da6b8a0 Mon Sep 17 00:00:00 2001 From: Romain Lespinasse Date: Sat, 11 Oct 2014 10:27:06 +0200 Subject: [PATCH 002/142] Choose a color from the Golo logo --- lib/linguist/languages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 51dd9d74..c5d1252c 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -867,7 +867,7 @@ Go: Golo: type: programming - color: "#195be0" + color: "#f6a51f" lexer: Golo extensions: - .golo From b2cb74cabf4ab359bc3ab525049ff0239c7e0a8e Mon Sep 17 00:00:00 2001 From: Josh Watzman Date: Wed, 6 Aug 2014 15:39:10 -0700 Subject: [PATCH 003/142] Add detection for Hack files with ".hh" file extension Hack is Facebook's dialect of PHP: http://hacklang.org/. This adds support for detecting it via the ".hh" file extension; although that extension techincally conflicts with C++ headers, the files look different enough that the existing classifier based on sample code has no trouble distinguising them. This diff deliberately does not deal with detecting ".php" as another valid extension for Hack code. That's much trickier since the code looks basically identical to PHP to the classifier, and needs a different approach. --- lib/linguist/languages.yml | 7 ++ samples/C++/bar.hh | 10 +++ samples/Hack/Assert.hh | 55 ++++++++++++++ samples/Hack/AssertRecipe.hh | 52 +++++++++++++ samples/Hack/Controller.hh | 39 ++++++++++ samples/Hack/DBResultRecipe.hh | 52 +++++++++++++ samples/Hack/Documentation.hh | 22 ++++++ samples/Hack/FakeDB.hh | 65 ++++++++++++++++ samples/Hack/GetAndPostRecipe.hh | 72 ++++++++++++++++++ samples/Hack/GetController.hh | 30 ++++++++ samples/Hack/HomeController.hh | 38 ++++++++++ samples/Hack/MySecureRequest.hh | 13 ++++ samples/Hack/Nav.hh | 104 ++++++++++++++++++++++++++ samples/Hack/NonStrictFile.hh | 27 +++++++ samples/Hack/Recipe.hh | 93 +++++++++++++++++++++++ samples/Hack/RecipeWithDemo.hh | 16 ++++ samples/Hack/Request.hh | 15 ++++ samples/Hack/StandardPage.hh | 81 ++++++++++++++++++++ samples/Hack/StrictFile.hh | 46 ++++++++++++ samples/Hack/UnescapedString.hh | 16 ++++ samples/Hack/UnescapedStringRecipe.hh | 59 +++++++++++++++ samples/Hack/UserID.hh | 33 ++++++++ samples/Hack/UserIDRecipe.hh | 54 +++++++++++++ samples/Hack/UsingUserID.hh | 22 ++++++ samples/Hack/error.hh | 43 +++++++++++ samples/Hack/funs.hh | 32 ++++++++ samples/Hack/index.hh | 14 ++++ samples/Hack/phpfile.hh | 31 ++++++++ samples/Hack/startup.hh | 14 ++++ 29 files changed, 1155 insertions(+) create mode 100644 samples/C++/bar.hh create mode 100644 samples/Hack/Assert.hh create mode 100644 samples/Hack/AssertRecipe.hh create mode 100644 samples/Hack/Controller.hh create mode 100644 samples/Hack/DBResultRecipe.hh create mode 100644 samples/Hack/Documentation.hh create mode 100644 samples/Hack/FakeDB.hh create mode 100644 samples/Hack/GetAndPostRecipe.hh create mode 100644 samples/Hack/GetController.hh create mode 100644 samples/Hack/HomeController.hh create mode 100644 samples/Hack/MySecureRequest.hh create mode 100644 samples/Hack/Nav.hh create mode 100644 samples/Hack/NonStrictFile.hh create mode 100644 samples/Hack/Recipe.hh create mode 100644 samples/Hack/RecipeWithDemo.hh create mode 100644 samples/Hack/Request.hh create mode 100644 samples/Hack/StandardPage.hh create mode 100644 samples/Hack/StrictFile.hh create mode 100644 samples/Hack/UnescapedString.hh create mode 100644 samples/Hack/UnescapedStringRecipe.hh create mode 100644 samples/Hack/UserID.hh create mode 100644 samples/Hack/UserIDRecipe.hh create mode 100644 samples/Hack/UsingUserID.hh create mode 100644 samples/Hack/error.hh create mode 100644 samples/Hack/funs.hh create mode 100644 samples/Hack/index.hh create mode 100644 samples/Hack/phpfile.hh create mode 100644 samples/Hack/startup.hh diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 56032ebb..11f372c4 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -980,6 +980,13 @@ HTTP: extensions: - .http +Hack: + type: programming + lexer: PHP + ace_mode: php + extensions: + - .hh + Haml: group: HTML type: markup diff --git a/samples/C++/bar.hh b/samples/C++/bar.hh new file mode 100644 index 00000000..a87343c2 --- /dev/null +++ b/samples/C++/bar.hh @@ -0,0 +1,10 @@ +class Bar +{ + protected: + + char *name; + + public: + + void hello(); +} diff --git a/samples/Hack/Assert.hh b/samples/Hack/Assert.hh new file mode 100644 index 00000000..c80fc87a --- /dev/null +++ b/samples/Hack/Assert.hh @@ -0,0 +1,55 @@ +( + (function(mixed): T) $fn, + mixed $x, + ): array { + if (is_array($x)) { + return array_map($fn, $x); + } + throw new AssertException('Expected an array'); + } +} diff --git a/samples/Hack/AssertRecipe.hh b/samples/Hack/AssertRecipe.hh new file mode 100644 index 00000000..e2f9eabd --- /dev/null +++ b/samples/Hack/AssertRecipe.hh @@ -0,0 +1,52 @@ +> + protected function getDescription(): ?string { + return 'When you have values with unknown types, it is useful to make '. + 'some runtime assertions and have the type checker understand. This '. + 'recipe demonstrates one approach.'; + } + + protected function getFilenames(): Vector { + return Vector { + 'Assert.php', + }; + } + + protected function getDocs(): Vector<(string, string)> { + return Vector{ + tuple ('Mixed Types', 'hack.annotations.mixedtypes'), + tuple ('Type Inference', 'hack.otherrulesandfeatures.typeinference'), + }; + } + + public function getDemoFilename(): string { + return 'demo.php'; + } + + public function getDemoResult(): string { + return assert_main(); + } + + public function getDemoXHP(): ?:xhp { + return null; + } +} diff --git a/samples/Hack/Controller.hh b/samples/Hack/Controller.hh new file mode 100644 index 00000000..a21aacb2 --- /dev/null +++ b/samples/Hack/Controller.hh @@ -0,0 +1,39 @@ +; + abstract protected function getJS(): Set; + abstract protected function getTitle(): string; + abstract protected function render(): :xhp; + + final protected function getHead(): :xhp { + $css = $this->getCSS()->toVector()->map( + ($css) ==> + ); + $js = $this->getJS()->toVector()->map( + ($js) ==>