├── 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 |
4 | <% other_types.each_with_index do |other_type, i| %>
5 | - <%= other_type.link_from(type) %>
6 | <% end %>
7 |
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 |
2 | <% types.each do |type| %>
3 | - <%= type.current?(current_type) ? "current" : "" %>" data-id="<%= type.html_id %>" data-name="<%= type.full_name.downcase %>">
4 | <%= type.name %>
5 | <% unless type.program? || type.types.empty? %>
6 | <%= ListItemsTemplate.new(type.types, current_type) %>
7 | <% end %>
8 |
9 | <% end %>
10 |
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 |
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 |
14 |
15 |
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 |
--------------------------------------------------------------------------------