Skip to content

Commit

Permalink
Showing 8 changed files with 100 additions and 63 deletions.
16 changes: 16 additions & 0 deletions spec/std/concurrent_spec.cr
Original file line number Diff line number Diff line change
@@ -4,6 +4,10 @@ private def method_with_named_args(chan, x = 1, y = 2)
chan.send(x + y)
end

private def method_named(expected_named)
Fiber.current.name.should eq(expected_named)
end

describe "concurrent" do
it "does four things concurrently" do
a, b, c, d = parallel(1 + 2, "hello".size, [1, 2, 3, 4].size, nil)
@@ -25,4 +29,16 @@ describe "concurrent" do
spawn method_with_named_args(chan, x: 10, y: 20)
chan.receive.should eq(30)
end

it "spawns named" do
spawn(name: "sub") do
Fiber.current.name.should eq("sub")
end
Fiber.yield
end

it "spawns named with macro" do
spawn method_named("foo"), name: "foo"
Fiber.yield
end
end
2 changes: 1 addition & 1 deletion spec/std/ecr/ecr_lexer_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "spec"
require "ecr"
require "ecr/lexer"

describe "ECR::Lexer" do
it "lexes without interpolation" do
2 changes: 1 addition & 1 deletion spec/std/ecr/ecr_spec.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require "spec"
require "ecr"
require "ecr/macros"
require "ecr/processor"

class ECRSpecHelloView
@msg : String
8 changes: 4 additions & 4 deletions src/concurrent.cr
Original file line number Diff line number Diff line change
@@ -55,8 +55,8 @@ end
#
# 2.times { ch.receive }
# ```
def spawn(&block)
fiber = Fiber.new(&block)
def spawn(*, name : String? = nil, &block)
fiber = Fiber.new(name, &block)
Scheduler.enqueue fiber
fiber
end
@@ -91,7 +91,7 @@ end
# This is because in the first case all spawned fibers refer to
# the same local variable, while in the second example copies of
# `i` are passed to a Proc that eventually invokes the call.
macro spawn(call)
macro spawn(call, *, name = nil)
{% if call.is_a?(Call) %}
->(
{% for arg, i in call.args %}
@@ -103,7 +103,7 @@ macro spawn(call)
{% end %}
{% end %}
) {
spawn do
spawn(name: {{name}}) do
{{call.name}}(
{% for arg, i in call.args %}
__arg{{i}},
62 changes: 7 additions & 55 deletions src/ecr.cr
Original file line number Diff line number Diff line change
@@ -7,10 +7,10 @@
#
# Quick Example:
#
# require "ecr/macros"
# require "ecr"
#
# class Greeting
# def initialize(@name)
# def initialize(@name : String)
# end
#
# ECR.def_to_s "greeting.ecr"
@@ -36,11 +36,13 @@
#
# Using loops:
#
# require "ecr/macros"
# require "ecr"
#
# class Greeting
# @names : Array(String)
#
# def initialize(*names)
# @names = names
# @names = names.to_a
# end
#
# ECR.def_to_s "greeting.ecr"
@@ -58,56 +60,6 @@
#
# Likewise, other Crystal logic can be implemented in ECR text.
module ECR
extend self

DefaultBufferName = "__str__"

# :nodoc:
def process_file(filename, buffer_name = DefaultBufferName)
process_string File.read(filename), filename, buffer_name
end

# :nodoc:
def process_string(string, filename, buffer_name = DefaultBufferName)
lexer = Lexer.new string

String.build do |str|
while true
token = lexer.next_token
case token.type
when :STRING
str << buffer_name
str << " << "
token.value.inspect(str)
str << "\n"
when :OUTPUT
str << "("
append_loc(str, filename, token)
str << token.value
str << ").to_s "
str << buffer_name
str << "\n"
when :CONTROL
append_loc(str, filename, token)
str << " " unless token.value.starts_with?(' ')
str << token.value
str << "\n"
when :EOF
break
end
end
end
end

private def append_loc(str, filename, token)
str << %(#<loc:")
str << filename
str << %(",)
str << token.line_number
str << %(,)
str << token.column_number
str << %(>)
end
end

require "./ecr/lexer"
require "./ecr/macros"
2 changes: 1 addition & 1 deletion src/ecr/process.cr
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
require "ecr"
require "ecr/processor"
puts ECR.process_file(ARGV[0], ARGV[1])
54 changes: 54 additions & 0 deletions src/ecr/processor.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require "./ecr/lexer"

module ECR
extend self

DefaultBufferName = "__str__"

# :nodoc:
def process_file(filename, buffer_name = DefaultBufferName)
process_string File.read(filename), filename, buffer_name
end

# :nodoc:
def process_string(string, filename, buffer_name = DefaultBufferName)
lexer = Lexer.new string

String.build do |str|
while true
token = lexer.next_token
case token.type
when :STRING
str << buffer_name
str << " << "
token.value.inspect(str)
str << "\n"
when :OUTPUT
str << "("
append_loc(str, filename, token)
str << token.value
str << ").to_s "
str << buffer_name
str << "\n"
when :CONTROL
append_loc(str, filename, token)
str << " " unless token.value.starts_with?(' ')
str << token.value
str << "\n"
when :EOF
break
end
end
end
end

private def append_loc(str, filename, token)
str << %(#<loc:")
str << filename
str << %(",)
str << token.line_number
str << %(,)
str << token.column_number
str << %(>)
end
end
17 changes: 16 additions & 1 deletion src/fiber.cr
Original file line number Diff line number Diff line change
@@ -20,8 +20,9 @@ class Fiber
protected property stack_bottom : Void*
protected property next_fiber : Fiber?
protected property prev_fiber : Fiber?
property name : String?

def initialize(&@proc : ->)
def initialize(@name : String? = nil, &@proc : ->)
@stack = Fiber.allocate_stack
@stack_bottom = @stack + STACK_SIZE
fiber_main = ->(f : Fiber) { f.run }
@@ -64,6 +65,7 @@ class Fiber
@stack = Pointer(Void).null
@stack_top = _fiber_get_stack_top
@stack_bottom = LibGC.stackbottom
@name = "main"

@@first_fiber = @@last_fiber = self
end
@@ -183,6 +185,19 @@ class Fiber
Fiber.current.yield
end

def to_s(io)
io << "#<" << self.class.name << ":0x"
object_id.to_s(16, io)
if name = @name
io << ": " << name
end
io << ">"
end

def inspect(io)
to_s(io)
end

protected def push_gc_roots
# Push the used section of the stack
LibGC.push_all_eager @stack_top, @stack_bottom

0 comments on commit 2f40a7b

Please sign in to comment.