├── spec ├── std │ ├── data │ │ ├── symlink.txt │ │ ├── argf_test_file_1.txt │ │ ├── argf_test_file_2.txt │ │ ├── test_template.ecr │ │ ├── websocket_longpacket.bin │ │ ├── test_file.ini │ │ └── test_file.txt │ ├── box_spec.cr │ ├── crypto │ │ ├── md5_spec.cr │ │ ├── bcrypt │ │ │ └── base64_spec.cr │ │ ├── subtle_spec.cr │ │ └── blowfish_spec.cr │ ├── uint_spec.cr │ ├── concucrrent_spec.cr │ ├── double_spec.cr │ ├── oauth │ │ ├── params_spec.cr │ │ ├── authorization_header_spec.cr │ │ ├── request_token_spec.cr │ │ └── access_token_spec.cr │ ├── html_spec.cr │ ├── http │ │ ├── server_spec.cr │ │ ├── client_spec.cr │ │ └── server │ │ │ └── handlers │ │ │ └── websocket_handler_spec.cr │ ├── file_utils_spec.cr │ ├── oauth2 │ │ └── session_spec.cr │ ├── string_builder_spec.cr │ ├── struct_spec.cr │ ├── signal_spec.cr │ ├── crystal │ │ ├── project_spec.cr │ │ └── path_dependency_spec.cr │ ├── yaml │ │ └── yaml_spec.cr │ ├── readline_spec.cr │ ├── ecr │ │ └── ecr_spec.cr │ ├── exception_spec.cr │ ├── symbol_spec.cr │ ├── llvm │ │ └── x86_abi_spec.cr │ ├── io │ │ └── argf_spec.cr │ ├── inifile_spec.cr │ ├── openssl │ │ └── hmac_spec.cr │ ├── bool_spec.cr │ ├── tempfile_spec.cr │ ├── env_spec.cr │ ├── thread_spec.cr │ ├── levenshtein_spec.cr │ ├── random_spec.cr │ ├── benchmark_spec.cr │ ├── xml │ │ └── html_spec.cr │ ├── reference_spec.cr │ └── html │ │ └── builder_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 │ ├── normalize │ │ ├── until_spec.cr │ │ ├── unless_spec.cr │ │ ├── range_literal_spec.cr │ │ ├── or_spec.cr │ │ ├── string_interpolation_spec.cr │ │ ├── ifdef_spec.cr │ │ ├── hash_literal_spec.cr │ │ ├── array_literal_spec.cr │ │ ├── return_next_break_spec.cr │ │ ├── and_spec.cr │ │ └── chained_comparisons_spec.cr │ ├── codegen │ │ ├── until_spec.cr │ │ ├── untyped_expression_spec.cr │ │ ├── no_return_spec.cr │ │ ├── asm_spec.cr │ │ ├── global_spec.cr │ │ ├── previous_def_spec.cr │ │ ├── generic_class_spec.cr │ │ ├── hooks_spec.cr │ │ └── private_def_spec.cr │ ├── compiler_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 │ │ ├── if_spec.cr │ │ ├── named_args_spec.cr │ │ └── global_spec.cr │ └── parser │ │ ├── to_s_spec.cr │ │ └── parser_doc_spec.cr └── all_spec.cr ├── src ├── http │ ├── http.cr │ ├── server │ │ └── handlers │ │ │ ├── error_handler.cr │ │ │ ├── log_handler.cr │ │ │ └── static_file_handler.cr │ └── request.cr ├── compiler │ ├── crystal │ │ ├── tools │ │ │ ├── init │ │ │ │ └── template │ │ │ │ │ ├── travis.yml.ecr │ │ │ │ │ ├── version.cr.ecr │ │ │ │ │ ├── projectfile.ecr │ │ │ │ │ ├── spec_helper.cr.ecr │ │ │ │ │ ├── example.cr.ecr │ │ │ │ │ ├── example_spec.cr.ecr │ │ │ │ │ ├── gitignore.ecr │ │ │ │ │ ├── readme.md.ecr │ │ │ │ │ └── license.ecr │ │ │ ├── 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 │ │ │ ├── doc.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 │ └── ecr.cr ├── openssl │ ├── openssl.cr │ ├── ssl.cr │ ├── md5.cr │ ├── sha1.cr │ ├── ssl │ │ ├── context.cr │ │ └── socket.cr │ ├── hmac.cr │ ├── lib_ssl.cr │ └── bio.cr ├── crystal │ ├── project │ │ ├── project_error.cr │ │ ├── dependency.cr │ │ ├── dsl.cr │ │ └── path_dependency.cr │ └── project_cli.cr ├── oauth2 │ ├── oauth2.cr │ ├── access_token │ │ └── bearer.cr │ └── error.cr ├── oauth │ ├── error.cr │ ├── oauth.cr │ ├── request_token.cr │ ├── authorization_header.cr │ ├── params.cr │ └── access_token.cr ├── time │ ├── day_of_week.cr │ └── time_format.cr ├── llvm │ ├── value.cr │ ├── context.cr │ ├── basic_block.cr │ ├── module_pass_manager.cr │ ├── basic_block_collection.cr │ ├── phi_table.cr │ ├── instruction_collection.cr │ ├── global_collection.cr │ ├── target_data.cr │ ├── generic_value.cr │ ├── pass_registry.cr │ ├── jit_compiler.cr │ ├── function_pass_manager.cr │ ├── function.cr │ ├── function_collection.cr │ ├── pass_manager_builder.cr │ ├── parameter_collection.cr │ ├── target.cr │ ├── module.cr │ ├── abi.cr │ └── target_machine.cr ├── io │ ├── error.cr │ ├── pointer_io.cr │ └── fd_set.cr ├── empty.cr ├── xml │ ├── attribute_type.cr │ ├── type.cr │ ├── error.cr │ ├── save_options.cr │ ├── html_parser_options.cr │ ├── namespace.cr │ ├── node_set.cr │ ├── attributes.cr │ └── xml.cr ├── dl.cr ├── box.cr ├── process │ └── status.cr ├── gc.cr ├── markdown │ └── markdown.cr ├── html.cr ├── json │ ├── lexer │ │ └── io_based.cr │ ├── token.cr │ └── any.cr ├── crypto │ ├── subtle.cr │ └── bcrypt │ │ └── base64.cr ├── fiber │ └── lib_pcl.cr ├── thread │ ├── condition_variable.cr │ ├── mutex.cr │ ├── lib_pthread.cr │ └── thread.cr ├── class.cr ├── inifile.cr ├── csv │ ├── token.cr │ └── lexer │ │ ├── io_based.cr │ │ └── string_based.cr ├── main.cr ├── spec │ ├── source.cr │ └── formatter.cr ├── intrinsics.cr ├── gc │ └── null.cr ├── file_utils.cr ├── tempfile.cr ├── curses │ ├── window.cr │ ├── lib_curses.cr │ └── curses.cr ├── yaml │ └── yaml.cr ├── value.cr ├── iterable.cr ├── proc.cr ├── regex │ └── lib_pcre.cr ├── socket │ ├── tcp_socket.cr │ └── unix_server.cr ├── prelude.cr ├── random.cr ├── secure_random.cr └── concurrent │ └── concurrent.cr ├── .editorconfig ├── .gitignore ├── samples ├── egrep.cr ├── http_server.cr ├── tcp_client.cr ├── mandelbrot2.cr ├── sieve.cr ├── tcp_server.cr ├── tree.cr ├── channel_select.cr ├── curses │ └── hello.cr ├── sdl │ ├── tv.txt │ ├── fire.txt │ └── sdl │ │ ├── surface.cr │ │ └── sdl.cr ├── channel_primes.cr ├── mandelbrot.cr ├── spectral-norm.cr ├── matmul.cr ├── impl.cr ├── wordcount.cr └── binary-trees.cr ├── Dockerfile.release ├── docs ├── char.cr └── main.cr ├── LICENSE ├── Dockerfile ├── Makefile ├── Vagrantfile └── BACKERS.md /spec/std/data/symlink.txt: -------------------------------------------------------------------------------- 1 | test_file.txt -------------------------------------------------------------------------------- /src/http/http.cr: -------------------------------------------------------------------------------- 1 | require "./**" 2 | 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/compiler/crystal_path/test_files/test_folder/file_three.cr: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/openssl/openssl.cr: -------------------------------------------------------------------------------- 1 | require "./bio" 2 | require "./ssl" 3 | require "./md5" 4 | -------------------------------------------------------------------------------- /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/crystal/project/project_error.cr: -------------------------------------------------------------------------------- 1 | class Crystal::ProjectError < Exception 2 | end 3 | -------------------------------------------------------------------------------- /src/oauth2/oauth2.cr: -------------------------------------------------------------------------------- 1 | require "cgi" 2 | require "http/client" 3 | require "json" 4 | require "./**" 5 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/version.cr.ecr: -------------------------------------------------------------------------------- 1 | module <%= module_name %> 2 | VERSION = "0.0.1" 3 | end 4 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/init/template/projectfile.ecr: -------------------------------------------------------------------------------- 1 | deps do 2 | # github "[your-github-name]/example" 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/sferik/crystal/master/spec/std/data/websocket_longpacket.bin -------------------------------------------------------------------------------- /src/openssl/ssl.cr: -------------------------------------------------------------------------------- 1 | require "./lib_ssl" 2 | 3 | LibSSL.ssl_load_error_strings 4 | LibSSL.ssl_library_init 5 | 6 | require "./ssl/*" 7 | -------------------------------------------------------------------------------- /src/oauth/error.cr: -------------------------------------------------------------------------------- 1 | class OAuth::Error < ::Exception 2 | def initialize(@response) 3 | super("OAuth:Error: #{@response.body}") 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /src/time/day_of_week.cr: -------------------------------------------------------------------------------- 1 | enum DayOfWeek 2 | Sunday 3 | Monday 4 | Tuesday 5 | Wednesday 6 | Thursday 7 | Friday 8 | Saturday 9 | end 10 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 "uri" 3 | require "cgi" 4 | require "secure_random" 5 | require "openssl/hmac" 6 | require "base64" 7 | require "./**" 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /samples/http_server.cr: -------------------------------------------------------------------------------- 1 | require "http/server" 2 | 3 | server = HTTP::Server.new 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/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 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc.cr: -------------------------------------------------------------------------------- 1 | require "cgi" 2 | require "markdown" 3 | 4 | module Crystal 5 | def self.generate_docs(program, base_dirs) 6 | generator = Doc::Generator.new(program, base_dirs) 7 | generator.run 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /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 | 11 | -------------------------------------------------------------------------------- /src/dl.cr: -------------------------------------------------------------------------------- 1 | lib LibDL 2 | LAZY = 1 3 | GLOBAL = 8 4 | fun dlopen(path : UInt8*, mode : LibC::Int) : Void* 5 | end 6 | 7 | module DL 8 | def self.dlopen(path, mode = LibDL::LAZY | LibDL::GLOBAL) 9 | LibDL.dlopen(path, mode) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /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/concucrrent_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".length, [1, 2, 3, 4].length) 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 | /.deps/ 2 | /libs/ 3 | /.crystal/ 4 | /doc/ 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 | /.deps.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 | -------------------------------------------------------------------------------- /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/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 | def exit_code 9 | @exit_status >> 8 10 | end 11 | 12 | def success? 13 | exit_code == 0 14 | end 15 | end 16 | 17 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /src/markdown/markdown.cr: -------------------------------------------------------------------------------- 1 | class Markdown 2 | def self.parse(text, renderer) 3 | parser = Parser.new(text, renderer) 4 | parser.parse 5 | end 6 | 7 | def self.to_html(text) 8 | String.build do |io| 9 | parse text, Markdown::HTMLRenderer.new(io) 10 | end 11 | end 12 | end 13 | 14 | require "./*" 15 | -------------------------------------------------------------------------------- /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/md5.cr: -------------------------------------------------------------------------------- 1 | require "./lib_crypto" 2 | 3 | class OpenSSL::MD5 4 | def self.hash(data : String) 5 | hash(data.cstr, LibC::SizeT.cast(data.bytesize)) 6 | end 7 | 8 | def self.hash(data : UInt8*, length : LibC::SizeT) 9 | buffer :: UInt8[16] 10 | LibCrypto.md5(data, length, buffer) 11 | buffer 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /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.cast(data.bytesize)) 6 | end 7 | 8 | def self.hash(data : UInt8*, length : LibC::SizeT) 9 | buffer :: UInt8[20] 10 | LibCrypto.sha1(data, length, 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 | -------------------------------------------------------------------------------- /src/llvm/module_pass_manager.cr: -------------------------------------------------------------------------------- 1 | struct 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 | end 18 | -------------------------------------------------------------------------------- /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/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/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/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/crystal/project/dependency.cr: -------------------------------------------------------------------------------- 1 | abstract class Crystal::Dependency 2 | abstract def install 3 | property locked_version 4 | 5 | @name :: String 6 | property name 7 | 8 | def initialize(@name) 9 | case @name 10 | when /^crystal(?:_|-)(.*)$/ 11 | @name = $1 12 | when /^(.*)(?:\_|-)crystal$/ 13 | @name = $1 14 | when /^(.*)\.cr$/ 15 | @name = $1 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /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 length 20 | @blocks.length 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/std/http/server_spec.cr: -------------------------------------------------------------------------------- 1 | require "http/server" 2 | 3 | module HTTP 4 | typeof(begin 5 | server = Server.new(8080) { |req| HTTP::Response.ok("text/plain", "OK") } 6 | server.listen 7 | server.listen_fork(workers: 2) 8 | server.close 9 | 10 | Server.new(8080, [ 11 | ErrorHandler.new, 12 | LogHandler.new, 13 | StaticFileHandler.new("."), 14 | ] 15 | ).listen 16 | end) 17 | end 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/crypto/subtle.cr: -------------------------------------------------------------------------------- 1 | module Crypto::Subtle 2 | def self.constant_time_compare(x, y) 3 | return 0 if x.length != y.length 4 | 5 | v = 0_u8 6 | 7 | x.length.times do |i| 8 | v = 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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | end 16 | -------------------------------------------------------------------------------- /src/thread/condition_variable.cr: -------------------------------------------------------------------------------- 1 | class ConditionVariable 2 | def initialize 3 | LibPThread.cond_init(out @cond, nil) 4 | end 5 | 6 | def signal 7 | LibPThread.cond_signal(self) 8 | end 9 | 10 | def wait(mutex : Mutex) 11 | LibPThread.cond_wait(self, mutex) 12 | end 13 | 14 | def finalize 15 | LibPThread.cond_destroy(pointerof(@cond)) 16 | end 17 | 18 | def to_unsafe 19 | pointerof(@cond) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /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.length 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.length 16 | slice.copy_to(@pointer.value, count) 17 | @pointer.value += count 18 | count 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /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 | # Returns the name of this class. 15 | # 16 | # ``` 17 | # String.name #=> "String" 18 | # ``` 19 | macro def name : String 20 | {{ @type.name.stringify }} 21 | end 22 | 23 | def to_s(io) 24 | io << name 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /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/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/crystal/project_cli.cr: -------------------------------------------------------------------------------- 1 | require "./project" 2 | 3 | project = Crystal::Project.new 4 | begin 5 | project.eval do 6 | {{ `cat Projectfile` }} 7 | end 8 | 9 | command = ARGV.shift? || "install" 10 | 11 | case command 12 | when "install" 13 | project.install_deps 14 | when "update" 15 | project.update_deps ARGV 16 | else 17 | puts "Invalid command: #{command}" 18 | end 19 | rescue ex : Crystal::ProjectError 20 | puts ex.message 21 | exit 1 22 | end 23 | 24 | -------------------------------------------------------------------------------- /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 | 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | end 25 | -------------------------------------------------------------------------------- /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 | CGI.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | end 16 | -------------------------------------------------------------------------------- /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.length.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 = StringIO.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 | CGI.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.length .. -1]}" 20 | end 21 | file 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /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 destroy 26 | LibPThread.mutex_destroy(self) 27 | end 28 | 29 | def to_unsafe 30 | pointerof(@mutex) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /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/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/crystal/project/dsl.cr: -------------------------------------------------------------------------------- 1 | struct Crystal::Project::DSL 2 | def initialize(@project) 3 | end 4 | 5 | def deps 6 | with Deps.new(@project) yield 7 | end 8 | 9 | struct Deps 10 | def initialize(@project) 11 | end 12 | 13 | def github(repository, name = nil : String, ssh = false, branch = nil : String) 14 | @project.dependencies << GitHubDependency.new(repository, name, ssh, branch) 15 | end 16 | 17 | def path(path, name = nil : String) 18 | @project.dependencies << PathDependency.new(path, name) 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | end 14 | 15 | LibXML.xmlSetStructuredErrorFunc nil, ->(ctx, error) { 16 | raise XML::Error.new(error) 17 | } 18 | 19 | LibXML.xmlSetGenericErrorFunc nil, ->(ctx, fmt) { 20 | # TODO: use va_start and va_end 21 | raise XML::Error.new(String.new(fmt).chomp, 0) 22 | } 23 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 14 | rescue IO::EOFError 15 | puts "#{client_addr} dissconnected" 16 | 17 | ensure 18 | client.close 19 | end 20 | 21 | server = TCPServer.new "127.0.0.1", 9000 22 | puts "listen on 127.0.0.1:9000" 23 | loop { spawn process(server.accept) } 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/llvm/generic_value.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::GenericValue 2 | def initialize(@unwrap) 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 | end 33 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | 14 | -------------------------------------------------------------------------------- /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/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 << {CGI.escape(key), CGI.escape(value)} 10 | end 11 | end 12 | 13 | def add_query(query) 14 | CGI.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 | CGI.escape tuple[0], io 24 | io << "%3D" 25 | CGI.escape tuple[1], io 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/time/time_format.cr: -------------------------------------------------------------------------------- 1 | struct TimeFormat 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 | -------------------------------------------------------------------------------- /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/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", "__temp_1 = ::Array(Int).new(2)\n__temp_1.length = 2\n__temp_2 = __temp_1.buffer\n__temp_2[0] = 1\n__temp_2[1] = 2\n__temp_1" 10 | end 11 | 12 | it "normalizes non-empty without of" do 13 | assert_expand "[1, 2]", "__temp_1 = ::Array(typeof(1, 2)).new(2)\n__temp_1.length = 2\n__temp_2 = __temp_1.buffer\n__temp_2[0] = 1\n__temp_2[1] = 2\n__temp_1" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /src/compiler/crystal/tools/doc/html/methods_inherited.html: -------------------------------------------------------------------------------- 1 | <% method_groups = ancestor.instance_methods.group_by { |method| method.name } %> 2 | <% unless method_groups.empty? %> 3 |

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.length - 1 %> 8 | <% end %> 9 | <% end %> 10 | -------------------------------------------------------------------------------- /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 | end 19 | 20 | class ASTNode 21 | def accept(visitor) 22 | if visitor.visit_any self 23 | if visitor.visit self 24 | accept_children visitor 25 | end 26 | visitor.end_visit self 27 | visitor.end_visit_any self 28 | end 29 | end 30 | 31 | def accept_children(visitor) 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /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/crypto/bcrypt/base64_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "secure_random" 3 | require "crypto/bcrypt/base64" 4 | 5 | describe Crypto::Bcrypt::Base64 do 6 | eqs = {"61dbe7dd1eddc479" => "LhDiWkS1XEOvXUPiWxO1MO", 7 | "e2a61a8db1245853" => "XRHfLhDfMEPgKRGyLRezKu", 8 | "e99508d693789c3f" => "XRi3LR.2XBW3Kxa2MUKxXe", 9 | "d2812979024320c4" => "XBG2KRG3LxiuKhOxKh/hL."} 10 | 11 | eqs.each do |a, b| 12 | it "encode #{a.inspect} to #{b.inspect}" do 13 | Crypto::Bcrypt::Base64.encode(a).should eq(b) 14 | end 15 | it "decode from #{b.inspect} to #{a.inspect}" do 16 | Crypto::Bcrypt::Base64.decode(b).should eq(a) 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /src/gc/null.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | fun __crystal_malloc(size : UInt32) : Void* 3 | LibC.malloc(LibC::SizeT.cast(size)) 4 | end 5 | 6 | # :nodoc: 7 | fun __crystal_malloc_atomic(size : UInt32) : Void* 8 | LibC.malloc(LibC::SizeT.cast(size)) 9 | end 10 | 11 | # :nodoc: 12 | fun __crystal_realloc(ptr : Void*, size : UInt32) : Void* 13 | LibC.realloc(ptr, LibC::SizeT.cast(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 | -------------------------------------------------------------------------------- /samples/curses/hello.cr: -------------------------------------------------------------------------------- 1 | # Copied without modifications from: https://github.com/ruby/curses/blob/master/sample/hello.rb 2 | 3 | require "curses" 4 | include Curses 5 | 6 | def show_message(message) 7 | width = message.length + 6 8 | win = Window.new(5, width, 9 | (lines - 5) / 2, (cols - width) / 2) 10 | win.box(0.chr, 0.chr) 11 | win.setpos(2, 3) 12 | win.addstr(message) 13 | win.refresh 14 | win.getch 15 | win.close 16 | end 17 | 18 | init_screen 19 | begin 20 | crmode 21 | # show_message("Hit any key") 22 | setpos((lines - 5) / 2, (cols - 10) / 2) 23 | addstr("Hit any key") 24 | refresh 25 | getch 26 | show_message("Hello, World!") 27 | refresh 28 | ensure 29 | close_screen 30 | end 31 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.length == 3 21 | end 22 | )) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /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/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/tempfile.cr: -------------------------------------------------------------------------------- 1 | lib LibC 2 | fun mkstemp(result : Char*) : Int 3 | end 4 | 5 | class Tempfile < FileDescriptorIO 6 | def initialize(name) 7 | if tmpdir = ENV["TMPDIR"]? 8 | tmpdir = tmpdir + File::SEPARATOR unless tmpdir.ends_with? File::SEPARATOR 9 | else 10 | tmpdir = "/tmp/" 11 | end 12 | @path = "#{tmpdir}#{name}.XXXXXX" 13 | super(LibC.mkstemp(@path), blocking: true) 14 | end 15 | 16 | getter path 17 | 18 | def self.open(filename) 19 | tempfile = Tempfile.new(filename) 20 | begin 21 | yield tempfile 22 | ensure 23 | tempfile.close 24 | end 25 | tempfile 26 | end 27 | 28 | def delete 29 | File.delete(@path) 30 | end 31 | 32 | def unlink 33 | delete 34 | end 35 | end 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 | def run_filter(in_chan, out_chan, prime) 21 | spawn { filter(in_chan, out_chan, prime) } 22 | end 23 | 24 | ch = Channel(Int32).new 25 | spawn { generate(ch) } 26 | 27 | 100.times do 28 | prime = ch.receive 29 | puts prime 30 | ch1 = Channel(Int32).new 31 | run_filter(ch, ch1, prime) 32 | ch = ch1 33 | end 34 | -------------------------------------------------------------------------------- /src/curses/window.cr: -------------------------------------------------------------------------------- 1 | struct Curses::Window 2 | def self.new(height, width, top, left) 3 | new LibCurses.newwin(height, width, top, left) 4 | end 5 | 6 | def initialize(@unwrap : LibCurses::Window) 7 | end 8 | 9 | def box(vert : Char, hor : Char) 10 | LibCurses.box self, LibCurses::Chtype.cast(vert.ord), LibCurses::Chtype.cast(hor.ord) 11 | end 12 | 13 | def setpos(x, y) 14 | LibCurses.wmove self, x, y 15 | end 16 | 17 | def addstr(str) 18 | LibCurses.waddstr self, str 19 | end 20 | 21 | def getch 22 | LibCurses.wgetch self 23 | end 24 | 25 | def refresh 26 | LibCurses.wrefresh self 27 | end 28 | 29 | def close 30 | LibCurses.delwin self 31 | end 32 | 33 | def to_unsafe 34 | @unwrap 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /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.path} - #{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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/curses/lib_curses.cr: -------------------------------------------------------------------------------- 1 | @[Link("ncurses")] 2 | lib LibCurses 3 | type Window = Void* 4 | 5 | alias Int = LibC::Int 6 | alias Char = LibC::Char 7 | alias Chtype = LibC::UInt 8 | 9 | $lines = LINES : Int 10 | $cols = COLS : Int 11 | 12 | fun initscr : Window 13 | fun printw(...) 14 | fun refresh 15 | fun getch : Int 16 | fun cbreak : Int 17 | fun move(x : Int, y : Int) : Int 18 | fun wmove(w : Window, x : Int, y : Int) : Int 19 | fun addstr(s : Char*) : Int 20 | fun waddstr(w : Window, s : Char*) : Int 21 | fun newwin(height : Int, width : Int, top : Int, left : Int) : Window 22 | fun box(w : Window, v : Chtype, h : Chtype) : Int 23 | fun endwin 24 | 25 | fun delwin(window : Window) 26 | fun wrefresh(window : Window) 27 | fun wgetch(window : Window) : Int 28 | end 29 | -------------------------------------------------------------------------------- /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/yaml/yaml.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module YAML 4 | # Exception thrown on a YAML parse error. 5 | class ParseException < Exception 6 | getter line_number 7 | getter column_number 8 | 9 | def initialize(message, @line_number, @column_number) 10 | super "#{message} at #{@line_number}:#{@column_number}" 11 | end 12 | end 13 | 14 | alias Type = String | Hash(Type, Type) | Array(Type) | Nil 15 | alias EventKind = LibYAML::EventType 16 | 17 | def self.load(data) 18 | parser = YAML::Parser.new(data) 19 | begin 20 | parser.parse 21 | ensure 22 | parser.close 23 | end 24 | end 25 | 26 | def self.load_all(data) 27 | parser = YAML::Parser.new(data) 28 | begin 29 | parser.parse_all 30 | ensure 31 | parser.close 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/llvm/jit_compiler.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::JITCompiler 2 | def initialize(mod) 3 | # if LibLLVM.create_jit_compiler_for_module(out @unwrap, mod, 3, out error) != 0 4 | if LibLLVM.create_mc_jit_compiler_for_module(out @unwrap, mod, nil, 0_u32, out error) != 0 5 | raise String.new(error) 6 | end 7 | end 8 | 9 | def run_function(func) 10 | ret = LibLLVM.run_function(self, func, 0, nil) 11 | GenericValue.new(ret) 12 | end 13 | 14 | def run_function(func, args : Array(LLVM::GenericValue)) 15 | ret = LibLLVM.run_function(self, func, args.length, (args.buffer as LibLLVM::GenericValueRef*)) 16 | GenericValue.new(ret) 17 | end 18 | 19 | def get_pointer_to_global(value) 20 | LibLLVM.get_pointer_to_global(self, value) 21 | end 22 | 23 | def to_unsafe 24 | @unwrap 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /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 | 28 | -------------------------------------------------------------------------------- /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/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 | NOERROR | NOWARNING 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /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/std/crystal/project_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "crystal/project" 3 | 4 | module Crystal 5 | describe "Project" do 6 | describe "dsl" do 7 | it "adds GitHub dependency" do 8 | project = Project.new 9 | project.eval do 10 | deps do 11 | github "owner/repo" 12 | end 13 | end 14 | project.dependencies.length.should eq(1) 15 | project.dependencies[0].should be_a(GitHubDependency) 16 | end 17 | 18 | it "adds local dependencies" do 19 | project = Project.new 20 | project.eval do 21 | deps do 22 | path "../path" 23 | end 24 | end 25 | 26 | project.dependencies.length.should eq(1) 27 | project.dependencies[0].should be_a(PathDependency) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /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/curses/curses.cr: -------------------------------------------------------------------------------- 1 | require "./*" 2 | 3 | module Curses 4 | extend self 5 | 6 | def init_screen 7 | @@stdscr ||= begin 8 | stdscr = LibCurses.initscr 9 | unless stdscr 10 | raise "Couldn't initialize ncurses" 11 | end 12 | Window.new stdscr 13 | end 14 | end 15 | 16 | def stdscr 17 | init_screen 18 | end 19 | 20 | def refresh 21 | LibCurses.refresh 22 | end 23 | 24 | def getch 25 | LibCurses.getch 26 | end 27 | 28 | def crmode 29 | LibCurses.cbreak 30 | end 31 | 32 | def lines 33 | LibCurses.lines 34 | end 35 | 36 | def cols 37 | LibCurses.cols 38 | end 39 | 40 | def setpos(x, y) 41 | LibCurses.move(x, y) 42 | end 43 | 44 | def addstr(str) 45 | LibCurses.addstr str 46 | end 47 | 48 | def close_screen 49 | LibCurses.endwin 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /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 alias to scalar" do 19 | doc = YAML.load("---\n- &x foo\n- *x\n") as Array 20 | doc.should eq(["foo", "foo"]) 21 | doc[0].should be(doc[1]) 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /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 | 16 | RUN PATH=$PATH:/opt/llvm-3.5.0-1/bin ./bin/crystal build --release src/compiler/crystal.cr 17 | 18 | ENV LIBRARY_PATH /opt/crystal/embedded/lib 19 | ENV PATH /opt/crystal-head:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 20 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/llvm/function_pass_manager.cr: -------------------------------------------------------------------------------- 1 | struct 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 | struct Runner 35 | def initialize(@fpm) 36 | end 37 | 38 | def run(f : LLVM::Function) 39 | LibLLVM.run_function_pass_manager(@fpm, f) != 0 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /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 | 11 | all: crystal 12 | spec: all_spec 13 | $(O)/all_spec 14 | doc: 15 | $(BUILD_PATH) ./bin/crystal doc docs/main.cr 16 | 17 | crystal: $(O)/crystal 18 | all_spec: $(O)/all_spec 19 | 20 | $(O)/all_spec: $(SOURCES) $(SPEC_SOURCES) 21 | @mkdir -p $(O) 22 | $(BUILD_PATH) ./bin/crystal build $(FLAGS) -o $@ spec/all_spec.cr 23 | 24 | $(O)/crystal: $(SOURCES) 25 | @mkdir -p $(O) 26 | $(BUILD_PATH) $(EXPORTS) ./bin/crystal build $(FLAGS) -o $@ src/compiler/crystal.cr 27 | 28 | clean: 29 | rm -rf $(O) 30 | rm -rf ./doc 31 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/std/exception_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | module ModuleWithLooooooooooooooooooooooooooooooooooooooooooooooongName 4 | def self.foo 5 | raise "Foo" 6 | end 7 | end 8 | 9 | describe "Exception" do 10 | pending "allocates enough space for backtrace frames" do 11 | begin 12 | ModuleWithLooooooooooooooooooooooooooooooooooooooooooooooongName.foo 13 | rescue ex 14 | ex.backtrace.each do |bt| 15 | puts bt 16 | end 17 | ex.backtrace.any? {|x| x.includes? "ModuleWithLooooooooooooooooooooooooooooooooooooooooooooooongName" }.should be_true 18 | end 19 | end 20 | 21 | it "unescapes linux backtrace" do 22 | frame = "_2A_Crystal_3A__3A_Compiler_23_compile_3C_Crystal_3A__3A_Compiler_3E__3A_Nil" 23 | fixed = "\u{2A}Crystal\u{3A}\u{3A}Compiler\u{23}compile\u{3C}Crystal\u{3A}\u{3A}Compiler\u{3E}\u{3A}Nil" 24 | Exception.unescape_linux_backtrace_frame(frame).should eq(fixed) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /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 attributes 23 | LibLLVM.get_function_attr(self) 24 | end 25 | 26 | def function_type 27 | Type.new LibLLVM.get_element_type(LibLLVM.type_of(self)) 28 | end 29 | 30 | def return_type 31 | Type.new LibLLVM.get_return_type(function_type) 32 | end 33 | 34 | def varargs? 35 | LibLLVM.is_function_var_arg(function_type) != 0 36 | end 37 | 38 | def params 39 | ParameterCollection.new self 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/json/any.cr: -------------------------------------------------------------------------------- 1 | # You can use `JSON::Any` inside a `JSON::Mapping` to make a property be parsed 2 | # to a `JSON::Type`. This is useful if you have properties with dynamic content 3 | # that must later be inspected at runtime. 4 | module JSON::Any 5 | # Reads a `JSON::Type` value from the given pull parser. 6 | def self.new(pull : JSON::PullParser) 7 | case pull.kind 8 | when :null 9 | pull.read_null 10 | when :bool 11 | pull.read_bool 12 | when :int 13 | pull.read_int 14 | when :float 15 | pull.read_float 16 | when :string 17 | pull.read_string 18 | when :begin_array 19 | ary = [] of JSON::Type 20 | pull.read_array do 21 | ary << new pull 22 | end 23 | ary 24 | when :begin_object 25 | hash = {} of String => JSON::Type 26 | pull.read_object do |key| 27 | hash[key] = new pull 28 | end 29 | hash 30 | else 31 | raise "Unknown pull kind: #{pull.kind}" 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /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 | 11 | it "can be compared with another symbol" do 12 | :s.between?(:a, :z).should be_true 13 | :a.between?(:s, :z).should be_false 14 | (:foo > :bar).should be_true 15 | (:foo < :bar).should be_false 16 | 17 | 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) 18 | 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) 19 | a.sort.should eq(b) 20 | end 21 | 22 | it "displays symbols that don't need quotes without quotes" do 23 | a = %i(+ - * / == < <= > >= ! != =~ !~ & | ^ ~ ** >> << % [] <=> === []? []=) 24 | b = "[:+, :-, :*, :/, :==, :<, :<=, :>, :>=, :!, :!=, :=~, :!~, :&, :|, :^, :~, :**, :>>, :<<, :%, :[], :<=>, :===, :[]?, :[]=]" 25 | a.inspect.should eq(b) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /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 = CharReader.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 | -------------------------------------------------------------------------------- /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.length.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 | -------------------------------------------------------------------------------- /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.length).map do |i| 9 | v = 0.0_f64 10 | (0...u.length).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.length).map do |i| 19 | v = 0.0_f64 20 | (0...u.length).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/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 = StringIO.new("hello") 7 | 8 | argf = IO::ARGF.new argv, stdin 9 | argf.path.should eq("-") 10 | argf.read.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 = StringIO.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.read(5) 25 | str.should eq("12345") 26 | 27 | argv.should eq([path2]) 28 | 29 | str = argf.read 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.read(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/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/socket/tcp_socket.cr: -------------------------------------------------------------------------------- 1 | require "./ip_socket" 2 | 3 | class TCPSocket < IPSocket 4 | def initialize(host, port, dns_timeout = nil, connect_timeout = nil) 5 | getaddrinfo(host, port, nil, LibC::SOCK_STREAM, LibC::IPPROTO_TCP, timeout: dns_timeout) do |ai| 6 | super(create_socket(ai.family, ai.socktype, ai.protocol)) 7 | 8 | if err = nonblocking_connect host, port, ai, timeout: connect_timeout 9 | close 10 | next false if ai.next 11 | raise err 12 | end 13 | 14 | true 15 | end 16 | end 17 | 18 | def initialize(fd : Int32) 19 | super fd 20 | end 21 | 22 | def self.open(host, port) 23 | sock = new(host, port) 24 | begin 25 | yield sock 26 | ensure 27 | sock.close 28 | end 29 | end 30 | 31 | def tcp_nodelay? 32 | v = 0 33 | ret = getsockopt LibC::TCP_NODELAY, v, level: LibC::IPPROTO_TCP 34 | ret != 0 35 | end 36 | 37 | def tcp_nodelay= val : Bool 38 | v = val ? 1 : 0 39 | setsockopt LibC::TCP_NODELAY, v, level: LibC::IPPROTO_TCP 40 | val 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /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.length 5 | n = a[0].length 6 | p = b[0].length 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/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 length correctly" do 21 | assert_type("require \"prelude\"; [1].length") { 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 | -------------------------------------------------------------------------------- /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 += length if index < 0 13 | 14 | unless 0 <= index < length 15 | raise IndexError.new 16 | end 17 | 18 | internal_at(index) 19 | end 20 | 21 | def each 22 | length.times do |i| 23 | yield internal_at(i) 24 | end 25 | end 26 | 27 | def empty? 28 | length == 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 length 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/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 | -------------------------------------------------------------------------------- /src/prelude.cr: -------------------------------------------------------------------------------- 1 | require "intrinsics" 2 | require "libc" 3 | require "macros" 4 | require "object" 5 | require "reference" 6 | require "exception" 7 | require "value" 8 | require "struct" 9 | require "proc" 10 | require "thread" 11 | require "gc" 12 | # require "gc/null" 13 | require "gc/boehm" 14 | require "class" 15 | require "comparable" 16 | require "enumerable" 17 | require "iterable" 18 | require "iterator" 19 | require "nil" 20 | require "bool" 21 | require "char" 22 | require "number" 23 | require "int" 24 | require "float" 25 | require "pointer" 26 | require "slice" 27 | require "range" 28 | require "char_reader" 29 | require "string" 30 | require "symbol" 31 | require "enum" 32 | require "static_array" 33 | require "array" 34 | require "hash" 35 | require "set" 36 | require "tuple" 37 | require "box" 38 | require "math/math" 39 | require "process" 40 | require "io" 41 | require "env" 42 | require "file" 43 | require "dir" 44 | require "time" 45 | require "random" 46 | require "regex" 47 | require "raise" 48 | require "errno" 49 | require "concurrent" 50 | require "signal" 51 | require "kernel" 52 | require "main" 53 | -------------------------------------------------------------------------------- /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/std/http/client_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "http/client" 3 | 4 | module HTTP 5 | describe Client do 6 | {% for method in %w(get post put head delete patch) %} 7 | typeof(Client.{{method.id}} "url") 8 | typeof(Client.new("host")) 9 | typeof(Client.new("host", port: 8080)) 10 | typeof(Client.new("host", ssl: true)) 11 | typeof(Client.new("host").{{method.id}}("uri")) 12 | typeof(Client.new("host").{{method.id}}("uri", headers: Headers {"Content-Type": "text/plain"})) 13 | typeof(Client.new("host").{{method.id}}("uri", body: "body")) 14 | {% end %} 15 | 16 | typeof(Client.post_form "url", {"a": "b"}) 17 | typeof(Client.new("host").basic_auth("username", "password")) 18 | typeof(Client.new("host").before_request { |req| HTTP::Response.ok("text/plain", "OK") }) 19 | typeof(Client.new("host").close) 20 | typeof(Client.get(URI.parse("http://www.example.com"))) 21 | 22 | it "raises if URI is missing scheme" do 23 | expect_raises(ArgumentError) do 24 | HTTP::Client.get "www.example.com" 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /src/crystal/project/path_dependency.cr: -------------------------------------------------------------------------------- 1 | require "crystal/project/dependency" 2 | require "crystal/project/project_error" 3 | 4 | module Crystal 5 | class PathDependency < Dependency 6 | def initialize(@path, name = nil) 7 | unless @path =~ /(.*\/)*(.*)/ 8 | raise ProjectError.new("Invalid path name: #{path}") 9 | end 10 | 11 | super(name || $2) 12 | 13 | @target_dir = "libs/#{@name}" 14 | end 15 | 16 | def install 17 | unless Dir.exists?(@target_dir) 18 | exec "ln -sf ../#{@path}/src #{@target_dir}" 19 | end 20 | 21 | @locked_version = current_version 22 | end 23 | 24 | def update 25 | exec "rm -rf libs/#{@path}" 26 | install 27 | end 28 | 29 | def current_version 30 | ref = `git -C #{@path} rev-parse HEAD 2>/dev/null`.chomp 31 | ref == "" || ref == "HEAD" ? "local" : ref 32 | end 33 | 34 | private def exec(cmd) 35 | result = `#{cmd}` 36 | unless $?.success? 37 | puts "Error executing command: #{cmd}" 38 | exit 1 39 | end 40 | result 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /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 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 | -------------------------------------------------------------------------------- /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.length 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.length 28 | LibSSL.ssl_write(@ssl, slice.pointer(count), count) 29 | end 30 | 31 | def close 32 | begin 33 | while LibSSL.ssl_shutdown(@ssl) == 0; end 34 | rescue IO::Error 35 | end 36 | end 37 | 38 | def self.open_client(io, context = Context.default) 39 | ssl_sock = new(io, :client, context) 40 | begin 41 | yield ssl_sock 42 | ensure 43 | ssl_sock.close 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /spec/std/crystal/path_dependency_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "crystal/project/path_dependency" 3 | 4 | module Crystal 5 | describe "PathDependency" do 6 | describe "#initialize" do 7 | it "uses the directory's name as the dependency name" do 8 | dependency = PathDependency.new("../path") 9 | 10 | dependency.name.should eq("path") 11 | end 12 | 13 | it "customizes path dependency name" do 14 | dependency = PathDependency.new("../path", "name") 15 | 16 | dependency.name.should eq("name") 17 | end 18 | 19 | %w(crystal_repo crystal-repo repo.cr repo_crystal repo-crystal).each do |repo_name| 20 | it "guesses name from project name like #{repo_name}" do 21 | dependency = PathDependency.new("owner/#{repo_name}") 22 | 23 | dependency.name.should eq("repo") 24 | end 25 | 26 | it "doesn't guess name from project name when specifying name" do 27 | dependency = PathDependency.new("owner/#{repo_name}", "name") 28 | 29 | dependency.name.should eq("name") 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /src/llvm/pass_manager_builder.cr: -------------------------------------------------------------------------------- 1 | struct 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.to_u32 8 | end 9 | 10 | def size_level=(level) 11 | LibLLVM.pass_manager_builder_set_size_level self, level.to_u32 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.to_u32 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 | end 38 | -------------------------------------------------------------------------------- /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 line to your application's `Projectfile`: 9 | 10 | ```crystal 11 | deps do 12 | github "[your-github-name]/<%= config.name %>" 13 | end 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/[your-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 | - [your-github-name](https://github.com/[your-github-name]) <%= config.author %> - creator, maintainer 44 | -------------------------------------------------------------------------------- /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.length.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.length.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.length.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.length.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 | -------------------------------------------------------------------------------- /src/llvm/parameter_collection.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::ParameterCollection 2 | def initialize(@function) 3 | end 4 | 5 | def count 6 | LibLLVM.count_param_types(@function.function_type).to_i 7 | end 8 | 9 | def length 10 | count 11 | end 12 | 13 | def size 14 | count 15 | end 16 | 17 | def to_a 18 | param_count = count() 19 | Array(LLVM::Value).build(param_count) do |buffer| 20 | LibLLVM.get_params(@function, buffer as LibLLVM::ValueRef*) 21 | param_count 22 | end 23 | end 24 | 25 | def [](index) 26 | param_count = count() 27 | index += param_count if index < 0 28 | 29 | unless 0 <= index < param_count 30 | raise IndexError.new 31 | end 32 | 33 | Value.new LibLLVM.get_param(@function, index) 34 | end 35 | 36 | def first 37 | raise IndexError.new if count == 0 38 | 39 | Value.new LibLLVM.get_param(@function, 0) 40 | end 41 | 42 | def types 43 | param_count = count() 44 | Array(LLVM::Type).build(param_count) do |buffer| 45 | LibLLVM.get_param_types(@function.function_type, buffer as LibLLVM::TypeRef*) 46 | param_count 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /src/http/request.cr: -------------------------------------------------------------------------------- 1 | require "./common" 2 | require "uri" 3 | 4 | class HTTP::Request 5 | getter method 6 | getter path 7 | getter headers 8 | getter body 9 | getter version 10 | 11 | def initialize(@method : String, @path, @headers = Headers.new : Headers, @body = nil, @version = "HTTP/1.1") 12 | if body = @body 13 | @headers["Content-length"] = body.bytesize.to_s 14 | elsif @method == "POST" || @method == "PUT" 15 | @headers["Content-length"] = "0" 16 | end 17 | end 18 | 19 | def uri 20 | URI.parse(@path) 21 | end 22 | 23 | def keep_alive? 24 | HTTP.keep_alive?(self) 25 | end 26 | 27 | def to_io(io) 28 | io << @method << " " << @path << " " << @version << "\r\n" 29 | HTTP.serialize_headers_and_body(io, @headers, @body) 30 | end 31 | 32 | def self.from_io(io) 33 | request_line = io.gets 34 | return unless request_line 35 | 36 | method, path, http_version = request_line.split 37 | HTTP.parse_headers_and_body(io) do |headers, body| 38 | return new method, path, headers, body.try &.read, http_version 39 | end 40 | 41 | # Unexpected end of http request 42 | nil 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | end 32 | -------------------------------------------------------------------------------- /src/random.cr: -------------------------------------------------------------------------------- 1 | require "random/mt19937" 2 | 3 | module Random 4 | DEFAULT = MT19937.new 5 | 6 | def self.new_seed 7 | Intrinsics.read_cycle_counter.to_u32 8 | end 9 | 10 | def self.new(seed = new_seed) 11 | MT19937.new(seed) 12 | end 13 | 14 | abstract def next_u32 15 | 16 | def next_bool 17 | next_u32.even? 18 | end 19 | 20 | def next_int 21 | next_u32.to_i32 22 | end 23 | 24 | def next_float 25 | # Divided by 2^32-1 26 | next_u32 * (1.0/4294967295.0) 27 | end 28 | 29 | def rand 30 | next_float 31 | end 32 | 33 | def rand(x : Int) 34 | if x > 0 35 | (next_u32 % x).to_i32 36 | else 37 | raise ArgumentError.new "incorrect rand value: #{x}" 38 | end 39 | end 40 | 41 | def rand(x : Range(Int, Int)) 42 | span = x.end - x.begin 43 | span += 1 unless x.excludes_end? 44 | if span > 0 45 | x.begin + rand(span) 46 | else 47 | raise ArgumentError.new "incorrect rand value: #{x}" 48 | end 49 | end 50 | 51 | def self.rand 52 | DEFAULT.rand 53 | end 54 | 55 | def self.rand(x) 56 | DEFAULT.rand(x) 57 | end 58 | end 59 | 60 | def rand 61 | Random.rand 62 | end 63 | 64 | def rand(x) 65 | Random.rand(x) 66 | end 67 | -------------------------------------------------------------------------------- /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.length, data_slice, LibC::SizeT.cast(data_slice.length), 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 | -------------------------------------------------------------------------------- /spec/std/crypto/blowfish_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "crypto/blowfish" 3 | 4 | describe "Blowfish" do 5 | it "encrypt pair and decrypt pair" do 6 | bf = Crypto::Blowfish.new("Who is John Galt?") 7 | orig_l, orig_r = 0xfedcba98, 0x76543210 8 | 9 | l, r = bf.encrypt_pair(orig_l, orig_r) 10 | l.should eq(0xcc91732b) 11 | r.should eq(0x8022f684) 12 | 13 | l, r = bf.decrypt_pair(l, r) 14 | l.should eq(orig_l) 15 | r.should eq(orig_r) 16 | end 17 | 18 | it "raises if the key is empty" do 19 | expect_raises ArgumentError, /Invalid key size/ do 20 | Crypto::Blowfish.new("") 21 | end 22 | end 23 | 24 | it "raises if the key length is bigger than 56" do 25 | expect_raises ArgumentError, /Invalid key size/ do 26 | Crypto::Blowfish.new("a" * 57) 27 | end 28 | end 29 | 30 | it "folds the salt during the key schedule" do 31 | length = 32 32 | salt = String.build {|io| length.times {|i| io << (i + length).chr} } 33 | orig_l, orig_r = 0x00, 0x00 34 | 35 | bf = Crypto::Blowfish.new 36 | bf.salted_expand_key("a" * length, salt) 37 | 38 | l, r = bf.encrypt_pair(orig_l, orig_r) 39 | l.should eq(0xc8f07bef) 40 | r.should eq(0x57deba64) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /samples/impl.cr: -------------------------------------------------------------------------------- 1 | class A 2 | property lorem 3 | def foo 4 | 1 5 | end 6 | end 7 | 8 | class B 9 | def foo 10 | 2 11 | end 12 | end 13 | 14 | def bar(o) 15 | while false 16 | o.foo 17 | end 18 | end 19 | 20 | def baz(o) 21 | o.foo 22 | end 23 | 24 | puts bar(A.new) 25 | puts bar(B.new) 26 | puts baz(A.new) 27 | 28 | A.new.lorem 29 | 30 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:16:8 31 | # 32 | # 2 implementations found 33 | # .../samples/impl.cr:3:3 34 | # .../samples/impl.cr:9:3 35 | 36 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:21:5 37 | # 38 | # 1 implementation found 39 | # .../samples/impl.cr:3:3 40 | 41 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:24:7 42 | # 43 | # 1 implementation found 44 | # .../samples/impl.cr:14:1 45 | 46 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:26:3 47 | # 48 | # 1 implementation found 49 | # .../src/kernel.cr:67:1 50 | 51 | # ./crystal tool implementations samples/impl.cr --cursor samples/impl.cr:28:9 52 | # 53 | # 1 implementation found 54 | # .../samples/impl.cr:2:3 55 | # ~> macro property: .../src/object.cr:364:5 56 | # ~> macro getter: .../src/object.cr:207:7 57 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 length 15 | count 16 | end 17 | 18 | def [](index : Int) 19 | length = self.length 20 | 21 | index += length if index < 0 22 | 23 | unless 0 <= index < length 24 | raise IndexError.new 25 | end 26 | 27 | each_with_index do |node, i| 28 | return node if i == index 29 | end 30 | 31 | raise IndexError.new 32 | end 33 | 34 | def [](name : String) 35 | self[name]? || raise KeyError.new("Missing attribute: #{name}") 36 | end 37 | 38 | def []?(name : String) 39 | find { |node| node.name == name } 40 | end 41 | 42 | def each 43 | return unless @node.element? 44 | 45 | props = self.props() 46 | until props.nil? 47 | yield Node.new(props) 48 | props = props.value.next 49 | end 50 | end 51 | 52 | def to_s(io) 53 | io << "[" 54 | join ", ", io, &.inspect(io) 55 | io << "]" 56 | end 57 | 58 | def inspect(io) 59 | to_s(io) 60 | end 61 | 62 | protected def props 63 | @node.to_unsafe.value.properties 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/std/env_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | 3 | describe "ENV" do 4 | it "gets non existent key raises" do 5 | expect_raises KeyError, "Missing ENV key: NON-EXISTENT" do 6 | ENV["NON-EXISTENT"] 7 | end 8 | end 9 | 10 | it "gets non existent key as nilable" do 11 | ENV["NON-EXISTENT"]?.should be_nil 12 | end 13 | 14 | it "set and gets" do 15 | (ENV["FOO"] = "1").should eq("1") 16 | ENV["FOO"].should eq("1") 17 | ENV["FOO"]?.should eq("1") 18 | end 19 | 20 | it "does has_key?" do 21 | ENV["FOO"] = "1" 22 | ENV.has_key?("BAR").should be_false 23 | ENV.has_key?("FOO").should be_true 24 | end 25 | 26 | it "deletes a key" do 27 | ENV["FOO"] = "1" 28 | ENV.delete("FOO").should eq("1") 29 | ENV.delete("FOO").should be_nil 30 | ENV.has_key?("FOO").should be_false 31 | end 32 | 33 | it "does .keys" do 34 | %w[FOO BAR].each {|k| ENV.keys.should_not contain(k) } 35 | ENV["FOO"] = ENV["BAR"] = "1" 36 | %w[FOO BAR].each {|k| ENV.keys.should contain(k) } 37 | end 38 | 39 | it "does .values" do 40 | [1,2].each {|i| ENV.values.should_not contain("SOMEVALUE_#{i}") } 41 | ENV["FOO"] = "SOMEVALUE_1" 42 | ENV["BAR"] = "SOMEVALUE_2" 43 | [1,2].each {|i| ENV.values.should contain("SOMEVALUE_#{i}") } 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /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 String.new(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 | -------------------------------------------------------------------------------- /src/secure_random.cr: -------------------------------------------------------------------------------- 1 | require "base64" 2 | require "openssl/lib_crypto" 3 | 4 | module SecureRandom 5 | def self.base64(n = 16) 6 | Base64.strict_encode(random_bytes(n)) 7 | end 8 | 9 | def self.urlsafe_base64(n = 16, padding = false) 10 | Base64.urlsafe_encode(random_bytes(n), padding) 11 | end 12 | 13 | def self.hex(n = 16) 14 | random_bytes(n).hexstring 15 | end 16 | 17 | def self.random_bytes(n = 16) 18 | if n < 0 19 | raise ArgumentError.new "negative size: #{n}" 20 | end 21 | 22 | slice = Slice(UInt8).new(n) 23 | result = LibCrypto.rand_bytes slice, n 24 | if result != 1 25 | error = LibCrypto.err_get_error 26 | error_string = String.new LibCrypto.err_error_string(error, nil) 27 | raise error_string 28 | end 29 | slice 30 | end 31 | 32 | def self.uuid 33 | bytes = random_bytes(16) 34 | bytes[6] = (bytes[6] & 0x0f) | 0x40 35 | bytes[8] = (bytes[8] & 0x3f) | 0x80 36 | 37 | String.new(36) do |buffer| 38 | buffer[8] = buffer[13] = buffer[18] = buffer[23] = 45_u8 39 | bytes[0, 4].hexstring(buffer + 0) 40 | bytes[4, 2].hexstring(buffer + 9) 41 | bytes[6, 2].hexstring(buffer + 14) 42 | bytes[8, 2].hexstring(buffer + 19) 43 | bytes[10, 6].hexstring(buffer + 24) 44 | {36, 36} 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /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/ecr/ecr.cr: -------------------------------------------------------------------------------- 1 | module ECR 2 | extend self 3 | 4 | DefaultBufferName = "__str__" 5 | 6 | def process_file(filename, buffer_name = DefaultBufferName) 7 | process_string File.read(filename), filename, buffer_name 8 | end 9 | 10 | def process_string(string, filename, buffer_name = DefaultBufferName) 11 | lexer = Lexer.new string 12 | 13 | String.build do |str| 14 | while true 15 | token = lexer.next_token 16 | case token.type 17 | when :STRING 18 | str << buffer_name 19 | str << " << " 20 | token.value.inspect(str) 21 | str << "\n" 22 | when :OUTPUT 23 | str << "(" 24 | append_loc(str, filename, token) 25 | str << token.value 26 | str << ").to_s " 27 | str << buffer_name 28 | str << "\n" 29 | when :CONTROL 30 | append_loc(str, filename, token) 31 | str << token.value 32 | str << "\n" 33 | when :EOF 34 | break 35 | end 36 | end 37 | end 38 | end 39 | 40 | private def append_loc(str, filename, token) 41 | str << %(#) 48 | end 49 | end 50 | 51 | require "./lexer" 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/llvm/module.cr: -------------------------------------------------------------------------------- 1 | struct LLVM::Module 2 | getter :unwrap 3 | 4 | def initialize(name) 5 | @unwrap = LibLLVM.module_create_with_name name 6 | end 7 | 8 | def target=(target) 9 | LibLLVM.set_target(self, target) 10 | end 11 | 12 | def data_layout=(data) 13 | LibLLVM.set_data_layout(self, data) 14 | end 15 | 16 | def dump 17 | LibLLVM.dump_module(self) 18 | end 19 | 20 | def functions 21 | FunctionCollection.new(self) 22 | end 23 | 24 | def globals 25 | GlobalCollection.new(self) 26 | end 27 | 28 | def write_bitcode(filename : String) 29 | LibLLVM.write_bitcode_to_file self, filename 30 | end 31 | 32 | def verify 33 | if LibLLVM.verify_module(self, LLVM::VerifierFailureAction::ReturnStatusAction, out message) == 1 34 | raise "Module validation failed: #{String.new(message)}" 35 | end 36 | end 37 | 38 | def print_to_file(filename) 39 | if LibLLVM.print_module_to_file(self, filename, out error_msg) != 0 40 | raise String.new(error_msg) 41 | end 42 | self 43 | end 44 | 45 | def new_function_pass_manager 46 | FunctionPassManager.new LibLLVM.create_function_pass_manager_for_module(self) 47 | end 48 | 49 | def inspect(io) 50 | LLVM.to_io(LibLLVM.print_module_to_string(self), io) 51 | self 52 | end 53 | 54 | def to_unsafe 55 | @unwrap 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /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 | Box(IO).unbox(ctx).read Slice.new(buffer, len) 10 | len 11 | }, 12 | ->(ctx) { 0 }, 13 | Box(IO).box(io), 14 | nil, 15 | nil, 16 | options, 17 | ) 18 | end 19 | 20 | def self.parse_html(string : String, options = HTMLParserOptions.default : HTMLParserOptions) 21 | from_ptr LibXML.htmlReadMemory(string, string.bytesize, nil, nil, options) 22 | end 23 | 24 | def self.parse_html(io : IO, options = HTMLParserOptions.default : HTMLParserOptions) 25 | from_ptr LibXML.htmlReadIO( 26 | ->(ctx, buffer, len) { 27 | Box(IO).unbox(ctx).read Slice.new(buffer, len) 28 | len 29 | }, 30 | ->(ctx) { 0 }, 31 | Box(IO).box(io), 32 | nil, 33 | nil, 34 | options, 35 | ) 36 | end 37 | 38 | protected def self.from_ptr(doc : LibXML::DocPtr) 39 | if doc 40 | Node.new doc 41 | else 42 | raise Error.new LibXML.xmlGetLastError 43 | end 44 | end 45 | end 46 | 47 | require "./*" 48 | 49 | -------------------------------------------------------------------------------- /spec/compiler/type_inference/if_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Type inference: if" do 4 | it "types an if without else" do 5 | assert_type("if 1 == 1; 1; end") { |mod| union_of(int32, mod.nil) } 6 | end 7 | 8 | it "types an if with else of same type" do 9 | assert_type("if 1 == 1; 1; else; 2; end") { int32 } 10 | end 11 | 12 | it "types an if with else of different type" do 13 | assert_type("if 1 == 1; 1; else; 'a'; end") { union_of(int32, char) } 14 | end 15 | 16 | it "types and if with and and assignment" do 17 | assert_type(" 18 | struct Number 19 | def abs 20 | self 21 | end 22 | end 23 | 24 | class Foo 25 | def coco 26 | @a = 1 || nil 27 | if (b = @a) && 1 == 1 28 | b.abs 29 | end 30 | end 31 | end 32 | 33 | Foo.new.coco 34 | ") { |mod| union_of(int32, mod.nil) } 35 | end 36 | 37 | it "can invoke method on var that is declared on the right hand side of an and" do 38 | assert_type(" 39 | if 1 == 2 && (b = 1) 40 | b + 1 41 | end 42 | ") { |mod| union_of(int32, mod.nil) } 43 | end 44 | 45 | it "errors if requires inside if" do 46 | assert_error %( 47 | if 1 == 2 48 | require "foo" 49 | end 50 | ), 51 | "can't require dynamically" 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /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_wait = pthread_cond_wait(cond : Cond*, mutext : Mutex*) : Int 39 | fun cond_destroy = pthread_cond_destroy(cond : Cond*) : Int 40 | end 41 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/compiler/codegen/generic_class_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Code gen: generic class type" do 4 | it "codegens inherited generic class instance var" do 5 | run(%( 6 | class Foo(T) 7 | def initialize(@x : T) 8 | end 9 | 10 | def x 11 | @x + 1 12 | end 13 | end 14 | 15 | class Bar < Foo(Int32) 16 | end 17 | 18 | Bar.new(1).x 19 | )).to_i.should eq(2) 20 | end 21 | 22 | it "instantiates generic class with default argument in initialize (#394)" do 23 | run(%( 24 | class Foo(T) 25 | def initialize(@x = 1) 26 | end 27 | 28 | def x 29 | @x 30 | end 31 | end 32 | 33 | Foo(Int32).new.x + 1 34 | )).to_i.should eq(2) 35 | end 36 | 37 | it "allows initializing instance variable (#665)" do 38 | run(%( 39 | class SomeType(T) 40 | @x = 1 41 | 42 | def x 43 | @x 44 | end 45 | end 46 | 47 | SomeType(Char).new.x 48 | )).to_i.should eq(1) 49 | end 50 | 51 | it "allows initializing instance variable in inherited generic type" do 52 | run(%( 53 | class Foo(T) 54 | @x = 1 55 | 56 | def x 57 | @x 58 | end 59 | end 60 | 61 | class Bar(T) < Foo(T) 62 | @y = 2 63 | end 64 | 65 | Bar(Char).new.x 66 | )).to_i.should eq(1) 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /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/compiler/crystal/tools/doc/macro.cr: -------------------------------------------------------------------------------- 1 | require "html" 2 | require "./item" 3 | 4 | class Crystal::Doc::Macro 5 | include Item 6 | 7 | getter type 8 | getter :macro 9 | 10 | def initialize(@generator, @type, @macro) 11 | end 12 | 13 | def name 14 | @macro.name 15 | end 16 | 17 | def args 18 | @macro.args 19 | end 20 | 21 | def doc 22 | @macro.doc 23 | end 24 | 25 | def source_link 26 | @generator.source_link(@macro) 27 | end 28 | 29 | def id 30 | String.build do |io| 31 | io << to_s.gsub(' ', "") 32 | io << "-macro" 33 | end 34 | end 35 | 36 | def html_id 37 | HTML.escape(id) 38 | end 39 | 40 | def anchor 41 | "#" + CGI.escape(id) 42 | end 43 | 44 | def prefix 45 | "" 46 | end 47 | 48 | def abstract? 49 | false 50 | end 51 | 52 | def kind 53 | "macro " 54 | end 55 | 56 | def to_s(io) 57 | io << name 58 | args_to_s io 59 | end 60 | 61 | def args_to_s 62 | String.build { |io| args_to_s io } 63 | end 64 | 65 | def args_to_s(io) 66 | return if @macro.args.empty? 67 | 68 | io << '(' 69 | @macro.args.each_with_index do |arg, i| 70 | io << ", " if i > 0 71 | io << '*' if @macro.splat_index == i 72 | io << arg 73 | end 74 | io << ')' 75 | end 76 | 77 | def args_to_html 78 | args_to_s 79 | end 80 | 81 | def must_be_included? 82 | @generator.must_include? @macro 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | macro method_missing(name, args, block) 58 | return llvm_nil if @end 59 | 60 | @builder.{{name.id}}({{*args}}) {{block}} 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /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/llvm/target_machine.cr: -------------------------------------------------------------------------------- 1 | struct 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 | triple = String.new(triple_c) 18 | LibLLVM.dispose_message(triple_c) 19 | triple 20 | end 21 | 22 | def emit_obj_to_file(llvm_mod, filename) 23 | emit_to_file llvm_mod, filename, LLVM::CodeGenFileType::ObjectFile 24 | end 25 | 26 | def emit_asm_to_file(llvm_mod, filename) 27 | emit_to_file llvm_mod, filename, LLVM::CodeGenFileType::AssemblyFile 28 | end 29 | 30 | private def emit_to_file(llvm_mod, filename, type) 31 | status = LibLLVM.target_machine_emit_to_file(self, llvm_mod, filename, type, out error_msg) 32 | unless status == 0 33 | raise String.new(error_msg) 34 | end 35 | true 36 | end 37 | 38 | def abi 39 | triple = self.triple 40 | case triple 41 | when /x86_64/ 42 | ABI::X86_64.new(self) 43 | when /i386|i686/ 44 | ABI::X86.new(self) 45 | else 46 | raise "Unsupported ABI for target triple: #{triple}" 47 | end 48 | end 49 | 50 | def to_unsafe 51 | @unwrap 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /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/socket/unix_server.cr: -------------------------------------------------------------------------------- 1 | require "./unix_socket" 2 | 3 | class UNIXServer < UNIXSocket 4 | def initialize(@path : String, socktype = Socket::Type::STREAM : Socket::Type, backlog = 128) 5 | File.delete(path) if File.exists?(path) 6 | 7 | sock = create_socket(LibC::AF_UNIX, socktype.value, 0) 8 | 9 | addr = LibC::SockAddrUn.new 10 | addr.family = typeof(addr.family).cast(LibC::AF_UNIX) 11 | if path.bytesize + 1 > addr.path.length 12 | raise "Path length exceeds the maximum size of #{addr.path.length - 1} bytes" 13 | end 14 | addr.path.buffer.copy_from(path.cstr, path.bytesize + 1) 15 | if LibC.bind(sock, (pointerof(addr) as LibC::SockAddr*), LibC::SocklenT.cast(sizeof(LibC::SockAddrUn))) != 0 16 | LibC.close(sock) 17 | raise Errno.new("Error binding UNIX server at #{path}") 18 | end 19 | 20 | if LibC.listen(sock, backlog) != 0 21 | LibC.close(sock) 22 | raise Errno.new("Error listening UNIX server at #{path}") 23 | end 24 | 25 | super sock 26 | end 27 | 28 | def accept 29 | client_fd = LibC.accept(@fd, out client_addr, out client_addrlen) 30 | UNIXSocket.new(client_fd) 31 | end 32 | 33 | def accept 34 | sock = accept 35 | begin 36 | yield sock 37 | ensure 38 | sock.close 39 | end 40 | end 41 | 42 | def close 43 | super 44 | ensure 45 | if path = @path 46 | File.delete(path) if File.exists?(path) 47 | @path = nil 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/std/benchmark_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "benchmark" 3 | 4 | describe Benchmark::IPS::Job do 5 | it "generally works" do 6 | # test several things to avoid running a benchmark over and over again in 7 | # the specs 8 | j = Benchmark::IPS::Job.new(0.001, 0.001) 9 | a = j.report("a") { sleep 0.001 } 10 | b = j.report("b") { sleep 0.002 } 11 | 12 | j.execute 13 | 14 | # the mean should be calculated 15 | a.mean.should be > 10 16 | 17 | # one of the reports should be normalized to the fastest 18 | a.slower.should eq(1) 19 | b.slower.should be > 1 20 | end 21 | end 22 | 23 | private def create_entry 24 | Benchmark::IPS::Entry.new("label", -> { 1+1 }) 25 | end 26 | 27 | describe Benchmark::IPS::Entry, "#set_cycles" do 28 | it "sets the number of cycles needed to make 100ms" do 29 | e = create_entry 30 | e.set_cycles(2.seconds, 100) 31 | e.cycles.should eq(5) 32 | 33 | e.set_cycles(100.milliseconds, 1) 34 | e.cycles.should eq(1) 35 | end 36 | 37 | it "sets the cycles to 1 no matter what" do 38 | e = create_entry 39 | e.set_cycles(2.seconds, 1) 40 | e.cycles.should eq(1) 41 | end 42 | end 43 | 44 | describe Benchmark::IPS::Entry, "#calculate_stats" do 45 | it "correctly caculates basic stats" do 46 | e = create_entry 47 | e.calculate_stats([2, 4, 4, 4, 5, 5, 7, 9]) 48 | 49 | e.size.should eq(8) 50 | e.mean.should eq(5.0) 51 | e.variance.should eq(4.0) 52 | e.stddev.should eq(2.0) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /src/crypto/bcrypt/base64.cr: -------------------------------------------------------------------------------- 1 | # :nodoc: 2 | module Crypto::Bcrypt::Base64 3 | extend self 4 | 5 | ALPHABET = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" 6 | DECODE_TABLE = Int8[ 7 | 0, 1, 8 | 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, 9 | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10 | 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, 28, 29, 30, 31, 11 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 12 | 49, 50, 51, 52, 53, -1, -1, -1, -1, -1 13 | ] 14 | 15 | def encode(data) 16 | ::Base64.strict_encode data, ALPHABET 17 | end 18 | 19 | def decode(data) 20 | slice = data.to_slice 21 | encode_size = (slice.length * 4 / 3.0).to_i + 1 22 | 23 | String.new(encode_size) do |buf| 24 | appender = buf.appender 25 | from_base64(slice) { |byte| appender << byte } 26 | {appender.count, 0} 27 | end 28 | end 29 | 30 | private def from_base64(data) 31 | i = 0 32 | while true 33 | c1 = DECODE_TABLE[data[i]-46] 34 | i += 1 35 | c2 = DECODE_TABLE[data[i]-46] 36 | i += 1 37 | yield ((c1 << 2 | c2 >> 4) & 0xff).to_u8 38 | 39 | break if (i == data.length) 40 | 41 | c1 = c2 << 4 42 | c2 = DECODE_TABLE[data[i]-46] 43 | i += 1 44 | yield ((c1 | c2 >> 2) & 0xff).to_u8 45 | 46 | c1 = c2 << 6 47 | c2 = DECODE_TABLE[data[i]-46] 48 | i += 1 49 | yield ((c1 | c2) & 0xff).to_u8 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/std/xml/html_spec.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "xml" 3 | 4 | describe XML do 5 | it "parses HTML" do 6 | doc = XML.parse_html(%(\ 7 | 8 | 9 | 10 | Samantha 11 | 12 | 13 |

