├── spec ├── std │ ├── data │ │ ├── dir │ │ │ ├── subdir2 │ │ │ │ └── .gitkeep │ │ │ ├── f1.txt │ │ │ ├── f2.txt │ │ │ ├── f3.txx │ │ │ ├── g2.txt │ │ │ └── subdir │ │ │ │ ├── f1.txt │ │ │ │ └── subdir2 │ │ │ │ └── f2.txt │ │ ├── symlink.txt │ │ ├── argf_test_file_1.txt │ │ ├── argf_test_file_2.txt │ │ ├── test_template.ecr │ │ ├── websocket_longpacket.bin │ │ ├── test_file.ini │ │ └── test_file.txt │ ├── openssl │ │ ├── cipher_spec.ciphertext │ │ ├── pkcs5_spec.cr │ │ ├── hmac_spec.cr │ │ ├── digest_spec.cr │ │ └── cipher_spec.cr │ ├── box_spec.cr │ ├── crypto │ │ ├── md5_spec.cr │ │ ├── bcrypt │ │ │ └── password_spec.cr │ │ └── subtle_spec.cr │ ├── uint_spec.cr │ ├── concurrent_spec.cr │ ├── double_spec.cr │ ├── oauth │ │ ├── params_spec.cr │ │ ├── authorization_header_spec.cr │ │ ├── request_token_spec.cr │ │ └── access_token_spec.cr │ ├── html_spec.cr │ ├── file_utils_spec.cr │ ├── oauth2 │ │ └── session_spec.cr │ ├── zlib │ │ ├── deflate_spec.cr │ │ ├── inflate_spec.cr │ │ ├── stress_spec.cr │ │ └── zlib_spec.cr │ ├── string_builder_spec.cr │ ├── struct_spec.cr │ ├── signal_spec.cr │ ├── class_spec.cr │ ├── http │ │ ├── http_spec.cr │ │ ├── server │ │ │ └── handlers │ │ │ │ └── websocket_handler_spec.cr │ │ └── server_spec.cr │ ├── readline_spec.cr │ ├── ecr │ │ └── ecr_spec.cr │ ├── symbol_spec.cr │ ├── llvm │ │ └── x86_abi_spec.cr │ ├── io │ │ └── argf_spec.cr │ ├── inifile_spec.cr │ ├── yaml │ │ └── yaml_spec.cr │ ├── semantic_version_spec.cr │ ├── bool_spec.cr │ ├── tempfile_spec.cr │ ├── thread_spec.cr │ ├── levenshtein_spec.cr │ ├── thread │ │ └── condition_variable_spec.cr │ ├── random_spec.cr │ ├── reference_spec.cr │ ├── html │ │ └── builder_spec.cr │ └── string_pool_spec.cr ├── compiler │ ├── crystal_path │ │ └── test_files │ │ │ ├── file_one.cr │ │ │ ├── file_two.cr │ │ │ └── test_folder │ │ │ ├── file_three.cr │ │ │ ├── test_folder.cr │ │ │ └── not_a_crystal_file.txt │ ├── data │ │ ├── compiler_sample │ │ └── build │ ├── normalize │ │ ├── until_spec.cr │ │ ├── unless_spec.cr │ │ ├── range_literal_spec.cr │ │ ├── string_interpolation_spec.cr │ │ ├── ifdef_spec.cr │ │ ├── array_literal_spec.cr │ │ ├── hash_literal_spec.cr │ │ ├── or_spec.cr │ │ ├── return_next_break_spec.cr │ │ ├── and_spec.cr │ │ └── chained_comparisons_spec.cr │ ├── codegen │ │ ├── until_spec.cr │ │ ├── untyped_expression_spec.cr │ │ ├── asm_spec.cr │ │ ├── global_spec.cr │ │ ├── previous_def_spec.cr │ │ ├── no_return_spec.cr │ │ └── private_def_spec.cr │ ├── type_inference │ │ ├── c_type_spec.cr │ │ ├── reflection_spec.cr │ │ ├── responds_to_spec.cr │ │ ├── array_spec.cr │ │ ├── method_missing_spec.cr │ │ ├── dependencies_spec.cr │ │ ├── c_enum_spec.cr │ │ ├── named_args_spec.cr │ │ └── global_spec.cr │ ├── compiler_spec.cr │ └── parser │ │ └── parser_doc_spec.cr └── all_spec.cr ├── .dockerignore ├── src ├── http │ ├── http.cr │ └── server │ │ └── handlers │ │ ├── error_handler.cr │ │ ├── log_handler.cr │ │ ├── deflate_handler.cr │ │ └── static_file_handler.cr ├── compiler │ ├── crystal │ │ ├── tools │ │ │ ├── init │ │ │ │ └── template │ │ │ │ │ ├── travis.yml.ecr │ │ │ │ │ ├── version.cr.ecr │ │ │ │ │ ├── spec_helper.cr.ecr │ │ │ │ │ ├── example.cr.ecr │ │ │ │ │ ├── shard.yml.ecr │ │ │ │ │ ├── example_spec.cr.ecr │ │ │ │ │ ├── gitignore.ecr │ │ │ │ │ ├── readme.md.ecr │ │ │ │ │ └── license.ecr │ │ │ ├── doc.cr │ │ │ ├── doc │ │ │ │ ├── item.cr │ │ │ │ ├── html │ │ │ │ │ ├── other_types.html │ │ │ │ │ ├── method_summary.html │ │ │ │ │ ├── list_items.html │ │ │ │ │ ├── methods_inherited.html │ │ │ │ │ ├── main.html │ │ │ │ │ └── method_detail.html │ │ │ │ ├── constant.cr │ │ │ │ ├── templates.cr │ │ │ │ └── macro.cr │ │ │ └── print_types_visitor.cr │ │ ├── core_ext │ │ │ └── enumerable.cr │ │ ├── config.cr │ │ ├── version.cr │ │ ├── codegen │ │ │ ├── target_machine.cr │ │ │ ├── types.cr │ │ │ ├── crystal_llvm_builder.cr │ │ │ └── asm.cr │ │ ├── macros │ │ │ └── virtual_file.cr │ │ ├── syntax │ │ │ ├── visitor.cr │ │ │ └── location.cr │ │ └── semantic │ │ │ ├── flags.cr │ │ │ └── match.cr │ └── crystal.cr ├── ecr │ ├── process.cr │ └── macros.cr ├── concurrent │ ├── error.cr │ └── concurrent.cr ├── oauth2 │ ├── oauth2.cr │ ├── access_token │ │ └── bearer.cr │ ├── error.cr │ └── session.cr ├── oauth │ ├── error.cr │ ├── oauth.cr │ ├── request_token.cr │ ├── authorization_header.cr │ ├── params.cr │ └── access_token.cr ├── llvm │ ├── value.cr │ ├── context.cr │ ├── basic_block.cr │ ├── basic_block_collection.cr │ ├── phi_table.cr │ ├── instruction_collection.cr │ ├── module_pass_manager.cr │ ├── global_collection.cr │ ├── target_data.cr │ ├── pass_registry.cr │ ├── generic_value.cr │ ├── function_collection.cr │ ├── function_pass_manager.cr │ ├── parameter_collection.cr │ ├── function.cr │ ├── jit_compiler.cr │ ├── pass_manager_builder.cr │ ├── abi.cr │ ├── target.cr │ └── target_machine.cr ├── time │ ├── day_of_week.cr │ └── format.cr ├── io │ ├── error.cr │ ├── pointer_io.cr │ └── fd_set.cr ├── empty.cr ├── box.cr ├── xml │ ├── attribute_type.cr │ ├── save_options.cr │ ├── type.cr │ ├── html_parser_options.cr │ ├── namespace.cr │ ├── error.cr │ ├── node_set.cr │ ├── attributes.cr │ └── xml.cr ├── openssl │ ├── md5.cr │ ├── sha1.cr │ ├── pkcs5.cr │ ├── ssl │ │ ├── context.cr │ │ └── socket.cr │ ├── openssl.cr │ ├── digest │ │ └── digest_base.cr │ ├── hmac.cr │ └── lib_ssl.cr ├── gc.cr ├── crypto │ ├── subtle.cr │ └── bcrypt │ │ └── blowfish.cr ├── json │ ├── lexer │ │ └── io_based.cr │ └── token.cr ├── reflect.cr ├── fiber │ └── lib_pcl.cr ├── html.cr ├── csv │ ├── error.cr │ ├── token.cr │ └── lexer │ │ ├── io_based.cr │ │ └── string_based.cr ├── inifile.cr ├── main.cr ├── spec │ ├── source.cr │ ├── formatter.cr │ └── dsl.cr ├── thread │ ├── mutex.cr │ ├── condition_variable.cr │ ├── thread.cr │ └── lib_pthread.cr ├── intrinsics.cr ├── gc │ └── null.cr ├── file_utils.cr ├── markdown │ └── markdown.cr ├── value.cr ├── dl.cr ├── iterable.cr ├── proc.cr ├── class.cr ├── regex │ └── lib_pcre.cr ├── prelude.cr ├── process │ └── status.cr ├── zlib │ └── inflate.cr ├── unwind.cr └── file │ └── flock.cr ├── samples ├── quine.cr ├── egrep.cr ├── http_server.cr ├── tcp_client.cr ├── mandelbrot2.cr ├── sieve.cr ├── tcp_server.cr ├── tree.cr ├── channel_primes.cr ├── channel_select.cr ├── sdl │ ├── tv.txt │ ├── fire.txt │ └── sdl │ │ ├── surface.cr │ │ └── sdl.cr ├── mandelbrot.cr ├── spectral-norm.cr ├── matmul.cr ├── impl.cr ├── wordcount.cr └── binary-trees.cr ├── .editorconfig ├── .gitignore ├── Dockerfile.release ├── docs ├── char.cr └── main.cr ├── LICENSE ├── Dockerfile ├── .travis.yml ├── Vagrantfile ├── BACKERS.md └── Makefile /spec/std/data/dir/subdir2/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/std/data/symlink.txt: -------------------------------------------------------------------------------- 1 | test_file.txt -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .crystal 3 | .vagrant 4 | -------------------------------------------------------------------------------- /spec/std/data/argf_test_file_1.txt: -------------------------------------------------------------------------------- 1 | 12345 2 | -------------------------------------------------------------------------------- /spec/std/data/argf_test_file_2.txt: -------------------------------------------------------------------------------- 1 | 67890 2 | -------------------------------------------------------------------------------- /spec/compiler/crystal_path/test_files/file_one.cr: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/compiler/crystal_path/test_files/file_two.cr: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/compiler/data/compiler_sample: -------------------------------------------------------------------------------- 1 | print "Hello!" 2 | -------------------------------------------------------------------------------- /src/http/http.cr: -------------------------------------------------------------------------------- 1 | require "uri" 2 | require "./**" 3 | -------------------------------------------------------------------------------- /spec/std/data/dir/f1.txt: -------------------------------------------------------------------------------- 1 | This file is for Dir.glob specs -------------------------------------------------------------------------------- /spec/std/data/dir/f2.txt: -------------------------------------------------------------------------------- 1 | This file is for Dir.glob specs -------------------------------------------------------------------------------- /spec/std/data/dir/f3.txx: -------------------------------------------------------------------------------- 1 | This file is for Dir.glob specs -------------------------------------------------------------------------------- /spec/std/data/dir/g2.txt: -------------------------------------------------------------------------------- 1 | This file is for Dir.glob specs -------------------------------------------------------------------------------- /spec/compiler/crystal_path/test_files/test_folder/file_three.cr: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/std/data/dir/subdir/f1.txt: -------------------------------------------------------------------------------- 1 | This file is for Dir.glob specs -------------------------------------------------------------------------------- /spec/compiler/crystal_path/test_files/test_folder/test_folder.cr: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/compiler/crystal_path/test_files/test_folder/not_a_crystal_file.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/compiler/data/build: -------------------------------------------------------------------------------- 1 | puts "this file is never compiled (#1412)" 2 | -------------------------------------------------------------------------------- /spec/std/data/dir/subdir/subdir2/f2.txt: -------------------------------------------------------------------------------- 1 | This file is for Dir.glob specs -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/travis.yml.ecr: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /src/compiler/crystal.cr: -------------------------------------------------------------------------------- 1 | require "./crystal/**" 2 | 3 | Crystal::Command.run 4 | -------------------------------------------------------------------------------- /src/ecr/process.cr: -------------------------------------------------------------------------------- 1 | require "ecr" 2 | puts ECR.process_file(ARGV[0], ARGV[1]) 3 | -------------------------------------------------------------------------------- /samples/quine.cr: -------------------------------------------------------------------------------- 1 | s = "s = @; puts s.sub(\"@\", s.dump)"; puts s.sub("@", s.dump) 2 | -------------------------------------------------------------------------------- /spec/all_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "./compiler/**" 3 | require "./std/**" 4 | -------------------------------------------------------------------------------- /spec/std/data/test_template.ecr: -------------------------------------------------------------------------------- 1 | Hello <%= @msg %> <% 3.times { |i| %><%= i %><% } %> 2 | -------------------------------------------------------------------------------- /src/concurrent/error.cr: -------------------------------------------------------------------------------- 1 | module Concurrent 2 | class CanceledError < Exception; end 3 | end 4 | -------------------------------------------------------------------------------- /src/oauth2/oauth2.cr: -------------------------------------------------------------------------------- 1 | require "http/client" 2 | require "http/params" 3 | require "json" 4 | require "./**" 5 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/version.cr.ecr: -------------------------------------------------------------------------------- 1 | module <%= module_name %> 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/spec_helper.cr.ecr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/<%= @config.name %>" 3 | -------------------------------------------------------------------------------- /spec/std/data/websocket_longpacket.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinh/crystal/master/spec/std/data/websocket_longpacket.bin -------------------------------------------------------------------------------- /spec/std/openssl/cipher_spec.ciphertext: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinh/crystal/master/spec/std/openssl/cipher_spec.ciphertext -------------------------------------------------------------------------------- /src/oauth/error.cr: -------------------------------------------------------------------------------- 1 | class OAuth::Error < ::Exception 2 | def initialize(@response) 3 | super("OAuth:Error: #{@response.body}") 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/std/data/test_file.ini: -------------------------------------------------------------------------------- 1 | [general] 2 | log_level = DEBUG 3 | 4 | [section1] 5 | foo = 1 6 | bar = 2 7 | 8 | [section2] 9 | x.y.z = coco lala 10 | 11 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/example.cr.ecr: -------------------------------------------------------------------------------- 1 | require "./<%= config.name %>/*" 2 | 3 | module <%= module_name %> 4 | # TODO Put your code here 5 | end 6 | -------------------------------------------------------------------------------- /src/llvm/value.cr: -------------------------------------------------------------------------------- 1 | require "./value_methods" 2 | 3 | struct LLVM::Value 4 | include ValueMethods 5 | 6 | def to_value 7 | self 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/time/day_of_week.cr: -------------------------------------------------------------------------------- 1 | enum Time::DayOfWeek 2 | Sunday 3 | Monday 4 | Tuesday 5 | Wednesday 6 | Thursday 7 | Friday 8 | Saturday 9 | end 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cr] 2 | charset = utf-8 3 | end_of_line = lf 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /src/oauth/oauth.cr: -------------------------------------------------------------------------------- 1 | require "http/client" 2 | require "http/params" 3 | require "uri" 4 | require "secure_random" 5 | require "openssl/hmac" 6 | require "base64" 7 | require "./**" 8 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/shard.yml.ecr: -------------------------------------------------------------------------------- 1 | name: <%= config.name %> 2 | version: 0.1.0 3 | 4 | authors: 5 | - <%= config.author %> <<%= config.email %>> 6 | 7 | license: MIT 8 | -------------------------------------------------------------------------------- /spec/std/box_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "Box" do 4 | it "boxes and unboxes" do 5 | a = 1 6 | box = Box.box(a) 7 | Box(Int32).unbox(box).should eq(1) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/compiler/crystal/core_ext/enumerable.cr: -------------------------------------------------------------------------------- 1 | module Enumerable 2 | def to_s_with_line_numbers 3 | map_with_index { |line, i| "#{"%3d" % (i + 1)}. #{line.to_s.chomp}" }.join "\n" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /samples/egrep.cr: -------------------------------------------------------------------------------- 1 | if ARGV.empty? 2 | puts "usage: cat somefile | egrep 'some'" 3 | exit 4 | end 5 | 6 | regx = Regex.new(ARGV[0]) 7 | while str = STDIN.gets 8 | STDOUT.print(str) if str =~ regx 9 | end 10 | -------------------------------------------------------------------------------- /spec/compiler/normalize/until_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: until" do 4 | it "normalizes until" do 5 | assert_normalize "until 1; 2; end", "while !1\n 2\nend" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc.cr: -------------------------------------------------------------------------------- 1 | require "markdown" 2 | 3 | module Crystal 4 | def self.generate_docs(program, base_dirs) 5 | generator = Doc::Generator.new(program, base_dirs) 6 | generator.run 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/item.cr: -------------------------------------------------------------------------------- 1 | module Crystal::Doc::Item 2 | def formatted_doc 3 | @generator.doc(self) 4 | end 5 | 6 | def formatted_summary 7 | @generator.summary(self) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/io/error.cr: -------------------------------------------------------------------------------- 1 | module IO 2 | class Error < Exception 3 | end 4 | 5 | class EOFError < Error 6 | def initialize(message = "end of file reached") 7 | super(message) 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/compiler/normalize/unless_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: unless" do 4 | it "normalizes unless" do 5 | assert_normalize "unless 1; 2; end", "if 1\nelse\n 2\nend" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /src/llvm/context.cr: -------------------------------------------------------------------------------- 1 | class LLVM::Context 2 | def initialize(@unwrap) 3 | end 4 | 5 | def self.global 6 | new LibLLVM.get_global_context 7 | end 8 | 9 | def to_unsafe 10 | @unwrap 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.tags 3 | /.tags_sorted_by_file 4 | /.vagrant 5 | .crystal/ 6 | coverage/ 7 | /deps/ 8 | /.build/ 9 | .*.swp 10 | /Makefile.local 11 | all_spec 12 | /tmp 13 | /doc/ 14 | /src/llvm/ext/llvm_ext.o 15 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/example_spec.cr.ecr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe <%= module_name %> do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /samples/http_server.cr: -------------------------------------------------------------------------------- 1 | require "http/server" 2 | 3 | server = HTTP::Server.new "0.0.0.0", 8080 do |request| 4 | HTTP::Response.ok "text/plain", "Hello world!" 5 | end 6 | 7 | puts "Listening on http://0.0.0.0:8080" 8 | server.listen 9 | -------------------------------------------------------------------------------- /spec/std/crypto/md5_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "crypto/md5" 3 | 4 | describe "MD5" do 5 | it "calculates hash from string" do 6 | Crypto::MD5.hex_digest("foo").should eq("acbd18db4cc2f85cedef654fccc4a4d8") 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/std/uint_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "UInt" do 4 | it "compares with <=>" do 5 | (1_u32 <=> 0_u32).should eq(1) 6 | (0_u32 <=> 0_u32).should eq(0) 7 | (0_u32 <=> 1_u32).should eq(-1) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/empty.cr: -------------------------------------------------------------------------------- 1 | lib LibCrystalMain 2 | @[Raises] 3 | fun __crystal_main(argc : Int32, argv : UInt8**) 4 | end 5 | 6 | fun main(argc : Int32, argv : UInt8**) : Int32 7 | LibCrystalMain.__crystal_main(argc, argv) 8 | 0 9 | end 10 | -------------------------------------------------------------------------------- /samples/tcp_client.cr: -------------------------------------------------------------------------------- 1 | require "socket" 2 | 3 | # goes with tcp_server.cr 4 | 5 | socket = TCPSocket.new "127.0.0.1", 9000 6 | 10.times do |i| 7 | socket.puts "#{i}" 8 | puts "server response #{socket.gets}" 9 | sleep 0.5 10 | end 11 | -------------------------------------------------------------------------------- /src/ecr/macros.cr: -------------------------------------------------------------------------------- 1 | macro embed_ecr(filename, io_name) 2 | \{{ run("ecr/process", {{filename}}, {{io_name}}) }} 3 | end 4 | 5 | macro ecr_file(filename) 6 | def to_s(__io__) 7 | embed_ecr {{filename}}, "__io__" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/box.cr: -------------------------------------------------------------------------------- 1 | class Box(T) 2 | getter object 3 | 4 | def initialize(@object : T) 5 | end 6 | 7 | def self.box(object) 8 | new(object) as Void* 9 | end 10 | 11 | def self.unbox(pointer : Void*) 12 | (pointer as self).object 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/std/concurrent_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "concurrent" do 4 | it "does three things concurrently" do 5 | a, b, c = parallel(1 + 2, "hello".size, [1, 2, 3, 4].size) 6 | a.should eq(3) 7 | b.should eq(5) 8 | c.should eq(4) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/std/double_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "Double" do 4 | describe "**" do 5 | assert { (2.5 ** 2).should eq(6.25) } 6 | assert { (2.5 ** 2.5_f32).should eq(9.882117688026186) } 7 | assert { (2.5 ** 2.5).should eq(9.882117688026186) } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/gitignore.ecr: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /libs/ 3 | /.crystal/ 4 | /.shards/ 5 | 6 | <% if config.skeleton_type == "lib" %> 7 | # Libraries don't need dependency lock 8 | # Dependencies will be locked in application that uses them 9 | /shard.lock 10 | <% end %> 11 | -------------------------------------------------------------------------------- /src/http/server/handlers/error_handler.cr: -------------------------------------------------------------------------------- 1 | class HTTP::ErrorHandler < HTTP::Handler 2 | def call(request) 3 | begin 4 | call_next(request) 5 | rescue ex : Exception 6 | Response.error("text/plain", "ERROR: #{ex.inspect_with_backtrace}\n") 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /src/xml/attribute_type.cr: -------------------------------------------------------------------------------- 1 | enum XML::AttributeType 2 | CDATA = 1 3 | ID = 2 4 | IDREF = 3 5 | IDREFS = 4 6 | ENTITY = 5 7 | ENTITIES = 6 8 | NMTOKEN = 7 9 | NMTOKENS = 8 10 | ENUMERATION = 9 11 | NOTATION = 10 12 | end 13 | -------------------------------------------------------------------------------- /samples/mandelbrot2.cr: -------------------------------------------------------------------------------- 1 | require "complex" 2 | 3 | def mandelbrot(a) 4 | Iterator.of(a).take(100).inject(a) { |z, c| z*z + c } 5 | end 6 | 7 | (1.0).step(-1, -0.05) do |y| 8 | (-2.0).step(0.5, 0.0315) do |x| 9 | print mandelbrot(x + y.i).abs < 2 ? '*' : ' ' 10 | end 11 | puts 12 | end 13 | -------------------------------------------------------------------------------- /src/llvm/basic_block.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::BasicBlock 2 | def initialize(@unwrap) 3 | end 4 | 5 | def instructions 6 | InstructionCollection.new self 7 | end 8 | 9 | def delete 10 | LibLLVM.delete_basic_block self 11 | end 12 | 13 | def to_unsafe 14 | @unwrap 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/html/other_types.html: -------------------------------------------------------------------------------- 1 | <% unless other_types.empty? %> 2 |

<%= title %>

