From 07fdea7496f97dc923e246f77593428f1055d153 Mon Sep 17 00:00:00 2001 From: Arfon Smith Date: Tue, 22 Apr 2014 14:18:51 -0500 Subject: [PATCH] Adding Crystal samples to address https://github.com/github/github/issues/24802 --- lib/linguist/samples.json | 258 +++++++++++++- samples/Crystal/const_spec.cr | 169 +++++++++ samples/Crystal/declare_var_spec.cr | 79 +++++ samples/Crystal/transformer.cr | 515 ++++++++++++++++++++++++++++ 4 files changed, 1018 insertions(+), 3 deletions(-) create mode 100644 samples/Crystal/const_spec.cr create mode 100644 samples/Crystal/declare_var_spec.cr create mode 100644 samples/Crystal/transformer.cr diff --git a/lib/linguist/samples.json b/lib/linguist/samples.json index 51e39804..793b2816 100644 --- a/lib/linguist/samples.json +++ b/lib/linguist/samples.json @@ -96,6 +96,9 @@ "Creole": [ ".creole" ], + "Crystal": [ + ".cr" + ], "CSS": [ ".css" ], @@ -661,8 +664,8 @@ ".gemrc" ] }, - "tokens_total": 583212, - "languages_total": 696, + "tokens_total": 584718, + "languages_total": 699, "tokens": { "ABAP": { "*/**": 1, @@ -16233,6 +16236,253 @@ "Ruby": 1, "distribution.": 1 }, + "Crystal": { + "SHEBANG#!bin/crystal": 2, + "require": 2, + "describe": 2, + "do": 26, + "it": 21, + "run": 14, + "(": 201, + ")": 201, + ".to_i.should": 11, + "eq": 16, + "end": 135, + ".to_f32.should": 2, + ".to_b.should": 1, + "be_true": 1, + "assert_type": 7, + "{": 7, + "int32": 8, + "}": 7, + "union_of": 1, + "char": 1, + "result": 3, + "types": 3, + "[": 9, + "]": 9, + "mod": 1, + "result.program": 1, + "foo": 3, + "mod.types": 1, + "as": 4, + "NonGenericClassType": 1, + "foo.instance_vars": 1, + ".type.should": 3, + "mod.int32": 1, + "GenericClassType": 2, + "foo_i32": 4, + "foo.instantiate": 2, + "of": 3, + "Type": 2, + "|": 8, + "ASTNode": 4, + "foo_i32.lookup_instance_var": 2, + "module": 1, + "Crystal": 1, + "class": 2, + "def": 84, + "transform": 81, + "transformer": 1, + "transformer.before_transform": 1, + "self": 77, + "node": 164, + "transformer.transform": 1, + "transformer.after_transform": 1, + "Transformer": 1, + "before_transform": 1, + "after_transform": 1, + "Expressions": 2, + "exps": 6, + "node.expressions.each": 1, + "exp": 3, + "new_exp": 3, + "exp.transform": 3, + "if": 23, + "new_exp.is_a": 1, + "exps.concat": 1, + "new_exp.expressions": 1, + "else": 2, + "<<": 1, + "exps.length": 1, + "node.expressions": 3, + "Call": 1, + "node_obj": 1, + "node.obj": 9, + "node_obj.transform": 1, + "transform_many": 23, + "node.args": 3, + "node_block": 1, + "node.block": 2, + "node_block.transform": 1, + "node_block_arg": 1, + "node.block_arg": 6, + "node_block_arg.transform": 1, + "And": 1, + "node.left": 3, + "node.left.transform": 3, + "node.right": 3, + "node.right.transform": 3, + "Or": 1, + "StringInterpolation": 1, + "ArrayLiteral": 1, + "node.elements": 1, + "node_of": 1, + "node.of": 2, + "node_of.transform": 1, + "HashLiteral": 1, + "node.keys": 1, + "node.values": 2, + "of_key": 1, + "node.of_key": 2, + "of_key.transform": 1, + "of_value": 1, + "node.of_value": 2, + "of_value.transform": 1, + "If": 1, + "node.cond": 5, + "node.cond.transform": 5, + "node.then": 3, + "node.then.transform": 3, + "node.else": 5, + "node.else.transform": 3, + "Unless": 1, + "IfDef": 1, + "MultiAssign": 1, + "node.targets": 1, + "SimpleOr": 1, + "Def": 1, + "node.body": 12, + "node.body.transform": 10, + "receiver": 2, + "node.receiver": 4, + "receiver.transform": 2, + "block_arg": 2, + "block_arg.transform": 2, + "Macro": 1, + "PointerOf": 1, + "node.exp": 3, + "node.exp.transform": 3, + "SizeOf": 1, + "InstanceSizeOf": 1, + "IsA": 1, + "node.obj.transform": 5, + "node.const": 1, + "node.const.transform": 1, + "RespondsTo": 1, + "Case": 1, + "node.whens": 1, + "node_else": 1, + "node_else.transform": 1, + "When": 1, + "node.conds": 1, + "ImplicitObj": 1, + "ClassDef": 1, + "superclass": 1, + "node.superclass": 2, + "superclass.transform": 1, + "ModuleDef": 1, + "While": 1, + "Generic": 1, + "node.name": 5, + "node.name.transform": 5, + "node.type_vars": 1, + "ExceptionHandler": 1, + "node.rescues": 1, + "node_ensure": 1, + "node.ensure": 2, + "node_ensure.transform": 1, + "Rescue": 1, + "node.types": 2, + "Union": 1, + "Hierarchy": 1, + "Metaclass": 1, + "Arg": 1, + "default_value": 1, + "node.default_value": 2, + "default_value.transform": 1, + "restriction": 1, + "node.restriction": 2, + "restriction.transform": 1, + "BlockArg": 1, + "node.fun": 1, + "node.fun.transform": 1, + "Fun": 1, + "node.inputs": 1, + "output": 1, + "node.output": 2, + "output.transform": 1, + "Block": 1, + "node.args.map": 1, + "Var": 2, + "FunLiteral": 1, + "node.def.body": 1, + "node.def.body.transform": 1, + "FunPointer": 1, + "obj": 1, + "obj.transform": 1, + "Return": 1, + "node.exps": 5, + "Break": 1, + "Next": 1, + "Yield": 1, + "scope": 1, + "node.scope": 2, + "scope.transform": 1, + "Include": 1, + "Extend": 1, + "RangeLiteral": 1, + "node.from": 1, + "node.from.transform": 1, + "node.to": 2, + "node.to.transform": 2, + "Assign": 1, + "node.target": 1, + "node.target.transform": 1, + "node.value": 3, + "node.value.transform": 3, + "Nop": 1, + "NilLiteral": 1, + "BoolLiteral": 1, + "NumberLiteral": 1, + "CharLiteral": 1, + "StringLiteral": 1, + "SymbolLiteral": 1, + "RegexLiteral": 1, + "MetaVar": 1, + "InstanceVar": 1, + "ClassVar": 1, + "Global": 1, + "Require": 1, + "Path": 1, + "Self": 1, + "LibDef": 1, + "FunDef": 1, + "body": 1, + "body.transform": 1, + "TypeDef": 1, + "StructDef": 1, + "UnionDef": 1, + "EnumDef": 1, + "ExternalVar": 1, + "IndirectRead": 1, + "IndirectWrite": 1, + "TypeOf": 1, + "Primitive": 1, + "Not": 1, + "TypeFilteredNode": 1, + "TupleLiteral": 1, + "Cast": 1, + "DeclareVar": 1, + "node.var": 1, + "node.var.transform": 1, + "node.declared_type": 1, + "node.declared_type.transform": 1, + "Alias": 1, + "TupleIndexer": 1, + "Attribute": 1, + "exps.map": 1 + }, "CSS": { ".clearfix": 8, "{": 1661, @@ -60965,6 +61215,7 @@ "Common Lisp": 103, "Coq": 18259, "Creole": 134, + "Crystal": 1506, "CSS": 43867, "Cuda": 290, "Dart": 74, @@ -61138,6 +61389,7 @@ "Common Lisp": 1, "Coq": 12, "Creole": 1, + "Crystal": 3, "CSS": 2, "Cuda": 2, "Dart": 1, @@ -61284,5 +61536,5 @@ "YAML": 2, "Zephir": 2 }, - "md5": "400a9cd944fe65c38a9fa18d58b773b9" + "md5": "5cbb8fcefc5e9c773796d772fe48907d" } \ No newline at end of file diff --git a/samples/Crystal/const_spec.cr b/samples/Crystal/const_spec.cr new file mode 100644 index 00000000..3ab20f14 --- /dev/null +++ b/samples/Crystal/const_spec.cr @@ -0,0 +1,169 @@ +#!/usr/bin/env bin/crystal --run +require "../../spec_helper" + +describe "Codegen: const" do + it "define a constant" do + run("A = 1; A").to_i.should eq(1) + end + + it "support nested constant" do + run("class B; A = 1; end; B::A").to_i.should eq(1) + end + + it "support constant inside a def" do + run(" + class Foo + A = 1 + + def foo + A + end + end + + Foo.new.foo + ").to_i.should eq(1) + end + + it "finds nearest constant first" do + run(" + A = 1 + + class Foo + A = 2.5_f32 + + def foo + A + end + end + + Foo.new.foo + ").to_f32.should eq(2.5) + end + + it "allows constants with same name" do + run(" + A = 1 + + class Foo + A = 2.5_f32 + + def foo + A + end + end + + A + Foo.new.foo + ").to_f32.should eq(2.5) + end + + it "constants with expression" do + run(" + A = 1 + 1 + A + ").to_i.should eq(2) + end + + it "finds global constant" do + run(" + A = 1 + + class Foo + def foo + A + end + end + + Foo.new.foo + ").to_i.should eq(1) + end + + it "define a constant in lib" do + run("lib Foo; A = 1; end; Foo::A").to_i.should eq(1) + end + + it "invokes block in const" do + run("require \"prelude\"; A = [\"1\"].map { |x| x.to_i }; A[0]").to_i.should eq(1) + end + + it "declare constants in right order" do + run("A = 1 + 1; B = true ? A : 0; B").to_i.should eq(2) + end + + it "uses correct types lookup" do + run(" + module A + class B + def foo + 1 + end + end + + C = B.new; + end + + def foo + A::C.foo + end + + foo + ").to_i.should eq(1) + end + + it "codegens variable assignment in const" do + run(" + class Foo + def initialize(@x) + end + + def x + @x + end + end + + A = begin + f = Foo.new(1) + f + end + + def foo + A.x + end + + foo + ").to_i.should eq(1) + end + + it "declaring var" do + run(" + BAR = begin + a = 1 + while 1 == 2 + b = 2 + end + a + end + class Foo + def compile + BAR + end + end + + Foo.new.compile + ").to_i.should eq(1) + end + + it "initialize const that might raise an exception" do + run(" + require \"prelude\" + CONST = (raise \"OH NO\" if 1 == 2) + + def doit + CONST + rescue + end + + doit.nil? + ").to_b.should be_true + end +end diff --git a/samples/Crystal/declare_var_spec.cr b/samples/Crystal/declare_var_spec.cr new file mode 100644 index 00000000..c6a44127 --- /dev/null +++ b/samples/Crystal/declare_var_spec.cr @@ -0,0 +1,79 @@ +#!/usr/bin/env bin/crystal --run +require "../../spec_helper" + +describe "Type inference: declare var" do + it "types declare var" do + assert_type("a :: Int32") { int32 } + end + + it "types declare var and reads it" do + assert_type("a :: Int32; a") { int32 } + end + + it "types declare var and changes its type" do + assert_type("a :: Int32; while 1 == 2; a = 'a'; end; a") { union_of(int32, char) } + end + + it "declares instance var which appears in initialize" do + result = assert_type(" + class Foo + @x :: Int32 + end + + Foo.new") { types["Foo"] } + + mod = result.program + + foo = mod.types["Foo"] as NonGenericClassType + foo.instance_vars["@x"].type.should eq(mod.int32) + end + + it "declares instance var of generic class" do + result = assert_type(" + class Foo(T) + @x :: T + end + + Foo(Int32).new") do + foo = types["Foo"] as GenericClassType + foo_i32 = foo.instantiate([int32] of Type | ASTNode) + foo_i32.lookup_instance_var("@x").type.should eq(int32) + foo_i32 + end + end + + it "declares instance var of generic class after reopen" do + result = assert_type(" + class Foo(T) + end + + f = Foo(Int32).new + + class Foo(T) + @x :: T + end + + f") do + foo = types["Foo"] as GenericClassType + foo_i32 = foo.instantiate([int32] of Type | ASTNode) + foo_i32.lookup_instance_var("@x").type.should eq(int32) + foo_i32 + end + end + + it "declares an instance variable in initialize" do + assert_type(" + class Foo + def initialize + @x :: Int32 + end + + def x + @x + end + end + + Foo.new.x + ") { int32 } + end +end diff --git a/samples/Crystal/transformer.cr b/samples/Crystal/transformer.cr new file mode 100644 index 00000000..8bb78fbe --- /dev/null +++ b/samples/Crystal/transformer.cr @@ -0,0 +1,515 @@ +module Crystal + class ASTNode + def transform(transformer) + transformer.before_transform self + node = transformer.transform self + transformer.after_transform self + node + end + end + + class Transformer + def before_transform(node) + end + + def after_transform(node) + end + + def transform(node : Expressions) + exps = [] of ASTNode + node.expressions.each do |exp| + new_exp = exp.transform(self) + if new_exp + if new_exp.is_a?(Expressions) + exps.concat new_exp.expressions + else + exps << new_exp + end + end + end + + if exps.length == 1 + exps[0] + else + node.expressions = exps + node + end + end + + def transform(node : Call) + if node_obj = node.obj + node.obj = node_obj.transform(self) + end + transform_many node.args + + if node_block = node.block + node.block = node_block.transform(self) + end + + if node_block_arg = node.block_arg + node.block_arg = node_block_arg.transform(self) + end + + node + end + + def transform(node : And) + node.left = node.left.transform(self) + node.right = node.right.transform(self) + node + end + + def transform(node : Or) + node.left = node.left.transform(self) + node.right = node.right.transform(self) + node + end + + def transform(node : StringInterpolation) + transform_many node.expressions + node + end + + def transform(node : ArrayLiteral) + transform_many node.elements + + if node_of = node.of + node.of = node_of.transform(self) + end + + node + end + + def transform(node : HashLiteral) + transform_many node.keys + transform_many node.values + + if of_key = node.of_key + node.of_key = of_key.transform(self) + end + + if of_value = node.of_value + node.of_value = of_value.transform(self) + end + + node + end + + def transform(node : If) + node.cond = node.cond.transform(self) + node.then = node.then.transform(self) + node.else = node.else.transform(self) + node + end + + def transform(node : Unless) + node.cond = node.cond.transform(self) + node.then = node.then.transform(self) + node.else = node.else.transform(self) + node + end + + def transform(node : IfDef) + node.cond = node.cond.transform(self) + node.then = node.then.transform(self) + node.else = node.else.transform(self) + node + end + + def transform(node : MultiAssign) + transform_many node.targets + transform_many node.values + node + end + + def transform(node : SimpleOr) + node.left = node.left.transform(self) + node.right = node.right.transform(self) + node + end + + def transform(node : Def) + transform_many node.args + node.body = node.body.transform(self) + + if receiver = node.receiver + node.receiver = receiver.transform(self) + end + + if block_arg = node.block_arg + node.block_arg = block_arg.transform(self) + end + + node + end + + def transform(node : Macro) + transform_many node.args + node.body = node.body.transform(self) + + if receiver = node.receiver + node.receiver = receiver.transform(self) + end + + if block_arg = node.block_arg + node.block_arg = block_arg.transform(self) + end + + node + end + + def transform(node : PointerOf) + node.exp = node.exp.transform(self) + node + end + + def transform(node : SizeOf) + node.exp = node.exp.transform(self) + node + end + + def transform(node : InstanceSizeOf) + node.exp = node.exp.transform(self) + node + end + + def transform(node : IsA) + node.obj = node.obj.transform(self) + node.const = node.const.transform(self) + node + end + + def transform(node : RespondsTo) + node.obj = node.obj.transform(self) + node + end + + def transform(node : Case) + node.cond = node.cond.transform(self) + transform_many node.whens + + if node_else = node.else + node.else = node_else.transform(self) + end + + node + end + + def transform(node : When) + transform_many node.conds + node.body = node.body.transform(self) + node + end + + def transform(node : ImplicitObj) + node + end + + def transform(node : ClassDef) + node.body = node.body.transform(self) + + if superclass = node.superclass + node.superclass = superclass.transform(self) + end + + node + end + + def transform(node : ModuleDef) + node.body = node.body.transform(self) + node + end + + def transform(node : While) + node.cond = node.cond.transform(self) + node.body = node.body.transform(self) + node + end + + def transform(node : Generic) + node.name = node.name.transform(self) + transform_many node.type_vars + node + end + + def transform(node : ExceptionHandler) + node.body = node.body.transform(self) + transform_many node.rescues + + if node_ensure = node.ensure + node.ensure = node_ensure.transform(self) + end + + node + end + + def transform(node : Rescue) + node.body = node.body.transform(self) + transform_many node.types + node + end + + def transform(node : Union) + transform_many node.types + node + end + + def transform(node : Hierarchy) + node.name = node.name.transform(self) + node + end + + def transform(node : Metaclass) + node.name = node.name.transform(self) + node + end + + def transform(node : Arg) + if default_value = node.default_value + node.default_value = default_value.transform(self) + end + + if restriction = node.restriction + node.restriction = restriction.transform(self) + end + + node + end + + def transform(node : BlockArg) + node.fun = node.fun.transform(self) + node + end + + def transform(node : Fun) + transform_many node.inputs + + if output = node.output + node.output = output.transform(self) + end + + node + end + + def transform(node : Block) + node.args.map! { |exp| exp.transform(self) as Var } + node.body = node.body.transform(self) + node + end + + def transform(node : FunLiteral) + node.def.body = node.def.body.transform(self) + node + end + + def transform(node : FunPointer) + if obj = node.obj + node.obj = obj.transform(self) + end + node + end + + def transform(node : Return) + transform_many node.exps + node + end + + def transform(node : Break) + transform_many node.exps + node + end + + def transform(node : Next) + transform_many node.exps + node + end + + def transform(node : Yield) + if scope = node.scope + node.scope = scope.transform(self) + end + transform_many node.exps + node + end + + def transform(node : Include) + node.name = node.name.transform(self) + node + end + + def transform(node : Extend) + node.name = node.name.transform(self) + node + end + + def transform(node : RangeLiteral) + node.from = node.from.transform(self) + node.to = node.to.transform(self) + node + end + + def transform(node : Assign) + node.target = node.target.transform(self) + node.value = node.value.transform(self) + node + end + + def transform(node : Nop) + node + end + + def transform(node : NilLiteral) + node + end + + def transform(node : BoolLiteral) + node + end + + def transform(node : NumberLiteral) + node + end + + def transform(node : CharLiteral) + node + end + + def transform(node : StringLiteral) + node + end + + def transform(node : SymbolLiteral) + node + end + + def transform(node : RegexLiteral) + node + end + + def transform(node : Var) + node + end + + def transform(node : MetaVar) + node + end + + def transform(node : InstanceVar) + node + end + + def transform(node : ClassVar) + node + end + + def transform(node : Global) + node + end + + def transform(node : Require) + node + end + + def transform(node : Path) + node + end + + def transform(node : Self) + node + end + + def transform(node : LibDef) + node.body = node.body.transform(self) + node + end + + def transform(node : FunDef) + if body = node.body + node.body = body.transform(self) + end + node + end + + def transform(node : TypeDef) + node + end + + def transform(node : StructDef) + node + end + + def transform(node : UnionDef) + node + end + + def transform(node : EnumDef) + node + end + + def transform(node : ExternalVar) + node + end + + def transform(node : IndirectRead) + node.obj = node.obj.transform(self) + node + end + + def transform(node : IndirectWrite) + node.obj = node.obj.transform(self) + node.value = node.value.transform(self) + node + end + + def transform(node : TypeOf) + transform_many node.expressions + node + end + + def transform(node : Primitive) + node + end + + def transform(node : Not) + node + end + + def transform(node : TypeFilteredNode) + node + end + + def transform(node : TupleLiteral) + transform_many node.exps + node + end + + def transform(node : Cast) + node.obj = node.obj.transform(self) + node.to = node.to.transform(self) + node + end + + def transform(node : DeclareVar) + node.var = node.var.transform(self) + node.declared_type = node.declared_type.transform(self) + node + end + + def transform(node : Alias) + node.value = node.value.transform(self) + node + end + + def transform(node : TupleIndexer) + node + end + + def transform(node : Attribute) + node + end + + def transform_many(exps) + exps.map! { |exp| exp.transform(self) } if exps + end + end +end