Boat

14 | 15 | 16 | )) 17 | 18 | html = doc.children[1] 19 | html.name.should eq("html") 20 | 21 | head = html.children.find { |node| node.name == "head" }.not_nil! 22 | head.name.should eq("head") 23 | 24 | title = head.children.find { |node| node.name == "title" }.not_nil! 25 | title.text.should eq("Samantha") 26 | 27 | body = html.children.find { |node| node.name == "body" }.not_nil! 28 | 29 | h1 = body.children.find { |node| node.name == "h1" }.not_nil! 30 | 31 | attrs = h1.attributes 32 | attrs.empty?.should be_false 33 | attrs.length.should eq(1) 34 | 35 | attr = attrs[0] 36 | attr.name.should eq("class") 37 | attr.content.should eq("large") 38 | attr.text.should eq("large") 39 | attr.inner_text.should eq("large") 40 | end 41 | 42 | it "parses HTML from IO" do 43 | io = StringIO.new(%(\ 44 | 45 | 46 | 47 | Samantha 48 | 49 | 50 |

Boat

51 | 52 | 53 | )) 54 | 55 | doc = XML.parse_html(io) 56 | html = doc.children[1] 57 | html.name.should eq("html") 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /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 | Scheduler.sleep(seconds) 10 | end 11 | 12 | def sleep(time : TimeSpan) 13 | sleep(time.total_seconds) 14 | end 15 | 16 | macro spawn 17 | %fiber = Fiber.new do 18 | begin 19 | {{ yield }} 20 | rescue %ex 21 | STDERR.puts "Unhandled exception:" 22 | %ex.inspect_with_backtrace STDERR 23 | STDERR.flush 24 | end 25 | end 26 | 27 | Scheduler.enqueue %fiber 28 | end 29 | 30 | # TODO: this doesn't work if a Call has a block or named arguments... yet 31 | macro spawn(exp) 32 | {% if exp.is_a?(Call) %} 33 | ->( 34 | {% for arg, i in exp.args %} 35 | __arg{{i}} : typeof({{arg}}), 36 | {% end %} 37 | ) { 38 | spawn do 39 | {{exp.name}}( 40 | {% for arg, i in exp.args %} 41 | __arg{{i}}, 42 | {% end %} 43 | ) 44 | end 45 | }.call({{*exp.args}}) 46 | {% else %} 47 | spawn do 48 | {{exp}} 49 | end 50 | {% end %} 51 | end 52 | 53 | macro parallel(*jobs) 54 | %channel = Channel(Bool).new 55 | 56 | {% for job, i in jobs %} 57 | %ret{i} = nil 58 | spawn do 59 | %ret{i} = {{job}} 60 | %channel.send true 61 | end 62 | {% end %} 63 | 64 | {{ jobs.length }}.times { %channel.receive } 65 | 66 | { 67 | {% for job, i in jobs %} 68 | %ret{i}.not_nil!, 69 | {% end %} 70 | } 71 | end 72 | -------------------------------------------------------------------------------- /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 | file_path = @publicdir + request.path 9 | if Dir.exists?(file_path) 10 | HTTP::Response.new(200, directory_listing(request.path, file_path), HTTP::Headers{"Content-Type": "text/html"}) 11 | elsif File.exists?(file_path) 12 | HTTP::Response.new(200, File.read(file_path), HTTP::Headers{"Content-Type": mime_type(file_path)}) 13 | else 14 | call_next(request) 15 | end 16 | end 17 | 18 | private def mime_type(path) 19 | case File.extname(path) 20 | when ".txt" then "text/plain" 21 | when ".htm", ".html" then "text/html" 22 | when ".css" then "text/css" 23 | when ".js" then "application/javascript" 24 | else "application/octet-stream" 25 | end 26 | end 27 | 28 | private def directory_listing(request_path, path) 29 | HTML::Builder.new.build do 30 | html do 31 | title { text "Directory listing for #{request_path}" } 32 | body do 33 | h2 { text "Directory listing for #{request_path}" } 34 | hr 35 | ul do 36 | Dir.foreach(path) do |entry| 37 | next if entry == "." || entry == ".." 38 | li do 39 | a({href: "#{request_path == "/" ? "" : request_path}/#{entry}"}) { text entry } 40 | end 41 | end 42 | end 43 | end 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /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 | CGI.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/compiler/codegen/hooks_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Code gen: hooks" do 4 | it "does inherited macro" do 5 | run(" 6 | class Foo 7 | macro inherited 8 | $x = 1 9 | end 10 | end 11 | 12 | class Bar < Foo 13 | end 14 | 15 | $x 16 | ").to_i.should eq(1) 17 | end 18 | 19 | it "does included macro" do 20 | run(" 21 | module Foo 22 | macro included 23 | $x = 1 24 | end 25 | end 26 | 27 | class Bar 28 | include Foo 29 | end 30 | 31 | $x 32 | ").to_i.should eq(1) 33 | end 34 | 35 | it "does extended macro" do 36 | run(" 37 | module Foo 38 | macro extended 39 | $x = 1 40 | end 41 | end 42 | 43 | class Bar 44 | extend Foo 45 | end 46 | 47 | $x 48 | ").to_i.should eq(1) 49 | end 50 | 51 | it "does inherited macro recursively" do 52 | run(" 53 | $x = 0 54 | class Foo 55 | macro inherited 56 | $x += 1 57 | end 58 | end 59 | 60 | class Bar < Foo 61 | end 62 | 63 | class Baz < Bar 64 | end 65 | 66 | $x 67 | ").to_i.should eq(2) 68 | end 69 | 70 | it "does inherited macro before class body" do 71 | run(" 72 | $x = 123 73 | class Foo 74 | macro inherited 75 | $y = $x 76 | end 77 | end 78 | 79 | class Bar < Foo 80 | $x += 1 81 | end 82 | 83 | $y 84 | ").to_i.should eq(123) 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /docs/main.cr: -------------------------------------------------------------------------------- 1 | require "../src/big_int/**" 2 | require "../src/crypto/**" 3 | require "../src/csv/**" 4 | require "../src/curses/**" 5 | require "../src/ecr" 6 | require "../src/event/**" 7 | require "../src/fiber/**" 8 | # require "../src/fs/fs" 9 | require "../src/gc/**" 10 | require "../src/html/**" 11 | require "../src/http/**" 12 | require "../src/io/**" 13 | require "../src/json/**" 14 | require "../src/llvm/**" 15 | require "../src/logger" 16 | require "../src/macros" 17 | require "../src/math/**" 18 | require "../src/markdown" 19 | require "../src/oauth/**" 20 | require "../src/oauth2/**" 21 | require "../src/openssl/**" 22 | require "../src/process/**" 23 | require "../src/regex/**" 24 | require "../src/socket/**" 25 | require "../src/spec/**" 26 | require "../src/string/**" 27 | require "../src/thread/**" 28 | require "../src/time/**" 29 | require "../src/xml/**" 30 | require "../src/yaml/**" 31 | require "../src/benchmark" 32 | require "../src/array" 33 | require "../src/bit_array" 34 | require "../src/box" 35 | require "../src/cgi" 36 | require "../src/colorize" 37 | require "../src/complex" 38 | require "../src/deque" 39 | require "../src/dl" 40 | require "../src/inifile" 41 | require "../src/levenshtein" 42 | require "../src/matrix" 43 | require "../src/option_parser" 44 | require "../src/partial_comparable" 45 | require "../src/readline" 46 | require "../src/secure_random" 47 | require "../src/signal" 48 | require "../src/simple_hash" 49 | require "../src/string_pool" 50 | require "../src/string_scanner" 51 | require "../src/tempfile" 52 | require "../src/uri" 53 | require "./macros" 54 | require "./char" 55 | -------------------------------------------------------------------------------- /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 | property :a 7 | property :b 8 | property :c 9 | end 10 | 11 | def item_check(tree) 12 | tree = tree.not_nil! 13 | return tree.b if tree.a.nil? 14 | tree.b + item_check(tree.a) - item_check(tree.c) 15 | end 16 | 17 | def bottom_up_tree(item, depth) 18 | return Node.new(nil, item, nil) unless depth > 0 19 | item_item = 2 * item 20 | depth -= 1 21 | Node.new(bottom_up_tree(item_item - 1, depth), item, bottom_up_tree(item_item, depth)) 22 | end 23 | 24 | max_depth = (ARGV[0]? || 15).to_i 25 | min_depth = 4 26 | 27 | max_depth = min_depth + 2 if min_depth + 2 > max_depth 28 | 29 | stretch_depth = max_depth + 1 30 | stretch_tree = bottom_up_tree(0, stretch_depth) 31 | 32 | puts "stretch tree of depth #{stretch_depth}\t check: #{item_check(stretch_tree)}" 33 | stretch_tree = nil 34 | 35 | long_lived_tree = bottom_up_tree(0, max_depth) 36 | 37 | min_depth.step(max_depth + 1, 2) do |depth| 38 | iterations = 2**(max_depth - depth + min_depth) 39 | 40 | check = 0 41 | 42 | (1..iterations).each do |i| 43 | temp_tree = bottom_up_tree(i, depth) 44 | check += item_check(temp_tree) 45 | 46 | temp_tree = bottom_up_tree(-i, depth) 47 | check += item_check(temp_tree) 48 | end 49 | 50 | puts "#{iterations * 2}\t trees of depth #{depth}\t check: #{check}" 51 | end 52 | 53 | puts "long lived tree of depth #{max_depth}\t check: #{item_check(long_lived_tree)}" 54 | -------------------------------------------------------------------------------- /spec/compiler/parser/to_s_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | private def expect_to_s(original, expected = original, file = __FILE__, line = __LINE__) 4 | it "does to_s of #{original.inspect}", file, line do 5 | Parser.parse(original).to_s.should eq(expected), file, line 6 | end 7 | end 8 | 9 | describe "ASTNode#to_s" do 10 | expect_to_s "([] of T).foo" 11 | expect_to_s "({} of K => V).foo" 12 | expect_to_s "foo(bar)" 13 | expect_to_s "(~1).foo" 14 | expect_to_s "1 && (a = 2)" 15 | expect_to_s "(a = 2) && 1" 16 | expect_to_s "foo(a as Int32)", "foo((a as Int32))" 17 | expect_to_s "@foo.bar" 18 | expect_to_s %(:foo) 19 | expect_to_s %(:"{") 20 | expect_to_s %(/hello world/) 21 | expect_to_s %(/\\s/) 22 | expect_to_s %(/\\?/) 23 | expect_to_s %(/\\(group\\)/) 24 | expect_to_s %(/\\//), "/\\//" 25 | expect_to_s %(/\#{1 / 2}/) 26 | expect_to_s %(foo &.bar), %(foo(&.bar)) 27 | expect_to_s %(foo &.bar(1, 2, 3)), %(foo(&.bar(1, 2, 3))) 28 | expect_to_s %(foo do |k, v|\n k.bar(1, 2, 3)\nend) 29 | expect_to_s %(foo(3, &.*(2))) 30 | expect_to_s %(return begin\n 1\n 2\nend) 31 | expect_to_s %(macro foo\n %bar = 1\nend) 32 | expect_to_s %(macro foo\n %bar = 1; end) 33 | expect_to_s %(macro foo\n %bar{1, x} = 1\nend) 34 | expect_to_s %({% foo %}) 35 | expect_to_s %({{ foo }}) 36 | expect_to_s %({% if foo %}\n foo_then\n{% end %}) 37 | expect_to_s %({% if foo %}\n foo_then\n{% else %}\n foo_else\n{% end %}) 38 | expect_to_s %({% for foo in bar %}\n {{ foo }}\n{% end %}) 39 | expect_to_s %(macro foo\n {% for foo in bar %}\n {{ foo }}\n {% end %}\nend) 40 | end 41 | -------------------------------------------------------------------------------- /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 = StringIO.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 | -------------------------------------------------------------------------------- /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.length > 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 length 67 | @matches.try(&.length) || 0 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/compiler/codegen/private_def_spec.cr: -------------------------------------------------------------------------------- 1 | require "../../spec_helper" 2 | 3 | describe "Codegen: private def" do 4 | it "codegens private def in same file" do 5 | compiler = Compiler.new 6 | sources = [ 7 | Compiler::Source.new("foo.cr", %( 8 | private def foo 9 | 1 10 | end 11 | 12 | foo 13 | )), 14 | ] 15 | compiler.prelude = "empty" 16 | 17 | tempfile = Tempfile.new("crystal-spec-output") 18 | output_filename = tempfile.path 19 | tempfile.close 20 | 21 | compiler.compile sources, output_filename 22 | end 23 | 24 | it "codegens overloaded private def in same file" do 25 | compiler = Compiler.new 26 | sources = [ 27 | Compiler::Source.new("foo.cr", %( 28 | private def foo(x : Int32) 29 | 1 30 | end 31 | 32 | private def foo(x : Char) 33 | 2 34 | end 35 | 36 | a = 3 || 'a' 37 | foo a 38 | )), 39 | ] 40 | compiler.prelude = "empty" 41 | 42 | tempfile = Tempfile.new("crystal-spec-output") 43 | output_filename = tempfile.path 44 | tempfile.close 45 | 46 | compiler.compile sources, output_filename 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /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/openssl/bio.cr: -------------------------------------------------------------------------------- 1 | require "./lib_crypto" 2 | 3 | # :nodoc: 4 | struct OpenSSL::BIO 5 | CRYSTAL_BIO = begin 6 | crystal_bio = LibCrypto::BioMethod.new 7 | crystal_bio.name = "Crystal BIO".cstr 8 | 9 | crystal_bio.bwrite = LibCrypto::BioMethodWrite.new do |bio, data, len| 10 | io = Box(IO).unbox(bio.value.ptr) 11 | io.write Slice.new(data, len) 12 | len 13 | end 14 | 15 | crystal_bio.bread = LibCrypto::BioMethodRead.new do |bio, buffer, len| 16 | io = Box(IO).unbox(bio.value.ptr) 17 | io.flush 18 | io.read(Slice.new(buffer, len)).to_i 19 | end 20 | 21 | crystal_bio.ctrl = LibCrypto::BioMethodCtrl.new do |bio, cmd, num, ptr| 22 | io = Box(IO).unbox(bio.value.ptr) 23 | 24 | val = case cmd 25 | when LibCrypto::CTRL_FLUSH 26 | io.flush 27 | 1 28 | when LibCrypto::CTRL_PUSH, LibCrypto::CTRL_POP 29 | 0 30 | else 31 | STDERR.puts "WARNING: Unsupported BIO ctrl call (#{cmd})" 32 | 0 33 | end 34 | LibCrypto::Long.cast(val) 35 | end 36 | 37 | crystal_bio.create = LibCrypto::BioMethodCreate.new do |bio| 38 | bio.value.shutdown = 1 39 | bio.value.init = 1 40 | bio.value.num = -1 41 | end 42 | 43 | crystal_bio.destroy = LibCrypto::BioMethodDestroy.new do |bio| 44 | bio.value.ptr = Pointer(Void).null; 45 | 1 46 | end 47 | 48 | crystal_bio 49 | end 50 | 51 | def initialize(io) 52 | @bio = LibCrypto.bio_new(pointerof(CRYSTAL_BIO)) 53 | @bio.value.ptr = @boxed_io = Box(IO).box(io) 54 | end 55 | 56 | def to_unsafe 57 | @bio 58 | end 59 | end 60 | --------------------------------------------------------------------------------