3 | 8 | <% end %> 9 | -------------------------------------------------------------------------------- /spec/compiler/codegen/until_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Codegen: until" do 4 | it "codegens until" do 5 | run(%( 6 | require "bool" 7 | 8 | a = 1 9 | until a == 10 10 | a = a + 1 11 | end 12 | a 13 | )).to_i.should eq(10) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/openssl/md5.cr: -------------------------------------------------------------------------------- 1 | require "./lib_crypto" 2 | 3 | class OpenSSL::MD5 4 | def self.hash(data : String) 5 | hash(data.cstr, data.bytesize) 6 | end 7 | 8 | def self.hash(data : UInt8*, bytesize : Int) 9 | buffer :: UInt8[16] 10 | LibCrypto.md5(data, bytesize, buffer) 11 | buffer 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /src/gc.cr: -------------------------------------------------------------------------------- 1 | module GC 2 | def self.malloc(size : Int) 3 | __crystal_malloc(size.to_u32) 4 | end 5 | 6 | def self.malloc_atomic(size : Int) 7 | __crystal_malloc_atomic(size.to_u32) 8 | end 9 | 10 | def self.realloc(pointer : Void*, size : Int) 11 | __crystal_realloc(pointer, size.to_u32) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/compiler/normalize/range_literal_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: range literal" do 4 | it "normalizes not exclusive" do 5 | assert_expand "1..2", "::Range.new(1, 2, false)" 6 | end 7 | 8 | it "normalizes exclusive" do 9 | assert_expand "1...2", "::Range.new(1, 2, true)" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /src/openssl/sha1.cr: -------------------------------------------------------------------------------- 1 | require "./lib_crypto" 2 | 3 | class OpenSSL::SHA1 4 | def self.hash(data : String) 5 | hash(data.cstr, LibC::SizeT.new(data.bytesize)) 6 | end 7 | 8 | def self.hash(data : UInt8*, bytesize : LibC::SizeT) 9 | buffer :: UInt8[20] 10 | LibCrypto.sha1(data, bytesize, buffer) 11 | buffer 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/std/data/test_file.txt: -------------------------------------------------------------------------------- 1 | Hello World 2 | Hello World 3 | Hello World 4 | Hello World 5 | Hello World 6 | Hello World 7 | Hello World 8 | Hello World 9 | Hello World 10 | Hello World 11 | Hello World 12 | Hello World 13 | Hello World 14 | Hello World 15 | Hello World 16 | Hello World 17 | Hello World 18 | Hello World 19 | Hello World 20 | Hello World 21 | -------------------------------------------------------------------------------- /spec/std/oauth/params_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "oauth" 3 | 4 | describe OAuth::Params do 5 | it "builds" do 6 | params = OAuth::Params.new 7 | params.add "foo", "value1" 8 | params.add "bar", "a+b" 9 | params.add "a=", "=/=" 10 | params.to_s.should eq("a%253D%3D%253D%252F%253D%26bar%3Da%252Bb%26foo%3Dvalue1") 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/std/oauth/authorization_header_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "oauth" 3 | 4 | describe OAuth::AuthorizationHeader do 5 | it "builds" do 6 | params = OAuth::AuthorizationHeader.new 7 | params.add "foo", "value1" 8 | params.add "bar", "a+b" 9 | params.add "baz", "=/=" 10 | params.to_s.should eq(%(OAuth foo="value1", bar="a%2Bb", baz="%3D%2F%3D")) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /src/llvm/basic_block_collection.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::BasicBlockCollection 2 | def initialize(@function) 3 | end 4 | 5 | def append(name = "") 6 | BasicBlock.new LibLLVM.append_basic_block(@function, name) 7 | end 8 | 9 | def append(name = "") 10 | block = append name 11 | builder = Builder.new 12 | builder.position_at_end block 13 | yield builder 14 | block 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /src/compiler/crystal/config.cr: -------------------------------------------------------------------------------- 1 | module Crystal 2 | module Config 3 | PATH = {{ env("CRYSTAL_CONFIG_PATH") || "" }} 4 | VERSION = {{ env("CRYSTAL_CONFIG_VERSION") || `(git describe --tags --long 2>/dev/null)`.stringify.chomp }} 5 | CACHE_DIR = ENV["CRYSTAL_CACHE_DIR"]? || ".crystal" 6 | 7 | def self.cache_dir 8 | @@cache_dir ||= File.expand_path(CACHE_DIR) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /src/openssl/pkcs5.cr: -------------------------------------------------------------------------------- 1 | require "./openssl" 2 | 3 | module OpenSSL::PKCS5 4 | def self.pbkdf2_hmac_sha1(secret, salt, iterations = 2**16, key_size = 64) 5 | buffer = Slice(UInt8).new(key_size) 6 | if LibCrypto.pkcs5_pbkdf2_hmac_sha1(secret, secret.bytesize, salt, salt.bytesize, iterations, key_size, buffer) != 1 7 | raise OpenSSL::Error.new "pkcs5_pbkdf2_hmac" 8 | end 9 | buffer 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /src/compiler/crystal/version.cr: -------------------------------------------------------------------------------- 1 | require "./config" 2 | 3 | def Crystal.version_string 4 | build_date = {{ `date -u`.stringify.chomp }} 5 | version = Crystal::Config::VERSION 6 | pieces = version.split("-") 7 | tag = pieces[0]? || "?" 8 | if sha = pieces[2]? 9 | sha = sha[1..-1] if sha.starts_with? 'g' 10 | "#{tag} [#{sha}] (#{build_date})" 11 | else 12 | "#{tag} (#{build_date})" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /src/llvm/phi_table.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::PhiTable 2 | getter blocks 3 | getter values 4 | 5 | def initialize 6 | @blocks = [] of LLVM::BasicBlock 7 | @values = [] of LLVM::Value 8 | end 9 | 10 | def add(block, value) 11 | @blocks << block 12 | @values << value.to_value 13 | end 14 | 15 | def empty? 16 | @blocks.empty? 17 | end 18 | 19 | def size 20 | @blocks.size 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /src/crypto/subtle.cr: -------------------------------------------------------------------------------- 1 | module Crypto::Subtle 2 | def self.constant_time_compare(x, y) 3 | return 0 if x.size != y.size 4 | 5 | v = 0_u8 6 | 7 | x.size.times do |i| 8 | v |= x[i] ^ y[i] 9 | end 10 | 11 | constant_time_byte_eq(v, 0) 12 | end 13 | 14 | def self.constant_time_byte_eq(x, y) 15 | z = ~(x ^ y) 16 | z &= z >> 4 17 | z &= z >> 2 18 | z &= z >> 1 19 | z 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src/llvm/instruction_collection.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::InstructionCollection 2 | def initialize(@basic_block) 3 | end 4 | 5 | def empty? 6 | llvm_first.nil? 7 | end 8 | 9 | def first? 10 | value = llvm_first 11 | value ? Value.new(value) : nil 12 | end 13 | 14 | def first 15 | first?.not_nil! 16 | end 17 | 18 | private def llvm_first 19 | LibLLVM.get_first_instruction @basic_block 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /samples/sieve.cr: -------------------------------------------------------------------------------- 1 | # Compute prime numbers up to 100 with the Sieve of Eratosthenes 2 | max = 100 3 | 4 | sieve = Array.new(max + 1, true) 5 | sieve[0] = false 6 | sieve[1] = false 7 | 8 | 2.step(Math.sqrt(max)) do |i| 9 | if sieve[i] 10 | (i * i).step(max, i) do |j| 11 | sieve[j] = false 12 | end 13 | end 14 | end 15 | 16 | sieve.each_with_index do |prime, number| 17 | if prime 18 | puts number 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/std/html_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "html" 3 | 4 | describe "HTML" do 5 | describe ".escape" do 6 | it "does not change a safe string" do 7 | str = HTML.escape("safe_string") 8 | 9 | str.should eq("safe_string") 10 | end 11 | 12 | it "escapes dangerous characters from a string" do 13 | str = HTML.escape("< & >") 14 | 15 | str.should eq("< & >") 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /src/json/lexer/io_based.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | class JSON::Lexer::IOBased < JSON::Lexer 3 | def initialize(io) 4 | super() 5 | @io = io 6 | @current_char = @io.read_char || '\0' 7 | end 8 | 9 | private getter current_char 10 | 11 | private def next_char_no_column_increment 12 | @current_char = @io.read_char || '\0' 13 | end 14 | 15 | private def consume_string 16 | consume_string_with_buffer 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /src/reflect.cr: -------------------------------------------------------------------------------- 1 | # # :nodoc: 2 | struct Reflect(X) 3 | # Note: This type might be removed. 4 | # 5 | # For now it's just a way to implement `Enumerable#sum` in a way that the 6 | # initial value given to it has the type of the first type in the union, 7 | # if the type is a union. 8 | def self.first 9 | {% if X.union? %} 10 | {{X.union_types.first}} 11 | {% else %} 12 | X 13 | {% end %} 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/fiber/lib_pcl.cr: -------------------------------------------------------------------------------- 1 | @[Link("pcl")] 2 | lib LibPcl 3 | alias Int = LibC::Int 4 | 5 | type Coroutine = Void* 6 | 7 | fun co_thread_init : Int 8 | fun co_create(func : (Void* ->), data : Void*, stack : Void*, size : Int) : Coroutine 9 | fun co_call(cr : Coroutine) 10 | fun co_resume 11 | fun co_current : Coroutine 12 | fun co_get_data(cr : Coroutine) : Void* 13 | fun co_set_data(cr : Coroutine, data : Void*) : Void* 14 | end 15 | -------------------------------------------------------------------------------- /src/html.cr: -------------------------------------------------------------------------------- 1 | module HTML 2 | SUBSTITUTIONS = { 3 | '&' => "&", 4 | '\"' => """, 5 | '\'' => "'", 6 | '<' => "<", 7 | '>' => ">", 8 | } 9 | 10 | def self.escape(string : String) 11 | string.gsub(SUBSTITUTIONS) 12 | end 13 | 14 | def self.escape(string : String, io : IO) 15 | string.each_char do |char| 16 | io << SUBSTITUTIONS.fetch(char, char) 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /Dockerfile.release: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | RUN \ 4 | apt-key adv --keyserver keys.gnupg.net --recv-keys 09617FD37CC06B54 && \ 5 | echo "deb http://dist.crystal-lang.org/apt crystal main" > /etc/apt/sources.list.d/crystal.list && \ 6 | apt-get update && \ 7 | apt-get install -y crystal gcc pkg-config libssl-dev && \ 8 | apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 9 | 10 | WORKDIR /opt/crystal 11 | 12 | CMD ["bash"] 13 | -------------------------------------------------------------------------------- /src/csv/error.cr: -------------------------------------------------------------------------------- 1 | class CSV 2 | # Raises when an error related to a CSV is found 3 | class Error < Exception 4 | end 5 | 6 | # Raised when an error is encountered during CSV parsing. 7 | class MalformedCSVError < Error 8 | getter line_number 9 | getter column_number 10 | 11 | def initialize(message, @line_number, @column_number) 12 | super("#{message} at #{@line_number}:#{@column_number}") 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/std/file_utils_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "file_utils" 3 | 4 | describe "FileUtils" do 5 | describe "cmp" do 6 | it "compares two equal files" do 7 | FileUtils.cmp("#{__DIR__}/data/test_file.txt", "#{__DIR__}/data/test_file.txt").should be_true 8 | end 9 | 10 | it "compares two different files" do 11 | FileUtils.cmp("#{__DIR__}/data/test_file.txt", "#{__DIR__}/data/test_file.ini").should be_false 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /src/io/pointer_io.cr: -------------------------------------------------------------------------------- 1 | struct PointerIO 2 | include IO 3 | 4 | def initialize(@pointer : UInt8**) 5 | end 6 | 7 | def read(slice : Slice(UInt8)) 8 | count = slice.size 9 | slice.copy_from(@pointer.value, count) 10 | @pointer.value += count 11 | count 12 | end 13 | 14 | def write(slice : Slice(UInt8)) 15 | count = slice.size 16 | slice.copy_to(@pointer.value, count) 17 | @pointer.value += count 18 | nil 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /src/llvm/module_pass_manager.cr: -------------------------------------------------------------------------------- 1 | class LLVM::ModulePassManager 2 | def initialize 3 | @unwrap = LibLLVM.pass_manager_create 4 | end 5 | 6 | def add_target_data(target_data) 7 | LibLLVM.add_target_data target_data, self 8 | end 9 | 10 | def run(mod) 11 | LibLLVM.run_pass_manager(self, mod) != 0 12 | end 13 | 14 | def to_unsafe 15 | @unwrap 16 | end 17 | 18 | def finalize 19 | LibLLVM.dispose_pass_manager(@unwrap) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/constant.cr: -------------------------------------------------------------------------------- 1 | require "./item" 2 | 3 | class Crystal::Doc::Constant 4 | include Item 5 | 6 | getter type 7 | getter const 8 | 9 | def initialize(@generator, @type : Type, @const) 10 | end 11 | 12 | def doc 13 | @const.doc 14 | end 15 | 16 | def name 17 | @const.name 18 | end 19 | 20 | def value 21 | @const.value 22 | end 23 | 24 | def formatted_value 25 | Highlighter.highlight value.to_s 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/std/oauth2/session_spec.cr: -------------------------------------------------------------------------------- 1 | require "oauth2" 2 | require "http/client" 3 | 4 | module OAuth2 5 | typeof(begin 6 | client = Client.new "localhost", "client_id", "client_secret", redirect_uri: "uri", authorize_uri: "/baz" 7 | token = OAuth2::AccessToken::Bearer.new("token", 3600) 8 | session = Session.new(client, token) { |s| } 9 | session = Session.new(client, token, Time.new) { |s| } 10 | session.authenticate(HTTP::Client.new("localhost")) 11 | end) 12 | end 13 | -------------------------------------------------------------------------------- /src/csv/token.cr: -------------------------------------------------------------------------------- 1 | # A token in a CSV. It consists of a `Kind` and a value. 2 | # The value only makes sense when the *kind* is `Cell`. 3 | struct CSV::Token 4 | # Token kinds. 5 | enum Kind 6 | Cell 7 | Newline 8 | Eof 9 | end 10 | 11 | # The `Kind`. 12 | property kind 13 | 14 | # The string value. Only makes sense for a `Cell`. 15 | property value 16 | 17 | # :nodoc: 18 | def initialize 19 | @kind = Kind::Cell 20 | @value = "" 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /src/inifile.cr: -------------------------------------------------------------------------------- 1 | class IniFile 2 | def self.load(str) 3 | ini = {} of String => Hash(String, String) 4 | 5 | section = "" 6 | str.lines.each do |line| 7 | if line =~ /\s*(.*[^\s])\s*=\s*(.*[^\s])/ 8 | ini[section] ||= {} of String => String if section == "" 9 | ini[section][$1] = $2 10 | elsif line =~ /\[(.*)\]/ 11 | section = $1 12 | ini[section] = {} of String => String 13 | end 14 | end 15 | ini 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /src/compiler/crystal/codegen/target_machine.cr: -------------------------------------------------------------------------------- 1 | require "llvm" 2 | require "../program" 3 | 4 | module Crystal 5 | module TargetMachine 6 | def self.create(target_triple, cpu, release) 7 | LLVM.init_x86 8 | 9 | opt_level = release ? LLVM::CodeGenOptLevel::Aggressive : LLVM::CodeGenOptLevel::None 10 | 11 | target = LLVM::Target.from_triple(target_triple) 12 | target.create_target_machine(target_triple, cpu: cpu, opt_level: opt_level).not_nil! 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/llvm/global_collection.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::GlobalCollection 2 | def initialize(@mod) 3 | end 4 | 5 | def add(type, name) 6 | Value.new LibLLVM.add_global(@mod, type, name) 7 | end 8 | 9 | def []?(name) 10 | global = LibLLVM.get_named_global(@mod, name) 11 | global ? Value.new(global) : nil 12 | end 13 | 14 | def [](name) 15 | global = self[name]? 16 | if global 17 | global 18 | else 19 | raise "Global not found: #{name}" 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/std/zlib/deflate_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "zlib" 3 | 4 | module Zlib 5 | describe Deflate do 6 | it "should be able to deflate" do 7 | deflate = Deflate.new(MemoryIO.new("this is a test string !!!!\n")) 8 | slice = Slice(UInt8).new(32) 9 | read = deflate.read_fully(slice) 10 | 11 | slice[0, read.to_i32].hexstring.should eq("789c2bc9c82c5600a2448592d4e21285e292a2ccbc74054520e00200854f087b") 12 | deflate.read(slice).should eq(0) 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/main.cr: -------------------------------------------------------------------------------- 1 | lib LibCrystalMain 2 | @[Raises] 3 | fun __crystal_main(argc : Int32, argv : UInt8**) 4 | end 5 | 6 | macro redefine_main(name = main) 7 | fun main = {{name}}(argc : Int32, argv : UInt8**) : Int32 8 | GC.init 9 | {{yield LibCrystalMain.__crystal_main(argc, argv)}} 10 | 0 11 | rescue ex 12 | ex.inspect_with_backtrace STDERR 13 | 1 14 | ensure 15 | AtExitHandlers.run 16 | STDOUT.flush 17 | end 18 | end 19 | 20 | redefine_main do |main| 21 | {{main}} 22 | end 23 | -------------------------------------------------------------------------------- /src/oauth/request_token.cr: -------------------------------------------------------------------------------- 1 | class OAuth::RequestToken 2 | getter token 3 | getter secret 4 | 5 | def initialize(@token, @secret) 6 | end 7 | 8 | def self.from_response(response) 9 | token = nil 10 | secret = nil 11 | 12 | HTTP::Params.parse(response) do |key, value| 13 | case key 14 | when "oauth_token" then token = value 15 | when "oauth_token_secret" then secret = value 16 | end 17 | end 18 | 19 | new token.not_nil!, secret.not_nil! 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/std/oauth/request_token_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "oauth" 3 | 4 | describe OAuth::RequestToken do 5 | it "creates from response" do 6 | token = OAuth::RequestToken.from_response("oauth_token_secret=p58A6bzyGaT8PR54gM0S4ZesOVC2ManiTmwHcho8&oauth_callback_confirmed=true&oauth_token=qyprd6Pe2PbnSxUcyHcWz0VnTF8bg1rxsBbUwOpkQ6bSQEyK") 7 | token.secret.should eq("p58A6bzyGaT8PR54gM0S4ZesOVC2ManiTmwHcho8") 8 | token.token.should eq("qyprd6Pe2PbnSxUcyHcWz0VnTF8bg1rxsBbUwOpkQ6bSQEyK") 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/compiler/normalize/string_interpolation_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: string interpolation" do 4 | it "normalizes string interpolation" do 5 | assert_expand "\"foo\#{bar}baz\"", "(((::String::Builder.new << \"foo\") << bar) << \"baz\").to_s" 6 | end 7 | 8 | it "normalizes string interpolation with long string" do 9 | s = "*" * 200 10 | assert_expand "\"foo\#{bar}#{s}\"", 11 | "((((::String::Builder.new(218)) << \"foo\") << bar) << \"#{s}\").to_s" 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/std/string_builder_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe String::Builder do 4 | it "builds" do 5 | str = String::Builder.build do |builder| 6 | builder << 123 7 | builder << 456 8 | end 9 | str.should eq("123456") 10 | str.size.should eq(6) 11 | str.bytesize.should eq(6) 12 | end 13 | 14 | it "raises if invokes to_s twice" do 15 | builder = String::Builder.new 16 | builder << 123 17 | builder.to_s.should eq("123") 18 | 19 | expect_raises { builder.to_s } 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src/oauth/authorization_header.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | struct OAuth::AuthorizationHeader 3 | def initialize 4 | @str = MemoryIO.new 5 | @str << "OAuth " 6 | @first = true 7 | end 8 | 9 | def add(key, value) 10 | return unless value 11 | 12 | @str << ", " unless @first 13 | @str << key 14 | @str << %(=") 15 | URI.escape value, @str 16 | @str << '"' 17 | @first = false 18 | end 19 | 20 | def to_s(io : IO) 21 | @str.to_s(io) 22 | end 23 | 24 | def to_s 25 | @str.to_s 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/std/struct_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | struct StructSpecTestClass 4 | def initialize(@x, @y) 5 | end 6 | end 7 | 8 | describe "Struct" do 9 | it "does to_s" do 10 | s = StructSpecTestClass.new(1, "hello") 11 | s.to_s.should eq(%(StructSpecTestClass(@x=1, @y="hello"))) 12 | end 13 | 14 | it "does ==" do 15 | s = StructSpecTestClass.new(1, "hello") 16 | s.should eq(s) 17 | end 18 | 19 | it "does hash" do 20 | s = StructSpecTestClass.new(1, "hello") 21 | s.hash.should eq(31 + "hello".hash) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/html/method_summary.html: -------------------------------------------------------------------------------- 1 | <% unless methods.empty? %> 2 |

<%= title %>

3 | 13 | <% end %> 14 | -------------------------------------------------------------------------------- /src/spec/source.cr: -------------------------------------------------------------------------------- 1 | module Spec 2 | # :nodoc: 3 | def self.lines_cache 4 | @@lines_cache ||= {} of String => Array(String) 5 | end 6 | 7 | # :nodoc: 8 | def self.read_line(file, line) 9 | return nil unless File.file?(file) 10 | 11 | lines = lines_cache[file] ||= File.read_lines(file) 12 | lines[line - 1]? 13 | end 14 | 15 | # :nodoc: 16 | def self.relative_file(file) 17 | cwd = Dir.working_directory 18 | if file.starts_with?(cwd) 19 | file = ".#{file[cwd.size..-1]}" 20 | end 21 | file 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /samples/tcp_server.cr: -------------------------------------------------------------------------------- 1 | require "socket" 2 | 3 | # goes with tcp_client.cr 4 | 5 | def process(client) 6 | client_addr = "#{client.peeraddr.ip_address}:#{client.peeraddr.ip_port}" 7 | puts "#{client_addr} connected" 8 | 9 | while msg = client.read_line 10 | puts "#{client_addr} msg '#{msg.chop}'" 11 | client << msg 12 | end 13 | rescue IO::EOFError 14 | puts "#{client_addr} dissconnected" 15 | ensure 16 | client.close 17 | end 18 | 19 | server = TCPServer.new "127.0.0.1", 9000 20 | puts "listen on 127.0.0.1:9000" 21 | loop { spawn process(server.accept) } 22 | -------------------------------------------------------------------------------- /src/compiler/crystal/macros/virtual_file.cr: -------------------------------------------------------------------------------- 1 | # A VirtualFile is used as a Location's filename when 2 | # expanding a macro. It contains the macro expanded source 3 | # code so the user can debug it as if there was a file in the 4 | # filesystem with those contents. 5 | class Crystal::VirtualFile 6 | getter :macro 7 | getter :source 8 | getter :expanded_location 9 | 10 | def initialize(@macro, @source, @expanded_location) 11 | end 12 | 13 | def to_s 14 | "expanded macro: #{@macro.name}" 15 | end 16 | 17 | def to_s(io) 18 | io << to_s 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /src/thread/mutex.cr: -------------------------------------------------------------------------------- 1 | class Mutex 2 | def initialize 3 | LibPThread.mutex_init(out @mutex, nil) 4 | end 5 | 6 | def lock 7 | LibPThread.mutex_lock(self) 8 | end 9 | 10 | def try_lock 11 | LibPThread.mutex_trylock(self) 12 | end 13 | 14 | def unlock 15 | LibPThread.mutex_unlock(self) 16 | end 17 | 18 | def synchronize 19 | lock 20 | yield self 21 | ensure 22 | unlock 23 | end 24 | 25 | def finalize 26 | LibPThread.mutex_destroy(self) 27 | end 28 | 29 | def to_unsafe 30 | pointerof(@mutex) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/c_type_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: type" do 4 | it "can call methods of original type" do 5 | assert_type(" 6 | lib Lib 7 | type X = Void* 8 | fun foo : X 9 | end 10 | 11 | Lib.foo.address 12 | ") { uint64 } 13 | end 14 | 15 | it "can call methods of parent type" do 16 | assert_error(" 17 | lib Lib 18 | type X = Void* 19 | fun foo : X 20 | end 21 | 22 | Lib.foo.baz 23 | ", "undefined method 'baz'") 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/compiler/normalize/ifdef_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: ifdef" do 4 | it "keeps then if condition is true" do 5 | assert_normalize "ifdef foo; 1; else; 2; end", "1", flags: "foo" 6 | end 7 | 8 | it "keeps else if condition is false" do 9 | assert_normalize "ifdef bar; 1; else; 2; end", "2", flags: "foo" 10 | end 11 | 12 | it "keeps then if condition is true inside lib" do 13 | assert_normalize "lib LibFoo; ifdef foo; type A = B; else; type A = D; end; end", "lib LibFoo\n type A = B\nend", flags: "foo" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/io/fd_set.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | struct IO::FdSet 3 | NFDBITS = sizeof(Int32) * 8 4 | 5 | def self.from_ios(ios) 6 | fdset = new 7 | ios.try &.each do |io| 8 | fdset.set io 9 | end 10 | fdset 11 | end 12 | 13 | def initialize 14 | @fdset = StaticArray(Int32, 32).new(0) 15 | end 16 | 17 | def set(io) 18 | @fdset[io.fd / NFDBITS] |= 1 << (io.fd % NFDBITS) 19 | end 20 | 21 | def is_set(io) 22 | @fdset[io.fd / NFDBITS] & 1 << (io.fd % NFDBITS) != 0 23 | end 24 | 25 | def to_unsafe 26 | pointerof(@fdset) as Void* 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/std/oauth/access_token_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "oauth" 3 | 4 | describe OAuth::AccessToken do 5 | it "creates from response body" do 6 | access_token = OAuth::AccessToken.from_response("oauth_token=1234-nyi1G37179bVdYNZGZqKQEdO&oauth_token_secret=f7T6ibH25q4qkVTAUN&user_id=1234&screen_name=someuser") 7 | access_token.token.should eq("1234-nyi1G37179bVdYNZGZqKQEdO") 8 | access_token.secret.should eq("f7T6ibH25q4qkVTAUN") 9 | access_token.extra["user_id"].should eq("1234") 10 | access_token.extra["screen_name"].should eq("someuser") 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/compiler/normalize/array_literal_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: array literal" do 4 | it "normalizes empty with of" do 5 | assert_expand "[] of Int", "::Array(Int).new" 6 | end 7 | 8 | it "normalizes non-empty with of" do 9 | assert_expand "[1, 2] of Int", "::Array(Int).build(2) do |__temp_1|\n __temp_1[0] = 1\n __temp_1[1] = 2\n 2\nend" 10 | end 11 | 12 | it "normalizes non-empty without of" do 13 | assert_expand "[1, 2]", "::Array(typeof(1, 2)).build(2) do |__temp_1|\n __temp_1[0] = 1\n __temp_1[1] = 2\n 2\nend" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/html/list_items.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/openssl/ssl/context.cr: -------------------------------------------------------------------------------- 1 | class OpenSSL::SSL::Context 2 | def self.default 3 | @@default ||= new 4 | end 5 | 6 | def initialize 7 | @handle = LibSSL.ssl_ctx_new(LibSSL.sslv23_method) 8 | end 9 | 10 | def finalize 11 | LibSSL.ssl_ctx_free(@handle) 12 | end 13 | 14 | def certificate_chain=(file_path) 15 | LibSSL.ssl_ctx_use_certificate_chain_file(@handle, file_path) 16 | end 17 | 18 | def private_key=(file_path) 19 | LibSSL.ssl_ctx_use_privatekey_file(@handle, file_path, LibSSL::SSLFileType::PEM) 20 | end 21 | 22 | def to_unsafe 23 | @handle 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/std/openssl/pkcs5_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "openssl/pkcs5" 3 | 4 | describe OpenSSL::PKCS5 do 5 | it "computes pbkdf2_hmac_sha1" do 6 | [ 7 | {1, 16, "0c60c80f961f0e71f3a9b524af601206"}, 8 | {1, 32, "0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164"}, 9 | {2**16, 16, "1b345dd55f62a35aecdb9229bc7ae95b"}, 10 | {2**16, 32, "1b345dd55f62a35aecdb9229bc7ae95b305a8d538940134627e46f82d3a41e5e"} 11 | ].each do |tuple| 12 | OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", tuple[0], tuple[1]).hexstring.should eq tuple[2] 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/xml/save_options.cr: -------------------------------------------------------------------------------- 1 | @[Flags] 2 | enum XML::SaveOptions 3 | # Format save output 4 | FORMAT = 1 5 | 6 | # Drop the xml declaration 7 | NO_DECL = 2 8 | 9 | # No empty tags 10 | NO_EMPTY = 4 11 | 12 | # Disable XHTML1 specific rules 13 | NO_XHTML = 8 14 | 15 | # Force XHTML1 specific rules 16 | XHTML = 16 17 | 18 | # Force XML serialization on HTML doc 19 | AS_XML = 32 20 | 21 | # Force HTML serialization on XML doc 22 | AS_HTML = 64 23 | 24 | # Format with non-significant whitespace 25 | WSNONSIG = 128 26 | 27 | def self.xml_default 28 | FORMAT | AS_XML 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/compiler/codegen/untyped_expression_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Code gen: untyped expression spec" do 4 | it "raises if class was never instantiated" do 5 | run(%( 6 | require "prelude" 7 | 8 | class Foo 9 | def foo 10 | 1 11 | end 12 | end 13 | 14 | pointer = Pointer(Foo).malloc(1_64) 15 | foo = pointer.value 16 | 17 | begin 18 | foo.foo 19 | false 20 | rescue ex 21 | ex.message.includes?("Foo in `foo` was never instantiated") 22 | end 23 | )).to_b.should be_true 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /src/intrinsics.cr: -------------------------------------------------------------------------------- 1 | lib Intrinsics 2 | fun debugtrap = "llvm.debugtrap" 3 | fun memcpy = "llvm.memcpy.p0i8.p0i8.i32"(dest : Void*, src : Void*, len : UInt32, align : UInt32, is_volatile : Bool) 4 | fun memmove = "llvm.memmove.p0i8.p0i8.i32"(dest : Void*, src : Void*, len : UInt32, align : UInt32, is_volatile : Bool) 5 | fun memset = "llvm.memset.p0i8.i32"(dest : Void*, val : UInt8, len : UInt32, align : UInt32, is_volatile : Bool) 6 | fun read_cycle_counter = "llvm.readcyclecounter" : UInt64 7 | fun bswap32 = "llvm.bswap.i32"(id : UInt32) : UInt32 8 | end 9 | 10 | macro debugger 11 | Intrinsics.debugtrap 12 | end 13 | -------------------------------------------------------------------------------- /docs/char.cr: -------------------------------------------------------------------------------- 1 | struct Char 2 | # Returns the codepoint of this char. 3 | # 4 | # The codepoint is the integer 5 | # representation. The Universal Coded Character Set (UCS) standard, 6 | # commonly known as Unicode, assigns names and meanings to numbers, these 7 | # numbers are called codepoints. 8 | # 9 | # For values below and including 127 this matches the ASCII codes 10 | # and thus its byte representation. 11 | # 12 | # ``` 13 | # 'a'.ord # => 97 14 | # '\0'.ord # => 0 15 | # '\u007f'.ord # => 127 16 | # '☃'.ord # => 9731 17 | # ``` 18 | def ord : Int32 19 | 1 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /src/llvm/target_data.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::TargetData 2 | def initialize(@unwrap) 3 | end 4 | 5 | def size_in_bits(type) 6 | LibLLVM.size_of_type_in_bits(self, type) 7 | end 8 | 9 | def size_in_bytes(type) 10 | size_in_bits(type) / 8 11 | end 12 | 13 | def abi_size(type) 14 | LibLLVM.abi_size_of_type(self, type) 15 | end 16 | 17 | def abi_alignment(type) 18 | LibLLVM.abi_alignment_of_type(self, type) 19 | end 20 | 21 | def to_unsafe 22 | @unwrap 23 | end 24 | 25 | def offset_of_element(struct_type, element) 26 | LibLLVM.offset_of_element(self, struct_type, element) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/compiler/normalize/hash_literal_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: hash literal" do 4 | it "normalizes empty with of" do 5 | assert_expand "{} of Int => Float", "::Hash(Int, Float).new" 6 | end 7 | 8 | it "normalizes non-empty with of" do 9 | assert_expand "{1 => 2, 3 => 4} of Int => Float", "__temp_1 = ::Hash(Int, Float).new\n__temp_1[1] = 2\n__temp_1[3] = 4\n__temp_1" 10 | end 11 | 12 | it "normalizes non-empty without of" do 13 | assert_expand "{1 => 2, 3 => 4}", "__temp_1 = ::Hash(typeof(1, 3), typeof(2, 4)).new\n__temp_1[1] = 2\n__temp_1[3] = 4\n__temp_1" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012-2013 Manas Technology Solutions. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /src/gc/null.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | fun __crystal_malloc(size : UInt32) : Void* 3 | LibC.malloc(size) 4 | end 5 | 6 | # :nodoc: 7 | fun __crystal_malloc_atomic(size : UInt32) : Void* 8 | LibC.malloc(size) 9 | end 10 | 11 | # :nodoc: 12 | fun __crystal_realloc(ptr : Void*, size : UInt32) : Void* 13 | LibC.realloc(ptr, size) 14 | end 15 | 16 | module GC 17 | def self.init 18 | end 19 | 20 | def self.collect 21 | end 22 | 23 | def self.enable 24 | end 25 | 26 | def self.disable 27 | end 28 | 29 | def self.free(pointer : Void*) 30 | LibC.free(pointer) 31 | end 32 | 33 | def self.add_finalizer(object) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /src/oauth/params.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | struct OAuth::Params 3 | def initialize 4 | @params = [] of {String, String} 5 | end 6 | 7 | def add(key, value) 8 | if value 9 | @params << {URI.escape(key), URI.escape(value)} 10 | end 11 | end 12 | 13 | def add_query(query) 14 | HTTP::Params.parse(query) do |key, value| 15 | add key, value 16 | end 17 | end 18 | 19 | def to_s(io : IO) 20 | @params.sort_by! &.[0] 21 | @params.each_with_index do |tuple, i| 22 | io << "%26" if i > 0 23 | URI.escape tuple[0], io 24 | io << "%3D" 25 | URI.escape tuple[1], io 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /src/time/format.cr: -------------------------------------------------------------------------------- 1 | struct Time::Format 2 | ISO_8601_DATE = new "%F" 3 | 4 | class Error < ::Exception 5 | end 6 | 7 | getter pattern 8 | 9 | def initialize(@pattern : String, @kind = Time::Kind::Unspecified) 10 | end 11 | 12 | def parse(string, kind = @kind) 13 | parser = Parser.new(string) 14 | parser.visit(pattern) 15 | parser.time(kind) 16 | end 17 | 18 | def format(time : Time) 19 | String.build do |str| 20 | format time, str 21 | end 22 | end 23 | 24 | def format(time : Time, io : IO) 25 | formatter = Formatter.new(time, io) 26 | formatter.visit(pattern) 27 | io 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /samples/tree.cr: -------------------------------------------------------------------------------- 1 | class Node 2 | def initialize(v) 3 | @value = v 4 | end 5 | 6 | def add(x) 7 | if x < @value 8 | if left = @left 9 | left.add(x) 10 | else 11 | @left = Node.new(x) 12 | end 13 | else 14 | if right = @right 15 | right.add(x) 16 | else 17 | @right = Node.new(x) 18 | end 19 | end 20 | end 21 | 22 | def print 23 | @left.try &.print 24 | print @value 25 | @right.try &.print 26 | end 27 | end 28 | 29 | root = Node.new('$') 30 | "crystalrocks!".each_char do |c| 31 | root.add c 32 | end 33 | 34 | root.print # => !$accklorrssty 35 | puts 36 | -------------------------------------------------------------------------------- /samples/channel_primes.cr: -------------------------------------------------------------------------------- 1 | # Ported from Go sample from this page: http://dancallahan.info/journal/go-concurrency/#How+do+channels+and+goroutines+work+together? 2 | 3 | def generate(chan) 4 | i = 2 5 | loop do 6 | chan.send(i) 7 | i += 1 8 | end 9 | end 10 | 11 | def filter(in_chan, out_chan, prime) 12 | loop do 13 | i = in_chan.receive 14 | if i % prime != 0 15 | out_chan.send(i) 16 | end 17 | end 18 | end 19 | 20 | ch = Channel(Int32).new 21 | spawn generate(ch) 22 | 23 | 100.times do 24 | prime = ch.receive 25 | puts prime 26 | ch1 = Channel(Int32).new 27 | spawn filter(ch, ch1, prime) 28 | ch = ch1 29 | end 30 | -------------------------------------------------------------------------------- /spec/std/signal_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "signal" 3 | 4 | describe "Signal" do 5 | typeof(Signal::PIPE.reset) 6 | typeof(Signal::PIPE.ignore) 7 | typeof(Signal::PIPE.trap { 1 }) 8 | 9 | it "runs a signal handler" do 10 | ran = false 11 | Signal::USR1.trap do 12 | ran = true 13 | end 14 | Process.kill Signal::USR1, Process.pid 15 | 10.times do |i| 16 | break if ran 17 | sleep 0.1 18 | end 19 | ran.should be_true 20 | end 21 | 22 | it "ignores a signal" do 23 | Signal::USR2.ignore 24 | Process.kill Signal::USR2, Process.pid 25 | end 26 | 27 | # TODO: test Signal::X.reset 28 | end 29 | -------------------------------------------------------------------------------- /src/llvm/pass_registry.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::PassRegistry 2 | def self.instance 3 | new LibLLVM.get_global_pass_registry 4 | end 5 | 6 | def initialize(@unwrap) 7 | end 8 | 9 | Inits = %w(core transform_utils scalar_opts obj_c_arc_opts vectorization inst_combine ipo instrumentation analysis ipa code_gen target) 10 | 11 | {% for name in Inits %} 12 | def initialize_{{name.id}} 13 | LibLLVM.initialize_{{name.id}} self 14 | end 15 | {% end %} 16 | 17 | def initialize_all 18 | {% for name in Inits %} 19 | initialize_{{name.id}} 20 | {% end %} 21 | end 22 | 23 | def to_unsafe 24 | @unwrap 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /src/json/token.cr: -------------------------------------------------------------------------------- 1 | class JSON::Token 2 | property :type 3 | property :string_value 4 | property :int_value 5 | property :float_value 6 | property :line_number 7 | property :column_number 8 | 9 | def initialize 10 | @type = :EOF 11 | @line_number = 0 12 | @column_number = 0 13 | @string_value = "" 14 | @int_value = 0_i64 15 | @float_value = 0.0 16 | end 17 | 18 | def to_s(io) 19 | case @type 20 | when :INT 21 | @int_value.to_s(io) 22 | when :FLOAT 23 | @float_value.to_s(io) 24 | when :STRING 25 | @string_value.to_s(io) 26 | else 27 | @type.to_s(io) 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/std/zlib/inflate_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "zlib" 3 | 4 | module Zlib 5 | describe Inflate do 6 | it "should be able to inflate" do 7 | io = MemoryIO.new 8 | "789c2bc9c82c5600a2448592d4e21285e292a2ccbc74054520e00200854f087b".scan(/../).each do |match| 9 | io.write_byte match[0].to_u8(16) 10 | end 11 | io.rewind 12 | 13 | inflate = Inflate.new(io) 14 | 15 | str = String::Builder.build do |builder| 16 | IO.copy(inflate, builder) 17 | end 18 | 19 | str.should eq("this is a test string !!!!\n") 20 | inflate.read(Slice(UInt8).new(10)).should eq(0) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/std/zlib/stress_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "zlib" 3 | 4 | module Zlib 5 | describe Zlib do 6 | it "inflate deflate should be inverse with random string" do 7 | expected = String.build do |io| 8 | 1_000_000.times { rand(2000).to_i.to_s(32, io) } 9 | end 10 | actual = Inflate.new(Deflate.new(MemoryIO.new(expected))).gets_to_end 11 | expected.should eq(actual) 12 | end 13 | 14 | it "inflate deflate should be inverse (utf-8)" do 15 | expected = "日本さん語日本さん語" 16 | actual = Inflate.new(Deflate.new(MemoryIO.new(expected))).gets_to_end 17 | expected.should eq(actual) 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/html/methods_inherited.html: -------------------------------------------------------------------------------- 1 | <% method_groups = methods.group_by { |method| method.name } %> 2 | <% unless method_groups.empty? %> 3 |

<%= label %> methods inherited from <%= ancestor.kind %> <%= ancestor.full_name %>

4 | <% method_groups.each_with_index do |method_name, methods, i| %> 5 | 6 | <%= methods.map { |method| method.name + method.args_to_s } .join("
") %>
7 | <%= method_name %>
<%= ", " if i != method_groups.size - 1 %> 8 | <% end %> 9 | <% end %> 10 | -------------------------------------------------------------------------------- /src/xml/type.cr: -------------------------------------------------------------------------------- 1 | enum XML::Type 2 | ELEMENT_NODE = 1 3 | ATTRIBUTE_NODE = 2 4 | TEXT_NODE = 3 5 | CDATA_SECTION_NODE = 4 6 | ENTITY_REF_NODE = 5 7 | ENTITY_NODE = 6 8 | PI_NODE = 7 9 | COMMENT_NODE = 8 10 | DOCUMENT_NODE = 9 11 | DOCUMENT_TYPE_NODE = 10 12 | DOCUMENT_FRAG_NODE = 11 13 | NOTATION_NODE = 12 14 | HTML_DOCUMENT_NODE = 13 15 | DTD_NODE = 14 16 | ELEMENT_DECL = 15 17 | ATTRIBUTE_DECL = 16 18 | ENTITY_DECL = 17 19 | NAMESPACE_DECL = 18 20 | XINCLUDE_START = 19 21 | XINCLUDE_END = 20 22 | DOCB_DOCUMENT_NODE = 21 23 | end 24 | -------------------------------------------------------------------------------- /src/openssl/openssl.cr: -------------------------------------------------------------------------------- 1 | require "./lib_ssl" 2 | 3 | module OpenSSL 4 | class Error < Exception 5 | getter err 6 | getter err_msg 7 | 8 | def initialize(msg = nil) 9 | unless (err = @err = LibCrypto.err_get_error) == 0 10 | @err_msg = String.new(LibCrypto.err_error_string(err, nil)) 11 | msg = msg ? "#{msg}: #{@err_msg}" : @err_msg 12 | end 13 | super(msg) 14 | end 15 | end 16 | 17 | LibSSL.ssl_library_init 18 | LibSSL.ssl_load_error_strings 19 | LibCrypto.openssl_add_all_algorithms 20 | LibCrypto.err_load_crypto_strings 21 | end 22 | 23 | require "./bio" 24 | require "./ssl/*" 25 | require "./digest/*" 26 | require "./md5" 27 | -------------------------------------------------------------------------------- /spec/compiler/normalize/or_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: or" do 4 | it "normalizes or without variable" do 5 | assert_expand "a || b", "if __temp_1 = a\n __temp_1\nelse\n b\nend" 6 | end 7 | 8 | it "normalizes or with variable on the left" do 9 | assert_expand_second "a = 1; a || b", "if a\n a\nelse\n b\nend" 10 | end 11 | 12 | it "normalizes or with assignment on the left" do 13 | assert_expand "(a = 1) || b", "if a = 1\n a\nelse\n b\nend" 14 | end 15 | 16 | it "normalizes or with is_a? on var" do 17 | assert_expand_second "a = 1; a.is_a?(Foo) || b", "if a.is_a?(Foo)\n a.is_a?(Foo)\nelse\n b\nend" 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /samples/channel_select.cr: -------------------------------------------------------------------------------- 1 | def generator(n : T) 2 | channel = Channel(T).new 3 | spawn do 4 | loop do 5 | sleep n 6 | channel.send n 7 | end 8 | end 9 | channel 10 | end 11 | 12 | ch1 = generator(1) 13 | ch2 = generator(1.5) 14 | ch3 = generator(5) 15 | 16 | loop do 17 | index, value = Channel.select(ch1.receive_op, ch2.receive_op, ch3.receive_op) 18 | case index 19 | when 0 20 | int = value as typeof(ch1.receive) 21 | puts "Int: #{int}" 22 | when 1 23 | float = value as typeof(ch2.receive) 24 | puts "Float: #{float}" 25 | when 2 26 | break 27 | else 28 | raise "BUG: Channel.select returned invalid index #{index}" 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/std/class_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe Class, "#===" do 4 | it "does ===" do 5 | (Int32 === 1).should be_true 6 | (Int32 === 1.5).should be_false 7 | (Array === [1]).should be_true 8 | (Array(Int32) === [1]).should be_true 9 | (Array(Int32) === ['a']).should be_false 10 | end 11 | end 12 | 13 | describe Class, ".cast" do 14 | it "casts, allowing the class to be passed in at runtime" do 15 | ar = [99, "something"] 16 | cl = {Int32, String} 17 | casted = {cl[0].cast(ar[0]), cl[1].cast(ar[1])} 18 | casted.should eq({99, "something"}) 19 | typeof(casted[0]).should eq(Int32) 20 | typeof(casted[1]).should eq(String) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /src/llvm/generic_value.cr: -------------------------------------------------------------------------------- 1 | class LLVM::GenericValue 2 | def initialize(@unwrap : LibLLVM::GenericValueRef) 3 | end 4 | 5 | def to_i 6 | LibLLVM.generic_value_to_int(self, 1) 7 | end 8 | 9 | def to_b 10 | to_i != 0 11 | end 12 | 13 | def to_f32 14 | LibLLVM.generic_value_to_float(LLVM::Float, self) 15 | end 16 | 17 | def to_f64 18 | LibLLVM.generic_value_to_float(LLVM::Double, self) 19 | end 20 | 21 | def to_string 22 | to_pointer as String 23 | end 24 | 25 | def to_pointer 26 | LibLLVM.generic_value_to_pointer(self) 27 | end 28 | 29 | def to_unsafe 30 | @unwrap 31 | end 32 | 33 | def finalize 34 | LibLLVM.dispose_generic_value(@unwrap) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /samples/sdl/tv.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | xxxxx xxxx x x xxxxx xxxxx xxxxx x 21 | x..... x...x x. x. x..... .x... x...x. x. 22 | x. x. x. x. x. x. x. x. x. x. 23 | x. x. x. x. x. x. x. x. x. x. 24 | x. xxxx x x . xxxxx x. xxxxx. x. 25 | x. x...x x . ...x. x. x...x. x. 26 | x. x. x. x. x. x. x. x. x. 27 | x. x. x. x. x. x. x. x. x. 28 | xxxxx x. x. x. xxxxx. x. x. x. xxxxx 29 | ..... . . . ..... . . . ..... 30 | -------------------------------------------------------------------------------- /src/oauth2/access_token/bearer.cr: -------------------------------------------------------------------------------- 1 | require "./access_token" 2 | 3 | class OAuth2::AccessToken::Bearer < OAuth2::AccessToken 4 | def token_type 5 | "Bearer" 6 | end 7 | 8 | def authenticate(request : HTTP::Request, ssl) 9 | request.headers["Authorization"] = "Bearer #{access_token}" 10 | end 11 | 12 | def to_json(io) 13 | io.json_object do |object| 14 | object.field "token_type", "bearer" 15 | object.field "access_token", access_token 16 | object.field "expires_in", expires_in 17 | object.field "refresh_token", refresh_token if refresh_token 18 | object.field "scope", scope if scope 19 | end 20 | end 21 | 22 | def_equals_and_hash access_token, expires_in, refresh_token, scope 23 | end 24 | -------------------------------------------------------------------------------- /src/compiler/crystal/syntax/visitor.cr: -------------------------------------------------------------------------------- 1 | require "./ast" 2 | 3 | module Crystal 4 | class Visitor 5 | def visit_any(node) 6 | true 7 | end 8 | 9 | # def visit(node) 10 | # true 11 | # end 12 | 13 | def end_visit(node) 14 | end 15 | 16 | def end_visit_any(node) 17 | end 18 | 19 | def accept(node) 20 | node.accept self 21 | end 22 | end 23 | 24 | class ASTNode 25 | def accept(visitor) 26 | if visitor.visit_any self 27 | if visitor.visit self 28 | accept_children visitor 29 | end 30 | visitor.end_visit self 31 | visitor.end_visit_any self 32 | end 33 | end 34 | 35 | def accept_children(visitor) 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /src/file_utils.cr: -------------------------------------------------------------------------------- 1 | module FileUtils 2 | extend self 3 | 4 | def cmp(filename1 : String, filename2 : String) 5 | return false unless File.size(filename1) == File.size(filename2) 6 | 7 | File.open(filename1, "rb") do |file1| 8 | File.open(filename2, "rb") do |file2| 9 | cmp(file1, file2) 10 | end 11 | end 12 | end 13 | 14 | def cmp(stream1 : IO, stream2 : IO) 15 | buf1 :: UInt8[1024] 16 | buf2 :: UInt8[1024] 17 | 18 | while true 19 | read1 = stream1.read buf1.to_slice 20 | read2 = stream2.read buf2.to_slice 21 | 22 | return false if read1 != read2 23 | return false if buf1.buffer.memcmp(buf2.buffer, read1) != 0 24 | return true if read1 == 0 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /samples/sdl/fire.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | xxxxxx xxxxx xx xx xxxxxx xxxxxx xxxxxx xx 21 | xxxxxx xxxxxx xx xx xxxxxx xxxxxx xxxxxx xx 22 | xx xx xx xx xx xx xx xx xx xx 23 | xx xx xx xxxxxx xx xx xx xx xx 24 | xx xxxxxx xxxxxx xxxxxx xx xxxxxx xx 25 | xx xxxxx xx xxxxxx xx xxxxxx xx 26 | xx xx xx xx xx xx xx xx xx 27 | xx xx xx xx xx xx xx xx xx 28 | xxxxxx xx xx xx xxxxxx xx xx xx xxxxxx 29 | xxxxxx xx xx xx xxxxxx xx xx xx xxxxxx 30 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/html/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | README - <%= repository_name %> 9 | 10 | 11 | 12 |
13 | 16 | 17 | 20 | 21 | <%= ListItemsTemplate.new(types, nil) %> 22 |
23 | 24 |
25 | <%= body %> 26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /src/http/server/handlers/log_handler.cr: -------------------------------------------------------------------------------- 1 | class HTTP::LogHandler < HTTP::Handler 2 | def call(request) 3 | time = Time.now 4 | response = call_next(request) 5 | elapsed = Time.now - time 6 | elapsed_text = elapsed_text(elapsed) 7 | 8 | puts "#{request.method} #{request.resource} - #{response.status_code} (#{elapsed_text})" 9 | response 10 | end 11 | 12 | private def elapsed_text(elapsed) 13 | minutes = elapsed.total_minutes 14 | return "#{minutes.round(2)}m" if minutes >= 1 15 | 16 | seconds = elapsed.total_seconds 17 | return "#{seconds.round(2)}s" if seconds >= 1 18 | 19 | millis = elapsed.total_milliseconds 20 | return "#{millis.round(2)}ms" if millis >= 1 21 | 22 | "#{(millis * 1000).round(2)}µs" 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /src/openssl/digest/digest_base.cr: -------------------------------------------------------------------------------- 1 | require "base64" 2 | 3 | module OpenSSL 4 | module DigestBase 5 | def file(file_name) 6 | File.open(file_name) do |io| 7 | self << io 8 | end 9 | end 10 | 11 | def update(io : IO) 12 | buffer :: UInt8[2048] 13 | while (read_bytes = io.read(buffer.to_slice)) > 0 14 | self << buffer.to_slice 15 | end 16 | self 17 | end 18 | 19 | def digest 20 | self.clone.finish 21 | end 22 | 23 | def <<(data) 24 | update(data) 25 | end 26 | 27 | def base64digest 28 | Base64.encode(digest) 29 | end 30 | 31 | def hexdigest 32 | digest.hexstring 33 | end 34 | 35 | def to_s(io) 36 | io << hexdigest 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /src/xml/html_parser_options.cr: -------------------------------------------------------------------------------- 1 | @[Flags] 2 | enum XML::HTMLParserOptions 3 | # Relaxed parsing 4 | RECOVER = 1 5 | 6 | # Do not default a doctype if not found 7 | NODEFDTD = 4 8 | 9 | # Suppress error reports 10 | NOERROR = 32 11 | 12 | # Suppress warning reports 13 | NOWARNING = 64 14 | 15 | # Pedantic error reporting 16 | PEDANTIC = 128 17 | 18 | # Remove blank nodes 19 | NOBLANKS = 256 20 | 21 | # Forbid network access 22 | NONET = 2048 23 | 24 | # Do not add implied html/body... elements 25 | NOIMPLIED = 8192 26 | 27 | # Compact small text nodes 28 | COMPACT = 65536 29 | 30 | # Ignore internal document encoding hint 31 | IGNORE_ENC = 2097152 32 | 33 | def self.default 34 | RECOVER | NOERROR | NOWARNING 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/compiler/codegen/asm_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Code gen: asm" do 4 | it "codegens without inputs" do 5 | run(%( 6 | dst :: Int32 7 | asm("mov $$1234, $0" : "=r"(dst)) 8 | dst 9 | )).to_i.should eq(1234) 10 | end 11 | 12 | it "codegens with one input" do 13 | run(%( 14 | src = 1234 15 | dst :: Int32 16 | asm("mov $1, $0" : "=r"(dst) : "r"(src)) 17 | dst 18 | )).to_i.should eq(1234) 19 | end 20 | 21 | it "codegens with two inputs" do 22 | run(%( 23 | c :: Int32 24 | a = 20 25 | b = 22 26 | asm( 27 | "add $2, $0" 28 | : "=r"(c) 29 | : "0"(a), "r"(b) 30 | ) 31 | c 32 | )).to_i.should eq(42) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /src/markdown/markdown.cr: -------------------------------------------------------------------------------- 1 | # Markdown library parses Markdown text. It supports rendering to HTML text. 2 | # Note: This library is in its early stage. Many features are still in development. 3 | # 4 | # Usage: 5 | # 6 | # require "markdown" 7 | # 8 | # text = "## This is title \n This is a [link](http://crystal-lang.org)" 9 | # 10 | # Markdown.to_html(text) 11 | # #=>

This is title

12 | # #=>

This is a link

13 | class Markdown 14 | def self.parse(text, renderer) 15 | parser = Parser.new(text, renderer) 16 | parser.parse 17 | end 18 | 19 | def self.to_html(text) 20 | String.build do |io| 21 | parse text, Markdown::HTMLRenderer.new(io) 22 | end 23 | end 24 | end 25 | 26 | require "./*" 27 | -------------------------------------------------------------------------------- /samples/sdl/sdl/surface.cr: -------------------------------------------------------------------------------- 1 | class SDL::Surface 2 | getter :surface 3 | getter :width 4 | getter :height 5 | getter :bpp 6 | 7 | def initialize(@surface, @width, @height, @bpp) 8 | end 9 | 10 | def lock 11 | LibSDL.lock_surface @surface 12 | end 13 | 14 | def unlock 15 | LibSDL.unlock_surface @surface 16 | end 17 | 18 | def update_rect(x, y, w, h) 19 | LibSDL.update_rect @surface, x, y, w, h 20 | end 21 | 22 | def flip 23 | LibSDL.flip @surface 24 | end 25 | 26 | def []=(offset, color) 27 | (@surface.value.pixels as UInt32*)[offset] = color.to_u32 28 | end 29 | 30 | def []=(x, y, color) 31 | self[y.to_i32 * @width + x.to_i32] = color 32 | end 33 | 34 | def offset(x, y) 35 | x.to_i32 + (y.to_i32 * @width) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /src/oauth2/error.cr: -------------------------------------------------------------------------------- 1 | class OAuth2::Error < Exception 2 | getter error 3 | getter error_description 4 | 5 | def initialize(@error, @error_description) 6 | if error_description = @error_description 7 | super("#{@error}: #{error_description}") 8 | else 9 | super(@error) 10 | end 11 | end 12 | 13 | def self.new(pull : JSON::PullParser) 14 | error = nil 15 | error_description = nil 16 | 17 | pull.read_object do |key| 18 | case key 19 | when "error" then error = pull.read_string 20 | when "error_description" then error_description = pull.read_string 21 | else 22 | raise "Uknown key in oauth2 error json: #{key}" 23 | end 24 | end 25 | 26 | new error.not_nil!, error_description 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /src/value.cr: -------------------------------------------------------------------------------- 1 | # Value is the base type of the primitive types (`Nil`, `Bool`, `Char`, `Number`), 2 | # `Symbol`, `Pointer`, `Tuple`, `StaticArray` and all structs. 3 | # 4 | # A Value is passed by value: when you pass it to methods, 5 | # return it from methods or assign it to variables, a copy 6 | # of the value is actually passed. 7 | # This is not important for nil, bools, integers, floats, symbols, 8 | # pointers and tuples, because they are immutable, but with a mutable 9 | # `Struct` or with a `StaticArray` you have to be careful. Read their 10 | # documentation to learn more about this. 11 | struct Value 12 | # Returns false. 13 | def ==(other) 14 | false 15 | end 16 | 17 | # Returns false. 18 | def ! 19 | false 20 | end 21 | 22 | # Returns false. 23 | def nil? 24 | false 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/compiler/codegen/global_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Code gen: global" do 4 | it "codegens global" do 5 | run("$foo = 1; def foo; $foo = 2; end; foo; $foo").to_i.should eq(2) 6 | end 7 | 8 | it "codegens global with union" do 9 | run("$foo = 1; def foo; $foo = 2.5_f32; end; foo; $foo.to_f").to_f64.should eq(2.5) 10 | end 11 | 12 | it "codegens global when not initialized" do 13 | run(%( 14 | struct Nil; def to_i; 0; end; end 15 | $foo.to_i 16 | )).to_i.should eq(0) 17 | end 18 | 19 | it "codegens global when not initialized" do 20 | run(%( 21 | struct Nil; def to_i; 0; end; end 22 | 23 | def foo 24 | $foo = 2 if 1 == 2 25 | end 26 | 27 | foo 28 | 29 | $foo.to_i 30 | )).to_i.should eq(0) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM manastech/crystal 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y build-essential curl libevent-dev && \ 5 | apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 6 | 7 | RUN curl http://crystal-lang.s3.amazonaws.com/llvm/llvm-3.5.0-1-linux-x86_64.tar.gz | tar xz -C /opt 8 | RUN curl http://crystal-lang.s3.amazonaws.com/pcl/libpcl-1.12-1-linux-x86_64.tar.gz | tar xz -C /opt/crystal/embedded --strip-components=1 9 | 10 | ADD . /opt/crystal-head 11 | 12 | WORKDIR /opt/crystal-head 13 | ENV CRYSTAL_CONFIG_VERSION HEAD 14 | ENV CRYSTAL_CONFIG_PATH libs:/opt/crystal-head/src:/opt/crystal-head/libs 15 | ENV LIBRARY_PATH /opt/crystal/embedded/lib 16 | ENV PATH /opt/crystal-head/bin:/opt/llvm-3.5.0-1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 17 | 18 | RUN make clean crystal release=1 19 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/html/method_detail.html: -------------------------------------------------------------------------------- 1 | <% unless methods.empty? %> 2 |

<%= title %>

3 | <% methods.each do |method| %> 4 |
5 |
6 | <%= method.abstract? ? "abstract " : "" %> 7 | <%= method.kind %><%= method.name %><%= method.args_to_html %> 8 | 9 | # 10 |
11 | <% if doc = method.formatted_doc %> 12 |
<%= doc %>
13 | <% end %> 14 |
15 |
16 | <% if source_link = method.source_link %> 17 | [View source] 18 | <% end %> 19 |
20 |
21 | <% end %> 22 | <% end %> 23 | -------------------------------------------------------------------------------- /src/xml/namespace.cr: -------------------------------------------------------------------------------- 1 | struct XML::Namespace 2 | getter document 3 | 4 | def initialize(@document : Node, @ns : LibXML::NS*) 5 | end 6 | 7 | def hash 8 | object_id 9 | end 10 | 11 | def href 12 | @ns.value.href ? String.new(@ns.value.href) : nil 13 | end 14 | 15 | def object_id 16 | @ns.address 17 | end 18 | 19 | def prefix 20 | @ns.value.prefix ? String.new(@ns.value.prefix) : nil 21 | end 22 | 23 | def to_s(io) 24 | io << "#" 38 | io 39 | end 40 | 41 | def inspect(io) 42 | to_s io 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/compiler/normalize/return_next_break_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: return next break" do 4 | ["return", "next", "break"].each do |keyword| 5 | it "removes nodes after #{keyword}" do 6 | assert_normalize "#{keyword} 1; 2", "#{keyword} 1" 7 | end 8 | end 9 | 10 | it "doesn't remove after return when there's an unless" do 11 | assert_normalize "return 1 unless 2; 3", "if 2\nelse\n return 1\nend\n3" 12 | end 13 | 14 | it "removes nodes after if that returns in both branches" do 15 | assert_normalize "if true; break; else; return; end; 1", "if true\n break\nelse\n return\nend" 16 | end 17 | 18 | it "doesn't remove nodes after if that returns in one branch" do 19 | assert_normalize "if true; 1; else; return; end; 1", "if true\n 1\nelse\n return\nend\n1" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/compiler/normalize/and_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: and" do 4 | it "normalizes and without variable" do 5 | assert_expand "a && b", "if __temp_1 = a\n b\nelse\n __temp_1\nend" 6 | end 7 | 8 | it "normalizes and with variable on the left" do 9 | assert_expand_second "a = 1; a && b", "if a\n b\nelse\n a\nend" 10 | end 11 | 12 | it "normalizes and with is_a? on var" do 13 | assert_expand_second "a = 1; a.is_a?(Foo) && b", "if a.is_a?(Foo)\n b\nelse\n a.is_a?(Foo)\nend" 14 | end 15 | 16 | it "normalizes and with is_a? on exp" do 17 | assert_expand_second "a = 1; 1.is_a?(Foo) && b", "if __temp_1 = 1.is_a?(Foo)\n b\nelse\n __temp_1\nend" 18 | end 19 | 20 | it "normalizes and with assignment" do 21 | assert_expand "(a = 1) && b", "if a = 1\n b\nelse\n a\nend" 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/compiler/normalize/chained_comparisons_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Normalize: chained comparisons" do 4 | it "normalizes one comparison with literal" do 5 | assert_normalize "1 <= 2 <= 3", "1 <= 2 && 2 <= 3" 6 | end 7 | 8 | it "normalizes one comparison with var" do 9 | assert_normalize "b = 1; 1 <= b <= 3", "b = 1\n1 <= b && b <= 3" 10 | end 11 | 12 | it "normalizes one comparison with call" do 13 | assert_normalize "1 <= b <= 3", "1 <= __temp_1 = b && __temp_1 <= 3" 14 | end 15 | 16 | it "normalizes two comparisons with literal" do 17 | assert_normalize "1 <= 2 <= 3 <= 4", "1 <= 2 && 2 <= 3 && 3 <= 4" 18 | end 19 | 20 | it "normalizes two comparisons with calls" do 21 | assert_normalize "1 <= a <= b <= 4", "1 <= __temp_2 = a && __temp_2 <= __temp_1 = b && __temp_1 <= 4" 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /src/dl.cr: -------------------------------------------------------------------------------- 1 | @[Link("dl")] 2 | lib LibDL 3 | LAZY = 1 4 | GLOBAL = 8 5 | 6 | struct Info 7 | fname : LibC::Char* 8 | fbase : Void* 9 | sname : LibC::Char* 10 | saddr : Void* 11 | end 12 | 13 | fun dladdr(addr : Void*, info : Info*) : LibC::Int 14 | fun dlsym(handle : Void*, symbol : LibC::Char*) : Void* 15 | fun dlopen(path : LibC::Char*, mode : LibC::Int) : Void* 16 | 17 | ifdef darwin 18 | RTLD_NEXT = Pointer(Void).new(-1) 19 | RTLD_DEFAULT = Pointer(Void).new(-2) 20 | RTLD_SELF = Pointer(Void).new(-3) 21 | RTLD_MAIN_ONLY = Pointer(Void).new(-5) 22 | else 23 | RTLD_NEXT = Pointer(Void).new(-1) 24 | RTLD_DEFAULT = Pointer(Void).new(0) 25 | end 26 | end 27 | 28 | module DL 29 | def self.dlopen(path, mode = LibDL::LAZY | LibDL::GLOBAL) 30 | LibDL.dlopen(path, mode) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /src/thread/condition_variable.cr: -------------------------------------------------------------------------------- 1 | class ConditionVariable 2 | def initialize 3 | if LibPThread.cond_init(out @cond, nil) != 0 4 | raise Errno.new("pthread_cond_init") 5 | end 6 | end 7 | 8 | def signal 9 | if LibPThread.cond_signal(self) != 0 10 | raise Errno.new("pthread_cond_signal") 11 | end 12 | end 13 | 14 | def broadcast 15 | if LibPThread.cond_broadcast(self) != 0 16 | raise Errno.new("pthread_cond_broadcast") 17 | end 18 | end 19 | 20 | def wait(mutex : Mutex) 21 | if LibPThread.cond_wait(self, mutex) != 0 22 | raise Errno.new("pthread_cond_wait") 23 | end 24 | end 25 | 26 | def finalize 27 | if LibPThread.cond_destroy(self) != 0 28 | raise Errno.new("pthread_cond_broadcast") 29 | end 30 | end 31 | 32 | def to_unsafe 33 | pointerof(@cond) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/compiler/compiler_spec.cr: -------------------------------------------------------------------------------- 1 | require "../spec_helper" 2 | require "tempfile" 3 | 4 | describe "Compiler" do 5 | it "compiles a file" do 6 | tempfile = Tempfile.new "compiler_spec_output" 7 | tempfile.close 8 | 9 | Crystal::Command.run ["build", "#{__DIR__}/data/compiler_sample", "-o", tempfile.path] 10 | 11 | File.exists?(tempfile.path).should be_true 12 | 13 | `#{tempfile.path}`.should eq("Hello!") 14 | end 15 | 16 | it "runs subcommand in preference to a filename " do 17 | Dir.cd "#{__DIR__}/data/" do 18 | tempfile = Tempfile.new "compiler_spec_output" 19 | tempfile.close 20 | 21 | Crystal::Command.run ["build", "#{__DIR__}/data/compiler_sample", "-o", tempfile.path] 22 | 23 | File.exists?(tempfile.path).should be_true 24 | 25 | `#{tempfile.path}`.should eq("Hello!") 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/std/http/http_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "http" 3 | 4 | describe HTTP do 5 | it "parses RFC1123" do 6 | time = Time.new(1994, 11, 6, 8, 49, 37) 7 | HTTP.parse_time("Sun, 06 Nov 1994 08:49:37 GMT").should eq(time) 8 | end 9 | 10 | it "parses RFC1036" do 11 | time = Time.new(1994, 11, 6, 8, 49, 37) 12 | HTTP.parse_time("Sunday, 06-Nov-94 08:49:37 GMT").should eq(time) 13 | end 14 | 15 | it "parses ANSI C" do 16 | time = Time.new(1994, 11, 6, 8, 49, 37) 17 | HTTP.parse_time("Sun Nov 6 08:49:37 1994").should eq(time) 18 | time2 = Time.new(1994, 11, 16, 8, 49, 37) 19 | HTTP.parse_time("Sun Nov 16 08:49:37 1994").should eq(time2) 20 | end 21 | 22 | it "generates RFC1123" do 23 | time = Time.new(1994, 11, 6, 8, 49, 37) 24 | HTTP.rfc1123_date(time).should eq("Sun, 06 Nov 1994 08:49:37 GMT") 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/std/readline_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "readline" 3 | 4 | describe Readline do 5 | typeof(Readline.readline) 6 | typeof(Readline.readline("Hello", true)) 7 | typeof(Readline.readline(prompt: "Hello")) 8 | typeof(Readline.readline(add_history: false)) 9 | typeof(Readline.line_buffer) 10 | typeof(Readline.point) 11 | typeof(Readline.autocomplete { |s| %w(foo bar) }) 12 | 13 | it "gets prefix in bytesize between two strings" do 14 | Readline.common_prefix_bytesize("", "foo").should eq(0) 15 | Readline.common_prefix_bytesize("foo", "").should eq(0) 16 | Readline.common_prefix_bytesize("a", "a").should eq(1) 17 | Readline.common_prefix_bytesize("open", "operate").should eq(3) 18 | Readline.common_prefix_bytesize("operate", "open").should eq(3) 19 | Readline.common_prefix_bytesize(["operate", "open", "optional"]).should eq(2) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/std/ecr/ecr_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "ecr" 3 | require "ecr/macros" 4 | 5 | class ECRSpecHelloView 6 | def initialize(@msg) 7 | end 8 | 9 | ecr_file "#{__DIR__}/../data/test_template.ecr" 10 | end 11 | 12 | describe "ECR" do 13 | it "builds a crystal program from a source" do 14 | program = ECR.process_string "hello <%= 1 %> wor\nld <% while true %> 2 <% end %>", "foo.cr" 15 | 16 | pieces = [ 17 | %(__str__ << "hello "), 18 | %((# 1 ).to_s __str__), 19 | %(__str__ << " wor\\nld "), 20 | %(# while true ), 21 | %(__str__ << " 2 "), 22 | %(# end ), 23 | ] 24 | program.should eq(pieces.join("\n") + "\n") 25 | end 26 | 27 | it "does ecr_file" do 28 | view = ECRSpecHelloView.new("world!") 29 | view.to_s.strip.should eq("Hello world! 012") 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /src/compiler/crystal/codegen/types.cr: -------------------------------------------------------------------------------- 1 | module Crystal 2 | class Type 3 | def llvm_name 4 | String.build do |io| 5 | llvm_name io 6 | end 7 | end 8 | 9 | def llvm_name(io) 10 | to_s io 11 | end 12 | end 13 | 14 | class PrimitiveType 15 | def llvm_name(io) 16 | io << name 17 | end 18 | end 19 | 20 | class AliasType 21 | def llvm_name(io) 22 | io << "alias." 23 | to_s io 24 | end 25 | end 26 | 27 | class CStructType 28 | def llvm_name(io) 29 | io << "struct." 30 | to_s io 31 | end 32 | end 33 | 34 | class CUnionType 35 | def llvm_name(io) 36 | io << "union." 37 | to_s io 38 | end 39 | end 40 | 41 | class TypeDefType 42 | def llvm_name(io) 43 | typedef.llvm_name(io) 44 | end 45 | end 46 | 47 | class Const 48 | property initializer 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/std/zlib/zlib_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "zlib" 3 | 4 | describe Zlib do 5 | it "should be able to calculate adler32" do 6 | adler = Zlib.adler32("foo").to_s(16) 7 | adler.should eq("2820145") 8 | end 9 | 10 | it "should be able to calculate adler32 combined" do 11 | adler1 = Zlib.adler32("hello") 12 | adler2 = Zlib.adler32(" world!") 13 | combined = Zlib.adler32_combine(adler1, adler2, " world!".size) 14 | Zlib.adler32("hello world!").should eq(combined) 15 | end 16 | 17 | it "should be able to calculate crc32" do 18 | crc = Zlib.crc32("foo").to_s(16) 19 | crc.should eq("8c736521") 20 | end 21 | 22 | it "should be able to calculate crc32 combined" do 23 | crc1 = Zlib.crc32("hello") 24 | crc2 = Zlib.crc32(" world!") 25 | combined = Zlib.crc32_combine(crc1, crc2, " world!".size) 26 | Zlib.crc32("hello world!").should eq(combined) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /src/iterable.cr: -------------------------------------------------------------------------------- 1 | # The Iterable mixin provides convenince methods to collection classes 2 | # that provide an `each` method that returns an `Iterator` over the collection. 3 | module Iterable 4 | # Must return an `Iterator` over the elements in this collection. 5 | abstract def each 6 | 7 | # Same as `each.cycle`. 8 | def cycle 9 | each.cycle 10 | end 11 | 12 | # Same as `each.cycle(n)`. 13 | def cycle(n) 14 | each.cycle(n) 15 | end 16 | 17 | # Same as `each.slice(count)`. 18 | def each_slice(count : Int) 19 | each.slice(count) 20 | end 21 | 22 | # Same as `each.cons(count)`. 23 | def each_cons(count : Int) 24 | each.cons(count) 25 | end 26 | 27 | # Same as `each.with_index(offset)`. 28 | def each_with_index(offset = 0) 29 | each.with_index(offset) 30 | end 31 | 32 | # Same as `each.with_object(obj)`. 33 | def each_with_object(obj) 34 | each.with_object(obj) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /src/csv/lexer/io_based.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | class CSV::Lexer::IOBased < CSV::Lexer 3 | def initialize(io) 4 | super() 5 | @io = io 6 | @current_char = @io.read_char || '\0' 7 | end 8 | 9 | def rewind 10 | @io.rewind 11 | @current_char = @io.read_char || '\0' 12 | end 13 | 14 | private def consume_unquoted_cell 15 | @buffer.clear 16 | while true 17 | case current_char 18 | when ',' 19 | check_last_empty_column 20 | break 21 | when '\r', '\n', '\0' 22 | break 23 | when '"' 24 | raise "unexpected quote" 25 | else 26 | @buffer << current_char 27 | next_char 28 | end 29 | end 30 | @buffer.to_s 31 | end 32 | 33 | private getter current_char 34 | 35 | private def next_char_no_column_increment 36 | @current_char = @io.read_char || '\0' 37 | end 38 | 39 | private def consume_string 40 | consume_string_with_buffer 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /src/xml/error.cr: -------------------------------------------------------------------------------- 1 | require "./libxml2" 2 | 3 | class XML::Error < Exception 4 | getter line_number 5 | 6 | def self.new(error : LibXML::Error*) 7 | new String.new(error.value.message).chomp, error.value.line 8 | end 9 | 10 | def initialize(message, @line_number) 11 | super(message) 12 | end 13 | 14 | # TODO: this logic isn't thread/fiber safe, but error checking is less needed than 15 | # the ability to parse HTML5 and malformed documents. In any case, fix this. 16 | @@errors = [] of self 17 | 18 | LibXML.xmlSetStructuredErrorFunc nil, ->(ctx, error) { 19 | @@errors << XML::Error.new(error) 20 | } 21 | 22 | LibXML.xmlSetGenericErrorFunc nil, ->(ctx, fmt) { 23 | # TODO: use va_start and va_end 24 | raise XML::Error.new(String.new(fmt).chomp, 0) 25 | } 26 | 27 | # :nodoc: 28 | def self.set_errors(node) 29 | unless @@errors.empty? 30 | node.errors = @@errors.dup 31 | @@errors.clear 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/reflection_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: reflection" do 4 | it "types Object class" do 5 | assert_type("Object") { types["Class"] } 6 | end 7 | 8 | it "types Class class" do 9 | assert_type("Class") { types["Class"] } 10 | end 11 | 12 | it "types Object and Class metaclases" do 13 | assert_type("Object.class") { types["Class"] } 14 | assert_type("Class.class") { types["Class"] } 15 | end 16 | 17 | it "types Reference metaclass" do 18 | assert_type("Reference") { types["Reference"].metaclass } 19 | assert_type("Reference.class") { types["Class"] } 20 | end 21 | 22 | it "types metaclass parent" do 23 | input = parse(" 24 | class Foo; end 25 | class Bar < Foo; end 26 | ") 27 | result = infer_type input 28 | mod = result.program 29 | 30 | (mod.types["Bar"].metaclass as ClassType).superclass.should eq(mod.types["Foo"].metaclass) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /src/llvm/function_collection.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::FunctionCollection 2 | def initialize(@mod) 3 | end 4 | 5 | def add(name, arg_types : Array(LLVM::Type), ret_type, varargs = false) 6 | fun_type = LLVM::Type.function(arg_types, ret_type, varargs) 7 | func = LibLLVM.add_function(@mod, name, fun_type) 8 | Function.new(func) 9 | end 10 | 11 | def add(name, arg_types : Array(LLVM::Type), ret_type, varargs = false) 12 | func = add(name, arg_types, ret_type, varargs) 13 | yield func 14 | func 15 | end 16 | 17 | def [](name) 18 | func = self[name]? 19 | func || raise "undefined llvm function: #{name}" 20 | end 21 | 22 | def []?(name) 23 | func = LibLLVM.get_named_function(@mod, name) 24 | func ? Function.new(func) : nil 25 | end 26 | 27 | def each 28 | f = LibLLVM.get_first_function(@mod) 29 | while f 30 | yield LLVM::Function.new f 31 | f = LibLLVM.get_next_function(f) 32 | end 33 | self 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /src/llvm/function_pass_manager.cr: -------------------------------------------------------------------------------- 1 | class LLVM::FunctionPassManager 2 | def initialize(@unwrap) 3 | end 4 | 5 | def add_target_data(target_data) 6 | LibLLVM.add_target_data target_data, self 7 | end 8 | 9 | def run(mod : Module) 10 | changed = false 11 | run do |runner| 12 | mod.functions.each do |func| 13 | changed ||= runner.run(func) 14 | end 15 | end 16 | changed 17 | end 18 | 19 | def run 20 | LibLLVM.initialize_function_pass_manager(self) 21 | 22 | runner = Runner.new(self) 23 | yield runner 24 | 25 | LibLLVM.finalize_function_pass_manager(self) 26 | 27 | self 28 | end 29 | 30 | def to_unsafe 31 | @unwrap 32 | end 33 | 34 | def finalize 35 | LibLLVM.dispose_pass_manager(@unwrap) 36 | end 37 | 38 | struct Runner 39 | def initialize(@fpm) 40 | end 41 | 42 | def run(f : LLVM::Function) 43 | LibLLVM.run_function_pass_manager(@fpm, f) != 0 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /samples/mandelbrot.cr: -------------------------------------------------------------------------------- 1 | def print_density(d) 2 | if d > 8 3 | print ' ' 4 | elsif d > 4 5 | print '.' 6 | elsif d > 2 7 | print '*' 8 | else 9 | print '+' 10 | end 11 | end 12 | 13 | def mandelconverger(real, imag, iters, creal, cimag) 14 | if iters > 255 || real*real + imag*imag >= 4 15 | iters 16 | else 17 | mandelconverger real*real - imag*imag + creal, 2*real*imag + cimag, iters + 1, creal, cimag 18 | end 19 | end 20 | 21 | def mandelconverge(real, imag) 22 | mandelconverger real, imag, 0, real, imag 23 | end 24 | 25 | def mandelhelp(xmin, xmax, xstep, ymin, ymax, ystep) 26 | ymin.step(ymax, ystep) do |y| 27 | xmin.step(xmax, xstep) do |x| 28 | print_density mandelconverge(x, y) 29 | end 30 | puts 31 | end 32 | end 33 | 34 | def mandel(realstart, imagstart, realmag, imagmag) 35 | mandelhelp realstart, realstart + realmag*78, realmag, imagstart, imagstart + imagmag*40, imagmag 36 | end 37 | 38 | mandel -2.3, -1.3, 0.05, 0.07 39 | -------------------------------------------------------------------------------- /samples/sdl/sdl/sdl.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module SDL 4 | def self.init(flags = LibSDL::INIT_EVERYTHING) 5 | if LibSDL.init(flags) != 0 6 | raise "Can't initialize SDL: #{error}" 7 | end 8 | end 9 | 10 | def self.set_video_mode(width, height, bpp, flags) 11 | surface = LibSDL.set_video_mode(width, height, bpp, flags) 12 | if surface.nil? 13 | raise "Can't set SDL video mode: #{error}" 14 | end 15 | Surface.new(surface, width, height, bpp) 16 | end 17 | 18 | def self.show_cursor 19 | LibSDL.show_cursor LibSDL::ENABLE 20 | end 21 | 22 | def self.hide_cursor 23 | LibSDL.show_cursor LibSDL::DISABLE 24 | end 25 | 26 | def self.error 27 | String.new LibSDL.get_error 28 | end 29 | 30 | def self.ticks 31 | LibSDL.get_ticks 32 | end 33 | 34 | def self.quit 35 | LibSDL.quit 36 | end 37 | 38 | def self.poll_events 39 | while LibSDL.poll_event(out event) == 1 40 | yield event 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /spec/std/symbol_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe Symbol do 4 | it "inspects" do 5 | :foo.inspect.should eq(%(:foo)) 6 | :"{".inspect.should eq(%(:"{")) 7 | :"hi there".inspect.should eq(%(:"hi there")) 8 | # :かたな.inspect.should eq(%(:かたな)) 9 | end 10 | it "can be compared with another symbol" do 11 | :s.between?(:a, :z).should be_true 12 | :a.between?(:s, :z).should be_false 13 | (:foo > :bar).should be_true 14 | (:foo < :bar).should be_false 15 | 16 | a = %i(q w e r t y u i o p a s d f g h j k l z x c v b n m) 17 | b = %i(a b c d e f g h i j k l m n o p q r s t u v w x y z) 18 | a.sort.should eq(b) 19 | end 20 | 21 | it "displays symbols that don't need quotes without quotes" do 22 | a = %i(+ - * / == < <= > >= ! != =~ !~ & | ^ ~ ** >> << % [] <=> === []? []=) 23 | b = "[:+, :-, :*, :/, :==, :<, :<=, :>, :>=, :!, :!=, :=~, :!~, :&, :|, :^, :~, :**, :>>, :<<, :%, :[], :<=>, :===, :[]?, :[]=]" 24 | a.inspect.should eq(b) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | sudo: required 3 | services: 4 | - docker 5 | matrix: 6 | include: 7 | - env: ARCH=i386 ARCH_CMD=linux32 8 | os: linux 9 | - env: ARCH=x86_64 ARCH_CMD=linux64 10 | os: linux 11 | - os: osx 12 | before_install: bin/ci prepare_system 13 | install: bin/ci prepare_build 14 | script: 15 | - bin/ci with_build_env 'make crystal spec doc' 16 | - bin/ci with_build_env 'find samples -name "*.cr" | xargs -L 1 ./bin/crystal build --no-codegen' 17 | branches: 18 | only: 19 | - master 20 | - gh-pages 21 | notifications: 22 | irc: 23 | channels: 24 | - "irc.freenode.net#crystal-lang" 25 | use_notice: true 26 | skip_join: true 27 | template: 28 | - "%{repository_slug}#%{commit} (%{branch} - %{commit_subject}): %{message} %{build_url}" 29 | slack: 30 | secure: Ng3nTqGWY+9p1pS6yjGqDhmRvdgbIZgTNpMWbO/ngwpCyicmD3jafZkShqqXbULZTJJr3OxIGzi6GHGusT0Ic/Pi9JCM3X3v/xuBruKIR+EnNyPo7IL4ZYAlwnXyJHlCHHDBq0gSHGvGJwsXn6IgZBPRfeIq+CCyQHVPyvc9EHE= 31 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/responds_to_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: responds_to?" do 4 | it "is bool" do 5 | assert_type("1.responds_to?(:foo)") { bool } 6 | end 7 | 8 | it "restricts type inside if scope 1" do 9 | nodes = parse " 10 | a = 1 || 'a' 11 | if a.responds_to?(:\"+\") 12 | a 13 | end 14 | " 15 | result = infer_type nodes 16 | mod, nodes = result.program, result.node as Expressions 17 | (nodes.last as If).then.type.should eq(mod.int32) 18 | end 19 | 20 | it "restricts other types inside if else" do 21 | assert_type(" 22 | a = 1 || 'a' 23 | if a.responds_to?(:\"+\") 24 | a.to_i32 25 | else 26 | a.ord 27 | end 28 | ") { int32 } 29 | end 30 | 31 | it "restricts in assignment" do 32 | assert_type(" 33 | a = 1 || 'a' 34 | if (b = a).responds_to?(:abs) 35 | b 36 | else 37 | 2 38 | end 39 | ") { int32 } 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /src/csv/lexer/string_based.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | class CSV::Lexer::StringBased < CSV::Lexer 3 | def initialize(string) 4 | super() 5 | @reader = Char::Reader.new(string) 6 | if @reader.current_char == '\n' 7 | @line_number += 1 8 | @column_number = 0 9 | end 10 | end 11 | 12 | def rewind 13 | @reader.pos = 0 14 | end 15 | 16 | private def consume_unquoted_cell 17 | start_pos = @reader.pos 18 | end_pos = start_pos 19 | while true 20 | case next_char 21 | when ',' 22 | end_pos = @reader.pos 23 | check_last_empty_column 24 | break 25 | when '\r', '\n', '\0' 26 | end_pos = @reader.pos 27 | break 28 | when '"' 29 | raise "unexpected quote" 30 | end 31 | end 32 | @reader.string.byte_slice(start_pos, end_pos - start_pos) 33 | end 34 | 35 | private def next_char_no_column_increment 36 | @reader.next_char 37 | end 38 | 39 | private def current_char 40 | @reader.current_char 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /src/proc.cr: -------------------------------------------------------------------------------- 1 | struct Proc 2 | def self.new(pointer : Void*, closure_data : Void*) 3 | func = {pointer, closure_data} 4 | ptr = pointerof(func) as self* 5 | ptr.value 6 | end 7 | 8 | def pointer 9 | internal_representation[0] 10 | end 11 | 12 | def closure_data 13 | internal_representation[1] 14 | end 15 | 16 | def closure? 17 | !closure_data.nil? 18 | end 19 | 20 | private def internal_representation 21 | func = self 22 | ptr = pointerof(func) as {Void*, Void*}* 23 | ptr.value 24 | end 25 | 26 | def ==(other : self) 27 | pointer == other.pointer && closure_data == other.closure_data 28 | end 29 | 30 | def ===(other : self) 31 | self == other 32 | end 33 | 34 | def ===(other) 35 | call(other) 36 | end 37 | 38 | def to_s(io) 39 | io << "#<" 40 | io << {{@type.name.stringify}} 41 | io << ":0x" 42 | pointer.address.to_s(16, io) 43 | if closure? 44 | io << ":closure" 45 | end 46 | io << ">" 47 | nil 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /src/crypto/bcrypt/blowfish.cr: -------------------------------------------------------------------------------- 1 | require "../blowfish" 2 | 3 | # :nodoc: 4 | class Crypto::Bcrypt::Blowfish < Crypto::Blowfish 5 | def enhance_key_schedule(data, key, cost) 6 | enhance_key_schedule(data, key) 7 | 8 | (1_u32 << cost).times do 9 | expand_key(key) 10 | expand_key(data) 11 | end 12 | end 13 | 14 | def enhance_key_schedule(data, key) 15 | pos = 0 16 | 17 | 0.upto(17) do |i| 18 | @p[i] ^= next_word(key, pointerof(pos)) 19 | end 20 | 21 | l, r, pos = 0, 0, 0 22 | 23 | 0.step(17, 2) do |i| 24 | l ^= next_word(data, pointerof(pos)) 25 | r ^= next_word(data, pointerof(pos)) 26 | l, r = encrypt_pair(l, r) 27 | @p[i] = l 28 | @p[i + 1] = r 29 | end 30 | 31 | 0.upto(3) do |i| 32 | 0.step(255, 2) do |j| 33 | l ^= next_word(data, pointerof(pos)) 34 | r ^= next_word(data, pointerof(pos)) 35 | l, r = encrypt_pair(l, r) 36 | @s[i][j] = l 37 | @s[i][j + 1] = r 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /samples/spectral-norm.cr: -------------------------------------------------------------------------------- 1 | # Copied with little modifications from: https://github.com/wmoxam/Ruby-Benchmarks-Game/blob/master/benchmarks/spectral-norm.rb 2 | 3 | def eval_A(i, j) 4 | return 1.0_f64 / ((i + j) * (i + j + 1.0) / 2.0 + i + 1.0) 5 | end 6 | 7 | def eval_A_times_u(u) 8 | (0...u.size).map do |i| 9 | v = 0.0_f64 10 | (0...u.size).each do |j| 11 | v += eval_A(i, j) * u[j] 12 | end 13 | v 14 | end 15 | end 16 | 17 | def eval_At_times_u(u) 18 | (0...u.size).map do |i| 19 | v = 0.0_f64 20 | (0...u.size).each do |j| 21 | v += eval_A(j, i) * u[j] 22 | end 23 | v 24 | end 25 | end 26 | 27 | def eval_AtA_times_u(u) 28 | eval_At_times_u(eval_A_times_u(u)) 29 | end 30 | 31 | n = (ARGV[0]? || 1000).to_i 32 | u = Array.new(n, 1.0_f64) 33 | v = Array.new(n, 1.0_f64) 34 | 10.times do 35 | v = eval_AtA_times_u(u) 36 | u = eval_AtA_times_u(v) 37 | end 38 | vBv = vv = 0.0_f64 39 | (0...n).each do |i| 40 | vBv += u[i] * v[i] 41 | vv += v[i] * v[i] 42 | end 43 | puts "#{(Math.sqrt(vBv / vv))}" 44 | -------------------------------------------------------------------------------- /spec/std/llvm/x86_abi_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "llvm" 3 | 4 | LLVM.init_x86 5 | 6 | private def abi 7 | triple = LLVM.default_target_triple 8 | target = LLVM::Target.from_triple(triple) 9 | machine = target.create_target_machine(triple) 10 | LLVM::ABI::X86.new(machine) 11 | end 12 | 13 | class LLVM::ABI 14 | describe X86 do 15 | it "does size" do 16 | abi.size(LLVM::Int32).should eq(4) 17 | end 18 | 19 | it "does align" do 20 | abi.align(LLVM::Int32).should eq(4) 21 | end 22 | 23 | describe "abi_info" do 24 | it "does with primitives" do 25 | arg_types = [LLVM::Int32, LLVM::Int64] 26 | return_type = LLVM::Int8 27 | info = abi.abi_info(arg_types, return_type, true) 28 | info.arg_types.size.should eq(2) 29 | 30 | info.arg_types[0].should eq(ArgType.direct(LLVM::Int32)) 31 | info.arg_types[1].should eq(ArgType.direct(LLVM::Int64)) 32 | info.return_type.should eq(ArgType.direct(LLVM::Int8)) 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | %w(precise trusty vivid).product([32, 64]).each do |dist, bits| 6 | box_name = "#{dist}#{bits}" 7 | config.vm.define(box_name) { |c| c.vm.box = "ubuntu/#{box_name}" } 8 | end 9 | 10 | config.vm.provider "virtualbox" do |vb| 11 | vb.memory = 4096 12 | vb.cpus = 2 13 | end 14 | 15 | config.vm.provision :shell, inline: %( 16 | curl -s http://dist.crystal-lang.org/apt/setup.sh | bash 17 | apt-get install -y crystal git libgmp3-dev zlib1g-dev libedit-dev libxml2-dev libssl-dev libyaml-dev libreadline-dev 18 | curl -s http://crystal-lang.s3.amazonaws.com/llvm/llvm-3.5.0-1-linux-`uname -m`.tar.gz | tar xz -C /opt 19 | echo 'export LIBRARY_PATH="/opt/crystal/embedded/lib"' > /etc/profile.d/crystal.sh 20 | echo 'export PATH="$PATH:/opt/llvm-3.5.0-1/bin"' >> /etc/profile.d/crystal.sh 21 | ) 22 | 23 | config.vm.provision :shell, privileged: false, inline: %( 24 | git clone /vagrant crystal 25 | ) 26 | end 27 | -------------------------------------------------------------------------------- /src/llvm/parameter_collection.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::ParameterCollection 2 | def initialize(@function) 3 | end 4 | 5 | def size 6 | LibLLVM.count_param_types(@function.function_type).to_i 7 | end 8 | 9 | def to_a 10 | param_size = size() 11 | Array(LLVM::Value).build(param_size) do |buffer| 12 | LibLLVM.get_params(@function, buffer as LibLLVM::ValueRef*) 13 | param_size 14 | end 15 | end 16 | 17 | def [](index) 18 | param_size = size() 19 | index += param_size if index < 0 20 | 21 | unless 0 <= index < param_size 22 | raise IndexError.new 23 | end 24 | 25 | Value.new LibLLVM.get_param(@function, index) 26 | end 27 | 28 | def first 29 | raise IndexError.new if size == 0 30 | 31 | Value.new LibLLVM.get_param(@function, 0) 32 | end 33 | 34 | def types 35 | param_size = size() 36 | Array(LLVM::Type).build(param_size) do |buffer| 37 | LibLLVM.get_param_types(@function.function_type, buffer as LibLLVM::TypeRef*) 38 | param_size 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /samples/matmul.cr: -------------------------------------------------------------------------------- 1 | # Copied with little modifications from: https://github.com/attractivechaos/plb/blob/master/matmul/matmul_v1.rb 2 | 3 | def matmul(a, b) 4 | m = a.size 5 | n = a[0].size 6 | p = b[0].size 7 | # transpose 8 | b2 = Array.new(n) { Array.new(p, 0.0) } 9 | (0...n).each do |i| 10 | (0...p).each do |j| 11 | b2[j][i] = b[i][j] 12 | end 13 | end 14 | # multiplication 15 | c = Array.new(m) { Array.new(p, 0.0) } 16 | (0...m).each do |i| 17 | (0...p).each do |j| 18 | s = 0.0 19 | ai, b2j = a[i], b2[j] 20 | (0...n).each do |k| 21 | s += ai[k] * b2j[k] 22 | end 23 | c[i][j] = s 24 | end 25 | end 26 | c 27 | end 28 | 29 | def matgen(n) 30 | tmp = 1.0 / n / n 31 | a = Array.new(n) { Array.new(n, 0.0) } 32 | (0...n).each do |i| 33 | (0...n).each do |j| 34 | a[i][j] = tmp * (i - j) * (i + j) 35 | end 36 | end 37 | a 38 | end 39 | 40 | n = (ARGV[0]? || 500).to_i 41 | n = n / 2 * 2 42 | a = matgen(n) 43 | b = matgen(n) 44 | c = matmul(a, b) 45 | puts c[n / 2][n / 2] 46 | -------------------------------------------------------------------------------- /spec/std/io/argf_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe IO::ARGF do 4 | it "reads from STDIN if ARGV isn't specified" do 5 | argv = [] of String 6 | stdin = MemoryIO.new("hello") 7 | 8 | argf = IO::ARGF.new argv, stdin 9 | argf.path.should eq("-") 10 | argf.gets_to_end.should eq("hello") 11 | argf.read_byte.should be_nil 12 | end 13 | 14 | it "reads from ARGV if specified" do 15 | path1 = "#{__DIR__}/../data/argf_test_file_1.txt" 16 | path2 = "#{__DIR__}/../data/argf_test_file_2.txt" 17 | stdin = MemoryIO.new("") 18 | argv = [path1, path2] 19 | 20 | argf = IO::ARGF.new argv, stdin 21 | argf.path.should eq(path1) 22 | argv.should eq([path1, path2]) 23 | 24 | str = argf.gets(5) 25 | str.should eq("12345") 26 | 27 | argv.should eq([path2]) 28 | 29 | str = argf.gets_to_end 30 | str.should eq("\n67890\n") 31 | 32 | argv.empty?.should be_true 33 | 34 | argf.read_byte.should be_nil 35 | 36 | argv << path1 37 | str = argf.gets(5) 38 | str.should eq("12345") 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/std/inifile_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "inifile" 3 | 4 | describe "IniFile" do 5 | describe "parse from string" do 6 | it "parses key = value" do 7 | IniFile.load("key = value").should eq({"" => {"key" => "value"}}) 8 | end 9 | 10 | it "ignores whitespaces" do 11 | IniFile.load(" key = value ").should eq({"" => {"key" => "value"}}) 12 | end 13 | 14 | it "parses sections" do 15 | IniFile.load("[section]\na = 1").should eq({"section" => {"a" => "1"}}) 16 | end 17 | 18 | it "empty section" do 19 | IniFile.load("[section]").should eq({"section" => {} of String => String}) 20 | end 21 | 22 | it "parse file" do 23 | IniFile.load(File.read "#{__DIR__}/data/test_file.ini").should eq({ 24 | "general" => { 25 | "log_level" => "DEBUG", 26 | }, 27 | "section1" => { 28 | "foo" => "1", 29 | "bar" => "2", 30 | }, 31 | "section2" => { 32 | "x.y.z" => "coco lala", 33 | }, 34 | }) 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /src/class.cr: -------------------------------------------------------------------------------- 1 | class Class 2 | def inspect(io) 3 | to_s(io) 4 | end 5 | 6 | def hash 7 | crystal_type_id 8 | end 9 | 10 | def ==(other : Class) 11 | crystal_type_id == other.crystal_type_id 12 | end 13 | 14 | def ===(other) 15 | other.is_a?(self) 16 | end 17 | 18 | # Returns the name of this class. 19 | # 20 | # ``` 21 | # String.name # => "String" 22 | # ``` 23 | macro def name : String 24 | {{ @type.name.stringify }} 25 | end 26 | 27 | # Casts `other` to this class. 28 | # 29 | # This is the same as using `as`, but allows the class to be passed around as 30 | # an argument. See the [documentation on 31 | # as](//crystal-lang.org/docs/syntax_and_semantics/as.html) for more 32 | # information. 33 | # 34 | # klass = Int32 35 | # number = [99, "str"][0] 36 | # typeof(number) # => (String | Int32) 37 | # typeof(klass.cast(number)) # => Int32 38 | # 39 | macro def cast(other) : self 40 | other as self 41 | end 42 | 43 | def to_s(io) 44 | io << name 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/array_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: array" do 4 | it "types array literal of int" do 5 | assert_type("require \"prelude\"; [1, 2, 3]") { array_of(int32) } 6 | end 7 | 8 | it "types array literal of union" do 9 | assert_type("require \"prelude\"; [1, 2.5]") { array_of(union_of int32, float64) } 10 | end 11 | 12 | it "types empty typed array literal of int" do 13 | assert_type("require \"prelude\"; [] of Int32") { array_of(int32) } 14 | end 15 | 16 | it "types non-empty typed array literal of int" do 17 | assert_type("require \"prelude\"; [1, 2, 3] of Int32") { array_of(int32) } 18 | end 19 | 20 | it "types array literal size correctly" do 21 | assert_type("require \"prelude\"; [1].size") { int32 } 22 | end 23 | 24 | it "recalculates array literal type after element type changes" do 25 | assert_type(%( 26 | require "prelude" 27 | $a = 1 28 | x = [$a] 29 | $a = 1.1 30 | x 31 | )) { array_of(union_of int32, float64) } 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/std/yaml/yaml_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "yaml" 3 | 4 | describe "YAML" do 5 | describe "parser" do 6 | assert { YAML.load("foo").should eq("foo") } 7 | assert { YAML.load("- foo\n- bar").should eq(["foo", "bar"]) } 8 | assert { YAML.load_all("---\nfoo\n---\nbar\n").should eq(["foo", "bar"]) } 9 | assert { YAML.load("foo: bar").should eq({"foo" => "bar"}) } 10 | assert { YAML.load("--- []\n").should eq([] of YAML::Type) } 11 | assert { YAML.load("---\n...").should eq("") } 12 | 13 | it "parses recursive sequence" do 14 | doc = YAML.load("--- &foo\n- *foo\n") as Array 15 | doc[0].should be(doc) 16 | end 17 | 18 | it "parses recursive mapping" do 19 | doc = YAML.load(%(--- &1 20 | friends: 21 | - *1 22 | )) as Hash 23 | (doc["friends"] as Array)[0].should be(doc) 24 | end 25 | 26 | it "parses alias to scalar" do 27 | doc = YAML.load("---\n- &x foo\n- *x\n") as Array 28 | doc.should eq(["foo", "foo"]) 29 | doc[0].should be(doc[1]) 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /src/regex/lib_pcre.cr: -------------------------------------------------------------------------------- 1 | @[Link("pcre")] 2 | lib LibPCRE 3 | alias Int = LibC::Int 4 | 5 | type Pcre = Void* 6 | type PcreExtra = Void* 7 | fun compile = pcre_compile(pattern : UInt8*, options : Int, errptr : UInt8**, erroffset : Int*, tableptr : Void*) : Pcre 8 | fun study = pcre_study(code : Pcre, options : Int, errptr : UInt8**) : PcreExtra 9 | fun exec = pcre_exec(code : Pcre, extra : PcreExtra, subject : UInt8*, length : Int, offset : Int, options : Int, 10 | ovector : Int*, ovecsize : Int) : Int32 11 | fun full_info = pcre_fullinfo(code : Pcre, extra : PcreExtra, what : Int, where : Int32*) : Int 12 | fun get_stringnumber = pcre_get_stringnumber(code : Pcre, string_name : UInt8*) : Int 13 | 14 | INFO_CAPTURECOUNT = 2 15 | INFO_NAMEENTRYSIZE = 7 16 | INFO_NAMECOUNT = 8 17 | INFO_NAMETABLE = 9 18 | 19 | alias Malloc = LibC::SizeT -> Void* 20 | alias Free = Void* -> 21 | 22 | $pcre_malloc : Malloc 23 | $pcre_free : Free 24 | end 25 | 26 | LibPCRE.pcre_malloc = ->GC.malloc(LibC::SizeT) 27 | LibPCRE.pcre_free = ->GC.free(Void*) 28 | -------------------------------------------------------------------------------- /src/xml/node_set.cr: -------------------------------------------------------------------------------- 1 | struct XML::NodeSet 2 | include Enumerable(Node) 3 | 4 | def initialize(@doc : Node, @set : LibXML::NodeSet*) 5 | end 6 | 7 | def self.new(doc : Node) 8 | new doc, LibXML.xmlXPathNodeSetCreate(nil) 9 | end 10 | 11 | def [](index : Int) 12 | index += size if index < 0 13 | 14 | unless 0 <= index < size 15 | raise IndexError.new 16 | end 17 | 18 | internal_at(index) 19 | end 20 | 21 | def each 22 | size.times do |i| 23 | yield internal_at(i) 24 | end 25 | end 26 | 27 | def empty? 28 | size == 0 29 | end 30 | 31 | def hash 32 | object_id 33 | end 34 | 35 | def inspect(io) 36 | io << "[" 37 | join ", ", io, &.inspect(io) 38 | io << "]" 39 | end 40 | 41 | def size 42 | @set.value.node_nr 43 | end 44 | 45 | def object_id 46 | @set.address 47 | end 48 | 49 | def to_s(io) 50 | join "\n", io 51 | end 52 | 53 | def to_unsafe 54 | @set 55 | end 56 | 57 | private def internal_at(index) 58 | Node.new(@set.value.node_tab[index]) 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/std/semantic_version_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "semantic_version" 3 | 4 | describe SemanticVersion do 5 | it "compares <" do 6 | sversions = %w( 7 | 1.2.3-2 8 | 1.2.3-10 9 | 1.2.3-alpha 10 | 1.2.3-alpha.2 11 | 1.2.3-alpha.10 12 | 1.2.3-beta 13 | 1.2.3 14 | 1.2.4-alpha 15 | 1.2.4-beta 16 | 1.2.4 17 | ) 18 | versions = sversions.map { |s| SemanticVersion.parse(s) }.to_a 19 | 20 | versions.each_with_index do |v, i| 21 | v.to_s.should eq(sversions[i]) 22 | end 23 | 24 | versions.each_cons(2) do |pair| 25 | pair[0].should be < pair[1] 26 | end 27 | end 28 | 29 | it "compares build equivalence" do 30 | sversions = [ 31 | "1.2.3+1", 32 | "1.2.3+999", 33 | "1.2.3+a", 34 | ] 35 | versions = sversions.map { |s| SemanticVersion.parse(s) }.to_a 36 | 37 | versions.each_with_index do |v, i| 38 | v.to_s.should eq(sversions[i]) 39 | end 40 | 41 | versions.each_cons(2) do |pair| 42 | pair[0].should eq(pair[1]) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /src/llvm/function.cr: -------------------------------------------------------------------------------- 1 | require "./value_methods" 2 | 3 | struct LLVM::Function 4 | include LLVM::ValueMethods 5 | 6 | def basic_blocks 7 | BasicBlockCollection.new self 8 | end 9 | 10 | def call_convention 11 | LLVM::CallConvention.new LibLLVM.get_function_call_convention(self) 12 | end 13 | 14 | def call_convention=(cc) 15 | LibLLVM.set_function_call_convention(self, cc) 16 | end 17 | 18 | def add_attribute(attribute) 19 | LibLLVM.add_function_attr self, attribute 20 | end 21 | 22 | def add_target_dependent_attribute(name, value) 23 | LibLLVM.add_target_dependent_function_attr self, name, value 24 | end 25 | 26 | def attributes 27 | LibLLVM.get_function_attr(self) 28 | end 29 | 30 | def function_type 31 | Type.new LibLLVM.get_element_type(LibLLVM.type_of(self)) 32 | end 33 | 34 | def return_type 35 | Type.new LibLLVM.get_return_type(function_type) 36 | end 37 | 38 | def varargs? 39 | LibLLVM.is_function_var_arg(function_type) != 0 40 | end 41 | 42 | def params 43 | ParameterCollection.new self 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/compiler/codegen/previous_def_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "codegen: previous_def" do 4 | it "codegens previous def" do 5 | run(%( 6 | def foo 7 | 1 8 | end 9 | 10 | def foo 11 | previous_def + 1 12 | end 13 | 14 | foo 15 | )).to_i.should eq(2) 16 | end 17 | 18 | it "codeges previous def when inside fun and forwards args" do 19 | run(%( 20 | def foo(z) 21 | z + 1 22 | end 23 | 24 | def foo(z) 25 | ->(x : Int32) { x + previous_def } 26 | end 27 | 28 | x = foo(2) 29 | x.call(3) 30 | )).to_i.should eq(6) 31 | end 32 | 33 | it "codegens previous def when inside fun with self" do 34 | run(%( 35 | class Foo 36 | def initialize 37 | @x = 1 38 | end 39 | 40 | def bar 41 | @x 42 | end 43 | end 44 | 45 | class Foo 46 | def bar 47 | x = ->{ previous_def } 48 | end 49 | end 50 | 51 | Foo.new.bar.call 52 | )).to_i.should eq(1) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/std/openssl/hmac_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "openssl/hmac" 3 | 4 | describe OpenSSL::HMAC do 5 | [ 6 | {:dss, "46b4ec586117154dacd49d664e5d63fdc88efb51"}, 7 | {:dss1, "46b4ec586117154dacd49d664e5d63fdc88efb51"}, 8 | {:md4, "f3593b56f00b25c8af31d02ddef6d2d0"}, 9 | {:md5, "0c7a250281315ab863549f66cd8a3a53"}, 10 | {:sha, "df3c18b162b0c3b1884ba1b8eaf60559c41abc50"}, 11 | {:sha1, "46b4ec586117154dacd49d664e5d63fdc88efb51"}, 12 | {:sha224, "4c1f774863acb63b7f6e9daa9b5c543fa0d5eccf61e3ffc3698eacdd"}, 13 | {:sha256, "f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317"}, 14 | {:sha384, "3d10d391bee2364df2c55cf605759373e1b5a4ca9355d8f3fe42970471eca2e422a79271a0e857a69923839015877fc6"}, 15 | {:sha512, "114682914c5d017dfe59fdc804118b56a3a652a0b8870759cf9e792ed7426b08197076bf7d01640b1b0684df79e4b67e37485669e8ce98dbab60445f0db94fce"}, 16 | {:ripemd160, "20d23140503df606c91bda9293f1ad4a23afe509"}, 17 | ].each do |tuple| 18 | it "computes #{tuple[0]}" do 19 | OpenSSL::HMAC.hexdigest(tuple[0], "foo", "bar").should eq(tuple[1]) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/method_missing_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: method_missing" do 4 | it "does error in method_missing macro with virtual type" do 5 | assert_error %( 6 | abstract class Foo 7 | end 8 | 9 | class Bar < Foo 10 | macro method_missing(name, args, block) 11 | 2 12 | end 13 | end 14 | 15 | class Baz < Foo 16 | end 17 | 18 | foo = Baz.new || Bar.new 19 | foo.lala 20 | ), "undefined method 'lala' for Baz" 21 | end 22 | 23 | it "does error in method_missing if wrong number of args" do 24 | assert_error %( 25 | class Foo 26 | macro method_missing(name, args) 27 | end 28 | end 29 | ), "macro 'method_missing' expects 1 or 3 arguments: (call) or (name, args, block)" 30 | end 31 | 32 | it "does method missing for generic type" do 33 | assert_type(%( 34 | class Foo(T) 35 | macro method_missing(name, args, block) 36 | 1 37 | end 38 | end 39 | 40 | Foo(Int32).new.foo 41 | )) { int32 } 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /src/openssl/ssl/socket.cr: -------------------------------------------------------------------------------- 1 | class OpenSSL::SSL::Socket 2 | include IO 3 | 4 | def initialize(io, mode = :client, context = Context.default) 5 | @ssl = LibSSL.ssl_new(context) 6 | @bio = BIO.new(io) 7 | LibSSL.ssl_set_bio(@ssl, @bio, @bio) 8 | 9 | if mode == :client 10 | LibSSL.ssl_connect(@ssl) 11 | else 12 | LibSSL.ssl_accept(@ssl) 13 | end 14 | end 15 | 16 | def finalize 17 | LibSSL.ssl_free(@ssl) 18 | end 19 | 20 | def read(slice : Slice(UInt8)) 21 | count = slice.size 22 | return 0 if count == 0 23 | LibSSL.ssl_read(@ssl, slice.pointer(count), count) 24 | end 25 | 26 | def write(slice : Slice(UInt8)) 27 | count = slice.size 28 | LibSSL.ssl_write(@ssl, slice.pointer(count), count) 29 | nil 30 | end 31 | 32 | def close 33 | begin 34 | while LibSSL.ssl_shutdown(@ssl) == 0; end 35 | rescue IO::Error 36 | end 37 | end 38 | 39 | def self.open_client(io, context = Context.default) 40 | ssl_sock = new(io, :client, context) 41 | begin 42 | yield ssl_sock 43 | ensure 44 | ssl_sock.close 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /src/prelude.cr: -------------------------------------------------------------------------------- 1 | require "intrinsics" 2 | require "reflect" 3 | require "libc" 4 | require "macros" 5 | require "object" 6 | require "reference" 7 | require "exception" 8 | require "value" 9 | require "struct" 10 | require "proc" 11 | require "thread" 12 | require "gc" 13 | # require "gc/null" 14 | require "gc/boehm" 15 | require "class" 16 | require "comparable" 17 | require "enumerable" 18 | require "iterable" 19 | require "iterator" 20 | require "nil" 21 | require "bool" 22 | require "char" 23 | require "number" 24 | require "int" 25 | require "float" 26 | require "pointer" 27 | require "slice" 28 | require "range" 29 | require "char/reader" 30 | require "string" 31 | require "symbol" 32 | require "enum" 33 | require "static_array" 34 | require "array" 35 | require "hash" 36 | require "set" 37 | require "tuple" 38 | require "box" 39 | require "math/math" 40 | require "process" 41 | require "io" 42 | require "env" 43 | require "file" 44 | require "dir" 45 | require "time" 46 | require "random" 47 | require "regex" 48 | require "raise" 49 | require "errno" 50 | require "concurrent" 51 | require "signal" 52 | require "kernel" 53 | require "main" 54 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/templates.cr: -------------------------------------------------------------------------------- 1 | require "ecr/macros" 2 | 3 | module Crystal::Doc 4 | record TypeTemplate, type, types do 5 | ecr_file "#{__DIR__}/html/type.html" 6 | end 7 | 8 | record ListItemsTemplate, types, current_type do 9 | ecr_file "#{__DIR__}/html/list_items.html" 10 | end 11 | 12 | record MethodSummaryTemplate, title, methods do 13 | ecr_file "#{__DIR__}/html/method_summary.html" 14 | end 15 | 16 | record MethodDetailTemplate, title, methods do 17 | ecr_file "#{__DIR__}/html/method_detail.html" 18 | end 19 | 20 | record MethodsInheritedTemplate, type, ancestor, methods, label do 21 | ecr_file "#{__DIR__}/html/methods_inherited.html" 22 | end 23 | 24 | record OtherTypesTemplate, title, type, other_types do 25 | ecr_file "#{__DIR__}/html/other_types.html" 26 | end 27 | 28 | record MainTemplate, body, types, repository_name do 29 | ecr_file "#{__DIR__}/html/main.html" 30 | end 31 | 32 | struct JsTypeTemplate 33 | ecr_file "#{__DIR__}/html/js/doc.js" 34 | end 35 | 36 | struct StyleTemplate 37 | ecr_file "#{__DIR__}/html/css/style.css" 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/std/http/server/handlers/websocket_handler_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "http/server" 3 | 4 | describe HTTP::WebSocketHandler do 5 | it "returns not found if the request is not an websocket upgrade" do 6 | handler = HTTP::WebSocketHandler.new { } 7 | response = handler.call HTTP::Request.new("GET", "/") 8 | response.status_code.should eq(404) 9 | response.upgrade_handler.should be_nil 10 | end 11 | 12 | it "gives upgrade response for websocket upgrade request" do 13 | handler = HTTP::WebSocketHandler.new { } 14 | headers = HTTP::Headers{ 15 | "Upgrade": "websocket", 16 | "Connection": "Upgrade", 17 | "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", 18 | } 19 | request = HTTP::Request.new("GET", "/", headers) 20 | response = handler.call request 21 | response.status_code.should eq(101) 22 | response.headers["Upgrade"].should eq("websocket") 23 | response.headers["Connection"].should eq("Upgrade") 24 | response.headers["Sec-WebSocket-Accept"].should eq("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=") 25 | response.upgrade_handler.should_not be_nil 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/dependencies_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Crystal::Dependencies" do 4 | it "is empty" do 5 | deps = Dependencies.new 6 | deps.size.should eq(0) 7 | deps.to_a.should eq([] of ASTNode) 8 | end 9 | 10 | it "pushes one" do 11 | deps = Dependencies.new 12 | node = NilLiteral.new 13 | deps.push node 14 | deps.size.should eq(1) 15 | deps.to_a.map(&.object_id).should eq([node.object_id]) 16 | end 17 | 18 | it "pushes two" do 19 | deps = Dependencies.new 20 | node1 = NilLiteral.new 21 | node2 = NilLiteral.new 22 | deps.push node1 23 | deps.push node2 24 | deps.size.should eq(2) 25 | deps.to_a.map(&.object_id).should eq([node1.object_id, node2.object_id]) 26 | end 27 | 28 | it "pushes three" do 29 | deps = Dependencies.new 30 | node1 = NilLiteral.new 31 | node2 = NilLiteral.new 32 | node3 = NilLiteral.new 33 | deps.push node1 34 | deps.push node2 35 | deps.push node3 36 | deps.size.should eq(3) 37 | deps.to_a.map(&.object_id).should eq([node1.object_id, node2.object_id, node3.object_id]) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/std/bool_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "Bool" do 4 | describe "!" do 5 | assert { (!true).should be_false } 6 | assert { (!false).should be_true } 7 | end 8 | 9 | describe "|" do 10 | assert { (false | false).should be_false } 11 | assert { (false | true).should be_true } 12 | assert { (true | false).should be_true } 13 | assert { (true | true).should be_true } 14 | end 15 | 16 | describe "&" do 17 | assert { (false & false).should be_false } 18 | assert { (false & true).should be_false } 19 | assert { (true & false).should be_false } 20 | assert { (true & true).should be_true } 21 | end 22 | 23 | describe "^" do 24 | assert { (false ^ false).should be_false } 25 | assert { (false ^ true).should be_true } 26 | assert { (true ^ false).should be_true } 27 | assert { (true ^ true).should be_false } 28 | end 29 | 30 | describe "hash" do 31 | assert { true.hash.should eq(1) } 32 | assert { false.hash.should eq(0) } 33 | end 34 | 35 | describe "to_s" do 36 | assert { true.to_s.should eq("true") } 37 | assert { false.to_s.should eq("false") } 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/std/openssl/digest_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/openssl" 3 | 4 | describe OpenSSL::Digest do 5 | [ 6 | {"SHA1", "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"}, 7 | {"SHA256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"}, 8 | {"SHA512", "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"}, 9 | ].each do |tuple| 10 | it "should be able to calculate #{tuple[0]}" do 11 | digest = OpenSSL::Digest.new(tuple[0]) 12 | digest << "foo" 13 | digest.hexdigest.should eq(tuple[1]) 14 | end 15 | end 16 | 17 | it "raises a UnsupportedError if digest is unsupported" do 18 | expect_raises OpenSSL::Digest::UnsupportedError do 19 | OpenSSL::Digest.new("unsupported") 20 | end 21 | end 22 | 23 | it "returns the digest size" do 24 | OpenSSL::Digest.new("SHA1").digest_size.should eq 20 25 | OpenSSL::Digest.new("SHA256").digest_size.should eq 32 26 | end 27 | 28 | it "returns the block size" do 29 | OpenSSL::Digest.new("SHA1").block_size.should eq 64 30 | OpenSSL::Digest.new("SHA256").block_size.should eq 64 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /src/llvm/jit_compiler.cr: -------------------------------------------------------------------------------- 1 | class LLVM::JITCompiler 2 | def initialize(mod) 3 | # JIT compilers own an LLVM::Module, and when they are disposed the module is disposed, 4 | # so we must prevent the module from being dispose when the GC will want to free it. 5 | mod.take_ownership { raise "can't create two JIT compilers for the same module" } 6 | 7 | # if LibLLVM.create_jit_compiler_for_module(out @unwrap, mod, 3, out error) != 0 8 | if LibLLVM.create_mc_jit_compiler_for_module(out @unwrap, mod, nil, 0, out error) != 0 9 | raise LLVM.string_and_dispose(error) 10 | end 11 | end 12 | 13 | def run_function(func) 14 | ret = LibLLVM.run_function(self, func, 0, nil) 15 | GenericValue.new(ret) 16 | end 17 | 18 | def run_function(func, args : Array(LLVM::GenericValue)) 19 | ret = LibLLVM.run_function(self, func, args.size, (args.buffer as LibLLVM::GenericValueRef*)) 20 | GenericValue.new(ret) 21 | end 22 | 23 | def get_pointer_to_global(value) 24 | LibLLVM.get_pointer_to_global(self, value) 25 | end 26 | 27 | def to_unsafe 28 | @unwrap 29 | end 30 | 31 | def finalize 32 | LibLLVM.dispose_execution_engine(@unwrap) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/std/tempfile_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "tempfile" 3 | 4 | describe Tempfile do 5 | it "creates and writes" do 6 | tempfile = Tempfile.new "foo" 7 | tempfile.print "Hello!" 8 | tempfile.close 9 | 10 | File.exists?(tempfile.path).should be_true 11 | File.read(tempfile.path).should eq("Hello!") 12 | end 13 | 14 | it "creates and deletes" do 15 | tempfile = Tempfile.new "foo" 16 | tempfile.close 17 | tempfile.delete 18 | 19 | File.exists?(tempfile.path).should be_false 20 | end 21 | 22 | it "doesn't delete on open with block" do 23 | tempfile = Tempfile.open("foo") do |f| 24 | f.print "Hello!" 25 | end 26 | File.exists?(tempfile.path).should be_true 27 | end 28 | 29 | it "creates and writes with TMPDIR environment variable" do 30 | old_tmpdir = ENV["TMPDIR"]? 31 | ENV["TMPDIR"] = "/tmp" 32 | 33 | begin 34 | tempfile = Tempfile.new "foo" 35 | tempfile.print "Hello!" 36 | tempfile.close 37 | 38 | File.exists?(tempfile.path).should be_true 39 | File.read(tempfile.path).should eq("Hello!") 40 | ensure 41 | ENV["TMPDIR"] = old_tmpdir if old_tmpdir 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/readme.md.ecr: -------------------------------------------------------------------------------- 1 | # <%= config.name %> 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | <% if config.skeleton_type == "lib" %> 8 | Add this to your application's `shard.yml`: 9 | 10 | ```yaml 11 | dependencies: 12 | <%= config.name %>: 13 | github: <%= config.github_name %>/<%= config.name %> 14 | ``` 15 | <% else %> 16 | TODO: Write installation instructions here 17 | <% end %> 18 | 19 | ## Usage 20 | 21 | <% if config.skeleton_type == "lib" %> 22 | ```crystal 23 | require "<%= config.name %>" 24 | ``` 25 | <% end %> 26 | 27 | TODO: Write usage instructions here 28 | 29 | ## Development 30 | 31 | TODO: Write development instructions here 32 | 33 | ## Contributing 34 | 35 | 1. Fork it ( https://github.com/<%= config.github_name %>/<%= config.name %>/fork ) 36 | 2. Create your feature branch (git checkout -b my-new-feature) 37 | 3. Commit your changes (git commit -am 'Add some feature') 38 | 4. Push to the branch (git push origin my-new-feature) 39 | 5. Create a new Pull Request 40 | 41 | ## Contributors 42 | 43 | - [<%= config.github_name %>](https://github.com/<%= config.github_name %>) <%= config.author %> - creator, maintainer 44 | -------------------------------------------------------------------------------- /src/llvm/pass_manager_builder.cr: -------------------------------------------------------------------------------- 1 | class LLVM::PassManagerBuilder 2 | def initialize 3 | @unwrap = LibLLVM.pass_manager_builder_create 4 | end 5 | 6 | def opt_level=(level) 7 | LibLLVM.pass_manager_builder_set_opt_level self, level 8 | end 9 | 10 | def size_level=(level) 11 | LibLLVM.pass_manager_builder_set_size_level self, level 12 | end 13 | 14 | def disable_unroll_loops=(value) 15 | LibLLVM.pass_manager_builder_set_disable_unroll_loops self, value ? 1 : 0 16 | end 17 | 18 | def disable_simplify_lib_calls=(value) 19 | LibLLVM.pass_manager_builder_set_disable_simplify_lib_calls self, value ? 1 : 0 20 | end 21 | 22 | def use_inliner_with_threshold=(threshold) 23 | LibLLVM.pass_manager_builder_use_inliner_with_threshold self, threshold 24 | end 25 | 26 | def populate(pm : FunctionPassManager) 27 | LibLLVM.pass_manager_builder_populate_function_pass_manager self, pm 28 | end 29 | 30 | def populate(pm : ModulePassManager) 31 | LibLLVM.pass_manager_builder_populate_module_pass_manager self, pm 32 | end 33 | 34 | def to_unsafe 35 | @unwrap 36 | end 37 | 38 | def finalize 39 | LibLLVM.dispose_pass_manager_builder(@unwrap) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/license.ecr: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) <%= Time.now.year %> <%= config.author %> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /BACKERS.md: -------------------------------------------------------------------------------- 1 | # Bountysource Backers 2 | 3 | Thank you to everyone who backed our [Bountysource fundraiser](https://www.bountysource.com/teams/crystal-lang/fundraiser)! 4 | 5 | ### Your name and URL in BACKERS.md. 6 | 7 | - Adam Daniels, https://github.com/adam12 8 | - Bo Jeanes, http://bjeanes.com/ 9 | - Bruno Antunes, https://github.com/sardaukar 10 | - gottlike, https://github.com/gottlike 11 | - Hirofumi Wakasugi, https://github.com/5t111111 12 | - Jean-Baptiste Barth, http://jbbarth.com/ 13 | - jhp 14 | - Kris Leech, http://teamcoding.com/ 15 | - Luis Lavena, http://blog.mmediasys.com/ 16 | - Sb 17 | - Scott Fleckenstein, https://about.me/nullstyle 18 | - Serdar Dogruyol, http://www.serdardogruyol.com/ 19 | - Sergey Kucher, https://github.com/sergey-kucher 20 | - Simon George, http://www.sfcgeorge.co.uk/about 21 | - Yukihiro "Matz" Matsumoto, https://github.com/matz 22 | 23 | ### Your name in BACKERS.md. 24 | 25 | - Ashley Towns 26 | - Ben Miller 27 | - benoist 28 | - Dor Kalev 29 | - Hayashida Ryuichi 30 | - Jesse Doyle 31 | - Joakim Ekström 32 | - Jonne Haß 33 | - Joseph Method 34 | - Keiji Matsuzaki 35 | - marcpmichel 36 | - rhoeft 37 | - Ryan Worl 38 | - schaarw 39 | - Sergio Gil 40 | - Shannon Skipper 41 | - Sho Kusano 42 | -------------------------------------------------------------------------------- /src/xml/attributes.cr: -------------------------------------------------------------------------------- 1 | struct XML::Attributes 2 | include Enumerable(Node) 3 | 4 | def initialize(@node) 5 | end 6 | 7 | def empty? 8 | return true unless @node.element? 9 | 10 | props = self.props 11 | props.nil? 12 | end 13 | 14 | def [](index : Int) 15 | size = self.size 16 | 17 | index += size if index < 0 18 | 19 | unless 0 <= index < size 20 | raise IndexError.new 21 | end 22 | 23 | each_with_index do |node, i| 24 | return node if i == index 25 | end 26 | 27 | raise IndexError.new 28 | end 29 | 30 | def [](name : String) 31 | self[name]? || raise KeyError.new("Missing attribute: #{name}") 32 | end 33 | 34 | def []?(name : String) 35 | find { |node| node.name == name } 36 | end 37 | 38 | def each 39 | return unless @node.element? 40 | 41 | props = self.props 42 | until props.nil? 43 | yield Node.new(props) 44 | props = props.value.next 45 | end 46 | end 47 | 48 | def to_s(io) 49 | io << "[" 50 | join ", ", io, &.inspect(io) 51 | io << "]" 52 | end 53 | 54 | def inspect(io) 55 | to_s(io) 56 | end 57 | 58 | protected def props 59 | @node.to_unsafe.value.properties 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /src/openssl/hmac.cr: -------------------------------------------------------------------------------- 1 | require "./lib_crypto" 2 | 3 | class OpenSSL::HMAC 4 | def self.digest(algorithm : Symbol, key, data) 5 | evp = case algorithm 6 | when :dss then LibCrypto.evp_dss 7 | when :dss1 then LibCrypto.evp_dss1 8 | when :md4 then LibCrypto.evp_md4 9 | when :md5 then LibCrypto.evp_md5 10 | when :ripemd160 then LibCrypto.evp_ripemd160 11 | when :sha then LibCrypto.evp_sha 12 | when :sha1 then LibCrypto.evp_sha1 13 | when :sha224 then LibCrypto.evp_sha224 14 | when :sha256 then LibCrypto.evp_sha256 15 | when :sha384 then LibCrypto.evp_sha384 16 | when :sha512 then LibCrypto.evp_sha512 17 | else raise "Unsupported digest algorithm: #{algorithm}" 18 | end 19 | key_slice = key.to_slice 20 | data_slice = data.to_slice 21 | buffer = Slice(UInt8).new(128) 22 | LibCrypto.hmac(evp, key_slice, key_slice.size, data_slice, data_slice.size, buffer, out buffer_len) 23 | buffer[0, buffer_len.to_i] 24 | end 25 | 26 | def self.hexdigest(algorithm : Symbol, key, data) 27 | digest(algorithm, key, data).hexstring 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /samples/impl.cr: -------------------------------------------------------------------------------- 1 | class A 2 | property lorem 3 | 4 | def foo 5 | 1 6 | end 7 | end 8 | 9 | class B 10 | def foo 11 | 2 12 | end 13 | end 14 | 15 | def bar(o) 16 | while false 17 | o.foo 18 | end 19 | end 20 | 21 | def baz(o) 22 | o.foo 23 | end 24 | 25 | puts bar(A.new) 26 | puts bar(B.new) 27 | puts baz(A.new) 28 | 29 | A.new.lorem 30 | 31 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:16:8 32 | # 33 | # 2 implementations found 34 | # .../samples/impl.cr:3:3 35 | # .../samples/impl.cr:9:3 36 | 37 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:21:5 38 | # 39 | # 1 implementation found 40 | # .../samples/impl.cr:3:3 41 | 42 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:24:7 43 | # 44 | # 1 implementation found 45 | # .../samples/impl.cr:14:1 46 | 47 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:26:3 48 | # 49 | # 1 implementation found 50 | # .../src/kernel.cr:67:1 51 | 52 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:28:9 53 | # 54 | # 1 implementation found 55 | # .../samples/impl.cr:2:3 56 | # ~> macro property: .../src/object.cr:364:5 57 | # ~> macro getter: .../src/object.cr:207:7 58 | -------------------------------------------------------------------------------- /spec/std/openssl/cipher_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "openssl/cipher" 3 | 4 | describe OpenSSL::Cipher do 5 | it "encrypts/decrypts" do 6 | cipher = "aes-128-cbc" 7 | c1 = OpenSSL::Cipher.new(cipher) 8 | c2 = OpenSSL::Cipher.new(cipher) 9 | key = "\0" * 16 10 | iv = "\0" * 16 11 | data = "DATA" * 5 12 | ciphertext = File.read(File.join(__DIR__ + "/cipher_spec.ciphertext")) 13 | 14 | c1.name.should eq(c2.name) 15 | 16 | c1.encrypt 17 | c2.encrypt 18 | c1.key = c2.key = key 19 | c1.iv = c2.iv = iv 20 | 21 | s1 = MemoryIO.new 22 | s2 = MemoryIO.new 23 | s1.write(c1.update("DATA")) 24 | s1.write(c1.update("DATA" * 4)) 25 | s1.write(c1.final) 26 | s2.write(c2.update(data)) 27 | s2.write(c2.final) 28 | 29 | s1.to_slice.should eq(ciphertext.to_slice) 30 | s1.to_slice.should eq(s2.to_slice) 31 | 32 | c1.decrypt 33 | c2.decrypt 34 | c1.key = c2.key = key 35 | c1.iv = c2.iv = iv 36 | 37 | s3 = MemoryIO.new 38 | s4 = MemoryIO.new 39 | s3.write(c1.update(s1.to_slice)) 40 | s3.write(c1.final) 41 | 42 | s4.write(c2.update(s2.to_slice)) 43 | s4.write(c2.final) 44 | s3.to_s.should eq(data) 45 | s3.to_slice.should eq(s4.to_slice) 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/print_types_visitor.cr: -------------------------------------------------------------------------------- 1 | require "set" 2 | require "../syntax/ast" 3 | 4 | module Crystal 5 | def self.print_types(node) 6 | node.accept PrintTypesVisitor.new 7 | end 8 | 9 | class PrintTypesVisitor < Visitor 10 | def initialize 11 | @vars = Set(String).new 12 | end 13 | 14 | def visit(node) 15 | true 16 | end 17 | 18 | def visit(node : ClassDef) 19 | false 20 | end 21 | 22 | def visit(node : Def) 23 | false 24 | end 25 | 26 | def visit(node : FunDef) 27 | false 28 | end 29 | 30 | def visit(node : Macro) 31 | false 32 | end 33 | 34 | def visit(node : Assign) 35 | !node.target.is_a?(Path) 36 | end 37 | 38 | def visit(node : Var) 39 | output_name node 40 | end 41 | 42 | def visit(node : Global) 43 | output_name node 44 | end 45 | 46 | def visit(node : DeclareVar) 47 | var = node.var 48 | if var.is_a?(Var) 49 | output_name var 50 | end 51 | end 52 | 53 | def output_name(node) 54 | if !node.name.starts_with?('#') && !@vars.includes?(node.name) 55 | puts "#{node.name} : #{node.type?}" 56 | @vars.add node.name 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all spec crystal doc clean 2 | 3 | -include Makefile.local # for optional local options e.g. threads 4 | 5 | O := .build 6 | SOURCES := $(shell find src -name '*.cr') 7 | SPEC_SOURCES := $(shell find spec -name '*.cr') 8 | FLAGS := $(if $(release),--release )$(if $(stats),--stats )$(if $(threads),--threads $(threads) ) 9 | EXPORTS := $(if $(release),,CRYSTAL_CONFIG_PATH=`pwd`/src) 10 | SHELL = /bin/bash 11 | LLVM_CONFIG := $(shell command -v llvm-config-3.6 llvm-config-3.5 llvm-config | head -n 1) 12 | LLVM_EXT_DIR = src/llvm/ext 13 | LLVM_EXT_OBJ = $(LLVM_EXT_DIR)/llvm_ext.o 14 | 15 | all: crystal 16 | spec: all_spec 17 | $(O)/all_spec 18 | doc: 19 | $(BUILD_PATH) ./bin/crystal doc docs/main.cr 20 | 21 | crystal: $(O)/crystal 22 | all_spec: $(O)/all_spec 23 | 24 | llvm_ext: $(LLVM_EXT_OBJ) 25 | 26 | $(O)/all_spec: $(LLVM_EXT_OBJ) $(SOURCES) $(SPEC_SOURCES) 27 | @mkdir -p $(O) 28 | $(BUILD_PATH) ./bin/crystal build $(FLAGS) -o $@ spec/all_spec.cr 29 | 30 | $(O)/crystal: $(LLVM_EXT_OBJ) $(SOURCES) 31 | @mkdir -p $(O) 32 | $(BUILD_PATH) $(EXPORTS) ./bin/crystal build $(FLAGS) -o $@ src/compiler/crystal.cr 33 | 34 | $(LLVM_EXT_OBJ): $(LLVM_EXT_DIR)/llvm_ext.cc 35 | $(CXX) -c -o $@ $< `$(LLVM_CONFIG) --cxxflags` 36 | 37 | clean: 38 | rm -rf $(O) 39 | rm -rf ./doc 40 | rm -rf $(LLVM_EXT_OBJ) 41 | -------------------------------------------------------------------------------- /spec/std/http/server_spec.cr: -------------------------------------------------------------------------------- 1 | require "http/server" 2 | 3 | module HTTP 4 | typeof(begin 5 | # Initialize with custom host 6 | server = Server.new("0.0.0.0", 0) { |req| HTTP::Response.ok("text/plain", "OK") } 7 | server.listen 8 | server.listen_fork(workers: 2) 9 | server.close 10 | 11 | server = Server.new("0.0.0.0", 0, [ 12 | ErrorHandler.new, 13 | LogHandler.new, 14 | DeflateHandler.new, 15 | StaticFileHandler.new("."), 16 | ] 17 | ) 18 | server.listen 19 | server.close 20 | 21 | server = Server.new("0.0.0.0", 0, [StaticFileHandler.new(".")]) { |req| HTTP::Response.ok("text/plain", "OK") } 22 | server.listen 23 | server.close 24 | 25 | # Initialize with default host 26 | server = Server.new(0) { |req| HTTP::Response.ok("text/plain", "OK") } 27 | server.listen 28 | server.listen_fork(workers: 2) 29 | server.close 30 | 31 | server = Server.new(0, [ 32 | ErrorHandler.new, 33 | LogHandler.new, 34 | DeflateHandler.new, 35 | StaticFileHandler.new("."), 36 | ] 37 | ) 38 | server.listen 39 | server.close 40 | 41 | server = Server.new(0, [StaticFileHandler.new(".")]) { |req| HTTP::Response.ok("text/plain", "OK") } 42 | server.listen 43 | server.close 44 | end) 45 | end 46 | -------------------------------------------------------------------------------- /src/process/status.cr: -------------------------------------------------------------------------------- 1 | # The status of a terminated process. 2 | class Process::Status 3 | getter exit_status 4 | 5 | def initialize(@exit_status) 6 | end 7 | 8 | # Returns `true` if the process was terminated by a signal. 9 | def signal_exit? 10 | # define __WIFSIGNALED(status) (((signed char) (((status) & 0x7f) + 1) >> 1) > 0) 11 | ((LibC::SChar.new(@exit_status & 0x7f) + 1) >> 1) > 0 12 | end 13 | 14 | # Returns `true` if the process terminated normally. 15 | def normal_exit? 16 | # define __WIFEXITED(status) (__WTERMSIG(status) == 0) 17 | signal_code == 0 18 | end 19 | 20 | # If `signal_exit?` is `true`, returns the *Signal* the process 21 | # received and didn't handle. Will raise if `signal_exit?` is `false`. 22 | def exit_signal 23 | Signal.from_value(signal_code) 24 | end 25 | 26 | # If `normal_exit?` is `true`, returns the exit code of the process. 27 | def exit_code 28 | # define __WEXITSTATUS(status) (((status) & 0xff00) >> 8) 29 | (@exit_status & 0xff00) >> 8 30 | end 31 | 32 | # Returns `true` if the process exited normally with an exit code of 0. 33 | def success? 34 | normal_exit? && exit_code == 0 35 | end 36 | 37 | private def signal_code 38 | # define __WTERMSIG(status) ((status) & 0x7f) 39 | @exit_status & 0x7f 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/std/thread_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "Thread" do 4 | it "allows passing an argumentless fun to execute" do 5 | a = 0 6 | thread = Thread.new { a = 1; 10 } 7 | thread.join.should eq(10) 8 | a.should eq(1) 9 | end 10 | 11 | it "allows passing a fun with an argument to execute" do 12 | a = 0 13 | thread = Thread.new(3) { |i| a += i; 20 } 14 | thread.join.should eq(20) 15 | a.should eq(3) 16 | end 17 | 18 | it "raises inside thread and gets it on join" do 19 | thread = Thread.new { raise "OH NO" } 20 | expect_raises Exception, "OH NO" do 21 | thread.join 22 | end 23 | end 24 | 25 | it "gets a non-nilable value from join" do 26 | thread = Thread.new { 1 } 27 | value = thread.join 28 | (value + 2).should eq(3) 29 | end 30 | end 31 | 32 | describe "ConditionVariable" do 33 | pending "waits and send signal" do 34 | a = 0 35 | cv1 = ConditionVariable.new 36 | cv2 = ConditionVariable.new 37 | m = Mutex.new 38 | 39 | thread = Thread.new do 40 | 3.times do 41 | m.synchronize { cv1.wait(m); a += 1; cv2.signal } 42 | end 43 | end 44 | 45 | a.should eq(0) 46 | 3.times do |i| 47 | m.synchronize { cv1.signal; cv2.wait(m) } 48 | a.should eq(i + 1) 49 | end 50 | 51 | thread.join 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/c_enum_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: c enum" do 4 | it "types enum value" do 5 | assert_type("lib LibFoo; enum Bar; X, Y, Z = 10, W; end; end; LibFoo::Bar::X") { types["LibFoo"].types["Bar"] } 6 | end 7 | 8 | it "allows using an enum as a type in a fun" do 9 | assert_type(" 10 | lib LibC 11 | enum Foo 12 | A 13 | end 14 | fun my_mega_function(y : Foo) : Foo 15 | end 16 | 17 | LibC.my_mega_function(LibC::Foo::A) 18 | ") { types["LibC"].types["Foo"] } 19 | end 20 | 21 | it "allows using an enum as a type in a struct" do 22 | assert_type(" 23 | lib LibC 24 | enum Foo 25 | A 26 | end 27 | struct Bar 28 | x : Foo 29 | end 30 | end 31 | 32 | f = LibC::Bar.new 33 | f.x = LibC::Foo::A 34 | f.x 35 | ") { types["LibC"].types["Foo"] } 36 | end 37 | 38 | it "types enum value with base type" do 39 | assert_type("lib LibFoo; enum Bar : Int16; X; end; end; LibFoo::Bar::X") { types["LibFoo"].types["Bar"] } 40 | end 41 | 42 | it "errors if enum base type is not an integer" do 43 | assert_error "lib LibFoo; enum Bar : Float32; X; end; end; LibFoo::Bar::X", 44 | "enum base type must be an integer type" 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /src/compiler/crystal/syntax/location.cr: -------------------------------------------------------------------------------- 1 | require "../../../partial_comparable" 2 | 3 | module Crystal 4 | class Location 5 | include PartialComparable(self) 6 | 7 | getter line_number 8 | getter column_number 9 | getter filename 10 | 11 | def initialize(@line_number, @column_number, @filename) 12 | end 13 | 14 | def dirname 15 | filename = @filename 16 | if filename.is_a?(String) 17 | File.dirname(filename) 18 | else 19 | nil 20 | end 21 | end 22 | 23 | def inspect(io) 24 | to_s(io) 25 | end 26 | 27 | def original_filename 28 | case filename = @filename 29 | when String 30 | filename 31 | when VirtualFile 32 | filename.expanded_location.try &.original_filename 33 | else 34 | nil 35 | end 36 | end 37 | 38 | def inspect 39 | to_s 40 | end 41 | 42 | def to_s(io) 43 | io << filename << ":" << line_number << ":" << column_number 44 | end 45 | 46 | def <=>(other) 47 | self_file = @filename 48 | other_file = other.filename 49 | if self_file.is_a?(String) && other_file.is_a?(String) && self_file == other_file 50 | {@line_number, @column_number} <=> {other.line_number, other.column_number} 51 | else 52 | nil 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /src/xml/xml.cr: -------------------------------------------------------------------------------- 1 | module XML 2 | def self.parse(string : String, options = ParserOptions.default : ParserOptions) 3 | from_ptr LibXML.xmlReadMemory(string, string.bytesize, nil, nil, options) 4 | end 5 | 6 | def self.parse(io : IO, options = ParserOptions.default : ParserOptions) 7 | from_ptr LibXML.xmlReadIO( 8 | ->(ctx, buffer, len) { 9 | LibC::Int.new(Box(IO).unbox(ctx).read Slice.new(buffer, len)) 10 | }, 11 | ->(ctx) { 0 }, 12 | Box(IO).box(io), 13 | nil, 14 | nil, 15 | options, 16 | ) 17 | end 18 | 19 | def self.parse_html(string : String, options = HTMLParserOptions.default : HTMLParserOptions) 20 | from_ptr LibXML.htmlReadMemory(string, string.bytesize, nil, nil, options) 21 | end 22 | 23 | def self.parse_html(io : IO, options = HTMLParserOptions.default : HTMLParserOptions) 24 | from_ptr LibXML.htmlReadIO( 25 | ->(ctx, buffer, len) { 26 | LibC::Int.new(Box(IO).unbox(ctx).read Slice.new(buffer, len)) 27 | }, 28 | ->(ctx) { 0 }, 29 | Box(IO).box(io), 30 | nil, 31 | nil, 32 | options, 33 | ) 34 | end 35 | 36 | protected def self.from_ptr(doc : LibXML::DocPtr) 37 | raise Error.new(LibXML.xmlGetLastError) unless doc 38 | 39 | node = Node.new(doc) 40 | XML::Error.set_errors(node) 41 | node 42 | end 43 | end 44 | 45 | require "./*" 46 | -------------------------------------------------------------------------------- /spec/std/crypto/bcrypt/password_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "crypto/bcrypt/password" 3 | 4 | describe "Crypto::Bcrypt::Password" do 5 | describe "new" do 6 | password = Crypto::Bcrypt::Password.new("$2a$08$K8y0i4Wyqyei3SiGHLEd.OweXJt7sno2HdPVrMvVf06kGgAZvPkga") 7 | 8 | it "parses version" do 9 | password.version.should eq("2a") 10 | end 11 | 12 | it "parses cost" do 13 | password.cost.should eq(8) 14 | end 15 | 16 | it "parses salt" do 17 | password.salt.should eq("K8y0i4Wyqyei3SiGHLEd.O") 18 | end 19 | 20 | it "parses digest" do 21 | password.digest.should eq("weXJt7sno2HdPVrMvVf06kGgAZvPkga") 22 | end 23 | end 24 | 25 | describe "create" do 26 | password = Crypto::Bcrypt::Password.create("super secret", 5) 27 | 28 | it "uses cost" do 29 | password.cost.should eq(5) 30 | end 31 | 32 | it "generates salt" do 33 | password.salt.should_not be_nil 34 | end 35 | 36 | it "generates digest" do 37 | password.digest.should_not be_nil 38 | end 39 | end 40 | 41 | describe "==" do 42 | password = Crypto::Bcrypt::Password.create("secret", 4) 43 | 44 | it "verifies password is incorrect" do 45 | (password == "wrong").should be_false 46 | end 47 | 48 | it "verifies password is correct" do 49 | (password == "secret").should be_true 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /src/llvm/abi.cr: -------------------------------------------------------------------------------- 1 | # Based on https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/cabi.rs 2 | abstract class LLVM::ABI 3 | getter target_data 4 | getter is_osx 5 | getter is_windows 6 | 7 | def initialize(target_machine : TargetMachine) 8 | @target_data = target_machine.data_layout 9 | triple = target_machine.triple 10 | @is_osx = !!(triple =~ /apple/) 11 | @is_windows = !!(triple =~ /windows/) 12 | end 13 | 14 | abstract def abi_info(atys : Array(Type), rty : Type, ret_def : Bool) 15 | abstract def size(type : Type) 16 | abstract def align(type : Type) 17 | 18 | enum ArgKind 19 | Direct 20 | Indirect 21 | Ignore 22 | end 23 | 24 | struct ArgType 25 | getter kind 26 | getter type 27 | getter cast 28 | getter pad 29 | getter attr 30 | 31 | def self.direct(type, cast = nil, pad = nil, attr = nil) 32 | new ArgKind::Direct, type, cast, pad, attr 33 | end 34 | 35 | def self.indirect(type, attr) 36 | new ArgKind::Indirect, type, attr: attr 37 | end 38 | 39 | def self.ignore(type) 40 | new ArgKind::Ignore, type 41 | end 42 | 43 | def initialize(@kind, @type, @cast = nil, @pad = nil, @attr = nil) 44 | end 45 | end 46 | 47 | class FunctionType 48 | getter arg_types 49 | getter return_type 50 | 51 | def initialize(@arg_types, @return_type) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /src/llvm/target.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::Target 2 | def self.each 3 | target = LibLLVM.get_first_target 4 | while target 5 | yield Target.new target 6 | target = LibLLVM.get_next_target target 7 | end 8 | end 9 | 10 | def self.first 11 | Target.new LibLLVM.get_first_target 12 | end 13 | 14 | def self.from_triple(triple) 15 | return_code = LibLLVM.get_target_from_triple triple, out target, out error 16 | raise LLVM.string_and_dispose(error) unless return_code == 0 17 | new target 18 | end 19 | 20 | def initialize(@unwrap) 21 | end 22 | 23 | def name 24 | String.new LibLLVM.get_target_name(self) 25 | end 26 | 27 | def description 28 | String.new LibLLVM.get_target_description(self) 29 | end 30 | 31 | def create_target_machine(triple, cpu = "", features = "", 32 | opt_level = LLVM::CodeGenOptLevel::Default, 33 | reloc = LLVM::RelocMode::PIC, 34 | code_model = LLVM::CodeModel::Default) 35 | target_machine = LibLLVM.create_target_machine(self, triple, cpu, features, opt_level, reloc, code_model) 36 | target_machine ? TargetMachine.new(target_machine) : raise "Couldn't create target machine" 37 | end 38 | 39 | def to_s(io) 40 | io << name 41 | io << " - " 42 | io << description 43 | end 44 | 45 | def to_unsafe 46 | @unwrap 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/std/levenshtein_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "levenshtein" 3 | 4 | describe "levenshtein" do 5 | assert { Levenshtein.distance("algorithm", "altruistic").should eq(6) } 6 | assert { Levenshtein.distance("1638452297", "444488444").should eq(9) } 7 | assert { Levenshtein.distance("", "").should eq(0) } 8 | assert { Levenshtein.distance("", "a").should eq(1) } 9 | assert { Levenshtein.distance("aaapppp", "").should eq(7) } 10 | assert { Levenshtein.distance("frog", "fog").should eq(1) } 11 | assert { Levenshtein.distance("fly", "ant").should eq(3) } 12 | assert { Levenshtein.distance("elephant", "hippo").should eq(7) } 13 | assert { Levenshtein.distance("hippo", "elephant").should eq(7) } 14 | assert { Levenshtein.distance("hippo", "zzzzzzzz").should eq(8) } 15 | assert { Levenshtein.distance("hello", "hallo").should eq(1) } 16 | assert { Levenshtein.distance("こんにちは", "こんちは").should eq(1) } 17 | 18 | it "finds with finder" do 19 | finder = Levenshtein::Finder.new "hallo" 20 | finder.test "hay" 21 | finder.test "hall" 22 | finder.test "hallo world" 23 | finder.best_match.should eq("hall") 24 | end 25 | 26 | it "finds with finder and other values" do 27 | finder = Levenshtein::Finder.new "hallo" 28 | finder.test "hay", "HAY" 29 | finder.test "hall", "HALL" 30 | finder.test "hallo world", "HALLO WORLD" 31 | finder.best_match.should eq("HALL") 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /src/compiler/crystal/semantic/flags.cr: -------------------------------------------------------------------------------- 1 | class Crystal::Program 2 | def flags 3 | @flags ||= parse_flags(`uname -m -s`) 4 | end 5 | 6 | def flags=(flags) 7 | @flags = parse_flags(flags) 8 | end 9 | 10 | def has_flag?(name) 11 | flags.includes?(name) 12 | end 13 | 14 | def eval_flags(node) 15 | evaluator = FlagsEvaluator.new(self) 16 | node.accept evaluator 17 | evaluator.value 18 | end 19 | 20 | private def parse_flags(flags_name) 21 | flags_name.split.map(&.downcase).to_set 22 | end 23 | 24 | class FlagsEvaluator < Visitor 25 | getter value 26 | 27 | def initialize(@program) 28 | @value = false 29 | end 30 | 31 | def visit(node : Var) 32 | @value = @program.has_flag?(node.name) 33 | end 34 | 35 | def visit(node : Not) 36 | node.exp.accept self 37 | @value = !@value 38 | false 39 | end 40 | 41 | def visit(node : And) 42 | node.left.accept self 43 | left_value = @value 44 | node.right.accept self 45 | @value = left_value && @value 46 | false 47 | end 48 | 49 | def visit(node : Or) 50 | node.left.accept self 51 | left_value = @value 52 | node.right.accept self 53 | @value = left_value || @value 54 | false 55 | end 56 | 57 | def visit(node : ASTNode) 58 | raise "Bug: shouldn't visit #{node} in FlagsEvaluator" 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /spec/std/thread/condition_variable_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe ConditionVariable do 4 | it "signals" do 5 | mutex = Mutex.new 6 | cond = ConditionVariable.new 7 | pcond = ConditionVariable.new 8 | waiting = 0 9 | signaled = 0 10 | 11 | threads = 3.times.map do 12 | Thread.new do 13 | mutex.synchronize do 14 | waiting += 1 15 | pcond.signal 16 | cond.wait mutex 17 | end 18 | end 19 | end.to_a 20 | 21 | while signaled < 3 22 | mutex.synchronize do 23 | if waiting > 0 24 | waiting -= 1 25 | signaled += 1 26 | cond.signal 27 | end 28 | end 29 | end 30 | threads.map &.join 31 | end 32 | 33 | it "broadcasts" do 34 | mutex = Mutex.new 35 | cond = ConditionVariable.new 36 | pcond = ConditionVariable.new 37 | waiting = 0 38 | signaled = false 39 | 40 | threads = 3.times.map do 41 | Thread.new do 42 | mutex.synchronize do 43 | waiting += 1 44 | pcond.signal 45 | cond.wait mutex 46 | end 47 | end 48 | end.to_a 49 | 50 | until signaled 51 | mutex.synchronize do 52 | if waiting >= 3 53 | cond.broadcast 54 | signaled = true 55 | else 56 | pcond.wait mutex 57 | end 58 | end 59 | end 60 | 61 | threads.map &.join 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /samples/wordcount.cr: -------------------------------------------------------------------------------- 1 | # Ported from http://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs-rust.html 2 | 3 | require "option_parser" 4 | 5 | def do_work(in_filenames, output_filename, ignore_case) 6 | if in_filenames.empty? 7 | in_files = [STDIN] 8 | else 9 | in_files = in_filenames.map { |name| File.open(name, "r") } 10 | end 11 | 12 | if output_filename 13 | out_file = File.open(output_filename, "w") 14 | else 15 | out_file = STDOUT 16 | end 17 | 18 | counts = Hash(String, Int32).new(0) 19 | 20 | in_files.each do |in_file| 21 | in_file.each_line do |line| 22 | line = line.downcase if ignore_case 23 | line.scan(/\w+/) do |match| 24 | counts[match[0]] += 1 25 | end 26 | end 27 | end 28 | 29 | entries = counts.to_a.sort_by! &.[0] 30 | entries.each do |entry| 31 | word, count = entry 32 | out_file.puts "#{count}\t#{word}" 33 | end 34 | end 35 | 36 | output_filename = nil 37 | ignore_case = false 38 | 39 | OptionParser.parse! do |opts| 40 | opts.banner = "Usage: wordcount [OPTIONS] [FILES]" 41 | opts.on("-o NAME", "set output filename") do |filename| 42 | output_filename = filename 43 | end 44 | opts.on("-i", "--ignore-case", "ignore case") do 45 | ignore_case = true 46 | end 47 | opts.on("-h", "--help", "print this help menu") do 48 | puts opts 49 | end 50 | end 51 | 52 | in_filenames = ARGV 53 | 54 | do_work ARGV, output_filename, ignore_case 55 | -------------------------------------------------------------------------------- /src/spec/formatter.cr: -------------------------------------------------------------------------------- 1 | module Spec 2 | # :nodoc: 3 | abstract class Formatter 4 | def push(context) 5 | end 6 | 7 | def pop 8 | end 9 | 10 | def before_example(description) 11 | end 12 | 13 | def report(result) 14 | end 15 | 16 | def finish 17 | end 18 | end 19 | 20 | # :nodoc: 21 | class DotFormatter < Formatter 22 | def report(result) 23 | print Spec.color(LETTERS[result.kind], result.kind) 24 | end 25 | 26 | def finish 27 | puts 28 | end 29 | end 30 | 31 | # :nodoc: 32 | class VerboseFormatter < Formatter 33 | def initialize 34 | @ident = 0 35 | @last_description = "" 36 | end 37 | 38 | def push(context) 39 | print_ident 40 | puts context.description 41 | @ident += 1 42 | end 43 | 44 | def pop 45 | @ident -= 1 46 | end 47 | 48 | def print_ident 49 | @ident.times { print " " } 50 | end 51 | 52 | def before_example(description) 53 | print_ident 54 | print description 55 | @last_description = description 56 | end 57 | 58 | def report(result) 59 | print '\r' 60 | print_ident 61 | puts Spec.color(@last_description, result.kind) 62 | end 63 | end 64 | 65 | @@formatter = DotFormatter.new 66 | 67 | # :nodoc: 68 | def self.formatter=(@@formatter) 69 | end 70 | 71 | # :nodoc: 72 | def self.formatter 73 | @@formatter 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/std/random_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "Random" do 4 | it "limited number" do 5 | rand(1).should eq(0) 6 | 7 | x = rand(2) 8 | x.should be >= 0 9 | x.should be < 2 10 | end 11 | 12 | it "float number" do 13 | x = rand 14 | x.should be > 0 15 | x.should be < 1 16 | end 17 | 18 | it "raises on invalid number" do 19 | expect_raises ArgumentError, "incorrect rand value: 0" do 20 | rand(0) 21 | end 22 | end 23 | 24 | it "does with inclusive range" do 25 | rand(1..1).should eq(1) 26 | x = rand(1..3) 27 | x.should be >= 1 28 | x.should be <= 3 29 | end 30 | 31 | it "does with exclusive range" do 32 | rand(1...2).should eq(1) 33 | x = rand(1...4) 34 | x.should be >= 1 35 | x.should be < 4 36 | end 37 | 38 | it "raises on invalid range" do 39 | expect_raises ArgumentError, "incorrect rand value: 1...1" do 40 | rand(1...1) 41 | end 42 | end 43 | 44 | it "allows creating a new default random" do 45 | rand = Random.new 46 | value = rand.rand 47 | (0 <= value < 1).should be_true 48 | end 49 | 50 | it "allows creating a new default random with a seed" do 51 | rand = Random.new(1234) 52 | value1 = rand.rand 53 | 54 | rand = Random.new(1234) 55 | value2 = rand.rand 56 | 57 | value1.should eq(value2) 58 | end 59 | 60 | it "gets a random bool" do 61 | Random::DEFAULT.next_bool.should be_a(Bool) 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/macro.cr: -------------------------------------------------------------------------------- 1 | require "html" 2 | require "uri" 3 | require "./item" 4 | 5 | class Crystal::Doc::Macro 6 | include Item 7 | 8 | getter type 9 | getter :macro 10 | 11 | def initialize(@generator, @type, @macro) 12 | end 13 | 14 | def name 15 | @macro.name 16 | end 17 | 18 | def args 19 | @macro.args 20 | end 21 | 22 | def doc 23 | @macro.doc 24 | end 25 | 26 | def source_link 27 | @generator.source_link(@macro) 28 | end 29 | 30 | def id 31 | String.build do |io| 32 | io << to_s.gsub(' ', "") 33 | io << "-macro" 34 | end 35 | end 36 | 37 | def html_id 38 | HTML.escape(id) 39 | end 40 | 41 | def anchor 42 | "#" + URI.escape(id) 43 | end 44 | 45 | def prefix 46 | "" 47 | end 48 | 49 | def abstract? 50 | false 51 | end 52 | 53 | def kind 54 | "macro " 55 | end 56 | 57 | def to_s(io) 58 | io << name 59 | args_to_s io 60 | end 61 | 62 | def args_to_s 63 | String.build { |io| args_to_s io } 64 | end 65 | 66 | def args_to_s(io) 67 | return if @macro.args.empty? 68 | 69 | io << '(' 70 | @macro.args.each_with_index do |arg, i| 71 | io << ", " if i > 0 72 | io << '*' if @macro.splat_index == i 73 | io << arg 74 | end 75 | io << ')' 76 | end 77 | 78 | def args_to_html 79 | args_to_s 80 | end 81 | 82 | def must_be_included? 83 | @generator.must_include? @macro 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /src/openssl/lib_ssl.cr: -------------------------------------------------------------------------------- 1 | require "./lib_crypto" 2 | 3 | @[Link("ssl")] 4 | lib LibSSL 5 | alias Int = LibC::Int 6 | 7 | type SSLMethod = Void* 8 | type SSLContext = Void* 9 | type SSL = Void* 10 | 11 | enum SSLFileType 12 | PEM = 1 13 | ASN1 = 2 14 | end 15 | 16 | fun ssl_load_error_strings = SSL_load_error_strings 17 | fun ssl_library_init = SSL_library_init 18 | fun sslv23_method = SSLv23_method : SSLMethod 19 | fun ssl_ctx_new = SSL_CTX_new(method : SSLMethod) : SSLContext 20 | fun ssl_ctx_free = SSL_CTX_free(context : SSLContext) 21 | 22 | @[Raises] 23 | fun ssl_new = SSL_new(context : SSLContext) : SSL 24 | 25 | @[Raises] 26 | fun ssl_connect = SSL_connect(handle : SSL) : Int 27 | 28 | @[Raises] 29 | fun ssl_accept = SSL_accept(handle : SSL) : Int 30 | 31 | @[Raises] 32 | fun ssl_write = SSL_write(handle : SSL, text : UInt8*, length : Int) : Int 33 | 34 | @[Raises] 35 | fun ssl_read = SSL_read(handle : SSL, buffer : UInt8*, read_size : Int) : Int 36 | 37 | @[Raises] 38 | fun ssl_shutdown = SSL_shutdown(handle : SSL) : Int 39 | 40 | fun ssl_free = SSL_free(handle : SSL) 41 | fun ssl_ctx_use_certificate_chain_file = SSL_CTX_use_certificate_chain_file(ctx : SSLContext, file : UInt8*) : Int 42 | fun ssl_ctx_use_privatekey_file = SSL_CTX_use_PrivateKey_file(ctx : SSLContext, file : UInt8*, filetype : SSLFileType) : Int 43 | fun ssl_set_bio = SSL_set_bio(handle : SSL, rbio : LibCrypto::Bio*, wbio : LibCrypto::Bio*) 44 | end 45 | -------------------------------------------------------------------------------- /src/http/server/handlers/deflate_handler.cr: -------------------------------------------------------------------------------- 1 | require "zlib" 2 | 3 | class HTTP::DeflateHandler < HTTP::Handler 4 | DEFAULT_DEFLATE_TYPES = %w(text/html text/plain text/xml text/css text/javascript application/javascript application/json) 5 | 6 | property deflate_types 7 | 8 | def initialize(@deflate_types = DEFAULT_DEFLATE_TYPES) 9 | end 10 | 11 | def call(request) 12 | response = call_next(request) 13 | 14 | if should_deflate?(request, response) 15 | body_io = if response.body? 16 | MemoryIO.new(response.body) 17 | else 18 | response.body_io 19 | end 20 | 21 | deflate_io = Zlib::Deflate.new(body_io) 22 | 23 | headers = response.headers.dup 24 | headers.delete "Content-length" 25 | headers["Content-Encoding"] = "deflate" 26 | 27 | response = Response.new(response.status_code, nil, headers, response.status_message, response.version, deflate_io) 28 | end 29 | 30 | response 31 | end 32 | 33 | private def should_deflate?(request, response) 34 | return false unless HTTP::Response.mandatory_body?(response.status_code) 35 | return false if response.headers["Cache-Control"]? =~ /\bno-transform\b/ 36 | 37 | accept_encoding = request.headers["Accept-encoding"]? 38 | content_type = response.content_type 39 | accept_encoding && accept_encoding =~ /deflate/ && response.version == "HTTP/1.1" && content_type && deflate_types.includes?(content_type) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/std/crypto/subtle_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "crypto/subtle" 3 | 4 | describe "Subtle" do 5 | it "compares constant times" do 6 | data = [ 7 | {"a" => Slice.new(1, 0x11), "b" => Slice.new(1, 0x11), "result" => 1}, 8 | {"a" => Slice.new(1, 0x12), "b" => Slice.new(1, 0x11), "result" => 0}, 9 | {"a" => Slice.new(1, 0x11), "b" => Slice.new(2) { |i| 0x11 + i }, "result" => 0}, 10 | {"a" => Slice.new(2) { |i| 0x11 + i }, "b" => Slice.new(1, 0x11), "result" => 0}, 11 | ] 12 | 13 | data.each do |test| 14 | Crypto::Subtle.constant_time_compare(test["a"] as Slice(Int32), test["b"] as Slice(Int32)).should eq(test["result"]) 15 | end 16 | end 17 | 18 | it "compares constant time bytes on equality" do 19 | data = [ 20 | {"a" => 0x00_u8, "b" => 0x00_u8, "result" => 1}, 21 | {"a" => 0x00_u8, "b" => 0x01_u8, "result" => 0}, 22 | {"a" => 0x01_u8, "b" => 0x00_u8, "result" => 0}, 23 | {"a" => 0xff_u8, "b" => 0xff_u8, "result" => 1}, 24 | {"a" => 0xff_u8, "b" => 0xfe_u8, "result" => 0}, 25 | ] 26 | 27 | data.each do |test| 28 | Crypto::Subtle.constant_time_byte_eq(test["a"], test["b"]).should eq(test["result"]) 29 | end 30 | end 31 | 32 | it "compares constant time bytes bug" do 33 | h1 = "$2a$05$LEC1XBXgXECzKUO2LBDhKOa9lH9zigNKnksVaDwViFNgPU4WkrD53J" 34 | h2 = "$2a$05$LEC1XBXgXECzKUO2LBDhKOaHlSGFuDDwMuVg6gOzdxQ0xN4rFOwMUn" 35 | Crypto::Subtle.constant_time_compare(h1.to_slice, h2.to_slice).should eq(0) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /src/llvm/target_machine.cr: -------------------------------------------------------------------------------- 1 | class LLVM::TargetMachine 2 | def initialize(@unwrap) 3 | end 4 | 5 | def target 6 | target = LibLLVM.get_target_machine_target(self) 7 | target ? Target.new(target) : raise "Couldn't get target" 8 | end 9 | 10 | def data_layout 11 | layout = LibLLVM.get_target_machine_data(self) 12 | layout ? TargetData.new(layout) : raise "Missing layout for #{self}" 13 | end 14 | 15 | def triple 16 | triple_c = LibLLVM.get_target_machine_triple(self) 17 | LLVM.string_and_dispose(triple_c) 18 | end 19 | 20 | def emit_obj_to_file(llvm_mod, filename) 21 | emit_to_file llvm_mod, filename, LLVM::CodeGenFileType::ObjectFile 22 | end 23 | 24 | def emit_asm_to_file(llvm_mod, filename) 25 | emit_to_file llvm_mod, filename, LLVM::CodeGenFileType::AssemblyFile 26 | end 27 | 28 | private def emit_to_file(llvm_mod, filename, type) 29 | status = LibLLVM.target_machine_emit_to_file(self, llvm_mod, filename, type, out error_msg) 30 | unless status == 0 31 | raise LLVM.string_and_dispose(error_msg) 32 | end 33 | true 34 | end 35 | 36 | def abi 37 | triple = self.triple 38 | case triple 39 | when /x86_64/ 40 | ABI::X86_64.new(self) 41 | when /i386|i686/ 42 | ABI::X86.new(self) 43 | else 44 | raise "Unsupported ABI for target triple: #{triple}" 45 | end 46 | end 47 | 48 | def to_unsafe 49 | @unwrap 50 | end 51 | 52 | def finalize 53 | LibLLVM.dispose_target_machine(@unwrap) 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /src/compiler/crystal/codegen/crystal_llvm_builder.cr: -------------------------------------------------------------------------------- 1 | module Crystal 2 | class CrystalLLVMBuilder 3 | property :end 4 | 5 | def initialize(@builder, @printf) 6 | @end = false 7 | end 8 | 9 | def llvm_nil 10 | LLVMTyper::NIL_VALUE 11 | end 12 | 13 | def ret 14 | return llvm_nil if @end 15 | value = @builder.ret 16 | @end = true 17 | value 18 | end 19 | 20 | def ret(value) 21 | return llvm_nil if @end 22 | value = @builder.ret(value) 23 | @end = true 24 | value 25 | end 26 | 27 | def br(block) 28 | return llvm_nil if @end 29 | value = @builder.br(block) 30 | @end = true 31 | value 32 | end 33 | 34 | def unreachable 35 | if ENV["UNREACHABLE"]? == "1" 36 | printf "Reached the unreachable!" 37 | end 38 | return if @end 39 | value = @builder.unreachable 40 | @end = true 41 | value 42 | end 43 | 44 | def printf(format, args = [] of LLVM::Value) 45 | call @printf, [global_string_pointer(format)] + args 46 | end 47 | 48 | def position_at_end(block) 49 | @builder.position_at_end block 50 | @end = false 51 | end 52 | 53 | def insert_block 54 | @builder.insert_block 55 | end 56 | 57 | def to_unsafe 58 | @builder.to_unsafe 59 | end 60 | 61 | macro method_missing(name, args, block) 62 | return llvm_nil if @end 63 | 64 | @builder.{{name.id}}({{*args}}) {{block}} 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /src/thread/thread.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | # :nodoc: 4 | class Thread(T, R) 5 | # Don't use this class, it is used internally by the event scheduler. 6 | # Use spawn and channels instead. 7 | 8 | def self.new(&func : -> R) 9 | Thread(Nil, R).new(nil) { func.call } 10 | end 11 | 12 | def initialize(arg : T, &func : T -> R) 13 | @func = func 14 | @arg = arg 15 | @detached = false 16 | ret = LibPThread.create(out @th, nil, ->(data) { 17 | (data as Thread(T, R)).start 18 | }, self as Void*) 19 | 20 | if ret != 0 21 | raise Errno.new("pthread_create") 22 | end 23 | end 24 | 25 | def finalize 26 | LibPThread.detach(@th) unless @detached 27 | end 28 | 29 | def join 30 | if LibPThread.join(@th, out _ret) != 0 31 | raise Errno.new("pthread_join") 32 | end 33 | @detached = true 34 | 35 | if exception = @exception 36 | raise exception 37 | end 38 | 39 | # TODO: We need to cast ret to R, otherwise it'll be nilable 40 | # and we don't want that. But `@ret as R` gives 41 | # `can't cast Nil to NoReturn` in the case when the Thread's body is 42 | # NoReturn. The following trick works, but we should find another 43 | # way to do it. 44 | ret = @ret 45 | if ret.is_a?(R) # Always true 46 | ret 47 | else 48 | exit # unreachable, really 49 | end 50 | end 51 | 52 | protected def start 53 | begin 54 | @ret = @func.call(@arg) 55 | rescue ex 56 | @exception = ex 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /docs/main.cr: -------------------------------------------------------------------------------- 1 | require "../src/big_int/**" 2 | require "../src/crypto/**" 3 | require "../src/csv" 4 | require "../src/ecr" 5 | require "../src/event/**" 6 | require "../src/fiber/**" 7 | # require "../src/fs/fs" 8 | require "../src/gc/**" 9 | require "../src/html/**" 10 | require "../src/http/**" 11 | require "../src/io/**" 12 | require "../src/json/**" 13 | require "../src/llvm/**" 14 | require "../src/logger" 15 | require "../src/macros" 16 | require "../src/math/**" 17 | require "../src/markdown" 18 | require "../src/oauth/**" 19 | require "../src/oauth2/**" 20 | require "../src/openssl/**" 21 | require "../src/process/**" 22 | require "../src/regex/**" 23 | require "../src/socket/**" 24 | require "../src/spec/**" 25 | require "../src/string/**" 26 | require "../src/thread/**" 27 | require "../src/time/**" 28 | require "../src/xml/**" 29 | require "../src/yaml/**" 30 | require "../src/benchmark" 31 | require "../src/array" 32 | require "../src/bit_array" 33 | require "../src/box" 34 | require "../src/colorize" 35 | require "../src/complex" 36 | require "../src/deque" 37 | require "../src/dl" 38 | require "../src/inifile" 39 | require "../src/levenshtein" 40 | require "../src/matrix" 41 | require "../src/option_parser" 42 | require "../src/partial_comparable" 43 | require "../src/readline" 44 | require "../src/secure_random" 45 | require "../src/signal" 46 | require "../src/simple_hash" 47 | require "../src/string_pool" 48 | require "../src/string_scanner" 49 | require "../src/tempfile" 50 | require "../src/uri" 51 | require "./macros" 52 | require "./char" 53 | -------------------------------------------------------------------------------- /src/zlib/inflate.cr: -------------------------------------------------------------------------------- 1 | module Zlib 2 | class Inflate 3 | include IO 4 | 5 | def initialize(@input : IO, wbits = LibZ::MAX_BITS) 6 | @buf :: UInt8[8192] # input buffer used by zlib 7 | @stream = LibZ::ZStream.new 8 | ret = LibZ.inflateInit2(pointerof(@stream), wbits, LibZ.zlibVersion, sizeof(LibZ::ZStream)) 9 | check_error(ret) 10 | end 11 | 12 | private def check_error(err) 13 | msg = @stream.msg ? String.new(@stream.msg) : nil 14 | ZlibError.check_error(err, msg) 15 | end 16 | 17 | def write(slice : Slice(UInt8)) 18 | raise IO::Error.new "Can't write to InflateIO" 19 | end 20 | 21 | def read(slice : Slice(UInt8)) 22 | prepare_input_data 23 | 24 | @stream.avail_out = slice.size.to_u32 25 | @stream.next_out = slice.to_unsafe 26 | 27 | # if no data was read, and the stream is not finished keep inflating 28 | while perform_inflate != LibZ::STREAM_END && @stream.avail_out == slice.size.to_u32 29 | prepare_input_data 30 | end 31 | 32 | slice.size - @stream.avail_out 33 | end 34 | 35 | private def prepare_input_data 36 | return if @stream.avail_in > 0 37 | @stream.next_in = @buf.buffer 38 | @stream.avail_in = @input.read(@buf.to_slice).to_u32 39 | end 40 | 41 | private def perform_inflate 42 | flush = @stream.avail_in == 0 ? LibZ::Flush::FINISH : LibZ::Flush::NO_FLUSH 43 | ret = LibZ.inflate(pointerof(@stream), flush) 44 | check_error(ret) 45 | ret 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /src/oauth/access_token.cr: -------------------------------------------------------------------------------- 1 | class OAuth::AccessToken 2 | getter token 3 | getter secret 4 | 5 | def initialize(@token, @secret, @extra = nil) 6 | end 7 | 8 | def extra 9 | @extra ||= {} of String => String 10 | end 11 | 12 | def self.from_response(response) 13 | token = nil 14 | secret = nil 15 | extra = {} of String => String 16 | 17 | HTTP::Params.parse(response) do |key, value| 18 | case key 19 | when "oauth_token" then token = value 20 | when "oauth_token_secret" then secret = value 21 | else extra[key] = value 22 | end 23 | end 24 | 25 | new token.not_nil!, secret.not_nil!, extra 26 | end 27 | 28 | def self.new(pull : JSON::PullParser) 29 | token = nil 30 | secret = nil 31 | extra = {} of String => String 32 | 33 | pull.read_object do |key| 34 | case key 35 | when "oauth_token" 36 | token = pull.read_string 37 | when "oauth_token_secret" 38 | secret = pull.read_string 39 | else 40 | if pull.kind == :STRING 41 | extra[key] = pull.read_string 42 | else 43 | pull.skip 44 | end 45 | end 46 | end 47 | 48 | new token.not_nil!, secret.not_nil!, extra 49 | end 50 | 51 | def to_json(io : IO) 52 | io.json_object do |object| 53 | object.field "oauth_token", @token 54 | object.field "oauth_token_secret", @secret 55 | @extra.try &.each do |key, value| 56 | object.field key, value 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /src/unwind.cr: -------------------------------------------------------------------------------- 1 | lib LibUnwind 2 | struct Exception 3 | exception_class : LibC::SizeT 4 | exception_cleanup : LibC::SizeT 5 | private1 : UInt64 6 | private2 : UInt64 7 | exception_object : UInt64 8 | exception_type_id : Int32 9 | end 10 | 11 | @[Flags] 12 | enum Action 13 | SEARCH_PHASE = 1 14 | CLEANUP_PHASE = 2 15 | HANDLER_FRAME = 4 16 | FORCE_UNWIND = 8 17 | END_OF_STACK = 16 18 | end 19 | 20 | enum ReasonCode 21 | NO_REASON = 0 22 | FOREIGN_EXCEPTION_CAUGHT = 1 23 | FATAL_PHASE2_ERROR = 2 24 | FATAL_PHASE1_ERROR = 3 25 | NORMAL_STOP = 4 26 | END_OF_STACK = 5 27 | HANDLER_FOUND = 6 28 | INSTALL_CONTEXT = 7 29 | CONTINUE_UNWIND = 8 30 | end 31 | 32 | ifdef x86_64 33 | EH_REGISTER_0 = 0 34 | EH_REGISTER_1 = 1 35 | else 36 | EH_REGISTER_0 = 0 37 | EH_REGISTER_1 = 2 38 | end 39 | 40 | alias Context = Void* 41 | 42 | fun raise_exception = _Unwind_RaiseException(ex : Exception*) : Int32 43 | fun get_region_start = _Unwind_GetRegionStart(Context) : LibC::SizeT 44 | fun get_ip = _Unwind_GetIP(Context) : LibC::SizeT 45 | fun set_ip = _Unwind_SetIP(context : Context, ip : LibC::SizeT) : LibC::SizeT 46 | fun set_gr = _Unwind_SetGR(context : Context, index : Int32, value : LibC::SizeT) 47 | fun get_language_specific_data = _Unwind_GetLanguageSpecificData(Context) : UInt8* 48 | fun backtrace = _Unwind_Backtrace((Context, Void*) -> ReasonCode, Void*) : Int32 49 | end 50 | -------------------------------------------------------------------------------- /spec/compiler/codegen/no_return_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Code gen: no return" do 4 | it "codegens if with NoReturn on then and union on else" do 5 | run("lib LibC; fun exit(c : Int32) : NoReturn; end; (if 1 == 2; LibC.exit(1); else; 1 || 2.5; end).to_i").to_i.should eq(1) 6 | end 7 | 8 | it "codegens Pointer(NoReturn).malloc" do 9 | run("Pointer(NoReturn).malloc(1_u64); 1").to_i.should eq(1) 10 | end 11 | 12 | it "codegens if with no reutrn and variable used afterwards" do 13 | codegen(%( 14 | require "prelude" 15 | 16 | lib LibC 17 | fun exit2 : NoReturn 18 | end 19 | 20 | if (a = LibC.exit2) && a.size == 3 21 | end 22 | )) 23 | end 24 | 25 | it "codegen types exception handler as NoReturn if ensure is NoReturn" do 26 | codegen(%( 27 | require "prelude" 28 | 29 | lib LibC 30 | fun foo : NoReturn 31 | end 32 | 33 | begin 34 | 1 35 | ensure 36 | LibC.foo 37 | end 38 | )) 39 | end 40 | 41 | it "codegens no return variable declaration (#1508)" do 42 | run(%( 43 | foo :: NoReturn 44 | 1 45 | )).to_i.should eq(1) 46 | end 47 | 48 | it "codegens no return instance variable declaration (#1508)" do 49 | run(%( 50 | class Foo 51 | def initialize 52 | @foo :: NoReturn 53 | @x = 1 54 | end 55 | 56 | def x 57 | @x 58 | end 59 | end 60 | 61 | Foo.new.x 62 | )).to_i.should eq(1) 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /spec/std/reference_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | class ReferenceSpecTestClass 4 | def initialize(@x, @y) 5 | end 6 | end 7 | 8 | class ReferenceSpecTestClassBase 9 | end 10 | 11 | class ReferenceSpecTestClassSubclass < ReferenceSpecTestClassBase 12 | end 13 | 14 | describe "Reference" do 15 | it "compares reference to other reference" do 16 | o1 = Reference.new 17 | o2 = Reference.new 18 | (o1 == o1).should be_true 19 | (o1 == o2).should be_false 20 | (o1 == 1).should be_false 21 | end 22 | 23 | it "should not be nil" do 24 | Reference.new.nil?.should be_false 25 | end 26 | 27 | it "should be false when negated" do 28 | (!Reference.new).should be_false 29 | end 30 | 31 | it "does inspect" do 32 | r = ReferenceSpecTestClass.new(1, "hello") 33 | r.inspect.should eq(%(#)) 34 | end 35 | 36 | it "does to_s" do 37 | r = ReferenceSpecTestClass.new(1, "hello") 38 | r.to_s.should eq(%(#)) 39 | end 40 | 41 | it "does inspect for class" do 42 | String.inspect.should eq("String") 43 | end 44 | 45 | it "does to_s for class" do 46 | String.to_s.should eq("String") 47 | end 48 | 49 | it "does to_s for class if virtual" do 50 | [ReferenceSpecTestClassBase, ReferenceSpecTestClassSubclass].to_s.should eq("[ReferenceSpecTestClassBase, ReferenceSpecTestClassSubclass]") 51 | end 52 | 53 | it "returns itself" do 54 | x = "hello" 55 | x.itself.should be(x) 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/named_args_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: named args" do 4 | it "errors if named arg not found" do 5 | assert_error %( 6 | def foo(x, y = 1, z = 2) 7 | end 8 | 9 | foo 1, w: 3 10 | ), 11 | "no argument named 'w'" 12 | end 13 | 14 | it "errors if named arg already specified" do 15 | assert_error %( 16 | def foo(x, y = 1, z = 2) 17 | end 18 | 19 | foo 1, x: 1 20 | ), 21 | "argument 'x' already specified" 22 | end 23 | 24 | it "errors if named arg not found in new" do 25 | assert_error %( 26 | class Foo 27 | def initialize(x, y = 1, z = 2) 28 | end 29 | end 30 | 31 | Foo.new 1, w: 3 32 | ), 33 | "no argument named 'w'" 34 | end 35 | 36 | it "errors if named arg already specified" do 37 | assert_error %( 38 | class Foo 39 | def initialize(x, y = 1, z = 2) 40 | end 41 | end 42 | 43 | Foo.new 1, x: 1 44 | ), 45 | "argument 'x' already specified" 46 | end 47 | 48 | it "errors if doesn't pass named arg restriction" do 49 | assert_error %( 50 | def foo(x = 1 : Int32) 51 | end 52 | 53 | foo x: 1.5 54 | ), 55 | "no overload matches" 56 | end 57 | 58 | it "errors if named arg already specified but in same position" do 59 | assert_error %( 60 | def foo(headers = nil) 61 | end 62 | 63 | foo 1, headers: 2 64 | ), 65 | "argument 'headers' already specified" 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /src/file/flock.cr: -------------------------------------------------------------------------------- 1 | lib LibC 2 | @[Flags] 3 | enum FlockOp 4 | SH = 0x1 5 | EX = 0x2 6 | NB = 0x4 7 | UN = 0x8 8 | end 9 | 10 | fun flock(fd : Int, op : FlockOp) : Int 11 | end 12 | 13 | class File 14 | def flock_shared(blocking = true) 15 | flock_shared blocking 16 | begin 17 | yield 18 | ensure 19 | flock_unlock 20 | end 21 | end 22 | 23 | # Place a shared advisory lock. More than one process may hold a shared lock for a given file at a given time. 24 | # Errno::EWOULDBLOCK is raised if *blocking* is set to `false` and an existing exclusive lock is set. 25 | def flock_shared(blocking = true) 26 | flock LibC::FlockOp::SH, blocking 27 | end 28 | 29 | def flock_exclusive(blocking = true) 30 | flock_exclusive blocking 31 | begin 32 | yield 33 | ensure 34 | flock_unlock 35 | end 36 | end 37 | 38 | # Place an exclusive advisory lock. Only one process may hold an exclusive lock for a given file at a given time. 39 | # Errno::EWOULDBLOCK is raised if *blocking* is set to `false` and any existing lock is set. 40 | def flock_exclusive(blocking = true) 41 | flock LibC::FlockOp::EX, blocking 42 | end 43 | 44 | # Remove an existing advisory lock held by this process. 45 | def flock_unlock 46 | flock LibC::FlockOp::UN 47 | end 48 | 49 | private def flock(op : LibC::FlockOp, blocking = true : Bool) 50 | op |= LibC::FlockOp::NB unless blocking 51 | 52 | if LibC.flock(@fd, op) != 0 53 | raise Errno.new("flock") 54 | end 55 | 56 | nil 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /src/thread/lib_pthread.cr: -------------------------------------------------------------------------------- 1 | lib LibPThread 2 | alias Int = LibC::Int 3 | 4 | type Thread = Void* 5 | 6 | ifdef darwin 7 | type Mutex = Int64[8] 8 | else 9 | ifdef x86_64 10 | type Mutex = Int64[5] 11 | else 12 | type Mutex = Int64[3] 13 | end 14 | end 15 | 16 | ifdef darwin 17 | type MutexAttr = UInt8[16] 18 | else 19 | type MutexAttr = UInt8[4] 20 | end 21 | 22 | type Cond = Int64[6] 23 | type CondAttr = Void* 24 | 25 | fun create = pthread_create(thread : Thread*, attr : Void*, start : Void* ->, arg : Void*) : Int 26 | fun exit = pthread_exit(value : Void*) 27 | fun join = pthread_join(thread : Thread, value : Void**) : Int 28 | fun detach = pthread_detach(thread : Thread) : Int 29 | 30 | fun mutex_init = pthread_mutex_init(mutex : Mutex*, mutex_attr : MutexAttr*) : Int 31 | fun mutex_lock = pthread_mutex_lock(mutex : Mutex*) : Int 32 | fun mutex_trylock = pthread_mutex_trylock(mutex : Mutex*) : Int 33 | fun mutex_unlock = pthread_mutex_unlock(mutex : Mutex*) : Int 34 | fun mutex_destroy = pthread_mutex_destroy(mutex : Mutex*) : Int 35 | 36 | fun cond_init = pthread_cond_init(cond : Cond*, cond_attr : CondAttr) : Int 37 | fun cond_signal = pthread_cond_signal(cond : Cond*) : Int 38 | fun cond_broadcast = pthread_cond_broadcast(cond : Cond*) : Int 39 | fun cond_wait = pthread_cond_wait(cond : Cond*, mutext : Mutex*) : Int 40 | fun cond_timed_wait = pthread_cond_wait(cond : Cond*, mutext : Mutex*, abstime : LibC::TimeSpec) : Int 41 | fun cond_destroy = pthread_cond_destroy(cond : Cond*) : Int 42 | end 43 | -------------------------------------------------------------------------------- /spec/std/html/builder_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "html/builder" 3 | 4 | describe "HTML" do 5 | describe "Builder" do 6 | it "builds html" do 7 | str = HTML::Builder.new.build do 8 | doctype 9 | html do 10 | head do 11 | title { text "Crystal Programming Language" } 12 | end 13 | body do 14 | a({href: "http://crystal-lang.org"}) { text "Crystal rocks!" } 15 | form({method: "POST"}) do 16 | input({name: "name"}) 17 | end 18 | end 19 | end 20 | end 21 | str.should eq %(Crystal Programming LanguageCrystal rocks!
) 22 | end 23 | 24 | it "builds html with some tag attributes" do 25 | str = HTML::Builder.new.build do 26 | a({href: "http://crystal-lang.org", class: "crystal", id: "main"}) do 27 | text "Crystal rocks!" 28 | end 29 | end 30 | str.should eq %(Crystal rocks!) 31 | end 32 | 33 | it "escapes attribute values" do 34 | str = HTML::Builder.new.build do 35 | a({href: "<>"}) { } 36 | end 37 | str.should eq %() 38 | end 39 | 40 | it "escapes text" do 41 | str = HTML::Builder.new.build do 42 | a { text "<>" } 43 | end 44 | str.should eq %(<>) 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /samples/binary-trees.cr: -------------------------------------------------------------------------------- 1 | # Copied with little modifications from: http://benchmarksgame.alioth.debian.org/u64q/benchmark.php?test=binarytrees&lang=yarv&id=1&data=u64q 2 | 3 | class Node 4 | def initialize(@a, @b, @c) 5 | end 6 | 7 | property :a 8 | property :b 9 | property :c 10 | end 11 | 12 | def item_check(tree) 13 | tree = tree.not_nil! 14 | return tree.b if tree.a.nil? 15 | tree.b + item_check(tree.a) - item_check(tree.c) 16 | end 17 | 18 | def bottom_up_tree(item, depth) 19 | return Node.new(nil, item, nil) unless depth > 0 20 | item_item = 2 * item 21 | depth -= 1 22 | Node.new(bottom_up_tree(item_item - 1, depth), item, bottom_up_tree(item_item, depth)) 23 | end 24 | 25 | max_depth = (ARGV[0]? || 15).to_i 26 | min_depth = 4 27 | 28 | max_depth = min_depth + 2 if min_depth + 2 > max_depth 29 | 30 | stretch_depth = max_depth + 1 31 | stretch_tree = bottom_up_tree(0, stretch_depth) 32 | 33 | puts "stretch tree of depth #{stretch_depth}\t check: #{item_check(stretch_tree)}" 34 | stretch_tree = nil 35 | 36 | long_lived_tree = bottom_up_tree(0, max_depth) 37 | 38 | min_depth.step(max_depth + 1, 2) do |depth| 39 | iterations = 2**(max_depth - depth + min_depth) 40 | 41 | check = 0 42 | 43 | (1..iterations).each do |i| 44 | temp_tree = bottom_up_tree(i, depth) 45 | check += item_check(temp_tree) 46 | 47 | temp_tree = bottom_up_tree(-i, depth) 48 | check += item_check(temp_tree) 49 | end 50 | 51 | puts "#{iterations * 2}\t trees of depth #{depth}\t check: #{check}" 52 | end 53 | 54 | puts "long lived tree of depth #{max_depth}\t check: #{item_check(long_lived_tree)}" 55 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/global_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Global inference" do 4 | it "infers type of global assign" do 5 | node = parse "$foo = 1" 6 | result = infer_type node 7 | mod, node = result.program, result.node as Assign 8 | 9 | node.type.should eq(mod.int32) 10 | node.target.type.should eq(mod.int32) 11 | node.value.type.should eq(mod.int32) 12 | end 13 | 14 | it "infers type of global assign with union" do 15 | nodes = parse "$foo = 1; $foo = 'a'" 16 | result = infer_type nodes 17 | mod, node = result.program, result.node as Expressions 18 | 19 | (node[0] as Assign).target.type.should eq(mod.union_of(mod.int32, mod.char)) 20 | (node[1] as Assign).target.type.should eq(mod.union_of(mod.int32, mod.char)) 21 | end 22 | 23 | it "infers type of global reference" do 24 | assert_type("$foo = 1; def foo; $foo = 'a'; end; foo; $foo") { union_of(int32, char) } 25 | end 26 | 27 | it "infers type of read global variable when not previously assigned" do 28 | assert_type("def foo; $foo; end; foo; $foo") { |mod| mod.nil } 29 | end 30 | 31 | it "infers type of write global variable when not previously assigned" do 32 | assert_type("def foo; $foo = 1; end; foo; $foo") { |mod| union_of(mod.nil, int32) } 33 | end 34 | 35 | it "types constant depending on global (related to #708)" do 36 | assert_type(%( 37 | A = foo 38 | 39 | def foo 40 | if a = $foo 41 | a 42 | else 43 | $foo = 1 44 | end 45 | end 46 | 47 | A 48 | )) { int32 } 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /src/compiler/crystal/codegen/asm.cr: -------------------------------------------------------------------------------- 1 | require "./codegen" 2 | 3 | class Crystal::CodeGenVisitor 4 | def visit(node : Asm) 5 | constraints = MemoryIO.new 6 | 7 | if ptrof = node.ptrof 8 | output = node.output.not_nil! 9 | output_type = llvm_type((ptrof.type as PointerInstanceType).element_type) 10 | constraints << output.constraint 11 | else 12 | output_type = LLVM::Void 13 | end 14 | 15 | input_types = [] of LLVM::Type 16 | input_values = [] of LLVM::Value 17 | 18 | if inputs = node.inputs 19 | constraints << "," unless constraints.empty? 20 | 21 | inputs.each_with_index do |input, i| 22 | input.exp.accept self 23 | input_types << llvm_type(input.exp.type) 24 | input_values << @last 25 | constraints << "," if i > 0 26 | constraints << input.constraint 27 | end 28 | end 29 | 30 | if clobbers = node.clobbers 31 | constraints << "," unless constraints.empty? 32 | 33 | clobbers.each_with_index do |clobber, i| 34 | constraints << "," if i > 0 35 | constraints << "~{" 36 | constraints << clobber 37 | constraints << '}' 38 | end 39 | end 40 | 41 | fun_type = LLVM::Type.function(input_types, output_type) 42 | constraints = constraints.to_s 43 | 44 | value = LLVM.const_inline_asm(fun_type, node.text, constraints, node.volatile, node.alignstack) 45 | asm_value = call value, input_values 46 | 47 | if ptrof 48 | ptrof.accept self 49 | store asm_value, @last 50 | end 51 | 52 | @last = llvm_nil 53 | 54 | false 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/std/string_pool_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "string_pool" 3 | 4 | describe StringPool do 5 | it "is empty" do 6 | pool = StringPool.new 7 | pool.empty?.should be_true 8 | pool.size.should eq(0) 9 | end 10 | 11 | it "gets string" do 12 | pool = StringPool.new 13 | s1 = pool.get "foo" 14 | s2 = pool.get "foo" 15 | 16 | s1.should eq("foo") 17 | s2.should eq("foo") 18 | s1.should be(s2) 19 | pool.size.should eq(1) 20 | end 21 | 22 | it "gets string IO" do 23 | pool = StringPool.new 24 | io = MemoryIO.new "foo" 25 | 26 | s1 = pool.get io 27 | s2 = pool.get "foo" 28 | 29 | s1.should eq("foo") 30 | s2.should eq("foo") 31 | s1.should be(s2) 32 | pool.size.should eq(1) 33 | end 34 | 35 | it "gets slice" do 36 | pool = StringPool.new 37 | slice = Slice(UInt8).new(3, 'a'.ord.to_u8) 38 | 39 | s1 = pool.get(slice) 40 | s2 = pool.get(slice) 41 | 42 | s1.should eq("aaa") 43 | s2.should eq("aaa") 44 | s1.should be(s2) 45 | pool.size.should eq(1) 46 | end 47 | 48 | it "gets pointer with size" do 49 | pool = StringPool.new 50 | slice = Slice(UInt8).new(3, 'a'.ord.to_u8) 51 | 52 | s1 = pool.get(slice.pointer(slice.size), slice.size) 53 | s2 = pool.get(slice.pointer(slice.size), slice.size) 54 | 55 | s1.should eq("aaa") 56 | s2.should eq("aaa") 57 | s1.should be(s2) 58 | pool.size.should eq(1) 59 | end 60 | 61 | it "puts many" do 62 | pool = StringPool.new 63 | 10_000.times do |i| 64 | pool.get(i.to_s) 65 | end 66 | pool.size.should eq(10_000) 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /src/compiler/crystal/semantic/match.cr: -------------------------------------------------------------------------------- 1 | module Crystal 2 | class MatchContext 3 | property owner 4 | property type_lookup 5 | getter free_vars 6 | getter? strict 7 | 8 | def initialize(@owner, @type_lookup, @free_vars = nil, @strict = false) 9 | end 10 | 11 | def get_free_var(name) 12 | @free_vars.try &.[name]? 13 | end 14 | 15 | def set_free_var(name, type) 16 | free_vars = @free_vars ||= {} of String => Type 17 | free_vars[name] = type 18 | end 19 | 20 | def clone 21 | MatchContext.new(@owner, @type_lookup, @free_vars.clone) 22 | end 23 | end 24 | 25 | class Match 26 | getter :def 27 | getter :arg_types 28 | getter :context 29 | 30 | def initialize(@def, @arg_types, @context) 31 | end 32 | end 33 | 34 | struct Matches 35 | include Enumerable(Match) 36 | 37 | property :matches 38 | property :cover 39 | property :owner 40 | 41 | def initialize(@matches, @cover, @owner = nil, @success = true) 42 | end 43 | 44 | def cover_all? 45 | cover = @cover 46 | matches = @matches 47 | @success && matches && matches.size > 0 && (cover == true || (cover.is_a?(Cover) && cover.all?)) 48 | end 49 | 50 | def empty? 51 | return true unless @success 52 | 53 | if matches = @matches 54 | matches.empty? 55 | else 56 | true 57 | end 58 | end 59 | 60 | def each 61 | @success && @matches.try &.each do |match| 62 | yield match 63 | end 64 | end 65 | 66 | def size 67 | @matches.try(&.size) || 0 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /src/concurrent/concurrent.cr: -------------------------------------------------------------------------------- 1 | require "fiber" 2 | require "./*" 3 | 4 | def sleep(seconds : Number) 5 | if seconds < 0 6 | raise ArgumentError.new "sleep seconds must be positive" 7 | end 8 | 9 | Fiber.sleep(seconds) 10 | end 11 | 12 | def sleep(time : Time::Span) 13 | sleep(time.total_seconds) 14 | end 15 | 16 | def sleep 17 | Scheduler.reschedule 18 | end 19 | 20 | macro spawn 21 | %fiber = Fiber.new do 22 | begin 23 | {{ yield }} 24 | rescue %ex 25 | STDERR.puts "Unhandled exception:" 26 | %ex.inspect_with_backtrace STDERR 27 | STDERR.flush 28 | end 29 | end 30 | 31 | Scheduler.enqueue %fiber 32 | 33 | %fiber 34 | end 35 | 36 | # TODO: this doesn't work if a Call has a block or named arguments... yet 37 | macro spawn(exp) 38 | {% if exp.is_a?(Call) %} 39 | ->( 40 | {% for arg, i in exp.args %} 41 | __arg{{i}} : typeof({{arg}}), 42 | {% end %} 43 | ) { 44 | spawn do 45 | {{exp.name}}( 46 | {% for arg, i in exp.args %} 47 | __arg{{i}}, 48 | {% end %} 49 | ) 50 | end 51 | }.call({{*exp.args}}) 52 | {% else %} 53 | spawn do 54 | {{exp}} 55 | end 56 | {% end %} 57 | end 58 | 59 | macro parallel(*jobs) 60 | %channel = Channel(Bool).new 61 | 62 | {% for job, i in jobs %} 63 | %ret{i} = nil 64 | spawn do 65 | %ret{i} = {{job}} 66 | %channel.send true 67 | end 68 | {% end %} 69 | 70 | {{ jobs.size }}.times { %channel.receive } 71 | 72 | { 73 | {% for job, i in jobs %} 74 | %ret{i}.not_nil!, 75 | {% end %} 76 | } 77 | end 78 | -------------------------------------------------------------------------------- /spec/compiler/parser/parser_doc_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Parser doc" do 4 | [ 5 | {"class", "class Foo\nend"}, 6 | {"abstract class", "abstract class Foo\nend"}, 7 | {"struct", "struct Foo\nend"}, 8 | {"module", "module Foo\nend"}, 9 | {"def", "def foo\nend"}, 10 | {"abstract def", "abstract def foo"}, 11 | {"macro", "macro foo\nend"}, 12 | {"macro def", "macro def foo : Int32\nend"}, 13 | {"call without obj", "foo"}, 14 | {"fun def", "fun foo : Int32\nend"}, 15 | {"enum def", "enum Foo\nend"}, 16 | {"constant assign", "A = 1"}, 17 | {"alias", "alias Foo = Bar"}, 18 | {"attribute", "@[Some]"}, 19 | {"private def", "private def foo\nend"}, 20 | ].each do |tuple| 21 | desc, code = tuple 22 | 23 | it "includes doc for #{desc}" do 24 | parser = Parser.new(%( 25 | # This is Foo. 26 | # Use it well. 27 | #{code} 28 | )) 29 | parser.wants_doc = true 30 | node = parser.parse 31 | node.doc.should eq("This is Foo.\nUse it well.") 32 | end 33 | end 34 | 35 | it "disables doc parsing inside defs" do 36 | parser = Parser.new(%( 37 | # doc 1 38 | def foo 39 | # doc 2 40 | bar 41 | end 42 | 43 | # doc 3 44 | def baz 45 | end 46 | )) 47 | parser.wants_doc = true 48 | nodes = parser.parse as Expressions 49 | 50 | foo = nodes[0] as Def 51 | foo.doc.should eq("doc 1") 52 | 53 | bar = foo.body as Call 54 | bar.doc.should be_nil 55 | 56 | baz = nodes[1] as Def 57 | baz.doc.should eq("doc 3") 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /src/spec/dsl.cr: -------------------------------------------------------------------------------- 1 | module Spec::DSL 2 | def describe(description, file = __FILE__, line = __LINE__, &block) 3 | Spec::RootContext.describe(description.to_s, file, line, &block) 4 | end 5 | 6 | def context(description, file = __FILE__, line = __LINE__, &block) 7 | describe(description.to_s, file, line, &block) 8 | end 9 | 10 | def it(description, file = __FILE__, line = __LINE__, &block) 11 | return if Spec.aborted? 12 | return unless Spec.matches?(description, file, line) 13 | 14 | Spec.formatter.before_example description 15 | 16 | begin 17 | Spec.run_before_each_hooks 18 | block.call 19 | Spec::RootContext.report(:success, description, file, line) 20 | rescue ex : Spec::AssertionFailed 21 | Spec::RootContext.report(:fail, description, file, line, ex) 22 | Spec.abort! if Spec.fail_fast? 23 | rescue ex 24 | Spec::RootContext.report(:error, description, file, line, ex) 25 | Spec.abort! if Spec.fail_fast? 26 | ensure 27 | Spec.run_after_each_hooks 28 | end 29 | end 30 | 31 | def pending(description, file = __FILE__, line = __LINE__, &block) 32 | return if Spec.aborted? 33 | return unless Spec.matches?(description, file, line) 34 | 35 | Spec.formatter.before_example description 36 | 37 | Spec::RootContext.report(:pending, description, file, line) 38 | end 39 | 40 | def assert(file = __FILE__, line = __LINE__, &block) 41 | it("assert", file, line, &block) 42 | end 43 | 44 | def fail(msg, file = __FILE__, line = __LINE__) 45 | raise Spec::AssertionFailed.new(msg, file, line) 46 | end 47 | end 48 | 49 | include Spec::DSL 50 | -------------------------------------------------------------------------------- /src/http/server/handlers/static_file_handler.cr: -------------------------------------------------------------------------------- 1 | require "html/builder" 2 | 3 | class HTTP::StaticFileHandler < HTTP::Handler 4 | def initialize(@publicdir) 5 | end 6 | 7 | def call(request) 8 | request_path = request.path.not_nil! 9 | file_path = @publicdir + request_path 10 | if Dir.exists?(file_path) 11 | HTTP::Response.new(200, directory_listing(request_path, file_path), HTTP::Headers{"Content-Type": "text/html"}) 12 | elsif File.exists?(file_path) 13 | HTTP::Response.new(200, File.read(file_path), HTTP::Headers{"Content-Type": mime_type(file_path)}) 14 | else 15 | call_next(request) 16 | end 17 | end 18 | 19 | private def mime_type(path) 20 | case File.extname(path) 21 | when ".txt" then "text/plain" 22 | when ".htm", ".html" then "text/html" 23 | when ".css" then "text/css" 24 | when ".js" then "application/javascript" 25 | else "application/octet-stream" 26 | end 27 | end 28 | 29 | private def directory_listing(request_path, path) 30 | HTML::Builder.new.build do 31 | html do 32 | title { text "Directory listing for #{request_path}" } 33 | body do 34 | h2 { text "Directory listing for #{request_path}" } 35 | hr 36 | ul do 37 | Dir.foreach(path) do |entry| 38 | next if entry == "." || entry == ".." 39 | li do 40 | a({href: "#{request_path == "/" ? "" : request_path}/#{entry}"}) { text entry } 41 | end 42 | end 43 | end 44 | end 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/compiler/codegen/private_def_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | require "tempfile" 3 | 4 | describe "Codegen: private def" do 5 | it "codegens private def in same file" do 6 | compiler = Compiler.new 7 | sources = [ 8 | Compiler::Source.new("foo.cr", %( 9 | private def foo 10 | 1 11 | end 12 | 13 | foo 14 | )), 15 | ] 16 | compiler.prelude = "empty" 17 | 18 | tempfile = Tempfile.new("crystal-spec-output") 19 | output_filename = tempfile.path 20 | tempfile.close 21 | 22 | compiler.compile sources, output_filename 23 | end 24 | 25 | it "codegens overloaded private def in same file" do 26 | compiler = Compiler.new 27 | sources = [ 28 | Compiler::Source.new("foo.cr", %( 29 | private def foo(x : Int32) 30 | 1 31 | end 32 | 33 | private def foo(x : Char) 34 | 2 35 | end 36 | 37 | a = 3 || 'a' 38 | foo a 39 | )), 40 | ] 41 | compiler.prelude = "empty" 42 | 43 | tempfile = Tempfile.new("crystal-spec-output") 44 | output_filename = tempfile.path 45 | tempfile.close 46 | 47 | compiler.compile sources, output_filename 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /src/oauth2/session.cr: -------------------------------------------------------------------------------- 1 | # An OAuth2 session makes it easy to implement APIs that need to refresh 2 | # an access token once its expired before executing an HTTP request. 3 | class OAuth2::Session 4 | getter oauth2_client 5 | getter access_token 6 | getter expires_at 7 | 8 | # Creates an OAuth2::Session. 9 | # 10 | # Params: 11 | # * oauth2_client: the OAuth2::Client used to refresh an access token. 12 | # * access_token: the OAuth2::AccessToken to make requests. 13 | # * expires_at: the Time when the access token expires. 14 | # * callback: invoked when an access token is refreshed, giving you a chance to persist it. 15 | def initialize(@oauth2_client, @access_token, @expires_at = Time.utc_now, &@callback : OAuth2::Session ->) 16 | end 17 | 18 | # Authenticates an HTTP::Client, refreshing the access token if it is expired. 19 | # 20 | # Invoke this method on an HTTP::Client before executing an HTTP request. 21 | def authenticate(http_client) 22 | check_refresh_token 23 | @access_token.authenticate http_client 24 | end 25 | 26 | private def check_refresh_token 27 | if access_token_expired? 28 | refresh_access_token 29 | 30 | @callback.call(self) 31 | end 32 | end 33 | 34 | private def access_token_expired? 35 | Time.utc_now >= @expires_at 36 | end 37 | 38 | private def refresh_access_token 39 | old_access_token = @access_token 40 | @access_token = @oauth2_client.get_access_token_using_refresh_token(@access_token.refresh_token) 41 | @expires_at = Time.utc_now + @access_token.expires_in.seconds 42 | @access_token.refresh_token ||= old_access_token.refresh_token 43 | end 44 | end 45 | --------------------------------------------------------------------------------